blob: ee094ce9221f5798acfc6c1c9522225c5fe9d715 [file] [log] [blame]
Simon Glass89b86b82011-07-17 23:49:49 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This module builds a firmware image for a tegra-based board.
6
7This modules uses a few rudimentary other libraries for its activity.
8
9Here are the names we give to the various files we deal with. It is important
10to keep these consistent!
11
12 uboot u-boot.bin (with no device tree)
13 fdt the fdt blob
14 bct the BCT file
15 bootstub uboot + fdt
16 signed (uboot + fdt + bct) signed blob
17"""
18
Simon Glassceff3ff2012-04-04 11:23:45 -070019import glob
Simon Glass89b86b82011-07-17 23:49:49 -070020import os
21import re
22
23import cros_output
24from fdt import Fdt
25from pack_firmware import PackFirmware
26import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080027import struct
Simon Glass89b86b82011-07-17 23:49:49 -070028import tempfile
Simon Glass439fe7a2012-03-09 16:19:34 -080029from tools import CmdError
Simon Glass89b86b82011-07-17 23:49:49 -070030from tools import Tools
31from write_firmware import WriteFirmware
32
33# This data is required by bmpblk_utility. Does it ever change?
34# It was stored with the chromeos-bootimage ebuild, but we want
35# this utility to work outside the chroot.
36yaml_data = '''
37bmpblock: 1.0
38
39images:
40 devmode: DeveloperBmp/DeveloperBmp.bmp
41 recovery: RecoveryBmp/RecoveryBmp.bmp
42 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
43 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
44
45screens:
46 dev_en:
47 - [0, 0, devmode]
48 rec_en:
49 - [0, 0, recovery]
50 yuck_en:
51 - [0, 0, rec_yuck]
52 ins_en:
53 - [0, 0, rec_insert]
54
55localizations:
56 - [ dev_en, rec_en, yuck_en, ins_en ]
57'''
58
59class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070060 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070061
Simon Glass290a1802011-07-17 13:54:32 -070062 Sequence of events:
63 bundle = Bundle(tools.Tools(), cros_output.Output())
64 bundle.SetDirs(...)
65 bundle.SetFiles(...)
66 bundle.SetOptions(...)
67 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070068 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070069 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070070
Simon Glass290a1802011-07-17 13:54:32 -070071 Public properties:
72 fdt: The fdt object that we use for building our image. This wil be the
73 one specified by the user, except that we might add config options
74 to it. This is set up by SelectFdt() which must be called before
75 bundling starts.
76 uboot_fname: Full filename of the U-Boot binary we use.
77 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -070078 spl_source: Source device to load U-Boot from, in SPL:
79 straps: Select device according to CPU strap pins
80 spi: Boot from SPI
81 emmc: Boot from eMMC
Simon Glass290a1802011-07-17 13:54:32 -070082 """
Simon Glass89b86b82011-07-17 23:49:49 -070083
Simon Glass290a1802011-07-17 13:54:32 -070084 def __init__(self, tools, output):
85 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -070086
Simon Glass290a1802011-07-17 13:54:32 -070087 Args:
88 tools: A tools.Tools object to use for external tools.
89 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -070090 """
Simon Glass290a1802011-07-17 13:54:32 -070091 self._tools = tools
92 self._out = output
93
94 # Set up the things we need to know in order to operate.
95 self._board = None # Board name, e.g. tegra2_seaboard.
96 self._fdt_fname = None # Filename of our FDT.
97 self.uboot_fname = None # Filename of our U-Boot binary.
98 self.bct_fname = None # Filename of our BCT file.
99 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800100 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700101 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -0700102 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -0700103 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
104 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass559b6612012-05-23 13:28:45 -0700105 self.spl_source = 'straps' # SPL boot according to board settings
Simon Glass07267952012-06-08 12:45:13 -0700106 self.skeleton_fname = None # Filename of Coreboot skeleton file
Simon Glassbe0bc002012-08-16 12:50:48 -0700107 self.ecrw_fname = None # Filename of EC file
108 self.ecro_fname = None # Filename of EC read-only file
Simon Glass290a1802011-07-17 13:54:32 -0700109
110 def SetDirs(self, keydir):
111 """Set up directories required for Bundle.
112
113 Args:
114 keydir: Directory containing keys to use for signing firmware.
115 """
116 self._keydir = keydir
117
Simon Glass6dcc2f22011-07-28 15:26:49 +1200118 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glass07267952012-06-08 12:45:13 -0700119 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassbe0bc002012-08-16 12:50:48 -0700120 skeleton=None, ecrw=None, ecro=None, kernel=None):
Simon Glass290a1802011-07-17 13:54:32 -0700121 """Set up files required for Bundle.
122
123 Args:
124 board: The name of the board to target (e.g. tegra2_seaboard).
125 uboot: The filename of the u-boot.bin image to use.
126 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800127 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700128 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200129 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700130 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700131 exynos_bl1: The filename of the exynos BL1 file
132 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
133 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700134 ecrw: The filename of the EC (Embedded Controller) read-write file.
135 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700136 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700137 """
138 self._board = board
139 self.uboot_fname = uboot
140 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800141 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700142 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200143 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700144 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700145 self.exynos_bl1 = exynos_bl1
146 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700147 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700148 self.ecrw_fname = ecrw
149 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700150 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700151
152 def SetOptions(self, small):
153 """Set up options supported by Bundle.
154
155 Args:
156 small: Only create a signed U-Boot - don't produce the full packed
157 firmware image. This is useful for devs who want to replace just the
158 U-Boot part while keeping the keys, gbb, etc. the same.
159 """
160 self._small = small
161
162 def CheckOptions(self):
163 """Check provided options and select defaults."""
164 if not self._board:
165 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700166 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700167 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700168 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700169 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700170 base_name = re.sub('_', '-', self._board)
171
172 # In case the name exists with a prefix or suffix, find it.
173 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
174 found_list = glob.glob(self._tools.Filename(wildcard))
175 if len(found_list) == 1:
176 self._fdt_fname = found_list[0]
177 else:
178 # We didn't find anything definite, so set up our expected name.
179 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
180
Simon Glass881964d2012-04-04 11:34:09 -0700181 # Convert things like 'exynos5250-daisy' into a full path.
182 root, ext = os.path.splitext(self._fdt_fname)
183 if not ext and not os.path.dirname(root):
184 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
185
Simon Glass290a1802011-07-17 13:54:32 -0700186 if not self.uboot_fname:
187 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
188 if not self.bct_fname:
189 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700190 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700191 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700192 if not self.exynos_bl1:
193 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
194 if not self.exynos_bl2:
195 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700196 if not self.coreboot_fname:
197 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
198 if not self.skeleton_fname:
199 self.skeleton_fname = os.path.join(build_root, 'skeleton.bin')
Simon Glassbe0bc002012-08-16 12:50:48 -0700200 if not self.ecrw_fname:
201 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
202 if not self.ecro_fname:
203 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700204
Simon Glass75759302012-03-15 20:26:53 -0700205 def GetFiles(self):
206 """Get a list of files that we know about.
207
208 This is the opposite of SetFiles except that we may have put in some
209 default names. It returns a dictionary containing the filename for
210 each of a number of pre-defined files.
211
212 Returns:
213 Dictionary, with one entry for each file.
214 """
215 file_list = {
216 'bct' : self.bct_fname,
217 'exynos-bl1' : self.exynos_bl1,
218 'exynos-bl2' : self.exynos_bl2,
219 }
220 return file_list
221
Simon Glass56577572011-07-19 11:08:06 +1200222 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700223 """Create a GBB for the image.
224
Simon Glass56577572011-07-19 11:08:06 +1200225 Args:
226 hardware_id: Hardware ID to use for this board. If None, then the
227 default from the Fdt will be used
228
Simon Glass89b86b82011-07-17 23:49:49 -0700229 Returns:
230 Path of the created GBB file.
231
232 Raises:
233 CmdError if a command fails.
234 """
Simon Glass56577572011-07-19 11:08:06 +1200235 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800236 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700237 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700238 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700239
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800240 chromeos_config = self.fdt.GetProps("/chromeos-config")
Hung-Te Linec76cb62012-07-18 15:11:39 +0800241 # Build GBB flags.
242 # (src/platform/vboot_reference/firmware/include/gbb_header.h)
243 flag_properties = {
244 'fast-developer-mode': 0x01,
245 'gbb-flag-dev-screen-short-delay': 0x00000001,
246 'gbb-flag-load-option-roms': 0x00000002,
247 'gbb-flag-enable-alternate-os': 0x00000004,
248 'gbb-flag-force-dev-switch-on': 0x00000008,
249 'gbb-flag-force-dev-boot-usb': 0x00000010,
250 'gbb-flag-disable-fw-rollback-check': 0x00000020,
251 }
252 gbb_flags = 0
253 for flag_name, flag_value in flag_properties.items():
254 if flag_name not in chromeos_config:
255 continue
256 gbb_flags |= flag_value
257 self._out.Notice("Enabling %s." % flag_name)
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800258
Simon Glass89b86b82011-07-17 23:49:49 -0700259 self._out.Progress('Creating GBB')
260 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
261 sizes = ['%#x' % size for size in sizes]
262 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700263 keydir = self._tools.Filename(self._keydir)
264 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700265 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200266 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700267 '--rootkey=%s/root_key.vbpubk' % keydir,
268 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700269 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800270 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700271 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700272 cwd=odir)
273 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700274
Simon Glasse13ee2c2011-07-28 08:12:28 +1200275 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700276 """Sign an image so that the Tegra SOC will boot it.
277
278 Args:
279 bct: BCT file to use.
280 bootstub: Boot stub (U-Boot + fdt) file to sign.
281 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700282
283 Returns:
284 filename of signed image.
285
286 Raises:
287 CmdError if a command fails.
288 """
289 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200290 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700291 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200292 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700293 fd = open(config, 'w')
294 fd.write('Version = 1;\n')
295 fd.write('Redundancy = 1;\n')
296 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700297
298 # TODO(dianders): Right now, we don't have enough space in our flash map
299 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
300 # sure what this does for reliability, but at least things will fit...
301 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
302 if is_nand:
303 fd.write('Bctcopy = 1;\n')
304
Simon Glass89b86b82011-07-17 23:49:49 -0700305 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
306 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700307
Simon Glass89b86b82011-07-17 23:49:49 -0700308 fd.close()
309
310 self._tools.Run('cbootimage', [config, signed])
311 self._tools.OutputSize('BCT', bct)
312 self._tools.OutputSize('Signed image', signed)
313 return signed
314
Doug Anderson86ce5f42011-07-27 10:40:18 -0700315 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700316 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700317
318 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700319 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700320 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700321 """
Simon Glass468d8752012-09-19 16:36:19 -0700322 if bootcmd is not None:
323 if bootcmd == 'none':
324 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800325 self.fdt.PutString('/config', 'bootcmd', bootcmd)
326 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700327 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700328
Simon Glassa4934b72012-05-09 13:35:02 -0700329 def SetNodeEnabled(self, node_name, enabled):
330 """Set whether an node is enabled or disabled.
331
332 This simply sets the 'status' property of a node to "ok", or "disabled".
333
334 The node should either be a full path to the node (like '/uart@10200000')
335 or an alias property.
336
337 Aliases are supported like this:
338
339 aliases {
340 console = "/uart@10200000";
341 };
342
343 pointing to a node:
344
345 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700346 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700347 };
348
349 In this case, this function takes the name of the alias ('console' in
350 this case) and updates the status of the node that is pointed to, to
351 either ok or disabled. If the alias does not exist, a warning is
352 displayed.
353
354 Args:
355 node_name: Name of node (e.g. '/uart@10200000') or alias alias
356 (e.g. 'console') to adjust
357 enabled: True to enable, False to disable
358 """
359 # Look up the alias if this is an alias reference
360 if not node_name.startswith('/'):
361 lookup = self.fdt.GetString('/aliases', node_name, '')
362 if not lookup:
363 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
364 return
365 node_name = lookup
366 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700367 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700368 else:
369 status = 'disabled'
370 self.fdt.PutString(node_name, 'status', status)
371
372 def AddEnableList(self, enable_list):
373 """Process a list of nodes to enable/disable.
374
375 Args:
376 config_list: List of (node, value) tuples to add to the fdt. For each
377 tuple:
378 node: The fdt node to write to will be <node> or pointed to by
379 /aliases/<node>. We can tell which
380 value: 0 to disable the node, 1 to enable it
381 """
382 if enable_list:
383 for node_name, enabled in enable_list:
384 try:
385 enabled = int(enabled)
386 if enabled not in (0, 1):
387 raise ValueError
388 except ValueError as str:
389 raise CmdError("Invalid enable option value '%s' "
390 "(should be 0 or 1)" % enabled)
391 self.SetNodeEnabled(node_name, enabled)
392
Simon Glass290a1802011-07-17 13:54:32 -0700393 def AddConfigList(self, config_list, use_int=False):
394 """Add a list of config items to the fdt.
395
396 Normally these values are written to the fdt as strings, but integers
397 are also supported, in which case the values will be converted to integers
398 (if necessary) before being stored.
399
400 Args:
401 config_list: List of (config, value) tuples to add to the fdt. For each
402 tuple:
403 config: The fdt node to write to will be /config/<config>.
404 value: An integer or string value to write.
405 use_int: True to only write integer values.
406
407 Raises:
408 CmdError: if a value is required to be converted to integer but can't be.
409 """
410 if config_list:
411 for config in config_list:
412 value = config[1]
413 if use_int:
414 try:
415 value = int(value)
416 except ValueError as str:
417 raise CmdError("Cannot convert config option '%s' to integer" %
418 value)
419 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800420 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700421 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800422 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700423
Simon Glass7c2d5572011-11-15 14:47:08 -0800424 def DecodeTextBase(self, data):
425 """Look at a U-Boot image and try to decode its TEXT_BASE.
426
427 This works because U-Boot has a header with the value 0x12345678
428 immediately followed by the TEXT_BASE value. We can therefore read this
429 from the image with some certainty. We check only the first 40 words
430 since the header should be within that region.
431
Simon Glass96b50302012-07-20 06:55:28 +0100432 Since upstream Tegra has moved to having a 16KB SPL region at the start,
433 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
434 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
435
Simon Glass7c2d5572011-11-15 14:47:08 -0800436 Args:
437 data: U-Boot binary data
438
439 Returns:
440 Text base (integer) or None if none was found
441 """
442 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100443 for start in (0, 0x4000):
444 for i in range(start, start + 160, 4):
445 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800446
Simon Glass96b50302012-07-20 06:55:28 +0100447 # TODO(sjg): This does not cope with a big-endian target
448 value = struct.unpack('<I', word)[0]
449 if found:
450 return value - start
451 if value == 0x12345678:
452 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800453
454 return None
455
456 def CalcTextBase(self, name, fdt, fname):
457 """Calculate the TEXT_BASE to use for U-Boot.
458
459 Normally this value is in the fdt, so we just read it from there. But as
460 a second check we look at the image itself in case this is different, and
461 switch to that if it is.
462
463 This allows us to flash any U-Boot even if its TEXT_BASE is different.
464 This is particularly useful with upstream U-Boot which uses a different
465 value (which we will move to).
466 """
467 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200468 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800469 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100470 text_base_str = '%#x' % text_base if text_base else 'None'
471 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
472 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800473
474 # If they are different, issue a warning and switch over.
475 if text_base and text_base != fdt_text_base:
476 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
477 "fdt value of %x. Using %x" % (text_base, name,
478 fdt_text_base, text_base))
479 fdt_text_base = text_base
480 return fdt_text_base
481
Simon Glass6dcc2f22011-07-28 15:26:49 +1200482 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700483 """Create a boot stub and a signed boot stub.
484
Simon Glass6dcc2f22011-07-28 15:26:49 +1200485 For postload:
486 We add a /config/postload-text-offset entry to the signed bootstub's
487 fdt so that U-Boot can find the postload code.
488
489 The raw (unsigned) bootstub will have a value of -1 for this since we will
490 simply append the postload code to the bootstub and it can find it there.
491 This will be used for RW A/B firmware.
492
493 For the signed case this value will specify where in the flash to find
494 the postload code. This will be used for RO firmware.
495
Simon Glass89b86b82011-07-17 23:49:49 -0700496 Args:
497 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800498 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200499 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700500
501 Returns:
502 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200503 Full path to bootstub (uboot + fdt(-1) + postload).
504 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700505
506 Raises:
507 CmdError if a command fails.
508 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200509 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800510 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700511 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200512
513 # Make a copy of the fdt for the bootstub
514 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800515 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700516 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200517
Simon Glass89b86b82011-07-17 23:49:49 -0700518 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700519 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
520 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700521 self._tools.OutputSize('Combined binary', bootstub)
522
Simon Glasse13ee2c2011-07-28 08:12:28 +1200523 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700524 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700525 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200526 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200527
528 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
529 data = self._tools.ReadFile(signed)
530
531 if postload:
532 # We must add postload to the bootstub since A and B will need to
533 # be able to find it without the /config/postload-text-offset mechanism.
534 bs_data = self._tools.ReadFile(bootstub)
535 bs_data += self._tools.ReadFile(postload)
536 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
537 self._tools.WriteFile(bootstub, bs_data)
538 self._tools.OutputSize('Combined binary with postload', bootstub)
539
540 # Now that we know the file size, adjust the fdt and re-sign
541 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800542 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200543 fdt_data = self._tools.ReadFile(fdt.fname)
544 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
545 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
546 postload_bootstub, text_base)
547 if len(data) != os.path.getsize(signed):
548 raise CmdError('Signed file size changed from %d to %d after updating '
549 'fdt' % (len(data), os.path.getsize(signed)))
550
551 # Re-read the signed image, and add the post-load binary.
552 data = self._tools.ReadFile(signed)
553 data += self._tools.ReadFile(postload)
554 self._tools.OutputSize('Post-load binary', postload)
555
556 self._tools.WriteFile(signed_postload, data)
557 self._tools.OutputSize('Final bootstub with postload', signed_postload)
558
559 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700560
Simon Glasscbc83552012-07-23 15:26:22 +0100561 def _CreateCorebootStub(self, uboot, coreboot, seabios):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700562 """Create a coreboot boot stub.
563
564 Args:
565 uboot: Path to u-boot.bin (may be chroot-relative)
566 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700567 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700568
569 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100570 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700571
572 Raises:
573 CmdError if a command fails.
574 """
575 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700576
577 # U-Boot itself does not put a .elf extension on the elf file.
578 # The U-Boot ebuild does, but we shouldn't actually require it since
579 # devs may want to just use what U-Boot creates.
580 uboot_elf = uboot.replace('.bin', '')
581 if not os.path.exists(self._tools.Filename(uboot_elf)):
582 uboot_elf = uboot.replace('.bin', '.elf')
583 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Vincent Palatinf7286772011-10-12 14:31:53 -0700584 if seabios:
Simon Glass146cb8e2012-03-09 15:51:24 -0800585 self._tools.Run('cbfstool', [bootstub, 'add-payload', seabios,
Vincent Palatinf7286772011-10-12 14:31:53 -0700586 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800587 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700588 'img/U-Boot', 'lzma'])
589 else:
Simon Glass146cb8e2012-03-09 15:51:24 -0800590 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700591 'fallback/payload', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100592
593 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700594 return bootstub
595
Simon Glass3b404092012-05-23 13:10:36 -0700596 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700597 """Update the parameters in a BL2 blob.
598
599 We look at the list in the parameter block, extract the value of each
600 from the device tree, and write that value to the parameter block.
601
602 Args:
603 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700604 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700605 data: The BL2 data.
606 pos: The position of the start of the parameter block.
607
608 Returns:
609 The new contents of the parameter block, after updating.
610 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700611 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
612 if version != 1:
613 raise CmdError("Cannot update machine parameter block version '%d'" %
614 version)
615 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700616 raise CmdError("Machine parameter block size %d is invalid: "
617 "pos=%d, size=%d, space=%d, len=%d" %
618 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700619
620 # Move past the header and read the parameter list, which is terminated
621 # with \0.
622 pos += 12
623 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
624 param_len = param_list.find('\0')
625 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700626 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700627
628 # Work through the parameters one at a time, adding each value
629 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700630 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700631 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700632 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700633 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700634 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700635 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
636 if not mem_type in mem_types:
637 raise CmdError("Unknown memory type '%s'" % mem_type)
638 value = mem_types.index(mem_type)
639 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700640 elif param == 'M' :
641 mem_manuf = fdt.GetString('/dmc', 'mem-manuf')
642 mem_manufs = ['autodetect', 'elpida', 'samsung']
643 if not mem_manuf in mem_manufs:
644 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
645 value = mem_manufs.index(mem_manuf)
646 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700647 elif param == 'f' :
648 mem_freq = fdt.GetInt('/dmc', 'clock-frequency') / 1000000
649 if not mem_freq in [533, 667, 800]:
650 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
651 value = mem_freq
652 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700653 elif param == 'v':
654 value = 31
655 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700656 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700657 value = (spl_load_size + 0xfff) & ~0xfff
658 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
659 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700660 elif param == 'b':
661 # These values come from enum boot_mode in U-Boot's cpu.h
662 if self.spl_source == 'straps':
663 value = 32
664 elif self.spl_source == 'emmc':
665 value = 4
666 elif self.spl_source == 'spi':
667 value = 20
668 elif self.spl_source == 'usb':
669 value = 33
670 else:
671 raise CmdError("Invalid boot source '%s'" % self.spl_source)
672 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700673 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700674 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700675 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700676 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700677 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700678
679 # Put the data into our block.
680 data = data[:pos] + new_data + data[pos + len(new_data):]
681 self._out.Info('BL2 configuration complete')
682 return data
683
Simon Glasse5e8afb2012-05-23 11:19:23 -0700684 def _UpdateChecksum(self, data):
685 """Update the BL2 checksum.
686
687 The checksum is a 4 byte sum of all the bytes in the image before the
688 last 4 bytes (which hold the checksum).
689
690 Args:
691 data: The BL2 data to update.
692
693 Returns:
694 The new contents of the BL2 data, after updating the checksum.
695 """
696 checksum = 0
697 for ch in data[:-4]:
698 checksum += ord(ch)
699 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
700
Simon Glass559b6612012-05-23 13:28:45 -0700701 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700702 """Configure an Exynos BL2 binary for our needs.
703
704 We create a new modified BL2 and return its filename.
705
706 Args:
707 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700708 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700709 orig_bl2: Filename of original BL2 file to modify.
710 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700711 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700712 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700713 data = self._tools.ReadFile(orig_bl2)
714 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700715
716 # Locate the parameter block
717 data = self._tools.ReadFile(bl2)
718 marker = struct.pack('<L', 0xdeadbeef)
719 pos = data.rfind(marker)
720 if not pos:
721 raise CmdError("Could not find machine parameter block in '%s'" %
722 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700723 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700724 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700725 self._tools.WriteFile(bl2, data)
726 return bl2
727
Simon Glass89b86b82011-07-17 23:49:49 -0700728 def _PackOutput(self, msg):
729 """Helper function to write output from PackFirmware (verbose level 2).
730
731 This is passed to PackFirmware for it to use to write output.
732
733 Args:
734 msg: Message to display.
735 """
736 self._out.Notice(msg)
737
Simon Glass439fe7a2012-03-09 16:19:34 -0800738 def _BuildBlob(self, pack, fdt, blob_type):
739 """Build the blob data for a particular blob type.
740
741 Args:
742 blob_type: The type of blob to create data for. Supported types are:
743 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
744 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
745 """
746 if blob_type == 'coreboot':
747 coreboot = self._CreateCorebootStub(self.uboot_fname,
Simon Glasscbc83552012-07-23 15:26:22 +0100748 self.coreboot_fname, self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800749 pack.AddProperty('coreboot', coreboot)
750 pack.AddProperty('image', coreboot)
751 elif blob_type == 'signed':
752 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
753 self.postload_fname)
754 pack.AddProperty('bootstub', bootstub)
755 pack.AddProperty('signed', signed)
756 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700757 elif blob_type == 'exynos-bl1':
758 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700759
760 # TODO(sjg@chromium.org): Deprecate ecbin
761 elif blob_type in ['ecrw', 'ecbin']:
762 pack.AddProperty('ecrw', self.ecrw_fname)
763 pack.AddProperty('ecbin', self.ecrw_fname)
764 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700765 # crosbug.com/p/13143
766 # We cannot have an fmap in the EC image since there can be only one,
767 # which is the main fmap describing the whole image.
768 # Ultimately the EC will not have an fmap, since with software sync
769 # there is no flashrom involvement in updating the EC flash, and thus
770 # no need for the fmap.
771 # For now, mangle the fmap name to avoid problems.
772 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
773 data = self._tools.ReadFile(self.ecro_fname)
774 data = re.sub('__FMAP__', '__fMAP__', data)
775 self._tools.WriteFile(updated_ecro, data)
776 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700777 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700778 spl_payload = pack.GetBlobParams(blob_type)
779
780 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
781 # from all flash map files.
782 if not spl_payload:
783 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
784 prop_list = 'boot+dtb'
785
786 # Do this later, when we remove boot+dtb.
787 # raise CmdError("No parameters provided for blob type '%s'" %
788 # blob_type)
789 else:
790 prop_list = spl_payload[0].split(',')
791 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
792 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
793 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700794 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700795 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800796 elif pack.GetProperty(blob_type):
797 pass
798 else:
799 raise CmdError("Unknown blob type '%s' required in flash map" %
800 blob_type)
801
Simon Glass290a1802011-07-17 13:54:32 -0700802 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700803 """Create a full firmware image, along with various by-products.
804
805 This uses the provided u-boot.bin, fdt and bct to create a firmware
806 image containing all the required parts. If the GBB is not supplied
807 then this will just return a signed U-Boot as the image.
808
809 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200810 gbb: Full path to the GBB file, or empty if a GBB is not required.
811 fdt: Fdt object containing required information.
812
813 Returns:
814 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700815
816 Raises:
817 CmdError if a command fails.
818 """
Simon Glass02d124a2012-03-02 14:47:20 -0800819 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700820
Simon Glass439fe7a2012-03-09 16:19:34 -0800821 # Get the flashmap so we know what to build
822 pack = PackFirmware(self._tools, self._out)
823 pack.SelectFdt(fdt)
824
825 # Get all our blobs ready
826 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700827 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700828 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700829
Simon Glassde9c8072012-07-02 22:29:02 -0700830 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
831 if self.kernel_fname:
832 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
833
Simon Glass50f74602012-03-15 21:04:25 -0700834 # Make a copy of the fdt for the bootstub
835 fdt_data = self._tools.ReadFile(fdt.fname)
836 uboot_data = self._tools.ReadFile(self.uboot_fname)
837 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
838 self._tools.WriteFile(uboot_copy, uboot_data)
839
840 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
841 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700842
843 # TODO(sjg@chromium.org): Deprecate this property when all boards
844 # use a comma-separated list for section contents. We will then
845 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700846 pack.AddProperty('boot+dtb', bootstub)
847
Simon Glass439fe7a2012-03-09 16:19:34 -0800848 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100849 blob_list = pack.GetBlobList()
850 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700851 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800852 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700853
854 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700855 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800856 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800857 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800858 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700859 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800860 pack.AddProperty('fwid', fwid)
861 pack.AddProperty('gbb', gbb)
862 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700863
864 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700865
866 # Record position and size of all blob members in the FDT
867 pack.UpdateBlobPositions(fdt)
868
Simon Glasscbc83552012-07-23 15:26:22 +0100869 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
870 # has created a rom file without the dtb, because until now it is not
871 # complete. Add the dtb here.
872 # A better anwer might be to put the dtb in memory immediately after
873 # U-Boot as is done for ARM and have coreboot load it as a binary file
874 # instead of an elf. However, I need to check whether coreboot supports
875 # this, and whether this is desirable for other reasons.
876 if 'coreboot' in blob_list:
877 bootstub = pack.GetProperty('coreboot')
878 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
879 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
880 '0xac'])
881
Simon Glassc90cf582012-03-13 15:40:47 -0700882 image = os.path.join(self._tools.outdir, 'image.bin')
883 pack.PackImage(self._tools.outdir, image)
884 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700885
Simon Glass439fe7a2012-03-09 16:19:34 -0800886 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700887 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700888 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700889
Simon Glass290a1802011-07-17 13:54:32 -0700890 def SelectFdt(self, fdt_fname):
891 """Select an FDT to control the firmware bundling
892
893 Args:
894 fdt_fname: The filename of the fdt to use.
895
Simon Glassc0f3dc62011-08-09 14:19:05 -0700896 Returns:
897 The Fdt object of the original fdt file, which we will not modify.
898
Simon Glass290a1802011-07-17 13:54:32 -0700899 We make a copy of this which will include any on-the-fly changes we want
900 to make.
901 """
902 self._fdt_fname = fdt_fname
903 self.CheckOptions()
904 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800905 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700906 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700907 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700908
Simon Glassc90cf582012-03-13 15:40:47 -0700909 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -0700910 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700911
912 - Checks options, tools, output directory, fdt.
913 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700914
915 Args:
Simon Glass56577572011-07-19 11:08:06 +1200916 hardware_id: Hardware ID to use for this board. If None, then the
917 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700918 output_fname: Output filename for the image. If this is not None, then
919 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -0700920 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -0700921
922 Returns:
923 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700924 """
Simon Glass89b86b82011-07-17 23:49:49 -0700925 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700926 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200927 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700928
929 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -0700930 image, pack = self._CreateImage(gbb, self.fdt)
931 if show_map:
932 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -0700933 if output_fname:
934 shutil.copyfile(image, output_fname)
935 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -0700936 return image, pack.props