blob: 323fae2cc8a89a94dce9135a42fcc9e21d119a06 [file] [log] [blame]
Simon Glass89b86b82011-07-17 23:49:49 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This module builds a firmware image for a tegra-based board.
6
7This modules uses a few rudimentary other libraries for its activity.
8
9Here are the names we give to the various files we deal with. It is important
10to keep these consistent!
11
12 uboot u-boot.bin (with no device tree)
13 fdt the fdt blob
14 bct the BCT file
15 bootstub uboot + fdt
16 signed (uboot + fdt + bct) signed blob
17"""
18
Simon Glassceff3ff2012-04-04 11:23:45 -070019import glob
Simon Glass89b86b82011-07-17 23:49:49 -070020import os
21import re
22
23import cros_output
24from fdt import Fdt
25from pack_firmware import PackFirmware
26import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080027import struct
Simon Glass89b86b82011-07-17 23:49:49 -070028import tempfile
Simon Glass439fe7a2012-03-09 16:19:34 -080029from tools import CmdError
Simon Glass89b86b82011-07-17 23:49:49 -070030from tools import Tools
31from write_firmware import WriteFirmware
32
33# This data is required by bmpblk_utility. Does it ever change?
34# It was stored with the chromeos-bootimage ebuild, but we want
35# this utility to work outside the chroot.
36yaml_data = '''
37bmpblock: 1.0
38
39images:
40 devmode: DeveloperBmp/DeveloperBmp.bmp
41 recovery: RecoveryBmp/RecoveryBmp.bmp
42 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
43 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
44
45screens:
46 dev_en:
47 - [0, 0, devmode]
48 rec_en:
49 - [0, 0, recovery]
50 yuck_en:
51 - [0, 0, rec_yuck]
52 ins_en:
53 - [0, 0, rec_insert]
54
55localizations:
56 - [ dev_en, rec_en, yuck_en, ins_en ]
57'''
58
59class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070060 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070061
Simon Glass290a1802011-07-17 13:54:32 -070062 Sequence of events:
63 bundle = Bundle(tools.Tools(), cros_output.Output())
64 bundle.SetDirs(...)
65 bundle.SetFiles(...)
66 bundle.SetOptions(...)
67 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070068 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070069 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070070
Simon Glass290a1802011-07-17 13:54:32 -070071 Public properties:
72 fdt: The fdt object that we use for building our image. This wil be the
73 one specified by the user, except that we might add config options
74 to it. This is set up by SelectFdt() which must be called before
75 bundling starts.
76 uboot_fname: Full filename of the U-Boot binary we use.
77 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -070078 spl_source: Source device to load U-Boot from, in SPL:
79 straps: Select device according to CPU strap pins
80 spi: Boot from SPI
81 emmc: Boot from eMMC
Simon Glass290a1802011-07-17 13:54:32 -070082 """
Simon Glass89b86b82011-07-17 23:49:49 -070083
Simon Glass290a1802011-07-17 13:54:32 -070084 def __init__(self, tools, output):
85 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -070086
Simon Glass290a1802011-07-17 13:54:32 -070087 Args:
88 tools: A tools.Tools object to use for external tools.
89 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -070090 """
Simon Glass290a1802011-07-17 13:54:32 -070091 self._tools = tools
92 self._out = output
93
94 # Set up the things we need to know in order to operate.
95 self._board = None # Board name, e.g. tegra2_seaboard.
96 self._fdt_fname = None # Filename of our FDT.
97 self.uboot_fname = None # Filename of our U-Boot binary.
98 self.bct_fname = None # Filename of our BCT file.
99 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800100 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700101 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -0700102 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -0700103 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
104 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass559b6612012-05-23 13:28:45 -0700105 self.spl_source = 'straps' # SPL boot according to board settings
Simon Glass07267952012-06-08 12:45:13 -0700106 self.skeleton_fname = None # Filename of Coreboot skeleton file
Simon Glassbe0bc002012-08-16 12:50:48 -0700107 self.ecrw_fname = None # Filename of EC file
108 self.ecro_fname = None # Filename of EC read-only file
Simon Glass290a1802011-07-17 13:54:32 -0700109
110 def SetDirs(self, keydir):
111 """Set up directories required for Bundle.
112
113 Args:
114 keydir: Directory containing keys to use for signing firmware.
115 """
116 self._keydir = keydir
117
Simon Glass6dcc2f22011-07-28 15:26:49 +1200118 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glass07267952012-06-08 12:45:13 -0700119 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassbe0bc002012-08-16 12:50:48 -0700120 skeleton=None, ecrw=None, ecro=None, kernel=None):
Simon Glass290a1802011-07-17 13:54:32 -0700121 """Set up files required for Bundle.
122
123 Args:
124 board: The name of the board to target (e.g. tegra2_seaboard).
125 uboot: The filename of the u-boot.bin image to use.
126 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800127 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700128 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200129 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700130 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700131 exynos_bl1: The filename of the exynos BL1 file
132 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
133 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700134 ecrw: The filename of the EC (Embedded Controller) read-write file.
135 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700136 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700137 """
138 self._board = board
139 self.uboot_fname = uboot
140 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800141 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700142 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200143 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700144 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700145 self.exynos_bl1 = exynos_bl1
146 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700147 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700148 self.ecrw_fname = ecrw
149 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700150 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700151
152 def SetOptions(self, small):
153 """Set up options supported by Bundle.
154
155 Args:
156 small: Only create a signed U-Boot - don't produce the full packed
157 firmware image. This is useful for devs who want to replace just the
158 U-Boot part while keeping the keys, gbb, etc. the same.
159 """
160 self._small = small
161
162 def CheckOptions(self):
163 """Check provided options and select defaults."""
164 if not self._board:
165 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700166 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700167 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700168 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700169 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700170 base_name = re.sub('_', '-', self._board)
171
172 # In case the name exists with a prefix or suffix, find it.
173 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
174 found_list = glob.glob(self._tools.Filename(wildcard))
175 if len(found_list) == 1:
176 self._fdt_fname = found_list[0]
177 else:
178 # We didn't find anything definite, so set up our expected name.
179 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
180
Simon Glass881964d2012-04-04 11:34:09 -0700181 # Convert things like 'exynos5250-daisy' into a full path.
182 root, ext = os.path.splitext(self._fdt_fname)
183 if not ext and not os.path.dirname(root):
184 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
185
Simon Glass290a1802011-07-17 13:54:32 -0700186 if not self.uboot_fname:
187 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
188 if not self.bct_fname:
189 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700190 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700191 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700192 if not self.exynos_bl1:
193 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
194 if not self.exynos_bl2:
195 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700196 if not self.coreboot_fname:
197 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
198 if not self.skeleton_fname:
199 self.skeleton_fname = os.path.join(build_root, 'skeleton.bin')
Simon Glassbe0bc002012-08-16 12:50:48 -0700200 if not self.ecrw_fname:
201 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
202 if not self.ecro_fname:
203 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700204
Simon Glass75759302012-03-15 20:26:53 -0700205 def GetFiles(self):
206 """Get a list of files that we know about.
207
208 This is the opposite of SetFiles except that we may have put in some
209 default names. It returns a dictionary containing the filename for
210 each of a number of pre-defined files.
211
212 Returns:
213 Dictionary, with one entry for each file.
214 """
215 file_list = {
216 'bct' : self.bct_fname,
217 'exynos-bl1' : self.exynos_bl1,
218 'exynos-bl2' : self.exynos_bl2,
219 }
220 return file_list
221
Simon Glass56577572011-07-19 11:08:06 +1200222 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700223 """Create a GBB for the image.
224
Simon Glass56577572011-07-19 11:08:06 +1200225 Args:
226 hardware_id: Hardware ID to use for this board. If None, then the
227 default from the Fdt will be used
228
Simon Glass89b86b82011-07-17 23:49:49 -0700229 Returns:
230 Path of the created GBB file.
231
232 Raises:
233 CmdError if a command fails.
234 """
Simon Glass56577572011-07-19 11:08:06 +1200235 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800236 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700237 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700238 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700239
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800240 chromeos_config = self.fdt.GetProps("/chromeos-config")
Hung-Te Linec76cb62012-07-18 15:11:39 +0800241 # Build GBB flags.
242 # (src/platform/vboot_reference/firmware/include/gbb_header.h)
243 flag_properties = {
244 'fast-developer-mode': 0x01,
245 'gbb-flag-dev-screen-short-delay': 0x00000001,
246 'gbb-flag-load-option-roms': 0x00000002,
247 'gbb-flag-enable-alternate-os': 0x00000004,
248 'gbb-flag-force-dev-switch-on': 0x00000008,
249 'gbb-flag-force-dev-boot-usb': 0x00000010,
250 'gbb-flag-disable-fw-rollback-check': 0x00000020,
251 }
252 gbb_flags = 0
253 for flag_name, flag_value in flag_properties.items():
254 if flag_name not in chromeos_config:
255 continue
256 gbb_flags |= flag_value
257 self._out.Notice("Enabling %s." % flag_name)
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800258
Simon Glass89b86b82011-07-17 23:49:49 -0700259 self._out.Progress('Creating GBB')
260 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
261 sizes = ['%#x' % size for size in sizes]
262 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700263 keydir = self._tools.Filename(self._keydir)
264 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700265 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200266 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700267 '--rootkey=%s/root_key.vbpubk' % keydir,
268 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700269 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800270 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700271 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700272 cwd=odir)
273 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700274
Simon Glasse13ee2c2011-07-28 08:12:28 +1200275 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700276 """Sign an image so that the Tegra SOC will boot it.
277
278 Args:
279 bct: BCT file to use.
280 bootstub: Boot stub (U-Boot + fdt) file to sign.
281 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700282
283 Returns:
284 filename of signed image.
285
286 Raises:
287 CmdError if a command fails.
288 """
289 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200290 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700291 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200292 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700293 fd = open(config, 'w')
294 fd.write('Version = 1;\n')
295 fd.write('Redundancy = 1;\n')
296 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700297
298 # TODO(dianders): Right now, we don't have enough space in our flash map
299 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
300 # sure what this does for reliability, but at least things will fit...
301 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
302 if is_nand:
303 fd.write('Bctcopy = 1;\n')
304
Simon Glass89b86b82011-07-17 23:49:49 -0700305 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
306 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700307
Simon Glass89b86b82011-07-17 23:49:49 -0700308 fd.close()
309
310 self._tools.Run('cbootimage', [config, signed])
311 self._tools.OutputSize('BCT', bct)
312 self._tools.OutputSize('Signed image', signed)
313 return signed
314
Doug Anderson86ce5f42011-07-27 10:40:18 -0700315 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700316 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700317
318 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700319 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700320 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700321 """
Simon Glass290a1802011-07-17 13:54:32 -0700322 if bootcmd:
Simon Glass02d124a2012-03-02 14:47:20 -0800323 self.fdt.PutString('/config', 'bootcmd', bootcmd)
324 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700325 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700326
Simon Glassa4934b72012-05-09 13:35:02 -0700327 def SetNodeEnabled(self, node_name, enabled):
328 """Set whether an node is enabled or disabled.
329
330 This simply sets the 'status' property of a node to "ok", or "disabled".
331
332 The node should either be a full path to the node (like '/uart@10200000')
333 or an alias property.
334
335 Aliases are supported like this:
336
337 aliases {
338 console = "/uart@10200000";
339 };
340
341 pointing to a node:
342
343 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700344 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700345 };
346
347 In this case, this function takes the name of the alias ('console' in
348 this case) and updates the status of the node that is pointed to, to
349 either ok or disabled. If the alias does not exist, a warning is
350 displayed.
351
352 Args:
353 node_name: Name of node (e.g. '/uart@10200000') or alias alias
354 (e.g. 'console') to adjust
355 enabled: True to enable, False to disable
356 """
357 # Look up the alias if this is an alias reference
358 if not node_name.startswith('/'):
359 lookup = self.fdt.GetString('/aliases', node_name, '')
360 if not lookup:
361 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
362 return
363 node_name = lookup
364 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700365 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700366 else:
367 status = 'disabled'
368 self.fdt.PutString(node_name, 'status', status)
369
370 def AddEnableList(self, enable_list):
371 """Process a list of nodes to enable/disable.
372
373 Args:
374 config_list: List of (node, value) tuples to add to the fdt. For each
375 tuple:
376 node: The fdt node to write to will be <node> or pointed to by
377 /aliases/<node>. We can tell which
378 value: 0 to disable the node, 1 to enable it
379 """
380 if enable_list:
381 for node_name, enabled in enable_list:
382 try:
383 enabled = int(enabled)
384 if enabled not in (0, 1):
385 raise ValueError
386 except ValueError as str:
387 raise CmdError("Invalid enable option value '%s' "
388 "(should be 0 or 1)" % enabled)
389 self.SetNodeEnabled(node_name, enabled)
390
Simon Glass290a1802011-07-17 13:54:32 -0700391 def AddConfigList(self, config_list, use_int=False):
392 """Add a list of config items to the fdt.
393
394 Normally these values are written to the fdt as strings, but integers
395 are also supported, in which case the values will be converted to integers
396 (if necessary) before being stored.
397
398 Args:
399 config_list: List of (config, value) tuples to add to the fdt. For each
400 tuple:
401 config: The fdt node to write to will be /config/<config>.
402 value: An integer or string value to write.
403 use_int: True to only write integer values.
404
405 Raises:
406 CmdError: if a value is required to be converted to integer but can't be.
407 """
408 if config_list:
409 for config in config_list:
410 value = config[1]
411 if use_int:
412 try:
413 value = int(value)
414 except ValueError as str:
415 raise CmdError("Cannot convert config option '%s' to integer" %
416 value)
417 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800418 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700419 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800420 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700421
Simon Glass7c2d5572011-11-15 14:47:08 -0800422 def DecodeTextBase(self, data):
423 """Look at a U-Boot image and try to decode its TEXT_BASE.
424
425 This works because U-Boot has a header with the value 0x12345678
426 immediately followed by the TEXT_BASE value. We can therefore read this
427 from the image with some certainty. We check only the first 40 words
428 since the header should be within that region.
429
Simon Glass96b50302012-07-20 06:55:28 +0100430 Since upstream Tegra has moved to having a 16KB SPL region at the start,
431 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
432 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
433
Simon Glass7c2d5572011-11-15 14:47:08 -0800434 Args:
435 data: U-Boot binary data
436
437 Returns:
438 Text base (integer) or None if none was found
439 """
440 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100441 for start in (0, 0x4000):
442 for i in range(start, start + 160, 4):
443 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800444
Simon Glass96b50302012-07-20 06:55:28 +0100445 # TODO(sjg): This does not cope with a big-endian target
446 value = struct.unpack('<I', word)[0]
447 if found:
448 return value - start
449 if value == 0x12345678:
450 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800451
452 return None
453
454 def CalcTextBase(self, name, fdt, fname):
455 """Calculate the TEXT_BASE to use for U-Boot.
456
457 Normally this value is in the fdt, so we just read it from there. But as
458 a second check we look at the image itself in case this is different, and
459 switch to that if it is.
460
461 This allows us to flash any U-Boot even if its TEXT_BASE is different.
462 This is particularly useful with upstream U-Boot which uses a different
463 value (which we will move to).
464 """
465 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200466 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800467 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100468 text_base_str = '%#x' % text_base if text_base else 'None'
469 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
470 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800471
472 # If they are different, issue a warning and switch over.
473 if text_base and text_base != fdt_text_base:
474 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
475 "fdt value of %x. Using %x" % (text_base, name,
476 fdt_text_base, text_base))
477 fdt_text_base = text_base
478 return fdt_text_base
479
Simon Glass6dcc2f22011-07-28 15:26:49 +1200480 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700481 """Create a boot stub and a signed boot stub.
482
Simon Glass6dcc2f22011-07-28 15:26:49 +1200483 For postload:
484 We add a /config/postload-text-offset entry to the signed bootstub's
485 fdt so that U-Boot can find the postload code.
486
487 The raw (unsigned) bootstub will have a value of -1 for this since we will
488 simply append the postload code to the bootstub and it can find it there.
489 This will be used for RW A/B firmware.
490
491 For the signed case this value will specify where in the flash to find
492 the postload code. This will be used for RO firmware.
493
Simon Glass89b86b82011-07-17 23:49:49 -0700494 Args:
495 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800496 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200497 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700498
499 Returns:
500 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200501 Full path to bootstub (uboot + fdt(-1) + postload).
502 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700503
504 Raises:
505 CmdError if a command fails.
506 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200507 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800508 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700509 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200510
511 # Make a copy of the fdt for the bootstub
512 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800513 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700514 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200515
Simon Glass89b86b82011-07-17 23:49:49 -0700516 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700517 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
518 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700519 self._tools.OutputSize('Combined binary', bootstub)
520
Simon Glasse13ee2c2011-07-28 08:12:28 +1200521 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700522 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700523 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200524 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200525
526 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
527 data = self._tools.ReadFile(signed)
528
529 if postload:
530 # We must add postload to the bootstub since A and B will need to
531 # be able to find it without the /config/postload-text-offset mechanism.
532 bs_data = self._tools.ReadFile(bootstub)
533 bs_data += self._tools.ReadFile(postload)
534 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
535 self._tools.WriteFile(bootstub, bs_data)
536 self._tools.OutputSize('Combined binary with postload', bootstub)
537
538 # Now that we know the file size, adjust the fdt and re-sign
539 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800540 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200541 fdt_data = self._tools.ReadFile(fdt.fname)
542 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
543 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
544 postload_bootstub, text_base)
545 if len(data) != os.path.getsize(signed):
546 raise CmdError('Signed file size changed from %d to %d after updating '
547 'fdt' % (len(data), os.path.getsize(signed)))
548
549 # Re-read the signed image, and add the post-load binary.
550 data = self._tools.ReadFile(signed)
551 data += self._tools.ReadFile(postload)
552 self._tools.OutputSize('Post-load binary', postload)
553
554 self._tools.WriteFile(signed_postload, data)
555 self._tools.OutputSize('Final bootstub with postload', signed_postload)
556
557 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700558
Simon Glasscbc83552012-07-23 15:26:22 +0100559 def _CreateCorebootStub(self, uboot, coreboot, seabios):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700560 """Create a coreboot boot stub.
561
562 Args:
563 uboot: Path to u-boot.bin (may be chroot-relative)
564 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700565 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700566
567 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100568 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700569
570 Raises:
571 CmdError if a command fails.
572 """
573 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700574
575 # U-Boot itself does not put a .elf extension on the elf file.
576 # The U-Boot ebuild does, but we shouldn't actually require it since
577 # devs may want to just use what U-Boot creates.
578 uboot_elf = uboot.replace('.bin', '')
579 if not os.path.exists(self._tools.Filename(uboot_elf)):
580 uboot_elf = uboot.replace('.bin', '.elf')
581 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Vincent Palatinf7286772011-10-12 14:31:53 -0700582 if seabios:
Simon Glass146cb8e2012-03-09 15:51:24 -0800583 self._tools.Run('cbfstool', [bootstub, 'add-payload', seabios,
Vincent Palatinf7286772011-10-12 14:31:53 -0700584 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800585 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700586 'img/U-Boot', 'lzma'])
587 else:
Simon Glass146cb8e2012-03-09 15:51:24 -0800588 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700589 'fallback/payload', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100590
591 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700592 return bootstub
593
Simon Glass3b404092012-05-23 13:10:36 -0700594 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700595 """Update the parameters in a BL2 blob.
596
597 We look at the list in the parameter block, extract the value of each
598 from the device tree, and write that value to the parameter block.
599
600 Args:
601 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700602 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700603 data: The BL2 data.
604 pos: The position of the start of the parameter block.
605
606 Returns:
607 The new contents of the parameter block, after updating.
608 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700609 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
610 if version != 1:
611 raise CmdError("Cannot update machine parameter block version '%d'" %
612 version)
613 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700614 raise CmdError("Machine parameter block size %d is invalid: "
615 "pos=%d, size=%d, space=%d, len=%d" %
616 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700617
618 # Move past the header and read the parameter list, which is terminated
619 # with \0.
620 pos += 12
621 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
622 param_len = param_list.find('\0')
623 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700624 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700625
626 # Work through the parameters one at a time, adding each value
627 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700628 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700629 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700630 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700631 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700632 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700633 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
634 if not mem_type in mem_types:
635 raise CmdError("Unknown memory type '%s'" % mem_type)
636 value = mem_types.index(mem_type)
637 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700638 elif param == 'M' :
639 mem_manuf = fdt.GetString('/dmc', 'mem-manuf')
640 mem_manufs = ['autodetect', 'elpida', 'samsung']
641 if not mem_manuf in mem_manufs:
642 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
643 value = mem_manufs.index(mem_manuf)
644 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700645 elif param == 'f' :
646 mem_freq = fdt.GetInt('/dmc', 'clock-frequency') / 1000000
647 if not mem_freq in [533, 667, 800]:
648 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
649 value = mem_freq
650 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700651 elif param == 'v':
652 value = 31
653 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700654 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700655 value = (spl_load_size + 0xfff) & ~0xfff
656 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
657 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700658 elif param == 'b':
659 # These values come from enum boot_mode in U-Boot's cpu.h
660 if self.spl_source == 'straps':
661 value = 32
662 elif self.spl_source == 'emmc':
663 value = 4
664 elif self.spl_source == 'spi':
665 value = 20
666 elif self.spl_source == 'usb':
667 value = 33
668 else:
669 raise CmdError("Invalid boot source '%s'" % self.spl_source)
670 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700671 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700672 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700673 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700674 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700675 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700676
677 # Put the data into our block.
678 data = data[:pos] + new_data + data[pos + len(new_data):]
679 self._out.Info('BL2 configuration complete')
680 return data
681
Simon Glasse5e8afb2012-05-23 11:19:23 -0700682 def _UpdateChecksum(self, data):
683 """Update the BL2 checksum.
684
685 The checksum is a 4 byte sum of all the bytes in the image before the
686 last 4 bytes (which hold the checksum).
687
688 Args:
689 data: The BL2 data to update.
690
691 Returns:
692 The new contents of the BL2 data, after updating the checksum.
693 """
694 checksum = 0
695 for ch in data[:-4]:
696 checksum += ord(ch)
697 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
698
Simon Glass559b6612012-05-23 13:28:45 -0700699 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700700 """Configure an Exynos BL2 binary for our needs.
701
702 We create a new modified BL2 and return its filename.
703
704 Args:
705 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700706 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700707 orig_bl2: Filename of original BL2 file to modify.
708 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700709 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700710 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700711 data = self._tools.ReadFile(orig_bl2)
712 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700713
714 # Locate the parameter block
715 data = self._tools.ReadFile(bl2)
716 marker = struct.pack('<L', 0xdeadbeef)
717 pos = data.rfind(marker)
718 if not pos:
719 raise CmdError("Could not find machine parameter block in '%s'" %
720 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700721 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700722 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700723 self._tools.WriteFile(bl2, data)
724 return bl2
725
Simon Glass89b86b82011-07-17 23:49:49 -0700726 def _PackOutput(self, msg):
727 """Helper function to write output from PackFirmware (verbose level 2).
728
729 This is passed to PackFirmware for it to use to write output.
730
731 Args:
732 msg: Message to display.
733 """
734 self._out.Notice(msg)
735
Simon Glass439fe7a2012-03-09 16:19:34 -0800736 def _BuildBlob(self, pack, fdt, blob_type):
737 """Build the blob data for a particular blob type.
738
739 Args:
740 blob_type: The type of blob to create data for. Supported types are:
741 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
742 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
743 """
744 if blob_type == 'coreboot':
745 coreboot = self._CreateCorebootStub(self.uboot_fname,
Simon Glasscbc83552012-07-23 15:26:22 +0100746 self.coreboot_fname, self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800747 pack.AddProperty('coreboot', coreboot)
748 pack.AddProperty('image', coreboot)
749 elif blob_type == 'signed':
750 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
751 self.postload_fname)
752 pack.AddProperty('bootstub', bootstub)
753 pack.AddProperty('signed', signed)
754 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700755 elif blob_type == 'exynos-bl1':
756 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700757
758 # TODO(sjg@chromium.org): Deprecate ecbin
759 elif blob_type in ['ecrw', 'ecbin']:
760 pack.AddProperty('ecrw', self.ecrw_fname)
761 pack.AddProperty('ecbin', self.ecrw_fname)
762 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700763 # crosbug.com/p/13143
764 # We cannot have an fmap in the EC image since there can be only one,
765 # which is the main fmap describing the whole image.
766 # Ultimately the EC will not have an fmap, since with software sync
767 # there is no flashrom involvement in updating the EC flash, and thus
768 # no need for the fmap.
769 # For now, mangle the fmap name to avoid problems.
770 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
771 data = self._tools.ReadFile(self.ecro_fname)
772 data = re.sub('__FMAP__', '__fMAP__', data)
773 self._tools.WriteFile(updated_ecro, data)
774 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700775 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700776 spl_payload = pack.GetBlobParams(blob_type)
777
778 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
779 # from all flash map files.
780 if not spl_payload:
781 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
782 prop_list = 'boot+dtb'
783
784 # Do this later, when we remove boot+dtb.
785 # raise CmdError("No parameters provided for blob type '%s'" %
786 # blob_type)
787 else:
788 prop_list = spl_payload[0].split(',')
789 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
790 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
791 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700792 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700793 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800794 elif pack.GetProperty(blob_type):
795 pass
796 else:
797 raise CmdError("Unknown blob type '%s' required in flash map" %
798 blob_type)
799
Simon Glass290a1802011-07-17 13:54:32 -0700800 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700801 """Create a full firmware image, along with various by-products.
802
803 This uses the provided u-boot.bin, fdt and bct to create a firmware
804 image containing all the required parts. If the GBB is not supplied
805 then this will just return a signed U-Boot as the image.
806
807 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200808 gbb: Full path to the GBB file, or empty if a GBB is not required.
809 fdt: Fdt object containing required information.
810
811 Returns:
812 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700813
814 Raises:
815 CmdError if a command fails.
816 """
Simon Glass02d124a2012-03-02 14:47:20 -0800817 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700818
Simon Glass439fe7a2012-03-09 16:19:34 -0800819 # Get the flashmap so we know what to build
820 pack = PackFirmware(self._tools, self._out)
821 pack.SelectFdt(fdt)
822
823 # Get all our blobs ready
824 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700825 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700826 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700827
Simon Glassde9c8072012-07-02 22:29:02 -0700828 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
829 if self.kernel_fname:
830 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
831
Simon Glass50f74602012-03-15 21:04:25 -0700832 # Make a copy of the fdt for the bootstub
833 fdt_data = self._tools.ReadFile(fdt.fname)
834 uboot_data = self._tools.ReadFile(self.uboot_fname)
835 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
836 self._tools.WriteFile(uboot_copy, uboot_data)
837
838 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
839 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700840
841 # TODO(sjg@chromium.org): Deprecate this property when all boards
842 # use a comma-separated list for section contents. We will then
843 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700844 pack.AddProperty('boot+dtb', bootstub)
845
Simon Glass439fe7a2012-03-09 16:19:34 -0800846 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100847 blob_list = pack.GetBlobList()
848 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700849 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800850 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700851
852 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700853 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800854 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800855 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800856 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700857 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800858 pack.AddProperty('fwid', fwid)
859 pack.AddProperty('gbb', gbb)
860 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700861
862 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700863
864 # Record position and size of all blob members in the FDT
865 pack.UpdateBlobPositions(fdt)
866
Simon Glasscbc83552012-07-23 15:26:22 +0100867 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
868 # has created a rom file without the dtb, because until now it is not
869 # complete. Add the dtb here.
870 # A better anwer might be to put the dtb in memory immediately after
871 # U-Boot as is done for ARM and have coreboot load it as a binary file
872 # instead of an elf. However, I need to check whether coreboot supports
873 # this, and whether this is desirable for other reasons.
874 if 'coreboot' in blob_list:
875 bootstub = pack.GetProperty('coreboot')
876 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
877 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
878 '0xac'])
879
Simon Glassc90cf582012-03-13 15:40:47 -0700880 image = os.path.join(self._tools.outdir, 'image.bin')
881 pack.PackImage(self._tools.outdir, image)
882 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700883
Simon Glass439fe7a2012-03-09 16:19:34 -0800884 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700885 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700886 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700887
Simon Glass290a1802011-07-17 13:54:32 -0700888 def SelectFdt(self, fdt_fname):
889 """Select an FDT to control the firmware bundling
890
891 Args:
892 fdt_fname: The filename of the fdt to use.
893
Simon Glassc0f3dc62011-08-09 14:19:05 -0700894 Returns:
895 The Fdt object of the original fdt file, which we will not modify.
896
Simon Glass290a1802011-07-17 13:54:32 -0700897 We make a copy of this which will include any on-the-fly changes we want
898 to make.
899 """
900 self._fdt_fname = fdt_fname
901 self.CheckOptions()
902 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800903 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700904 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700905 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700906
Simon Glassc90cf582012-03-13 15:40:47 -0700907 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -0700908 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700909
910 - Checks options, tools, output directory, fdt.
911 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700912
913 Args:
Simon Glass56577572011-07-19 11:08:06 +1200914 hardware_id: Hardware ID to use for this board. If None, then the
915 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700916 output_fname: Output filename for the image. If this is not None, then
917 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -0700918 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -0700919
920 Returns:
921 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700922 """
Simon Glass89b86b82011-07-17 23:49:49 -0700923 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700924 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200925 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700926
927 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -0700928 image, pack = self._CreateImage(gbb, self.fdt)
929 if show_map:
930 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -0700931 if output_fname:
932 shutil.copyfile(image, output_fname)
933 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -0700934 return image, pack.props