blob: 6f37c51f069fc2da76e474b6f0be206ac07450ab [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 Glass23988ae2012-03-23 16:55:22 -070082
83 Private attributes:
84 _small: True to create a 'small' signed U-Boot, False to produce a
85 full image. The small U-Boot is enough to boot but will not have
86 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -070087 """
Simon Glass89b86b82011-07-17 23:49:49 -070088
Simon Glass290a1802011-07-17 13:54:32 -070089 def __init__(self, tools, output):
90 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -070091
Simon Glass290a1802011-07-17 13:54:32 -070092 Args:
93 tools: A tools.Tools object to use for external tools.
94 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -070095 """
Simon Glass290a1802011-07-17 13:54:32 -070096 self._tools = tools
97 self._out = output
98
99 # Set up the things we need to know in order to operate.
100 self._board = None # Board name, e.g. tegra2_seaboard.
101 self._fdt_fname = None # Filename of our FDT.
102 self.uboot_fname = None # Filename of our U-Boot binary.
103 self.bct_fname = None # Filename of our BCT file.
104 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800105 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700106 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -0700107 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -0700108 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
109 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass559b6612012-05-23 13:28:45 -0700110 self.spl_source = 'straps' # SPL boot according to board settings
Simon Glass07267952012-06-08 12:45:13 -0700111 self.skeleton_fname = None # Filename of Coreboot skeleton file
Simon Glassbe0bc002012-08-16 12:50:48 -0700112 self.ecrw_fname = None # Filename of EC file
113 self.ecro_fname = None # Filename of EC read-only file
Simon Glass23988ae2012-03-23 16:55:22 -0700114 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700115
116 def SetDirs(self, keydir):
117 """Set up directories required for Bundle.
118
119 Args:
120 keydir: Directory containing keys to use for signing firmware.
121 """
122 self._keydir = keydir
123
Simon Glass6dcc2f22011-07-28 15:26:49 +1200124 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glass07267952012-06-08 12:45:13 -0700125 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassbe0bc002012-08-16 12:50:48 -0700126 skeleton=None, ecrw=None, ecro=None, kernel=None):
Simon Glass290a1802011-07-17 13:54:32 -0700127 """Set up files required for Bundle.
128
129 Args:
130 board: The name of the board to target (e.g. tegra2_seaboard).
131 uboot: The filename of the u-boot.bin image to use.
132 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800133 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700134 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200135 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700136 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700137 exynos_bl1: The filename of the exynos BL1 file
138 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
139 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700140 ecrw: The filename of the EC (Embedded Controller) read-write file.
141 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700142 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700143 """
144 self._board = board
145 self.uboot_fname = uboot
146 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800147 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700148 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200149 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700150 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700151 self.exynos_bl1 = exynos_bl1
152 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700153 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700154 self.ecrw_fname = ecrw
155 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700156 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700157
158 def SetOptions(self, small):
159 """Set up options supported by Bundle.
160
161 Args:
162 small: Only create a signed U-Boot - don't produce the full packed
163 firmware image. This is useful for devs who want to replace just the
164 U-Boot part while keeping the keys, gbb, etc. the same.
165 """
166 self._small = small
167
168 def CheckOptions(self):
169 """Check provided options and select defaults."""
170 if not self._board:
171 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700172 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700173 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700174 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700175 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700176 base_name = re.sub('_', '-', self._board)
177
178 # In case the name exists with a prefix or suffix, find it.
179 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
180 found_list = glob.glob(self._tools.Filename(wildcard))
181 if len(found_list) == 1:
182 self._fdt_fname = found_list[0]
183 else:
184 # We didn't find anything definite, so set up our expected name.
185 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
186
Simon Glass881964d2012-04-04 11:34:09 -0700187 # Convert things like 'exynos5250-daisy' into a full path.
188 root, ext = os.path.splitext(self._fdt_fname)
189 if not ext and not os.path.dirname(root):
190 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
191
Simon Glass290a1802011-07-17 13:54:32 -0700192 if not self.uboot_fname:
193 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
194 if not self.bct_fname:
195 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700196 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700197 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700198 if not self.exynos_bl1:
199 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
200 if not self.exynos_bl2:
201 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700202 if not self.coreboot_fname:
203 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
204 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700205 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Simon Glassbe0bc002012-08-16 12:50:48 -0700206 if not self.ecrw_fname:
207 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
208 if not self.ecro_fname:
209 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700210
Simon Glass75759302012-03-15 20:26:53 -0700211 def GetFiles(self):
212 """Get a list of files that we know about.
213
214 This is the opposite of SetFiles except that we may have put in some
215 default names. It returns a dictionary containing the filename for
216 each of a number of pre-defined files.
217
218 Returns:
219 Dictionary, with one entry for each file.
220 """
221 file_list = {
222 'bct' : self.bct_fname,
223 'exynos-bl1' : self.exynos_bl1,
224 'exynos-bl2' : self.exynos_bl2,
225 }
226 return file_list
227
Simon Glass56577572011-07-19 11:08:06 +1200228 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700229 """Create a GBB for the image.
230
Simon Glass56577572011-07-19 11:08:06 +1200231 Args:
232 hardware_id: Hardware ID to use for this board. If None, then the
233 default from the Fdt will be used
234
Simon Glass89b86b82011-07-17 23:49:49 -0700235 Returns:
236 Path of the created GBB file.
237
238 Raises:
239 CmdError if a command fails.
240 """
Simon Glass56577572011-07-19 11:08:06 +1200241 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800242 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700243 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700244 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700245
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800246 chromeos_config = self.fdt.GetProps("/chromeos-config")
Hung-Te Linec76cb62012-07-18 15:11:39 +0800247 # Build GBB flags.
248 # (src/platform/vboot_reference/firmware/include/gbb_header.h)
249 flag_properties = {
250 'fast-developer-mode': 0x01,
251 'gbb-flag-dev-screen-short-delay': 0x00000001,
252 'gbb-flag-load-option-roms': 0x00000002,
253 'gbb-flag-enable-alternate-os': 0x00000004,
254 'gbb-flag-force-dev-switch-on': 0x00000008,
255 'gbb-flag-force-dev-boot-usb': 0x00000010,
256 'gbb-flag-disable-fw-rollback-check': 0x00000020,
Stefan Reinauere993af52012-10-05 10:47:45 -0700257 'gbb-flag-enter-triggers-tonorm': 0x00000040,
258 'gbb-flag-force-dev-boot-legacy': 0x00000080,
Hung-Te Linec76cb62012-07-18 15:11:39 +0800259 }
260 gbb_flags = 0
261 for flag_name, flag_value in flag_properties.items():
262 if flag_name not in chromeos_config:
263 continue
264 gbb_flags |= flag_value
265 self._out.Notice("Enabling %s." % flag_name)
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800266
Simon Glass89b86b82011-07-17 23:49:49 -0700267 self._out.Progress('Creating GBB')
268 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
269 sizes = ['%#x' % size for size in sizes]
270 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700271 keydir = self._tools.Filename(self._keydir)
272 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700273 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200274 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700275 '--rootkey=%s/root_key.vbpubk' % keydir,
276 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700277 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800278 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700279 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700280 cwd=odir)
281 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700282
Simon Glasse13ee2c2011-07-28 08:12:28 +1200283 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700284 """Sign an image so that the Tegra SOC will boot it.
285
286 Args:
287 bct: BCT file to use.
288 bootstub: Boot stub (U-Boot + fdt) file to sign.
289 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700290
291 Returns:
292 filename of signed image.
293
294 Raises:
295 CmdError if a command fails.
296 """
297 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200298 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700299 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200300 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700301 fd = open(config, 'w')
302 fd.write('Version = 1;\n')
303 fd.write('Redundancy = 1;\n')
304 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700305
306 # TODO(dianders): Right now, we don't have enough space in our flash map
307 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
308 # sure what this does for reliability, but at least things will fit...
309 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
310 if is_nand:
311 fd.write('Bctcopy = 1;\n')
312
Simon Glass89b86b82011-07-17 23:49:49 -0700313 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
314 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700315
Simon Glass89b86b82011-07-17 23:49:49 -0700316 fd.close()
317
318 self._tools.Run('cbootimage', [config, signed])
319 self._tools.OutputSize('BCT', bct)
320 self._tools.OutputSize('Signed image', signed)
321 return signed
322
Doug Anderson86ce5f42011-07-27 10:40:18 -0700323 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700324 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700325
326 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700327 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700328 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700329 """
Simon Glass468d8752012-09-19 16:36:19 -0700330 if bootcmd is not None:
331 if bootcmd == 'none':
332 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800333 self.fdt.PutString('/config', 'bootcmd', bootcmd)
334 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700335 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700336
Simon Glassa4934b72012-05-09 13:35:02 -0700337 def SetNodeEnabled(self, node_name, enabled):
338 """Set whether an node is enabled or disabled.
339
340 This simply sets the 'status' property of a node to "ok", or "disabled".
341
342 The node should either be a full path to the node (like '/uart@10200000')
343 or an alias property.
344
345 Aliases are supported like this:
346
347 aliases {
348 console = "/uart@10200000";
349 };
350
351 pointing to a node:
352
353 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700354 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700355 };
356
357 In this case, this function takes the name of the alias ('console' in
358 this case) and updates the status of the node that is pointed to, to
359 either ok or disabled. If the alias does not exist, a warning is
360 displayed.
361
362 Args:
363 node_name: Name of node (e.g. '/uart@10200000') or alias alias
364 (e.g. 'console') to adjust
365 enabled: True to enable, False to disable
366 """
367 # Look up the alias if this is an alias reference
368 if not node_name.startswith('/'):
369 lookup = self.fdt.GetString('/aliases', node_name, '')
370 if not lookup:
371 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
372 return
373 node_name = lookup
374 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700375 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700376 else:
377 status = 'disabled'
378 self.fdt.PutString(node_name, 'status', status)
379
380 def AddEnableList(self, enable_list):
381 """Process a list of nodes to enable/disable.
382
383 Args:
384 config_list: List of (node, value) tuples to add to the fdt. For each
385 tuple:
386 node: The fdt node to write to will be <node> or pointed to by
387 /aliases/<node>. We can tell which
388 value: 0 to disable the node, 1 to enable it
389 """
390 if enable_list:
391 for node_name, enabled in enable_list:
392 try:
393 enabled = int(enabled)
394 if enabled not in (0, 1):
395 raise ValueError
396 except ValueError as str:
397 raise CmdError("Invalid enable option value '%s' "
398 "(should be 0 or 1)" % enabled)
399 self.SetNodeEnabled(node_name, enabled)
400
Simon Glass290a1802011-07-17 13:54:32 -0700401 def AddConfigList(self, config_list, use_int=False):
402 """Add a list of config items to the fdt.
403
404 Normally these values are written to the fdt as strings, but integers
405 are also supported, in which case the values will be converted to integers
406 (if necessary) before being stored.
407
408 Args:
409 config_list: List of (config, value) tuples to add to the fdt. For each
410 tuple:
411 config: The fdt node to write to will be /config/<config>.
412 value: An integer or string value to write.
413 use_int: True to only write integer values.
414
415 Raises:
416 CmdError: if a value is required to be converted to integer but can't be.
417 """
418 if config_list:
419 for config in config_list:
420 value = config[1]
421 if use_int:
422 try:
423 value = int(value)
424 except ValueError as str:
425 raise CmdError("Cannot convert config option '%s' to integer" %
426 value)
427 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800428 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700429 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800430 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700431
Simon Glass7c2d5572011-11-15 14:47:08 -0800432 def DecodeTextBase(self, data):
433 """Look at a U-Boot image and try to decode its TEXT_BASE.
434
435 This works because U-Boot has a header with the value 0x12345678
436 immediately followed by the TEXT_BASE value. We can therefore read this
437 from the image with some certainty. We check only the first 40 words
438 since the header should be within that region.
439
Simon Glass96b50302012-07-20 06:55:28 +0100440 Since upstream Tegra has moved to having a 16KB SPL region at the start,
441 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
442 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
443
Simon Glass7c2d5572011-11-15 14:47:08 -0800444 Args:
445 data: U-Boot binary data
446
447 Returns:
448 Text base (integer) or None if none was found
449 """
450 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100451 for start in (0, 0x4000):
452 for i in range(start, start + 160, 4):
453 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800454
Simon Glass96b50302012-07-20 06:55:28 +0100455 # TODO(sjg): This does not cope with a big-endian target
456 value = struct.unpack('<I', word)[0]
457 if found:
458 return value - start
459 if value == 0x12345678:
460 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800461
462 return None
463
464 def CalcTextBase(self, name, fdt, fname):
465 """Calculate the TEXT_BASE to use for U-Boot.
466
467 Normally this value is in the fdt, so we just read it from there. But as
468 a second check we look at the image itself in case this is different, and
469 switch to that if it is.
470
471 This allows us to flash any U-Boot even if its TEXT_BASE is different.
472 This is particularly useful with upstream U-Boot which uses a different
473 value (which we will move to).
474 """
475 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200476 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800477 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100478 text_base_str = '%#x' % text_base if text_base else 'None'
479 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
480 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800481
482 # If they are different, issue a warning and switch over.
483 if text_base and text_base != fdt_text_base:
484 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
485 "fdt value of %x. Using %x" % (text_base, name,
486 fdt_text_base, text_base))
487 fdt_text_base = text_base
488 return fdt_text_base
489
Simon Glass6dcc2f22011-07-28 15:26:49 +1200490 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700491 """Create a boot stub and a signed boot stub.
492
Simon Glass6dcc2f22011-07-28 15:26:49 +1200493 For postload:
494 We add a /config/postload-text-offset entry to the signed bootstub's
495 fdt so that U-Boot can find the postload code.
496
497 The raw (unsigned) bootstub will have a value of -1 for this since we will
498 simply append the postload code to the bootstub and it can find it there.
499 This will be used for RW A/B firmware.
500
501 For the signed case this value will specify where in the flash to find
502 the postload code. This will be used for RO firmware.
503
Simon Glass89b86b82011-07-17 23:49:49 -0700504 Args:
505 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800506 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200507 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700508
509 Returns:
510 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200511 Full path to bootstub (uboot + fdt(-1) + postload).
512 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700513
514 Raises:
515 CmdError if a command fails.
516 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200517 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800518 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700519 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200520
521 # Make a copy of the fdt for the bootstub
522 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800523 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700524 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200525
Simon Glass89b86b82011-07-17 23:49:49 -0700526 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700527 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
528 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700529 self._tools.OutputSize('Combined binary', bootstub)
530
Simon Glasse13ee2c2011-07-28 08:12:28 +1200531 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700532 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700533 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200534 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200535
536 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
537 data = self._tools.ReadFile(signed)
538
539 if postload:
540 # We must add postload to the bootstub since A and B will need to
541 # be able to find it without the /config/postload-text-offset mechanism.
542 bs_data = self._tools.ReadFile(bootstub)
543 bs_data += self._tools.ReadFile(postload)
544 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
545 self._tools.WriteFile(bootstub, bs_data)
546 self._tools.OutputSize('Combined binary with postload', bootstub)
547
548 # Now that we know the file size, adjust the fdt and re-sign
549 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800550 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200551 fdt_data = self._tools.ReadFile(fdt.fname)
552 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
553 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
554 postload_bootstub, text_base)
555 if len(data) != os.path.getsize(signed):
556 raise CmdError('Signed file size changed from %d to %d after updating '
557 'fdt' % (len(data), os.path.getsize(signed)))
558
559 # Re-read the signed image, and add the post-load binary.
560 data = self._tools.ReadFile(signed)
561 data += self._tools.ReadFile(postload)
562 self._tools.OutputSize('Post-load binary', postload)
563
564 self._tools.WriteFile(signed_postload, data)
565 self._tools.OutputSize('Final bootstub with postload', signed_postload)
566
567 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700568
Simon Glasscbc83552012-07-23 15:26:22 +0100569 def _CreateCorebootStub(self, uboot, coreboot, seabios):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700570 """Create a coreboot boot stub.
571
572 Args:
573 uboot: Path to u-boot.bin (may be chroot-relative)
574 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700575 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700576
577 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100578 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700579
580 Raises:
581 CmdError if a command fails.
582 """
583 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700584
585 # U-Boot itself does not put a .elf extension on the elf file.
586 # The U-Boot ebuild does, but we shouldn't actually require it since
587 # devs may want to just use what U-Boot creates.
588 uboot_elf = uboot.replace('.bin', '')
589 if not os.path.exists(self._tools.Filename(uboot_elf)):
590 uboot_elf = uboot.replace('.bin', '.elf')
591 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Vincent Palatinf7286772011-10-12 14:31:53 -0700592 if seabios:
Simon Glass146cb8e2012-03-09 15:51:24 -0800593 self._tools.Run('cbfstool', [bootstub, 'add-payload', seabios,
Vincent Palatinf7286772011-10-12 14:31:53 -0700594 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800595 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700596 'img/U-Boot', 'lzma'])
597 else:
Simon Glass146cb8e2012-03-09 15:51:24 -0800598 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700599 'fallback/payload', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100600
601 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700602 return bootstub
603
Simon Glass3b404092012-05-23 13:10:36 -0700604 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700605 """Update the parameters in a BL2 blob.
606
607 We look at the list in the parameter block, extract the value of each
608 from the device tree, and write that value to the parameter block.
609
610 Args:
611 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700612 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700613 data: The BL2 data.
614 pos: The position of the start of the parameter block.
615
616 Returns:
617 The new contents of the parameter block, after updating.
618 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700619 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
620 if version != 1:
621 raise CmdError("Cannot update machine parameter block version '%d'" %
622 version)
623 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700624 raise CmdError("Machine parameter block size %d is invalid: "
625 "pos=%d, size=%d, space=%d, len=%d" %
626 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700627
628 # Move past the header and read the parameter list, which is terminated
629 # with \0.
630 pos += 12
631 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
632 param_len = param_list.find('\0')
633 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700634 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700635
636 # Work through the parameters one at a time, adding each value
637 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700638 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700639 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700640 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700641 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700642 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700643 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
644 if not mem_type in mem_types:
645 raise CmdError("Unknown memory type '%s'" % mem_type)
646 value = mem_types.index(mem_type)
647 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700648 elif param == 'M' :
649 mem_manuf = fdt.GetString('/dmc', 'mem-manuf')
650 mem_manufs = ['autodetect', 'elpida', 'samsung']
651 if not mem_manuf in mem_manufs:
652 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
653 value = mem_manufs.index(mem_manuf)
654 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700655 elif param == 'f' :
656 mem_freq = fdt.GetInt('/dmc', 'clock-frequency') / 1000000
657 if not mem_freq in [533, 667, 800]:
658 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
659 value = mem_freq
660 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700661 elif param == 'v':
662 value = 31
663 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700664 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700665 value = (spl_load_size + 0xfff) & ~0xfff
666 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
667 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700668 elif param == 'b':
669 # These values come from enum boot_mode in U-Boot's cpu.h
670 if self.spl_source == 'straps':
671 value = 32
672 elif self.spl_source == 'emmc':
673 value = 4
674 elif self.spl_source == 'spi':
675 value = 20
676 elif self.spl_source == 'usb':
677 value = 33
678 else:
679 raise CmdError("Invalid boot source '%s'" % self.spl_source)
680 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700681 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700682 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700683 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700684 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700685 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700686
687 # Put the data into our block.
688 data = data[:pos] + new_data + data[pos + len(new_data):]
689 self._out.Info('BL2 configuration complete')
690 return data
691
Simon Glasse5e8afb2012-05-23 11:19:23 -0700692 def _UpdateChecksum(self, data):
693 """Update the BL2 checksum.
694
695 The checksum is a 4 byte sum of all the bytes in the image before the
696 last 4 bytes (which hold the checksum).
697
698 Args:
699 data: The BL2 data to update.
700
701 Returns:
702 The new contents of the BL2 data, after updating the checksum.
703 """
704 checksum = 0
705 for ch in data[:-4]:
706 checksum += ord(ch)
707 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
708
Simon Glass559b6612012-05-23 13:28:45 -0700709 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700710 """Configure an Exynos BL2 binary for our needs.
711
712 We create a new modified BL2 and return its filename.
713
714 Args:
715 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700716 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700717 orig_bl2: Filename of original BL2 file to modify.
718 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700719 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700720 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700721 data = self._tools.ReadFile(orig_bl2)
722 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700723
724 # Locate the parameter block
725 data = self._tools.ReadFile(bl2)
726 marker = struct.pack('<L', 0xdeadbeef)
727 pos = data.rfind(marker)
728 if not pos:
729 raise CmdError("Could not find machine parameter block in '%s'" %
730 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700731 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700732 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700733 self._tools.WriteFile(bl2, data)
734 return bl2
735
Simon Glass89b86b82011-07-17 23:49:49 -0700736 def _PackOutput(self, msg):
737 """Helper function to write output from PackFirmware (verbose level 2).
738
739 This is passed to PackFirmware for it to use to write output.
740
741 Args:
742 msg: Message to display.
743 """
744 self._out.Notice(msg)
745
Simon Glass439fe7a2012-03-09 16:19:34 -0800746 def _BuildBlob(self, pack, fdt, blob_type):
747 """Build the blob data for a particular blob type.
748
749 Args:
750 blob_type: The type of blob to create data for. Supported types are:
751 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
752 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
753 """
754 if blob_type == 'coreboot':
755 coreboot = self._CreateCorebootStub(self.uboot_fname,
Simon Glasscbc83552012-07-23 15:26:22 +0100756 self.coreboot_fname, self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800757 pack.AddProperty('coreboot', coreboot)
758 pack.AddProperty('image', coreboot)
759 elif blob_type == 'signed':
760 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
761 self.postload_fname)
762 pack.AddProperty('bootstub', bootstub)
763 pack.AddProperty('signed', signed)
764 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700765 elif blob_type == 'exynos-bl1':
766 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700767
768 # TODO(sjg@chromium.org): Deprecate ecbin
769 elif blob_type in ['ecrw', 'ecbin']:
770 pack.AddProperty('ecrw', self.ecrw_fname)
771 pack.AddProperty('ecbin', self.ecrw_fname)
772 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700773 # crosbug.com/p/13143
774 # We cannot have an fmap in the EC image since there can be only one,
775 # which is the main fmap describing the whole image.
776 # Ultimately the EC will not have an fmap, since with software sync
777 # there is no flashrom involvement in updating the EC flash, and thus
778 # no need for the fmap.
779 # For now, mangle the fmap name to avoid problems.
780 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
781 data = self._tools.ReadFile(self.ecro_fname)
782 data = re.sub('__FMAP__', '__fMAP__', data)
783 self._tools.WriteFile(updated_ecro, data)
784 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700785 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700786 spl_payload = pack.GetBlobParams(blob_type)
787
788 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
789 # from all flash map files.
790 if not spl_payload:
791 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
792 prop_list = 'boot+dtb'
793
794 # Do this later, when we remove boot+dtb.
795 # raise CmdError("No parameters provided for blob type '%s'" %
796 # blob_type)
797 else:
798 prop_list = spl_payload[0].split(',')
799 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
800 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
801 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700802 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700803 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800804 elif pack.GetProperty(blob_type):
805 pass
806 else:
807 raise CmdError("Unknown blob type '%s' required in flash map" %
808 blob_type)
809
Simon Glass290a1802011-07-17 13:54:32 -0700810 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700811 """Create a full firmware image, along with various by-products.
812
813 This uses the provided u-boot.bin, fdt and bct to create a firmware
814 image containing all the required parts. If the GBB is not supplied
815 then this will just return a signed U-Boot as the image.
816
817 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200818 gbb: Full path to the GBB file, or empty if a GBB is not required.
819 fdt: Fdt object containing required information.
820
821 Returns:
822 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700823
824 Raises:
825 CmdError if a command fails.
826 """
Simon Glass02d124a2012-03-02 14:47:20 -0800827 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700828
Simon Glass439fe7a2012-03-09 16:19:34 -0800829 # Get the flashmap so we know what to build
830 pack = PackFirmware(self._tools, self._out)
831 pack.SelectFdt(fdt)
832
833 # Get all our blobs ready
834 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700835 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700836 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700837
Simon Glassde9c8072012-07-02 22:29:02 -0700838 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
839 if self.kernel_fname:
840 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
841
Simon Glass50f74602012-03-15 21:04:25 -0700842 # Make a copy of the fdt for the bootstub
843 fdt_data = self._tools.ReadFile(fdt.fname)
844 uboot_data = self._tools.ReadFile(self.uboot_fname)
845 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
846 self._tools.WriteFile(uboot_copy, uboot_data)
847
848 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
849 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700850
851 # TODO(sjg@chromium.org): Deprecate this property when all boards
852 # use a comma-separated list for section contents. We will then
853 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700854 pack.AddProperty('boot+dtb', bootstub)
855
Simon Glass439fe7a2012-03-09 16:19:34 -0800856 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100857 blob_list = pack.GetBlobList()
858 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700859 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800860 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700861
862 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700863 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800864 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800865 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800866 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700867 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800868 pack.AddProperty('fwid', fwid)
869 pack.AddProperty('gbb', gbb)
870 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700871
872 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700873
874 # Record position and size of all blob members in the FDT
875 pack.UpdateBlobPositions(fdt)
876
Simon Glasscbc83552012-07-23 15:26:22 +0100877 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
878 # has created a rom file without the dtb, because until now it is not
879 # complete. Add the dtb here.
880 # A better anwer might be to put the dtb in memory immediately after
881 # U-Boot as is done for ARM and have coreboot load it as a binary file
882 # instead of an elf. However, I need to check whether coreboot supports
883 # this, and whether this is desirable for other reasons.
884 if 'coreboot' in blob_list:
885 bootstub = pack.GetProperty('coreboot')
886 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
887 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
888 '0xac'])
Stefan Reinauer728be822012-10-02 16:54:09 -0700889 bootstub_tmp = bootstub + '.tmp'
890 self._tools.Run('dd', ['if=' + bootstub, 'of=' + bootstub_tmp,
891 'bs=1M', 'skip=7'])
892 shutil.move(bootstub_tmp, bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100893
Simon Glassc90cf582012-03-13 15:40:47 -0700894 image = os.path.join(self._tools.outdir, 'image.bin')
895 pack.PackImage(self._tools.outdir, image)
896 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700897
Simon Glass439fe7a2012-03-09 16:19:34 -0800898 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700899 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700900 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700901
Simon Glass290a1802011-07-17 13:54:32 -0700902 def SelectFdt(self, fdt_fname):
903 """Select an FDT to control the firmware bundling
904
905 Args:
906 fdt_fname: The filename of the fdt to use.
907
Simon Glassc0f3dc62011-08-09 14:19:05 -0700908 Returns:
909 The Fdt object of the original fdt file, which we will not modify.
910
Simon Glass290a1802011-07-17 13:54:32 -0700911 We make a copy of this which will include any on-the-fly changes we want
912 to make.
913 """
914 self._fdt_fname = fdt_fname
915 self.CheckOptions()
916 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800917 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700918 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700919 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700920
Simon Glassc90cf582012-03-13 15:40:47 -0700921 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -0700922 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700923
924 - Checks options, tools, output directory, fdt.
925 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700926
927 Args:
Simon Glass56577572011-07-19 11:08:06 +1200928 hardware_id: Hardware ID to use for this board. If None, then the
929 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700930 output_fname: Output filename for the image. If this is not None, then
931 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -0700932 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -0700933
934 Returns:
935 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700936 """
Simon Glass89b86b82011-07-17 23:49:49 -0700937 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700938 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200939 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700940
941 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -0700942 image, pack = self._CreateImage(gbb, self.fdt)
943 if show_map:
944 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -0700945 if output_fname:
946 shutil.copyfile(image, output_fname)
947 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -0700948 return image, pack.props