blob: a22077a7554c01bcb13c419e4b71fbcc86a34fd8 [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 Glassbe0bc002012-08-16 12:50:48 -0700107 self.ecrw_fname = None # Filename of EC file
108 self.ecro_fname = None # Filename of EC read-only file
Simon Glass290a1802011-07-17 13:54:32 -0700109
110 def SetDirs(self, keydir):
111 """Set up directories required for Bundle.
112
113 Args:
114 keydir: Directory containing keys to use for signing firmware.
115 """
116 self._keydir = keydir
117
Simon Glass6dcc2f22011-07-28 15:26:49 +1200118 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glass07267952012-06-08 12:45:13 -0700119 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassbe0bc002012-08-16 12:50:48 -0700120 skeleton=None, ecrw=None, ecro=None, kernel=None):
Simon Glass290a1802011-07-17 13:54:32 -0700121 """Set up files required for Bundle.
122
123 Args:
124 board: The name of the board to target (e.g. tegra2_seaboard).
125 uboot: The filename of the u-boot.bin image to use.
126 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800127 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700128 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200129 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700130 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700131 exynos_bl1: The filename of the exynos BL1 file
132 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
133 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700134 ecrw: The filename of the EC (Embedded Controller) read-write file.
135 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700136 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700137 """
138 self._board = board
139 self.uboot_fname = uboot
140 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800141 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700142 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200143 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700144 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700145 self.exynos_bl1 = exynos_bl1
146 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700147 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700148 self.ecrw_fname = ecrw
149 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700150 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700151
152 def SetOptions(self, small):
153 """Set up options supported by Bundle.
154
155 Args:
156 small: Only create a signed U-Boot - don't produce the full packed
157 firmware image. This is useful for devs who want to replace just the
158 U-Boot part while keeping the keys, gbb, etc. the same.
159 """
160 self._small = small
161
162 def CheckOptions(self):
163 """Check provided options and select defaults."""
164 if not self._board:
165 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700166 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700167 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700168 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700169 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700170 base_name = re.sub('_', '-', self._board)
171
172 # In case the name exists with a prefix or suffix, find it.
173 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
174 found_list = glob.glob(self._tools.Filename(wildcard))
175 if len(found_list) == 1:
176 self._fdt_fname = found_list[0]
177 else:
178 # We didn't find anything definite, so set up our expected name.
179 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
180
Simon Glass881964d2012-04-04 11:34:09 -0700181 # Convert things like 'exynos5250-daisy' into a full path.
182 root, ext = os.path.splitext(self._fdt_fname)
183 if not ext and not os.path.dirname(root):
184 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
185
Simon Glass290a1802011-07-17 13:54:32 -0700186 if not self.uboot_fname:
187 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
188 if not self.bct_fname:
189 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700190 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700191 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700192 if not self.exynos_bl1:
193 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
194 if not self.exynos_bl2:
195 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700196 if not self.coreboot_fname:
197 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
198 if not self.skeleton_fname:
199 self.skeleton_fname = os.path.join(build_root, 'skeleton.bin')
Simon Glassbe0bc002012-08-16 12:50:48 -0700200 if not self.ecrw_fname:
201 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
202 if not self.ecro_fname:
203 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700204
Simon Glass75759302012-03-15 20:26:53 -0700205 def GetFiles(self):
206 """Get a list of files that we know about.
207
208 This is the opposite of SetFiles except that we may have put in some
209 default names. It returns a dictionary containing the filename for
210 each of a number of pre-defined files.
211
212 Returns:
213 Dictionary, with one entry for each file.
214 """
215 file_list = {
216 'bct' : self.bct_fname,
217 'exynos-bl1' : self.exynos_bl1,
218 'exynos-bl2' : self.exynos_bl2,
219 }
220 return file_list
221
Simon Glass56577572011-07-19 11:08:06 +1200222 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700223 """Create a GBB for the image.
224
Simon Glass56577572011-07-19 11:08:06 +1200225 Args:
226 hardware_id: Hardware ID to use for this board. If None, then the
227 default from the Fdt will be used
228
Simon Glass89b86b82011-07-17 23:49:49 -0700229 Returns:
230 Path of the created GBB file.
231
232 Raises:
233 CmdError if a command fails.
234 """
Simon Glass56577572011-07-19 11:08:06 +1200235 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800236 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700237 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700238 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700239
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800240 chromeos_config = self.fdt.GetProps("/chromeos-config")
Hung-Te Linec76cb62012-07-18 15:11:39 +0800241 # Build GBB flags.
242 # (src/platform/vboot_reference/firmware/include/gbb_header.h)
243 flag_properties = {
244 'fast-developer-mode': 0x01,
245 'gbb-flag-dev-screen-short-delay': 0x00000001,
246 'gbb-flag-load-option-roms': 0x00000002,
247 'gbb-flag-enable-alternate-os': 0x00000004,
248 'gbb-flag-force-dev-switch-on': 0x00000008,
249 'gbb-flag-force-dev-boot-usb': 0x00000010,
250 'gbb-flag-disable-fw-rollback-check': 0x00000020,
251 }
252 gbb_flags = 0
253 for flag_name, flag_value in flag_properties.items():
254 if flag_name not in chromeos_config:
255 continue
256 gbb_flags |= flag_value
257 self._out.Notice("Enabling %s." % flag_name)
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800258
Simon Glass89b86b82011-07-17 23:49:49 -0700259 self._out.Progress('Creating GBB')
260 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
261 sizes = ['%#x' % size for size in sizes]
262 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700263 keydir = self._tools.Filename(self._keydir)
264 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700265 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200266 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700267 '--rootkey=%s/root_key.vbpubk' % keydir,
268 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700269 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800270 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700271 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700272 cwd=odir)
273 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700274
Simon Glasse13ee2c2011-07-28 08:12:28 +1200275 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700276 """Sign an image so that the Tegra SOC will boot it.
277
278 Args:
279 bct: BCT file to use.
280 bootstub: Boot stub (U-Boot + fdt) file to sign.
281 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700282
283 Returns:
284 filename of signed image.
285
286 Raises:
287 CmdError if a command fails.
288 """
289 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200290 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700291 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200292 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700293 fd = open(config, 'w')
294 fd.write('Version = 1;\n')
295 fd.write('Redundancy = 1;\n')
296 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700297
298 # TODO(dianders): Right now, we don't have enough space in our flash map
299 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
300 # sure what this does for reliability, but at least things will fit...
301 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
302 if is_nand:
303 fd.write('Bctcopy = 1;\n')
304
Simon Glass89b86b82011-07-17 23:49:49 -0700305 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
306 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700307
Simon Glass89b86b82011-07-17 23:49:49 -0700308 fd.close()
309
310 self._tools.Run('cbootimage', [config, signed])
311 self._tools.OutputSize('BCT', bct)
312 self._tools.OutputSize('Signed image', signed)
313 return signed
314
Doug Anderson86ce5f42011-07-27 10:40:18 -0700315 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700316 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700317
318 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700319 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700320 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700321 """
Simon Glass290a1802011-07-17 13:54:32 -0700322 if bootcmd:
Simon Glass02d124a2012-03-02 14:47:20 -0800323 self.fdt.PutString('/config', 'bootcmd', bootcmd)
324 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700325 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700326
Simon Glassa4934b72012-05-09 13:35:02 -0700327 def SetNodeEnabled(self, node_name, enabled):
328 """Set whether an node is enabled or disabled.
329
330 This simply sets the 'status' property of a node to "ok", or "disabled".
331
332 The node should either be a full path to the node (like '/uart@10200000')
333 or an alias property.
334
335 Aliases are supported like this:
336
337 aliases {
338 console = "/uart@10200000";
339 };
340
341 pointing to a node:
342
343 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700344 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700345 };
346
347 In this case, this function takes the name of the alias ('console' in
348 this case) and updates the status of the node that is pointed to, to
349 either ok or disabled. If the alias does not exist, a warning is
350 displayed.
351
352 Args:
353 node_name: Name of node (e.g. '/uart@10200000') or alias alias
354 (e.g. 'console') to adjust
355 enabled: True to enable, False to disable
356 """
357 # Look up the alias if this is an alias reference
358 if not node_name.startswith('/'):
359 lookup = self.fdt.GetString('/aliases', node_name, '')
360 if not lookup:
361 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
362 return
363 node_name = lookup
364 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700365 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700366 else:
367 status = 'disabled'
368 self.fdt.PutString(node_name, 'status', status)
369
370 def AddEnableList(self, enable_list):
371 """Process a list of nodes to enable/disable.
372
373 Args:
374 config_list: List of (node, value) tuples to add to the fdt. For each
375 tuple:
376 node: The fdt node to write to will be <node> or pointed to by
377 /aliases/<node>. We can tell which
378 value: 0 to disable the node, 1 to enable it
379 """
380 if enable_list:
381 for node_name, enabled in enable_list:
382 try:
383 enabled = int(enabled)
384 if enabled not in (0, 1):
385 raise ValueError
386 except ValueError as str:
387 raise CmdError("Invalid enable option value '%s' "
388 "(should be 0 or 1)" % enabled)
389 self.SetNodeEnabled(node_name, enabled)
390
Simon Glass290a1802011-07-17 13:54:32 -0700391 def AddConfigList(self, config_list, use_int=False):
392 """Add a list of config items to the fdt.
393
394 Normally these values are written to the fdt as strings, but integers
395 are also supported, in which case the values will be converted to integers
396 (if necessary) before being stored.
397
398 Args:
399 config_list: List of (config, value) tuples to add to the fdt. For each
400 tuple:
401 config: The fdt node to write to will be /config/<config>.
402 value: An integer or string value to write.
403 use_int: True to only write integer values.
404
405 Raises:
406 CmdError: if a value is required to be converted to integer but can't be.
407 """
408 if config_list:
409 for config in config_list:
410 value = config[1]
411 if use_int:
412 try:
413 value = int(value)
414 except ValueError as str:
415 raise CmdError("Cannot convert config option '%s' to integer" %
416 value)
417 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800418 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700419 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800420 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700421
Simon Glass7c2d5572011-11-15 14:47:08 -0800422 def DecodeTextBase(self, data):
423 """Look at a U-Boot image and try to decode its TEXT_BASE.
424
425 This works because U-Boot has a header with the value 0x12345678
426 immediately followed by the TEXT_BASE value. We can therefore read this
427 from the image with some certainty. We check only the first 40 words
428 since the header should be within that region.
429
Simon Glass96b50302012-07-20 06:55:28 +0100430 Since upstream Tegra has moved to having a 16KB SPL region at the start,
431 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
432 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
433
Simon Glass7c2d5572011-11-15 14:47:08 -0800434 Args:
435 data: U-Boot binary data
436
437 Returns:
438 Text base (integer) or None if none was found
439 """
440 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100441 for start in (0, 0x4000):
442 for i in range(start, start + 160, 4):
443 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800444
Simon Glass96b50302012-07-20 06:55:28 +0100445 # TODO(sjg): This does not cope with a big-endian target
446 value = struct.unpack('<I', word)[0]
447 if found:
448 return value - start
449 if value == 0x12345678:
450 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800451
452 return None
453
454 def CalcTextBase(self, name, fdt, fname):
455 """Calculate the TEXT_BASE to use for U-Boot.
456
457 Normally this value is in the fdt, so we just read it from there. But as
458 a second check we look at the image itself in case this is different, and
459 switch to that if it is.
460
461 This allows us to flash any U-Boot even if its TEXT_BASE is different.
462 This is particularly useful with upstream U-Boot which uses a different
463 value (which we will move to).
464 """
465 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200466 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800467 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100468 text_base_str = '%#x' % text_base if text_base else 'None'
469 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
470 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800471
472 # If they are different, issue a warning and switch over.
473 if text_base and text_base != fdt_text_base:
474 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
475 "fdt value of %x. Using %x" % (text_base, name,
476 fdt_text_base, text_base))
477 fdt_text_base = text_base
478 return fdt_text_base
479
Simon Glass6dcc2f22011-07-28 15:26:49 +1200480 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700481 """Create a boot stub and a signed boot stub.
482
Simon Glass6dcc2f22011-07-28 15:26:49 +1200483 For postload:
484 We add a /config/postload-text-offset entry to the signed bootstub's
485 fdt so that U-Boot can find the postload code.
486
487 The raw (unsigned) bootstub will have a value of -1 for this since we will
488 simply append the postload code to the bootstub and it can find it there.
489 This will be used for RW A/B firmware.
490
491 For the signed case this value will specify where in the flash to find
492 the postload code. This will be used for RO firmware.
493
Simon Glass89b86b82011-07-17 23:49:49 -0700494 Args:
495 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800496 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200497 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700498
499 Returns:
500 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200501 Full path to bootstub (uboot + fdt(-1) + postload).
502 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700503
504 Raises:
505 CmdError if a command fails.
506 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200507 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800508 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700509 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200510
511 # Make a copy of the fdt for the bootstub
512 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800513 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700514 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200515
Simon Glass89b86b82011-07-17 23:49:49 -0700516 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700517 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
518 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700519 self._tools.OutputSize('Combined binary', bootstub)
520
Simon Glasse13ee2c2011-07-28 08:12:28 +1200521 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700522 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700523 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200524 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200525
526 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
527 data = self._tools.ReadFile(signed)
528
529 if postload:
530 # We must add postload to the bootstub since A and B will need to
531 # be able to find it without the /config/postload-text-offset mechanism.
532 bs_data = self._tools.ReadFile(bootstub)
533 bs_data += self._tools.ReadFile(postload)
534 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
535 self._tools.WriteFile(bootstub, bs_data)
536 self._tools.OutputSize('Combined binary with postload', bootstub)
537
538 # Now that we know the file size, adjust the fdt and re-sign
539 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800540 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200541 fdt_data = self._tools.ReadFile(fdt.fname)
542 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
543 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
544 postload_bootstub, text_base)
545 if len(data) != os.path.getsize(signed):
546 raise CmdError('Signed file size changed from %d to %d after updating '
547 'fdt' % (len(data), os.path.getsize(signed)))
548
549 # Re-read the signed image, and add the post-load binary.
550 data = self._tools.ReadFile(signed)
551 data += self._tools.ReadFile(postload)
552 self._tools.OutputSize('Post-load binary', postload)
553
554 self._tools.WriteFile(signed_postload, data)
555 self._tools.OutputSize('Final bootstub with postload', signed_postload)
556
557 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700558
Simon Glasscbc83552012-07-23 15:26:22 +0100559 def _CreateCorebootStub(self, uboot, coreboot, seabios):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700560 """Create a coreboot boot stub.
561
562 Args:
563 uboot: Path to u-boot.bin (may be chroot-relative)
564 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700565 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700566
567 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100568 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700569
570 Raises:
571 CmdError if a command fails.
572 """
573 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700574
575 # U-Boot itself does not put a .elf extension on the elf file.
576 # The U-Boot ebuild does, but we shouldn't actually require it since
577 # devs may want to just use what U-Boot creates.
578 uboot_elf = uboot.replace('.bin', '')
579 if not os.path.exists(self._tools.Filename(uboot_elf)):
580 uboot_elf = uboot.replace('.bin', '.elf')
581 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Vincent Palatinf7286772011-10-12 14:31:53 -0700582 if seabios:
Simon Glass146cb8e2012-03-09 15:51:24 -0800583 self._tools.Run('cbfstool', [bootstub, 'add-payload', seabios,
Vincent Palatinf7286772011-10-12 14:31:53 -0700584 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800585 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700586 'img/U-Boot', 'lzma'])
587 else:
Simon Glass146cb8e2012-03-09 15:51:24 -0800588 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700589 'fallback/payload', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100590
591 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700592 return bootstub
593
Simon Glass3b404092012-05-23 13:10:36 -0700594 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700595 """Update the parameters in a BL2 blob.
596
597 We look at the list in the parameter block, extract the value of each
598 from the device tree, and write that value to the parameter block.
599
600 Args:
601 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700602 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700603 data: The BL2 data.
604 pos: The position of the start of the parameter block.
605
606 Returns:
607 The new contents of the parameter block, after updating.
608 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700609 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
610 if version != 1:
611 raise CmdError("Cannot update machine parameter block version '%d'" %
612 version)
613 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700614 raise CmdError("Machine parameter block size %d is invalid: "
615 "pos=%d, size=%d, space=%d, len=%d" %
616 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700617
618 # Move past the header and read the parameter list, which is terminated
619 # with \0.
620 pos += 12
621 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
622 param_len = param_list.find('\0')
623 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700624 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700625
626 # Work through the parameters one at a time, adding each value
627 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700628 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700629 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700630 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700631 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700632 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700633 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
634 if not mem_type in mem_types:
635 raise CmdError("Unknown memory type '%s'" % mem_type)
636 value = mem_types.index(mem_type)
637 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700638 elif param == 'M' :
639 mem_manuf = fdt.GetString('/dmc', 'mem-manuf')
640 mem_manufs = ['autodetect', 'elpida', 'samsung']
641 if not mem_manuf in mem_manufs:
642 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
643 value = mem_manufs.index(mem_manuf)
644 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glassdf95dd22012-03-13 15:46:16 -0700645 elif param == 'v':
646 value = 31
647 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700648 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700649 value = (spl_load_size + 0xfff) & ~0xfff
650 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
651 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700652 elif param == 'b':
653 # These values come from enum boot_mode in U-Boot's cpu.h
654 if self.spl_source == 'straps':
655 value = 32
656 elif self.spl_source == 'emmc':
657 value = 4
658 elif self.spl_source == 'spi':
659 value = 20
660 elif self.spl_source == 'usb':
661 value = 33
662 else:
663 raise CmdError("Invalid boot source '%s'" % self.spl_source)
664 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700665 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700666 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700667 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700668 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700669 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700670
671 # Put the data into our block.
672 data = data[:pos] + new_data + data[pos + len(new_data):]
673 self._out.Info('BL2 configuration complete')
674 return data
675
Simon Glasse5e8afb2012-05-23 11:19:23 -0700676 def _UpdateChecksum(self, data):
677 """Update the BL2 checksum.
678
679 The checksum is a 4 byte sum of all the bytes in the image before the
680 last 4 bytes (which hold the checksum).
681
682 Args:
683 data: The BL2 data to update.
684
685 Returns:
686 The new contents of the BL2 data, after updating the checksum.
687 """
688 checksum = 0
689 for ch in data[:-4]:
690 checksum += ord(ch)
691 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
692
Simon Glass559b6612012-05-23 13:28:45 -0700693 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700694 """Configure an Exynos BL2 binary for our needs.
695
696 We create a new modified BL2 and return its filename.
697
698 Args:
699 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700700 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700701 orig_bl2: Filename of original BL2 file to modify.
702 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700703 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700704 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700705 data = self._tools.ReadFile(orig_bl2)
706 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700707
708 # Locate the parameter block
709 data = self._tools.ReadFile(bl2)
710 marker = struct.pack('<L', 0xdeadbeef)
711 pos = data.rfind(marker)
712 if not pos:
713 raise CmdError("Could not find machine parameter block in '%s'" %
714 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700715 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700716 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700717 self._tools.WriteFile(bl2, data)
718 return bl2
719
Simon Glass89b86b82011-07-17 23:49:49 -0700720 def _PackOutput(self, msg):
721 """Helper function to write output from PackFirmware (verbose level 2).
722
723 This is passed to PackFirmware for it to use to write output.
724
725 Args:
726 msg: Message to display.
727 """
728 self._out.Notice(msg)
729
Simon Glass439fe7a2012-03-09 16:19:34 -0800730 def _BuildBlob(self, pack, fdt, blob_type):
731 """Build the blob data for a particular blob type.
732
733 Args:
734 blob_type: The type of blob to create data for. Supported types are:
735 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
736 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
737 """
738 if blob_type == 'coreboot':
739 coreboot = self._CreateCorebootStub(self.uboot_fname,
Simon Glasscbc83552012-07-23 15:26:22 +0100740 self.coreboot_fname, self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800741 pack.AddProperty('coreboot', coreboot)
742 pack.AddProperty('image', coreboot)
743 elif blob_type == 'signed':
744 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
745 self.postload_fname)
746 pack.AddProperty('bootstub', bootstub)
747 pack.AddProperty('signed', signed)
748 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700749 elif blob_type == 'exynos-bl1':
750 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700751
752 # TODO(sjg@chromium.org): Deprecate ecbin
753 elif blob_type in ['ecrw', 'ecbin']:
754 pack.AddProperty('ecrw', self.ecrw_fname)
755 pack.AddProperty('ecbin', self.ecrw_fname)
756 elif blob_type == 'ecro':
757 pack.AddProperty(blob_type, self.ecro_fname)
Simon Glass7e199222012-03-13 15:51:18 -0700758 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700759 spl_payload = pack.GetBlobParams(blob_type)
760
761 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
762 # from all flash map files.
763 if not spl_payload:
764 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
765 prop_list = 'boot+dtb'
766
767 # Do this later, when we remove boot+dtb.
768 # raise CmdError("No parameters provided for blob type '%s'" %
769 # blob_type)
770 else:
771 prop_list = spl_payload[0].split(',')
772 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
773 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
774 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700775 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700776 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800777 elif pack.GetProperty(blob_type):
778 pass
779 else:
780 raise CmdError("Unknown blob type '%s' required in flash map" %
781 blob_type)
782
Simon Glass290a1802011-07-17 13:54:32 -0700783 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700784 """Create a full firmware image, along with various by-products.
785
786 This uses the provided u-boot.bin, fdt and bct to create a firmware
787 image containing all the required parts. If the GBB is not supplied
788 then this will just return a signed U-Boot as the image.
789
790 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200791 gbb: Full path to the GBB file, or empty if a GBB is not required.
792 fdt: Fdt object containing required information.
793
794 Returns:
795 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700796
797 Raises:
798 CmdError if a command fails.
799 """
Simon Glass02d124a2012-03-02 14:47:20 -0800800 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700801
Simon Glass439fe7a2012-03-09 16:19:34 -0800802 # Get the flashmap so we know what to build
803 pack = PackFirmware(self._tools, self._out)
804 pack.SelectFdt(fdt)
805
806 # Get all our blobs ready
807 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700808 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700809 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700810
Simon Glassde9c8072012-07-02 22:29:02 -0700811 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
812 if self.kernel_fname:
813 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
814
Simon Glass50f74602012-03-15 21:04:25 -0700815 # Make a copy of the fdt for the bootstub
816 fdt_data = self._tools.ReadFile(fdt.fname)
817 uboot_data = self._tools.ReadFile(self.uboot_fname)
818 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
819 self._tools.WriteFile(uboot_copy, uboot_data)
820
821 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
822 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700823
824 # TODO(sjg@chromium.org): Deprecate this property when all boards
825 # use a comma-separated list for section contents. We will then
826 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700827 pack.AddProperty('boot+dtb', bootstub)
828
Simon Glass439fe7a2012-03-09 16:19:34 -0800829 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100830 blob_list = pack.GetBlobList()
831 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700832 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800833 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700834
835 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700836 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800837 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800838 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800839 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700840 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800841 pack.AddProperty('fwid', fwid)
842 pack.AddProperty('gbb', gbb)
843 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700844
845 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700846
847 # Record position and size of all blob members in the FDT
848 pack.UpdateBlobPositions(fdt)
849
Simon Glasscbc83552012-07-23 15:26:22 +0100850 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
851 # has created a rom file without the dtb, because until now it is not
852 # complete. Add the dtb here.
853 # A better anwer might be to put the dtb in memory immediately after
854 # U-Boot as is done for ARM and have coreboot load it as a binary file
855 # instead of an elf. However, I need to check whether coreboot supports
856 # this, and whether this is desirable for other reasons.
857 if 'coreboot' in blob_list:
858 bootstub = pack.GetProperty('coreboot')
859 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
860 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
861 '0xac'])
862
Simon Glassc90cf582012-03-13 15:40:47 -0700863 image = os.path.join(self._tools.outdir, 'image.bin')
864 pack.PackImage(self._tools.outdir, image)
865 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700866
Simon Glass439fe7a2012-03-09 16:19:34 -0800867 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700868 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700869 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700870
Simon Glass290a1802011-07-17 13:54:32 -0700871 def SelectFdt(self, fdt_fname):
872 """Select an FDT to control the firmware bundling
873
874 Args:
875 fdt_fname: The filename of the fdt to use.
876
Simon Glassc0f3dc62011-08-09 14:19:05 -0700877 Returns:
878 The Fdt object of the original fdt file, which we will not modify.
879
Simon Glass290a1802011-07-17 13:54:32 -0700880 We make a copy of this which will include any on-the-fly changes we want
881 to make.
882 """
883 self._fdt_fname = fdt_fname
884 self.CheckOptions()
885 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800886 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700887 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700888 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700889
Simon Glassc90cf582012-03-13 15:40:47 -0700890 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -0700891 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700892
893 - Checks options, tools, output directory, fdt.
894 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700895
896 Args:
Simon Glass56577572011-07-19 11:08:06 +1200897 hardware_id: Hardware ID to use for this board. If None, then the
898 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700899 output_fname: Output filename for the image. If this is not None, then
900 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -0700901 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -0700902
903 Returns:
904 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700905 """
Simon Glass89b86b82011-07-17 23:49:49 -0700906 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700907 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200908 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700909
910 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -0700911 image, pack = self._CreateImage(gbb, self.fdt)
912 if show_map:
913 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -0700914 if output_fname:
915 shutil.copyfile(image, output_fname)
916 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -0700917 return image, pack.props