blob: af60d7ff52ff6f070f51d0c522cbc7912a75d7ca [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')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700206 if not self.seabios_fname:
207 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700208 if not self.ecrw_fname:
209 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
210 if not self.ecro_fname:
211 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700212
Simon Glass75759302012-03-15 20:26:53 -0700213 def GetFiles(self):
214 """Get a list of files that we know about.
215
216 This is the opposite of SetFiles except that we may have put in some
217 default names. It returns a dictionary containing the filename for
218 each of a number of pre-defined files.
219
220 Returns:
221 Dictionary, with one entry for each file.
222 """
223 file_list = {
224 'bct' : self.bct_fname,
225 'exynos-bl1' : self.exynos_bl1,
226 'exynos-bl2' : self.exynos_bl2,
227 }
228 return file_list
229
Simon Glass56577572011-07-19 11:08:06 +1200230 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700231 """Create a GBB for the image.
232
Simon Glass56577572011-07-19 11:08:06 +1200233 Args:
234 hardware_id: Hardware ID to use for this board. If None, then the
235 default from the Fdt will be used
236
Simon Glass89b86b82011-07-17 23:49:49 -0700237 Returns:
238 Path of the created GBB file.
239
240 Raises:
241 CmdError if a command fails.
242 """
Simon Glass56577572011-07-19 11:08:06 +1200243 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800244 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700245 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700246 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700247
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800248 chromeos_config = self.fdt.GetProps("/chromeos-config")
Hung-Te Linec76cb62012-07-18 15:11:39 +0800249 # Build GBB flags.
250 # (src/platform/vboot_reference/firmware/include/gbb_header.h)
251 flag_properties = {
252 'fast-developer-mode': 0x01,
253 'gbb-flag-dev-screen-short-delay': 0x00000001,
254 'gbb-flag-load-option-roms': 0x00000002,
255 'gbb-flag-enable-alternate-os': 0x00000004,
256 'gbb-flag-force-dev-switch-on': 0x00000008,
257 'gbb-flag-force-dev-boot-usb': 0x00000010,
258 'gbb-flag-disable-fw-rollback-check': 0x00000020,
Stefan Reinauere993af52012-10-05 10:47:45 -0700259 'gbb-flag-enter-triggers-tonorm': 0x00000040,
260 'gbb-flag-force-dev-boot-legacy': 0x00000080,
Hung-Te Linec76cb62012-07-18 15:11:39 +0800261 }
262 gbb_flags = 0
263 for flag_name, flag_value in flag_properties.items():
264 if flag_name not in chromeos_config:
265 continue
266 gbb_flags |= flag_value
267 self._out.Notice("Enabling %s." % flag_name)
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800268
Simon Glass89b86b82011-07-17 23:49:49 -0700269 self._out.Progress('Creating GBB')
270 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
271 sizes = ['%#x' % size for size in sizes]
272 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700273 keydir = self._tools.Filename(self._keydir)
274 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700275 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200276 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700277 '--rootkey=%s/root_key.vbpubk' % keydir,
278 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700279 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800280 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700281 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700282 cwd=odir)
283 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700284
Simon Glasse13ee2c2011-07-28 08:12:28 +1200285 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700286 """Sign an image so that the Tegra SOC will boot it.
287
288 Args:
289 bct: BCT file to use.
290 bootstub: Boot stub (U-Boot + fdt) file to sign.
291 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700292
293 Returns:
294 filename of signed image.
295
296 Raises:
297 CmdError if a command fails.
298 """
299 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200300 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700301 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200302 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700303 fd = open(config, 'w')
304 fd.write('Version = 1;\n')
305 fd.write('Redundancy = 1;\n')
306 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700307
308 # TODO(dianders): Right now, we don't have enough space in our flash map
309 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
310 # sure what this does for reliability, but at least things will fit...
311 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
312 if is_nand:
313 fd.write('Bctcopy = 1;\n')
314
Simon Glass89b86b82011-07-17 23:49:49 -0700315 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
316 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700317
Simon Glass89b86b82011-07-17 23:49:49 -0700318 fd.close()
319
320 self._tools.Run('cbootimage', [config, signed])
321 self._tools.OutputSize('BCT', bct)
322 self._tools.OutputSize('Signed image', signed)
323 return signed
324
Doug Anderson86ce5f42011-07-27 10:40:18 -0700325 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700326 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700327
328 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700329 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700330 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700331 """
Simon Glass468d8752012-09-19 16:36:19 -0700332 if bootcmd is not None:
333 if bootcmd == 'none':
334 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800335 self.fdt.PutString('/config', 'bootcmd', bootcmd)
336 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700337 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700338
Simon Glassa4934b72012-05-09 13:35:02 -0700339 def SetNodeEnabled(self, node_name, enabled):
340 """Set whether an node is enabled or disabled.
341
342 This simply sets the 'status' property of a node to "ok", or "disabled".
343
344 The node should either be a full path to the node (like '/uart@10200000')
345 or an alias property.
346
347 Aliases are supported like this:
348
349 aliases {
350 console = "/uart@10200000";
351 };
352
353 pointing to a node:
354
355 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700356 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700357 };
358
359 In this case, this function takes the name of the alias ('console' in
360 this case) and updates the status of the node that is pointed to, to
361 either ok or disabled. If the alias does not exist, a warning is
362 displayed.
363
364 Args:
365 node_name: Name of node (e.g. '/uart@10200000') or alias alias
366 (e.g. 'console') to adjust
367 enabled: True to enable, False to disable
368 """
369 # Look up the alias if this is an alias reference
370 if not node_name.startswith('/'):
371 lookup = self.fdt.GetString('/aliases', node_name, '')
372 if not lookup:
373 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
374 return
375 node_name = lookup
376 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700377 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700378 else:
379 status = 'disabled'
380 self.fdt.PutString(node_name, 'status', status)
381
382 def AddEnableList(self, enable_list):
383 """Process a list of nodes to enable/disable.
384
385 Args:
386 config_list: List of (node, value) tuples to add to the fdt. For each
387 tuple:
388 node: The fdt node to write to will be <node> or pointed to by
389 /aliases/<node>. We can tell which
390 value: 0 to disable the node, 1 to enable it
391 """
392 if enable_list:
393 for node_name, enabled in enable_list:
394 try:
395 enabled = int(enabled)
396 if enabled not in (0, 1):
397 raise ValueError
398 except ValueError as str:
399 raise CmdError("Invalid enable option value '%s' "
400 "(should be 0 or 1)" % enabled)
401 self.SetNodeEnabled(node_name, enabled)
402
Simon Glass290a1802011-07-17 13:54:32 -0700403 def AddConfigList(self, config_list, use_int=False):
404 """Add a list of config items to the fdt.
405
406 Normally these values are written to the fdt as strings, but integers
407 are also supported, in which case the values will be converted to integers
408 (if necessary) before being stored.
409
410 Args:
411 config_list: List of (config, value) tuples to add to the fdt. For each
412 tuple:
413 config: The fdt node to write to will be /config/<config>.
414 value: An integer or string value to write.
415 use_int: True to only write integer values.
416
417 Raises:
418 CmdError: if a value is required to be converted to integer but can't be.
419 """
420 if config_list:
421 for config in config_list:
422 value = config[1]
423 if use_int:
424 try:
425 value = int(value)
426 except ValueError as str:
427 raise CmdError("Cannot convert config option '%s' to integer" %
428 value)
429 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800430 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700431 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800432 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700433
Simon Glass7c2d5572011-11-15 14:47:08 -0800434 def DecodeTextBase(self, data):
435 """Look at a U-Boot image and try to decode its TEXT_BASE.
436
437 This works because U-Boot has a header with the value 0x12345678
438 immediately followed by the TEXT_BASE value. We can therefore read this
439 from the image with some certainty. We check only the first 40 words
440 since the header should be within that region.
441
Simon Glass96b50302012-07-20 06:55:28 +0100442 Since upstream Tegra has moved to having a 16KB SPL region at the start,
443 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
444 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
445
Simon Glass7c2d5572011-11-15 14:47:08 -0800446 Args:
447 data: U-Boot binary data
448
449 Returns:
450 Text base (integer) or None if none was found
451 """
452 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100453 for start in (0, 0x4000):
454 for i in range(start, start + 160, 4):
455 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800456
Simon Glass96b50302012-07-20 06:55:28 +0100457 # TODO(sjg): This does not cope with a big-endian target
458 value = struct.unpack('<I', word)[0]
459 if found:
460 return value - start
461 if value == 0x12345678:
462 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800463
464 return None
465
466 def CalcTextBase(self, name, fdt, fname):
467 """Calculate the TEXT_BASE to use for U-Boot.
468
469 Normally this value is in the fdt, so we just read it from there. But as
470 a second check we look at the image itself in case this is different, and
471 switch to that if it is.
472
473 This allows us to flash any U-Boot even if its TEXT_BASE is different.
474 This is particularly useful with upstream U-Boot which uses a different
475 value (which we will move to).
476 """
477 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200478 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800479 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100480 text_base_str = '%#x' % text_base if text_base else 'None'
481 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
482 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800483
484 # If they are different, issue a warning and switch over.
485 if text_base and text_base != fdt_text_base:
486 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
487 "fdt value of %x. Using %x" % (text_base, name,
488 fdt_text_base, text_base))
489 fdt_text_base = text_base
490 return fdt_text_base
491
Simon Glass6dcc2f22011-07-28 15:26:49 +1200492 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700493 """Create a boot stub and a signed boot stub.
494
Simon Glass6dcc2f22011-07-28 15:26:49 +1200495 For postload:
496 We add a /config/postload-text-offset entry to the signed bootstub's
497 fdt so that U-Boot can find the postload code.
498
499 The raw (unsigned) bootstub will have a value of -1 for this since we will
500 simply append the postload code to the bootstub and it can find it there.
501 This will be used for RW A/B firmware.
502
503 For the signed case this value will specify where in the flash to find
504 the postload code. This will be used for RO firmware.
505
Simon Glass89b86b82011-07-17 23:49:49 -0700506 Args:
507 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800508 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200509 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700510
511 Returns:
512 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200513 Full path to bootstub (uboot + fdt(-1) + postload).
514 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700515
516 Raises:
517 CmdError if a command fails.
518 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200519 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800520 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700521 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200522
523 # Make a copy of the fdt for the bootstub
524 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800525 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700526 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200527
Simon Glass89b86b82011-07-17 23:49:49 -0700528 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700529 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
530 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700531 self._tools.OutputSize('Combined binary', bootstub)
532
Simon Glasse13ee2c2011-07-28 08:12:28 +1200533 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700534 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700535 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200536 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200537
538 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
539 data = self._tools.ReadFile(signed)
540
541 if postload:
542 # We must add postload to the bootstub since A and B will need to
543 # be able to find it without the /config/postload-text-offset mechanism.
544 bs_data = self._tools.ReadFile(bootstub)
545 bs_data += self._tools.ReadFile(postload)
546 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
547 self._tools.WriteFile(bootstub, bs_data)
548 self._tools.OutputSize('Combined binary with postload', bootstub)
549
550 # Now that we know the file size, adjust the fdt and re-sign
551 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800552 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200553 fdt_data = self._tools.ReadFile(fdt.fname)
554 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
555 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
556 postload_bootstub, text_base)
557 if len(data) != os.path.getsize(signed):
558 raise CmdError('Signed file size changed from %d to %d after updating '
559 'fdt' % (len(data), os.path.getsize(signed)))
560
561 # Re-read the signed image, and add the post-load binary.
562 data = self._tools.ReadFile(signed)
563 data += self._tools.ReadFile(postload)
564 self._tools.OutputSize('Post-load binary', postload)
565
566 self._tools.WriteFile(signed_postload, data)
567 self._tools.OutputSize('Final bootstub with postload', signed_postload)
568
569 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700570
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700571 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700572 """Create a coreboot boot stub.
573
574 Args:
575 uboot: Path to u-boot.bin (may be chroot-relative)
576 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700577 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700578
579 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100580 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700581
582 Raises:
583 CmdError if a command fails.
584 """
585 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700586
587 # U-Boot itself does not put a .elf extension on the elf file.
588 # The U-Boot ebuild does, but we shouldn't actually require it since
589 # devs may want to just use what U-Boot creates.
590 uboot_elf = uboot.replace('.bin', '')
591 if not os.path.exists(self._tools.Filename(uboot_elf)):
592 uboot_elf = uboot.replace('.bin', '.elf')
593 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700594 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700595 'fallback/payload', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100596
597 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700598 return bootstub
599
Simon Glass3b404092012-05-23 13:10:36 -0700600 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700601 """Update the parameters in a BL2 blob.
602
603 We look at the list in the parameter block, extract the value of each
604 from the device tree, and write that value to the parameter block.
605
606 Args:
607 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700608 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700609 data: The BL2 data.
610 pos: The position of the start of the parameter block.
611
612 Returns:
613 The new contents of the parameter block, after updating.
614 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700615 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
616 if version != 1:
617 raise CmdError("Cannot update machine parameter block version '%d'" %
618 version)
619 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700620 raise CmdError("Machine parameter block size %d is invalid: "
621 "pos=%d, size=%d, space=%d, len=%d" %
622 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700623
624 # Move past the header and read the parameter list, which is terminated
625 # with \0.
626 pos += 12
627 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
628 param_len = param_list.find('\0')
629 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700630 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700631
632 # Work through the parameters one at a time, adding each value
633 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700634 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700635 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700636 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700637 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700638 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700639 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
640 if not mem_type in mem_types:
641 raise CmdError("Unknown memory type '%s'" % mem_type)
642 value = mem_types.index(mem_type)
643 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700644 elif param == 'M' :
645 mem_manuf = fdt.GetString('/dmc', 'mem-manuf')
646 mem_manufs = ['autodetect', 'elpida', 'samsung']
647 if not mem_manuf in mem_manufs:
648 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
649 value = mem_manufs.index(mem_manuf)
650 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700651 elif param == 'f' :
652 mem_freq = fdt.GetInt('/dmc', 'clock-frequency') / 1000000
653 if not mem_freq in [533, 667, 800]:
654 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
655 value = mem_freq
656 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700657 elif param == 'v':
658 value = 31
659 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700660 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700661 value = (spl_load_size + 0xfff) & ~0xfff
662 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
663 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700664 elif param == 'b':
665 # These values come from enum boot_mode in U-Boot's cpu.h
666 if self.spl_source == 'straps':
667 value = 32
668 elif self.spl_source == 'emmc':
669 value = 4
670 elif self.spl_source == 'spi':
671 value = 20
672 elif self.spl_source == 'usb':
673 value = 33
674 else:
675 raise CmdError("Invalid boot source '%s'" % self.spl_source)
676 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700677 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700678 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700679 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700680 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700681 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700682
683 # Put the data into our block.
684 data = data[:pos] + new_data + data[pos + len(new_data):]
685 self._out.Info('BL2 configuration complete')
686 return data
687
Simon Glasse5e8afb2012-05-23 11:19:23 -0700688 def _UpdateChecksum(self, data):
689 """Update the BL2 checksum.
690
691 The checksum is a 4 byte sum of all the bytes in the image before the
692 last 4 bytes (which hold the checksum).
693
694 Args:
695 data: The BL2 data to update.
696
697 Returns:
698 The new contents of the BL2 data, after updating the checksum.
699 """
700 checksum = 0
701 for ch in data[:-4]:
702 checksum += ord(ch)
703 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
704
Simon Glass559b6612012-05-23 13:28:45 -0700705 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700706 """Configure an Exynos BL2 binary for our needs.
707
708 We create a new modified BL2 and return its filename.
709
710 Args:
711 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700712 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700713 orig_bl2: Filename of original BL2 file to modify.
714 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700715 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700716 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700717 data = self._tools.ReadFile(orig_bl2)
718 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700719
720 # Locate the parameter block
721 data = self._tools.ReadFile(bl2)
722 marker = struct.pack('<L', 0xdeadbeef)
723 pos = data.rfind(marker)
724 if not pos:
725 raise CmdError("Could not find machine parameter block in '%s'" %
726 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700727 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700728 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700729 self._tools.WriteFile(bl2, data)
730 return bl2
731
Simon Glass89b86b82011-07-17 23:49:49 -0700732 def _PackOutput(self, msg):
733 """Helper function to write output from PackFirmware (verbose level 2).
734
735 This is passed to PackFirmware for it to use to write output.
736
737 Args:
738 msg: Message to display.
739 """
740 self._out.Notice(msg)
741
Simon Glass439fe7a2012-03-09 16:19:34 -0800742 def _BuildBlob(self, pack, fdt, blob_type):
743 """Build the blob data for a particular blob type.
744
745 Args:
746 blob_type: The type of blob to create data for. Supported types are:
747 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
748 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
749 """
750 if blob_type == 'coreboot':
751 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700752 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800753 pack.AddProperty('coreboot', coreboot)
754 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700755 elif blob_type == 'legacy':
756 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800757 elif blob_type == 'signed':
758 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
759 self.postload_fname)
760 pack.AddProperty('bootstub', bootstub)
761 pack.AddProperty('signed', signed)
762 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700763 elif blob_type == 'exynos-bl1':
764 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700765
766 # TODO(sjg@chromium.org): Deprecate ecbin
767 elif blob_type in ['ecrw', 'ecbin']:
768 pack.AddProperty('ecrw', self.ecrw_fname)
769 pack.AddProperty('ecbin', self.ecrw_fname)
770 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700771 # crosbug.com/p/13143
772 # We cannot have an fmap in the EC image since there can be only one,
773 # which is the main fmap describing the whole image.
774 # Ultimately the EC will not have an fmap, since with software sync
775 # there is no flashrom involvement in updating the EC flash, and thus
776 # no need for the fmap.
777 # For now, mangle the fmap name to avoid problems.
778 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
779 data = self._tools.ReadFile(self.ecro_fname)
780 data = re.sub('__FMAP__', '__fMAP__', data)
781 self._tools.WriteFile(updated_ecro, data)
782 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700783 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700784 spl_payload = pack.GetBlobParams(blob_type)
785
786 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
787 # from all flash map files.
788 if not spl_payload:
789 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
790 prop_list = 'boot+dtb'
791
792 # Do this later, when we remove boot+dtb.
793 # raise CmdError("No parameters provided for blob type '%s'" %
794 # blob_type)
795 else:
796 prop_list = spl_payload[0].split(',')
797 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
798 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
799 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700800 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700801 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800802 elif pack.GetProperty(blob_type):
803 pass
804 else:
805 raise CmdError("Unknown blob type '%s' required in flash map" %
806 blob_type)
807
Simon Glass290a1802011-07-17 13:54:32 -0700808 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700809 """Create a full firmware image, along with various by-products.
810
811 This uses the provided u-boot.bin, fdt and bct to create a firmware
812 image containing all the required parts. If the GBB is not supplied
813 then this will just return a signed U-Boot as the image.
814
815 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200816 gbb: Full path to the GBB file, or empty if a GBB is not required.
817 fdt: Fdt object containing required information.
818
819 Returns:
820 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700821
822 Raises:
823 CmdError if a command fails.
824 """
Simon Glass02d124a2012-03-02 14:47:20 -0800825 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700826
Simon Glass439fe7a2012-03-09 16:19:34 -0800827 # Get the flashmap so we know what to build
828 pack = PackFirmware(self._tools, self._out)
829 pack.SelectFdt(fdt)
830
831 # Get all our blobs ready
832 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700833 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700834 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700835
Simon Glass47817052012-10-20 13:30:07 -0700836 # Let's create some copies of the fdt for vboot. These can be used to
837 # pass a different fdt to each firmware type. For now it is just used to
838 # check that the right fdt comes through.
839 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
840 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
841 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
842 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
843 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
844 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
845 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
846
Simon Glassde9c8072012-07-02 22:29:02 -0700847 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
848 if self.kernel_fname:
849 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
850
Simon Glass50f74602012-03-15 21:04:25 -0700851 # Make a copy of the fdt for the bootstub
852 fdt_data = self._tools.ReadFile(fdt.fname)
853 uboot_data = self._tools.ReadFile(self.uboot_fname)
854 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
855 self._tools.WriteFile(uboot_copy, uboot_data)
856
857 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
858 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700859
860 # TODO(sjg@chromium.org): Deprecate this property when all boards
861 # use a comma-separated list for section contents. We will then
862 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700863 pack.AddProperty('boot+dtb', bootstub)
864
Simon Glass439fe7a2012-03-09 16:19:34 -0800865 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100866 blob_list = pack.GetBlobList()
867 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700868 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800869 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700870
871 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700872 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800873 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800874 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800875 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700876 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800877 pack.AddProperty('fwid', fwid)
878 pack.AddProperty('gbb', gbb)
879 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700880
881 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700882
883 # Record position and size of all blob members in the FDT
884 pack.UpdateBlobPositions(fdt)
885
Simon Glasscbc83552012-07-23 15:26:22 +0100886 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
887 # has created a rom file without the dtb, because until now it is not
888 # complete. Add the dtb here.
889 # A better anwer might be to put the dtb in memory immediately after
890 # U-Boot as is done for ARM and have coreboot load it as a binary file
891 # instead of an elf. However, I need to check whether coreboot supports
892 # this, and whether this is desirable for other reasons.
893 if 'coreboot' in blob_list:
894 bootstub = pack.GetProperty('coreboot')
895 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
896 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
897 '0xac'])
Stefan Reinauer728be822012-10-02 16:54:09 -0700898 bootstub_tmp = bootstub + '.tmp'
899 self._tools.Run('dd', ['if=' + bootstub, 'of=' + bootstub_tmp,
900 'bs=1M', 'skip=7'])
901 shutil.move(bootstub_tmp, bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100902
Simon Glassc90cf582012-03-13 15:40:47 -0700903 image = os.path.join(self._tools.outdir, 'image.bin')
904 pack.PackImage(self._tools.outdir, image)
905 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700906
Simon Glass439fe7a2012-03-09 16:19:34 -0800907 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700908 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700909 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700910
Simon Glass290a1802011-07-17 13:54:32 -0700911 def SelectFdt(self, fdt_fname):
912 """Select an FDT to control the firmware bundling
913
914 Args:
915 fdt_fname: The filename of the fdt to use.
916
Simon Glassc0f3dc62011-08-09 14:19:05 -0700917 Returns:
918 The Fdt object of the original fdt file, which we will not modify.
919
Simon Glass290a1802011-07-17 13:54:32 -0700920 We make a copy of this which will include any on-the-fly changes we want
921 to make.
922 """
923 self._fdt_fname = fdt_fname
924 self.CheckOptions()
925 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800926 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700927 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700928 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700929
Simon Glassc90cf582012-03-13 15:40:47 -0700930 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -0700931 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700932
933 - Checks options, tools, output directory, fdt.
934 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700935
936 Args:
Simon Glass56577572011-07-19 11:08:06 +1200937 hardware_id: Hardware ID to use for this board. If None, then the
938 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700939 output_fname: Output filename for the image. If this is not None, then
940 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -0700941 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -0700942
943 Returns:
944 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700945 """
Simon Glass89b86b82011-07-17 23:49:49 -0700946 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700947 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200948 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700949
950 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -0700951 image, pack = self._CreateImage(gbb, self.fdt)
952 if show_map:
953 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -0700954 if output_fname:
955 shutil.copyfile(image, output_fname)
956 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -0700957 return image, pack.props