blob: d5a1d7845452ab9076456e3a5761f04da82e4aea [file] [log] [blame]
Simon Glass89b86b82011-07-17 23:49:49 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This module builds a firmware image for a tegra-based board.
6
7This modules uses a few rudimentary other libraries for its activity.
8
9Here are the names we give to the various files we deal with. It is important
10to keep these consistent!
11
12 uboot u-boot.bin (with no device tree)
13 fdt the fdt blob
14 bct the BCT file
15 bootstub uboot + fdt
16 signed (uboot + fdt + bct) signed blob
17"""
18
Simon Glassceff3ff2012-04-04 11:23:45 -070019import glob
Simon Glass89b86b82011-07-17 23:49:49 -070020import os
21import re
22
23import cros_output
24from fdt import Fdt
25from pack_firmware import PackFirmware
26import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080027import struct
Simon Glass89b86b82011-07-17 23:49:49 -070028import tempfile
Simon Glass439fe7a2012-03-09 16:19:34 -080029from tools import CmdError
Simon Glass89b86b82011-07-17 23:49:49 -070030from tools import Tools
31from write_firmware import WriteFirmware
32
33# This data is required by bmpblk_utility. Does it ever change?
34# It was stored with the chromeos-bootimage ebuild, but we want
35# this utility to work outside the chroot.
36yaml_data = '''
37bmpblock: 1.0
38
39images:
40 devmode: DeveloperBmp/DeveloperBmp.bmp
41 recovery: RecoveryBmp/RecoveryBmp.bmp
42 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
43 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
44
45screens:
46 dev_en:
47 - [0, 0, devmode]
48 rec_en:
49 - [0, 0, recovery]
50 yuck_en:
51 - [0, 0, rec_yuck]
52 ins_en:
53 - [0, 0, rec_insert]
54
55localizations:
56 - [ dev_en, rec_en, yuck_en, ins_en ]
57'''
58
59class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070060 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070061
Simon Glass290a1802011-07-17 13:54:32 -070062 Sequence of events:
63 bundle = Bundle(tools.Tools(), cros_output.Output())
64 bundle.SetDirs(...)
65 bundle.SetFiles(...)
66 bundle.SetOptions(...)
67 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070068 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070069 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070070
Simon Glass290a1802011-07-17 13:54:32 -070071 Public properties:
72 fdt: The fdt object that we use for building our image. This wil be the
73 one specified by the user, except that we might add config options
74 to it. This is set up by SelectFdt() which must be called before
75 bundling starts.
76 uboot_fname: Full filename of the U-Boot binary we use.
77 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -070078 spl_source: Source device to load U-Boot from, in SPL:
79 straps: Select device according to CPU strap pins
80 spi: Boot from SPI
81 emmc: Boot from eMMC
Simon Glass290a1802011-07-17 13:54:32 -070082 """
Simon Glass89b86b82011-07-17 23:49:49 -070083
Simon Glass290a1802011-07-17 13:54:32 -070084 def __init__(self, tools, output):
85 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -070086
Simon Glass290a1802011-07-17 13:54:32 -070087 Args:
88 tools: A tools.Tools object to use for external tools.
89 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -070090 """
Simon Glass290a1802011-07-17 13:54:32 -070091 self._tools = tools
92 self._out = output
93
94 # Set up the things we need to know in order to operate.
95 self._board = None # Board name, e.g. tegra2_seaboard.
96 self._fdt_fname = None # Filename of our FDT.
97 self.uboot_fname = None # Filename of our U-Boot binary.
98 self.bct_fname = None # Filename of our BCT file.
99 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800100 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700101 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -0700102 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -0700103 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
104 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass559b6612012-05-23 13:28:45 -0700105 self.spl_source = 'straps' # SPL boot according to board settings
Simon Glass07267952012-06-08 12:45:13 -0700106 self.skeleton_fname = None # Filename of Coreboot skeleton file
Simon Glassf0cf8b92012-06-21 08:17:30 -0700107 self.ecbin_fname = None # Filename of EC file
Simon Glass290a1802011-07-17 13:54:32 -0700108
109 def SetDirs(self, keydir):
110 """Set up directories required for Bundle.
111
112 Args:
113 keydir: Directory containing keys to use for signing firmware.
114 """
115 self._keydir = keydir
116
Simon Glass6dcc2f22011-07-28 15:26:49 +1200117 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glass07267952012-06-08 12:45:13 -0700118 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassde9c8072012-07-02 22:29:02 -0700119 skeleton=None, ecbin=None, kernel=None):
Simon Glass290a1802011-07-17 13:54:32 -0700120 """Set up files required for Bundle.
121
122 Args:
123 board: The name of the board to target (e.g. tegra2_seaboard).
124 uboot: The filename of the u-boot.bin image to use.
125 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800126 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700127 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200128 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700129 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700130 exynos_bl1: The filename of the exynos BL1 file
131 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
132 skeleton: The filename of the coreboot skeleton file.
Simon Glassf0cf8b92012-06-21 08:17:30 -0700133 ecbin: The filename of the EC (Embedded Controller) file.
Simon Glassde9c8072012-07-02 22:29:02 -0700134 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700135 """
136 self._board = board
137 self.uboot_fname = uboot
138 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800139 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700140 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200141 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700142 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700143 self.exynos_bl1 = exynos_bl1
144 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700145 self.skeleton_fname = skeleton
Simon Glassf0cf8b92012-06-21 08:17:30 -0700146 self.ecbin_fname = ecbin
Simon Glassde9c8072012-07-02 22:29:02 -0700147 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700148
149 def SetOptions(self, small):
150 """Set up options supported by Bundle.
151
152 Args:
153 small: Only create a signed U-Boot - don't produce the full packed
154 firmware image. This is useful for devs who want to replace just the
155 U-Boot part while keeping the keys, gbb, etc. the same.
156 """
157 self._small = small
158
159 def CheckOptions(self):
160 """Check provided options and select defaults."""
161 if not self._board:
162 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700163 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700164 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700165 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700166 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700167 base_name = re.sub('_', '-', self._board)
168
169 # In case the name exists with a prefix or suffix, find it.
170 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
171 found_list = glob.glob(self._tools.Filename(wildcard))
172 if len(found_list) == 1:
173 self._fdt_fname = found_list[0]
174 else:
175 # We didn't find anything definite, so set up our expected name.
176 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
177
Simon Glass881964d2012-04-04 11:34:09 -0700178 # Convert things like 'exynos5250-daisy' into a full path.
179 root, ext = os.path.splitext(self._fdt_fname)
180 if not ext and not os.path.dirname(root):
181 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
182
Simon Glass290a1802011-07-17 13:54:32 -0700183 if not self.uboot_fname:
184 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
185 if not self.bct_fname:
186 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700187 if not self.bmpblk_fname:
188 self.bmpblk_fname = os.path.join(build_root, 'default.bmpblk')
Simon Glass1d376832012-03-15 20:50:54 -0700189 if not self.exynos_bl1:
190 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
191 if not self.exynos_bl2:
192 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700193 if not self.coreboot_fname:
194 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
195 if not self.skeleton_fname:
196 self.skeleton_fname = os.path.join(build_root, 'skeleton.bin')
Simon Glassf0cf8b92012-06-21 08:17:30 -0700197 if not self.ecbin_fname:
198 self.ecbin_fname = os.path.join(build_root, 'ec.RW.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700199
Simon Glass75759302012-03-15 20:26:53 -0700200 def GetFiles(self):
201 """Get a list of files that we know about.
202
203 This is the opposite of SetFiles except that we may have put in some
204 default names. It returns a dictionary containing the filename for
205 each of a number of pre-defined files.
206
207 Returns:
208 Dictionary, with one entry for each file.
209 """
210 file_list = {
211 'bct' : self.bct_fname,
212 'exynos-bl1' : self.exynos_bl1,
213 'exynos-bl2' : self.exynos_bl2,
214 }
215 return file_list
216
Simon Glass56577572011-07-19 11:08:06 +1200217 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700218 """Create a GBB for the image.
219
Simon Glass56577572011-07-19 11:08:06 +1200220 Args:
221 hardware_id: Hardware ID to use for this board. If None, then the
222 default from the Fdt will be used
223
Simon Glass89b86b82011-07-17 23:49:49 -0700224 Returns:
225 Path of the created GBB file.
226
227 Raises:
228 CmdError if a command fails.
229 """
Simon Glass56577572011-07-19 11:08:06 +1200230 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800231 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700232 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700233 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700234
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800235 chromeos_config = self.fdt.GetProps("/chromeos-config")
Hung-Te Linec76cb62012-07-18 15:11:39 +0800236 # Build GBB flags.
237 # (src/platform/vboot_reference/firmware/include/gbb_header.h)
238 flag_properties = {
239 'fast-developer-mode': 0x01,
240 'gbb-flag-dev-screen-short-delay': 0x00000001,
241 'gbb-flag-load-option-roms': 0x00000002,
242 'gbb-flag-enable-alternate-os': 0x00000004,
243 'gbb-flag-force-dev-switch-on': 0x00000008,
244 'gbb-flag-force-dev-boot-usb': 0x00000010,
245 'gbb-flag-disable-fw-rollback-check': 0x00000020,
246 }
247 gbb_flags = 0
248 for flag_name, flag_value in flag_properties.items():
249 if flag_name not in chromeos_config:
250 continue
251 gbb_flags |= flag_value
252 self._out.Notice("Enabling %s." % flag_name)
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800253
Simon Glass89b86b82011-07-17 23:49:49 -0700254 self._out.Progress('Creating GBB')
255 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
256 sizes = ['%#x' % size for size in sizes]
257 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700258 keydir = self._tools.Filename(self._keydir)
259 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700260 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200261 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700262 '--rootkey=%s/root_key.vbpubk' % keydir,
263 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700264 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800265 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700266 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700267 cwd=odir)
268 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700269
Simon Glasse13ee2c2011-07-28 08:12:28 +1200270 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700271 """Sign an image so that the Tegra SOC will boot it.
272
273 Args:
274 bct: BCT file to use.
275 bootstub: Boot stub (U-Boot + fdt) file to sign.
276 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700277
278 Returns:
279 filename of signed image.
280
281 Raises:
282 CmdError if a command fails.
283 """
284 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200285 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700286 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200287 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700288 fd = open(config, 'w')
289 fd.write('Version = 1;\n')
290 fd.write('Redundancy = 1;\n')
291 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700292
293 # TODO(dianders): Right now, we don't have enough space in our flash map
294 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
295 # sure what this does for reliability, but at least things will fit...
296 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
297 if is_nand:
298 fd.write('Bctcopy = 1;\n')
299
Simon Glass89b86b82011-07-17 23:49:49 -0700300 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
301 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700302
Simon Glass89b86b82011-07-17 23:49:49 -0700303 fd.close()
304
305 self._tools.Run('cbootimage', [config, signed])
306 self._tools.OutputSize('BCT', bct)
307 self._tools.OutputSize('Signed image', signed)
308 return signed
309
Doug Anderson86ce5f42011-07-27 10:40:18 -0700310 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700311 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700312
313 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700314 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700315 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700316 """
Simon Glass290a1802011-07-17 13:54:32 -0700317 if bootcmd:
Simon Glass02d124a2012-03-02 14:47:20 -0800318 self.fdt.PutString('/config', 'bootcmd', bootcmd)
319 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700320 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700321
Simon Glassa4934b72012-05-09 13:35:02 -0700322 def SetNodeEnabled(self, node_name, enabled):
323 """Set whether an node is enabled or disabled.
324
325 This simply sets the 'status' property of a node to "ok", or "disabled".
326
327 The node should either be a full path to the node (like '/uart@10200000')
328 or an alias property.
329
330 Aliases are supported like this:
331
332 aliases {
333 console = "/uart@10200000";
334 };
335
336 pointing to a node:
337
338 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700339 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700340 };
341
342 In this case, this function takes the name of the alias ('console' in
343 this case) and updates the status of the node that is pointed to, to
344 either ok or disabled. If the alias does not exist, a warning is
345 displayed.
346
347 Args:
348 node_name: Name of node (e.g. '/uart@10200000') or alias alias
349 (e.g. 'console') to adjust
350 enabled: True to enable, False to disable
351 """
352 # Look up the alias if this is an alias reference
353 if not node_name.startswith('/'):
354 lookup = self.fdt.GetString('/aliases', node_name, '')
355 if not lookup:
356 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
357 return
358 node_name = lookup
359 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700360 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700361 else:
362 status = 'disabled'
363 self.fdt.PutString(node_name, 'status', status)
364
365 def AddEnableList(self, enable_list):
366 """Process a list of nodes to enable/disable.
367
368 Args:
369 config_list: List of (node, value) tuples to add to the fdt. For each
370 tuple:
371 node: The fdt node to write to will be <node> or pointed to by
372 /aliases/<node>. We can tell which
373 value: 0 to disable the node, 1 to enable it
374 """
375 if enable_list:
376 for node_name, enabled in enable_list:
377 try:
378 enabled = int(enabled)
379 if enabled not in (0, 1):
380 raise ValueError
381 except ValueError as str:
382 raise CmdError("Invalid enable option value '%s' "
383 "(should be 0 or 1)" % enabled)
384 self.SetNodeEnabled(node_name, enabled)
385
Simon Glass290a1802011-07-17 13:54:32 -0700386 def AddConfigList(self, config_list, use_int=False):
387 """Add a list of config items to the fdt.
388
389 Normally these values are written to the fdt as strings, but integers
390 are also supported, in which case the values will be converted to integers
391 (if necessary) before being stored.
392
393 Args:
394 config_list: List of (config, value) tuples to add to the fdt. For each
395 tuple:
396 config: The fdt node to write to will be /config/<config>.
397 value: An integer or string value to write.
398 use_int: True to only write integer values.
399
400 Raises:
401 CmdError: if a value is required to be converted to integer but can't be.
402 """
403 if config_list:
404 for config in config_list:
405 value = config[1]
406 if use_int:
407 try:
408 value = int(value)
409 except ValueError as str:
410 raise CmdError("Cannot convert config option '%s' to integer" %
411 value)
412 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800413 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700414 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800415 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700416
Simon Glass7c2d5572011-11-15 14:47:08 -0800417 def DecodeTextBase(self, data):
418 """Look at a U-Boot image and try to decode its TEXT_BASE.
419
420 This works because U-Boot has a header with the value 0x12345678
421 immediately followed by the TEXT_BASE value. We can therefore read this
422 from the image with some certainty. We check only the first 40 words
423 since the header should be within that region.
424
Simon Glass96b50302012-07-20 06:55:28 +0100425 Since upstream Tegra has moved to having a 16KB SPL region at the start,
426 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
427 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
428
Simon Glass7c2d5572011-11-15 14:47:08 -0800429 Args:
430 data: U-Boot binary data
431
432 Returns:
433 Text base (integer) or None if none was found
434 """
435 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100436 for start in (0, 0x4000):
437 for i in range(start, start + 160, 4):
438 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800439
Simon Glass96b50302012-07-20 06:55:28 +0100440 # TODO(sjg): This does not cope with a big-endian target
441 value = struct.unpack('<I', word)[0]
442 if found:
443 return value - start
444 if value == 0x12345678:
445 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800446
447 return None
448
449 def CalcTextBase(self, name, fdt, fname):
450 """Calculate the TEXT_BASE to use for U-Boot.
451
452 Normally this value is in the fdt, so we just read it from there. But as
453 a second check we look at the image itself in case this is different, and
454 switch to that if it is.
455
456 This allows us to flash any U-Boot even if its TEXT_BASE is different.
457 This is particularly useful with upstream U-Boot which uses a different
458 value (which we will move to).
459 """
460 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200461 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800462 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100463 text_base_str = '%#x' % text_base if text_base else 'None'
464 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
465 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800466
467 # If they are different, issue a warning and switch over.
468 if text_base and text_base != fdt_text_base:
469 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
470 "fdt value of %x. Using %x" % (text_base, name,
471 fdt_text_base, text_base))
472 fdt_text_base = text_base
473 return fdt_text_base
474
Simon Glass6dcc2f22011-07-28 15:26:49 +1200475 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700476 """Create a boot stub and a signed boot stub.
477
Simon Glass6dcc2f22011-07-28 15:26:49 +1200478 For postload:
479 We add a /config/postload-text-offset entry to the signed bootstub's
480 fdt so that U-Boot can find the postload code.
481
482 The raw (unsigned) bootstub will have a value of -1 for this since we will
483 simply append the postload code to the bootstub and it can find it there.
484 This will be used for RW A/B firmware.
485
486 For the signed case this value will specify where in the flash to find
487 the postload code. This will be used for RO firmware.
488
Simon Glass89b86b82011-07-17 23:49:49 -0700489 Args:
490 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800491 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200492 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700493
494 Returns:
495 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200496 Full path to bootstub (uboot + fdt(-1) + postload).
497 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700498
499 Raises:
500 CmdError if a command fails.
501 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200502 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800503 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700504 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200505
506 # Make a copy of the fdt for the bootstub
507 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800508 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700509 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200510
Simon Glass89b86b82011-07-17 23:49:49 -0700511 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700512 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
513 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700514 self._tools.OutputSize('Combined binary', bootstub)
515
Simon Glasse13ee2c2011-07-28 08:12:28 +1200516 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700517 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700518 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200519 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200520
521 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
522 data = self._tools.ReadFile(signed)
523
524 if postload:
525 # We must add postload to the bootstub since A and B will need to
526 # be able to find it without the /config/postload-text-offset mechanism.
527 bs_data = self._tools.ReadFile(bootstub)
528 bs_data += self._tools.ReadFile(postload)
529 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
530 self._tools.WriteFile(bootstub, bs_data)
531 self._tools.OutputSize('Combined binary with postload', bootstub)
532
533 # Now that we know the file size, adjust the fdt and re-sign
534 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800535 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200536 fdt_data = self._tools.ReadFile(fdt.fname)
537 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
538 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
539 postload_bootstub, text_base)
540 if len(data) != os.path.getsize(signed):
541 raise CmdError('Signed file size changed from %d to %d after updating '
542 'fdt' % (len(data), os.path.getsize(signed)))
543
544 # Re-read the signed image, and add the post-load binary.
545 data = self._tools.ReadFile(signed)
546 data += self._tools.ReadFile(postload)
547 self._tools.OutputSize('Post-load binary', postload)
548
549 self._tools.WriteFile(signed_postload, data)
550 self._tools.OutputSize('Final bootstub with postload', signed_postload)
551
552 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700553
Simon Glasscbc83552012-07-23 15:26:22 +0100554 def _CreateCorebootStub(self, uboot, coreboot, seabios):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700555 """Create a coreboot boot stub.
556
557 Args:
558 uboot: Path to u-boot.bin (may be chroot-relative)
559 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700560 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700561
562 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100563 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700564
565 Raises:
566 CmdError if a command fails.
567 """
568 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700569
570 # U-Boot itself does not put a .elf extension on the elf file.
571 # The U-Boot ebuild does, but we shouldn't actually require it since
572 # devs may want to just use what U-Boot creates.
573 uboot_elf = uboot.replace('.bin', '')
574 if not os.path.exists(self._tools.Filename(uboot_elf)):
575 uboot_elf = uboot.replace('.bin', '.elf')
576 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Vincent Palatinf7286772011-10-12 14:31:53 -0700577 if seabios:
Simon Glass146cb8e2012-03-09 15:51:24 -0800578 self._tools.Run('cbfstool', [bootstub, 'add-payload', seabios,
Vincent Palatinf7286772011-10-12 14:31:53 -0700579 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800580 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700581 'img/U-Boot', 'lzma'])
582 else:
Simon Glass146cb8e2012-03-09 15:51:24 -0800583 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700584 'fallback/payload', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100585
586 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700587 return bootstub
588
Simon Glass3b404092012-05-23 13:10:36 -0700589 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700590 """Update the parameters in a BL2 blob.
591
592 We look at the list in the parameter block, extract the value of each
593 from the device tree, and write that value to the parameter block.
594
595 Args:
596 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700597 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700598 data: The BL2 data.
599 pos: The position of the start of the parameter block.
600
601 Returns:
602 The new contents of the parameter block, after updating.
603 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700604 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
605 if version != 1:
606 raise CmdError("Cannot update machine parameter block version '%d'" %
607 version)
608 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700609 raise CmdError("Machine parameter block size %d is invalid: "
610 "pos=%d, size=%d, space=%d, len=%d" %
611 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700612
613 # Move past the header and read the parameter list, which is terminated
614 # with \0.
615 pos += 12
616 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
617 param_len = param_list.find('\0')
618 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700619 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700620
621 # Work through the parameters one at a time, adding each value
622 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700623 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700624 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700625 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700626 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700627 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700628 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
629 if not mem_type in mem_types:
630 raise CmdError("Unknown memory type '%s'" % mem_type)
631 value = mem_types.index(mem_type)
632 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700633 elif param == 'M' :
634 mem_manuf = fdt.GetString('/dmc', 'mem-manuf')
635 mem_manufs = ['autodetect', 'elpida', 'samsung']
636 if not mem_manuf in mem_manufs:
637 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
638 value = mem_manufs.index(mem_manuf)
639 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glassdf95dd22012-03-13 15:46:16 -0700640 elif param == 'v':
641 value = 31
642 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700643 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700644 value = (spl_load_size + 0xfff) & ~0xfff
645 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
646 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700647 elif param == 'b':
648 # These values come from enum boot_mode in U-Boot's cpu.h
649 if self.spl_source == 'straps':
650 value = 32
651 elif self.spl_source == 'emmc':
652 value = 4
653 elif self.spl_source == 'spi':
654 value = 20
655 elif self.spl_source == 'usb':
656 value = 33
657 else:
658 raise CmdError("Invalid boot source '%s'" % self.spl_source)
659 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700660 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700661 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700662 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700663 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700664 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700665
666 # Put the data into our block.
667 data = data[:pos] + new_data + data[pos + len(new_data):]
668 self._out.Info('BL2 configuration complete')
669 return data
670
Simon Glasse5e8afb2012-05-23 11:19:23 -0700671 def _UpdateChecksum(self, data):
672 """Update the BL2 checksum.
673
674 The checksum is a 4 byte sum of all the bytes in the image before the
675 last 4 bytes (which hold the checksum).
676
677 Args:
678 data: The BL2 data to update.
679
680 Returns:
681 The new contents of the BL2 data, after updating the checksum.
682 """
683 checksum = 0
684 for ch in data[:-4]:
685 checksum += ord(ch)
686 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
687
Simon Glass559b6612012-05-23 13:28:45 -0700688 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700689 """Configure an Exynos BL2 binary for our needs.
690
691 We create a new modified BL2 and return its filename.
692
693 Args:
694 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700695 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700696 orig_bl2: Filename of original BL2 file to modify.
697 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700698 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700699 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700700 data = self._tools.ReadFile(orig_bl2)
701 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700702
703 # Locate the parameter block
704 data = self._tools.ReadFile(bl2)
705 marker = struct.pack('<L', 0xdeadbeef)
706 pos = data.rfind(marker)
707 if not pos:
708 raise CmdError("Could not find machine parameter block in '%s'" %
709 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700710 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700711 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700712 self._tools.WriteFile(bl2, data)
713 return bl2
714
Simon Glass89b86b82011-07-17 23:49:49 -0700715 def _PackOutput(self, msg):
716 """Helper function to write output from PackFirmware (verbose level 2).
717
718 This is passed to PackFirmware for it to use to write output.
719
720 Args:
721 msg: Message to display.
722 """
723 self._out.Notice(msg)
724
Simon Glass439fe7a2012-03-09 16:19:34 -0800725 def _BuildBlob(self, pack, fdt, blob_type):
726 """Build the blob data for a particular blob type.
727
728 Args:
729 blob_type: The type of blob to create data for. Supported types are:
730 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
731 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
732 """
733 if blob_type == 'coreboot':
734 coreboot = self._CreateCorebootStub(self.uboot_fname,
Simon Glasscbc83552012-07-23 15:26:22 +0100735 self.coreboot_fname, self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800736 pack.AddProperty('coreboot', coreboot)
737 pack.AddProperty('image', coreboot)
738 elif blob_type == 'signed':
739 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
740 self.postload_fname)
741 pack.AddProperty('bootstub', bootstub)
742 pack.AddProperty('signed', signed)
743 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700744 elif blob_type == 'exynos-bl1':
745 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassf0cf8b92012-06-21 08:17:30 -0700746 elif blob_type == 'ecbin':
747 pack.AddProperty(blob_type, self.ecbin_fname)
Simon Glass7e199222012-03-13 15:51:18 -0700748 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700749 spl_payload = pack.GetBlobParams(blob_type)
750
751 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
752 # from all flash map files.
753 if not spl_payload:
754 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
755 prop_list = 'boot+dtb'
756
757 # Do this later, when we remove boot+dtb.
758 # raise CmdError("No parameters provided for blob type '%s'" %
759 # blob_type)
760 else:
761 prop_list = spl_payload[0].split(',')
762 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
763 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
764 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700765 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700766 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800767 elif pack.GetProperty(blob_type):
768 pass
769 else:
770 raise CmdError("Unknown blob type '%s' required in flash map" %
771 blob_type)
772
Simon Glass290a1802011-07-17 13:54:32 -0700773 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700774 """Create a full firmware image, along with various by-products.
775
776 This uses the provided u-boot.bin, fdt and bct to create a firmware
777 image containing all the required parts. If the GBB is not supplied
778 then this will just return a signed U-Boot as the image.
779
780 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200781 gbb: Full path to the GBB file, or empty if a GBB is not required.
782 fdt: Fdt object containing required information.
783
784 Returns:
785 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700786
787 Raises:
788 CmdError if a command fails.
789 """
Simon Glass02d124a2012-03-02 14:47:20 -0800790 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700791
Simon Glass439fe7a2012-03-09 16:19:34 -0800792 # Get the flashmap so we know what to build
793 pack = PackFirmware(self._tools, self._out)
794 pack.SelectFdt(fdt)
795
796 # Get all our blobs ready
797 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700798 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700799 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700800
Simon Glassde9c8072012-07-02 22:29:02 -0700801 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
802 if self.kernel_fname:
803 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
804
Simon Glass50f74602012-03-15 21:04:25 -0700805 # Make a copy of the fdt for the bootstub
806 fdt_data = self._tools.ReadFile(fdt.fname)
807 uboot_data = self._tools.ReadFile(self.uboot_fname)
808 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
809 self._tools.WriteFile(uboot_copy, uboot_data)
810
811 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
812 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700813
814 # TODO(sjg@chromium.org): Deprecate this property when all boards
815 # use a comma-separated list for section contents. We will then
816 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700817 pack.AddProperty('boot+dtb', bootstub)
818
Simon Glass439fe7a2012-03-09 16:19:34 -0800819 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100820 blob_list = pack.GetBlobList()
821 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700822 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800823 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700824
825 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700826 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800827 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800828 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800829 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700830 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800831 pack.AddProperty('fwid', fwid)
832 pack.AddProperty('gbb', gbb)
833 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700834
835 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700836
837 # Record position and size of all blob members in the FDT
838 pack.UpdateBlobPositions(fdt)
839
Simon Glasscbc83552012-07-23 15:26:22 +0100840 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
841 # has created a rom file without the dtb, because until now it is not
842 # complete. Add the dtb here.
843 # A better anwer might be to put the dtb in memory immediately after
844 # U-Boot as is done for ARM and have coreboot load it as a binary file
845 # instead of an elf. However, I need to check whether coreboot supports
846 # this, and whether this is desirable for other reasons.
847 if 'coreboot' in blob_list:
848 bootstub = pack.GetProperty('coreboot')
849 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
850 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
851 '0xac'])
852
Simon Glassc90cf582012-03-13 15:40:47 -0700853 image = os.path.join(self._tools.outdir, 'image.bin')
854 pack.PackImage(self._tools.outdir, image)
855 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700856
Simon Glass439fe7a2012-03-09 16:19:34 -0800857 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700858 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700859 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700860
Simon Glass290a1802011-07-17 13:54:32 -0700861 def SelectFdt(self, fdt_fname):
862 """Select an FDT to control the firmware bundling
863
864 Args:
865 fdt_fname: The filename of the fdt to use.
866
Simon Glassc0f3dc62011-08-09 14:19:05 -0700867 Returns:
868 The Fdt object of the original fdt file, which we will not modify.
869
Simon Glass290a1802011-07-17 13:54:32 -0700870 We make a copy of this which will include any on-the-fly changes we want
871 to make.
872 """
873 self._fdt_fname = fdt_fname
874 self.CheckOptions()
875 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800876 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700877 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700878 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700879
Simon Glassc90cf582012-03-13 15:40:47 -0700880 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -0700881 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700882
883 - Checks options, tools, output directory, fdt.
884 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700885
886 Args:
Simon Glass56577572011-07-19 11:08:06 +1200887 hardware_id: Hardware ID to use for this board. If None, then the
888 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700889 output_fname: Output filename for the image. If this is not None, then
890 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -0700891 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -0700892
893 Returns:
894 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700895 """
Simon Glass89b86b82011-07-17 23:49:49 -0700896 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700897 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200898 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700899
900 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -0700901 image, pack = self._CreateImage(gbb, self.fdt)
902 if show_map:
903 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -0700904 if output_fname:
905 shutil.copyfile(image, output_fname)
906 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -0700907 return image, pack.props