blob: 75d5f77fbce736eadedc2474c57f5eabd9fc9aa1 [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
Simon Glass4a887b12012-10-23 16:29:03 -070059# Build GBB flags.
60# (src/platform/vboot_reference/firmware/include/gbb_header.h)
61gbb_flag_properties = {
62 'dev-screen-short-delay': 0x00000001,
63 'load-option-roms': 0x00000002,
64 'enable-alternate-os': 0x00000004,
65 'force-dev-switch-on': 0x00000008,
66 'force-dev-boot-usb': 0x00000010,
67 'disable-fw-rollback-check': 0x00000020,
68 'enter-triggers-tonorm': 0x00000040,
69 'force-dev-boot-legacy': 0x00000080,
70}
71
Simon Glass89b86b82011-07-17 23:49:49 -070072class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070073 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070074
Simon Glass290a1802011-07-17 13:54:32 -070075 Sequence of events:
76 bundle = Bundle(tools.Tools(), cros_output.Output())
77 bundle.SetDirs(...)
78 bundle.SetFiles(...)
79 bundle.SetOptions(...)
80 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070081 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070082 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070083
Simon Glass290a1802011-07-17 13:54:32 -070084 Public properties:
85 fdt: The fdt object that we use for building our image. This wil be the
86 one specified by the user, except that we might add config options
87 to it. This is set up by SelectFdt() which must be called before
88 bundling starts.
89 uboot_fname: Full filename of the U-Boot binary we use.
90 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -070091 spl_source: Source device to load U-Boot from, in SPL:
92 straps: Select device according to CPU strap pins
93 spi: Boot from SPI
94 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -070095
96 Private attributes:
97 _small: True to create a 'small' signed U-Boot, False to produce a
98 full image. The small U-Boot is enough to boot but will not have
99 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700100 """
Simon Glass89b86b82011-07-17 23:49:49 -0700101
Simon Glass290a1802011-07-17 13:54:32 -0700102 def __init__(self, tools, output):
103 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700104
Simon Glass290a1802011-07-17 13:54:32 -0700105 Args:
106 tools: A tools.Tools object to use for external tools.
107 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700108 """
Simon Glass290a1802011-07-17 13:54:32 -0700109 self._tools = tools
110 self._out = output
111
112 # Set up the things we need to know in order to operate.
113 self._board = None # Board name, e.g. tegra2_seaboard.
114 self._fdt_fname = None # Filename of our FDT.
115 self.uboot_fname = None # Filename of our U-Boot binary.
116 self.bct_fname = None # Filename of our BCT file.
117 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800118 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700119 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -0700120 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -0700121 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
122 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass559b6612012-05-23 13:28:45 -0700123 self.spl_source = 'straps' # SPL boot according to board settings
Simon Glass07267952012-06-08 12:45:13 -0700124 self.skeleton_fname = None # Filename of Coreboot skeleton file
Simon Glassbe0bc002012-08-16 12:50:48 -0700125 self.ecrw_fname = None # Filename of EC file
126 self.ecro_fname = None # Filename of EC read-only file
Simon Glass23988ae2012-03-23 16:55:22 -0700127 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700128
129 def SetDirs(self, keydir):
130 """Set up directories required for Bundle.
131
132 Args:
133 keydir: Directory containing keys to use for signing firmware.
134 """
135 self._keydir = keydir
136
Simon Glass6dcc2f22011-07-28 15:26:49 +1200137 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glass07267952012-06-08 12:45:13 -0700138 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassbe0bc002012-08-16 12:50:48 -0700139 skeleton=None, ecrw=None, ecro=None, kernel=None):
Simon Glass290a1802011-07-17 13:54:32 -0700140 """Set up files required for Bundle.
141
142 Args:
143 board: The name of the board to target (e.g. tegra2_seaboard).
144 uboot: The filename of the u-boot.bin image to use.
145 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800146 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700147 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200148 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700149 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700150 exynos_bl1: The filename of the exynos BL1 file
151 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
152 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700153 ecrw: The filename of the EC (Embedded Controller) read-write file.
154 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700155 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700156 """
157 self._board = board
158 self.uboot_fname = uboot
159 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800160 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700161 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200162 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700163 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700164 self.exynos_bl1 = exynos_bl1
165 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700166 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700167 self.ecrw_fname = ecrw
168 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700169 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700170
171 def SetOptions(self, small):
172 """Set up options supported by Bundle.
173
174 Args:
175 small: Only create a signed U-Boot - don't produce the full packed
176 firmware image. This is useful for devs who want to replace just the
177 U-Boot part while keeping the keys, gbb, etc. the same.
178 """
179 self._small = small
180
181 def CheckOptions(self):
182 """Check provided options and select defaults."""
183 if not self._board:
184 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700185 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700186 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700187 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700188 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700189 base_name = re.sub('_', '-', self._board)
190
191 # In case the name exists with a prefix or suffix, find it.
192 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
193 found_list = glob.glob(self._tools.Filename(wildcard))
194 if len(found_list) == 1:
195 self._fdt_fname = found_list[0]
196 else:
197 # We didn't find anything definite, so set up our expected name.
198 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
199
Simon Glass881964d2012-04-04 11:34:09 -0700200 # Convert things like 'exynos5250-daisy' into a full path.
201 root, ext = os.path.splitext(self._fdt_fname)
202 if not ext and not os.path.dirname(root):
203 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
204
Simon Glass290a1802011-07-17 13:54:32 -0700205 if not self.uboot_fname:
206 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
207 if not self.bct_fname:
208 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700209 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700210 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700211 if not self.exynos_bl1:
212 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
213 if not self.exynos_bl2:
214 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700215 if not self.coreboot_fname:
216 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
217 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700218 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700219 if not self.seabios_fname:
220 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700221 if not self.ecrw_fname:
222 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
223 if not self.ecro_fname:
224 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700225
Simon Glass75759302012-03-15 20:26:53 -0700226 def GetFiles(self):
227 """Get a list of files that we know about.
228
229 This is the opposite of SetFiles except that we may have put in some
230 default names. It returns a dictionary containing the filename for
231 each of a number of pre-defined files.
232
233 Returns:
234 Dictionary, with one entry for each file.
235 """
236 file_list = {
237 'bct' : self.bct_fname,
238 'exynos-bl1' : self.exynos_bl1,
239 'exynos-bl2' : self.exynos_bl2,
240 }
241 return file_list
242
Simon Glass4a887b12012-10-23 16:29:03 -0700243 def DecodeGBBFlagsFromFdt(self):
244 """Get Google Binary Block flags from the FDT.
245
246 These should be in the chromeos-config node, like this:
247
248 chromeos-config {
249 gbb-flag-dev-screen-short-delay;
250 gbb-flag-force-dev-switch-on;
251 gbb-flag-force-dev-boot-usb;
252 gbb-flag-disable-fw-rollback-check;
253 };
254
255 Returns:
256 GBB flags value from FDT.
257 """
258 chromeos_config = self.fdt.GetProps("/chromeos-config")
259 gbb_flags = 0
260 for name in chromeos_config:
261 if name.startswith('gbb-flag-'):
262 flag_value = gbb_flag_properties.get(name[9:])
263 if flag_value:
264 gbb_flags |= flag_value
265 self._out.Notice("FDT: Enabling %s." % name)
266 else:
267 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
268 return gbb_flags
269
Simon Glass56577572011-07-19 11:08:06 +1200270 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700271 """Create a GBB for the image.
272
Simon Glass56577572011-07-19 11:08:06 +1200273 Args:
274 hardware_id: Hardware ID to use for this board. If None, then the
275 default from the Fdt will be used
276
Simon Glass89b86b82011-07-17 23:49:49 -0700277 Returns:
278 Path of the created GBB file.
279
280 Raises:
281 CmdError if a command fails.
282 """
Simon Glass56577572011-07-19 11:08:06 +1200283 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800284 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700285 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700286 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700287
Simon Glass4a887b12012-10-23 16:29:03 -0700288 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800289
Simon Glass4a887b12012-10-23 16:29:03 -0700290 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700291 self._out.Progress('Creating GBB')
292 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
293 sizes = ['%#x' % size for size in sizes]
294 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700295 keydir = self._tools.Filename(self._keydir)
296 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700297 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200298 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700299 '--rootkey=%s/root_key.vbpubk' % keydir,
300 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700301 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800302 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700303 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700304 cwd=odir)
305 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700306
Simon Glasse13ee2c2011-07-28 08:12:28 +1200307 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700308 """Sign an image so that the Tegra SOC will boot it.
309
310 Args:
311 bct: BCT file to use.
312 bootstub: Boot stub (U-Boot + fdt) file to sign.
313 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700314
315 Returns:
316 filename of signed image.
317
318 Raises:
319 CmdError if a command fails.
320 """
321 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200322 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700323 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200324 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700325 fd = open(config, 'w')
326 fd.write('Version = 1;\n')
327 fd.write('Redundancy = 1;\n')
328 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700329
330 # TODO(dianders): Right now, we don't have enough space in our flash map
331 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
332 # sure what this does for reliability, but at least things will fit...
333 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
334 if is_nand:
335 fd.write('Bctcopy = 1;\n')
336
Simon Glass89b86b82011-07-17 23:49:49 -0700337 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
338 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700339
Simon Glass89b86b82011-07-17 23:49:49 -0700340 fd.close()
341
342 self._tools.Run('cbootimage', [config, signed])
343 self._tools.OutputSize('BCT', bct)
344 self._tools.OutputSize('Signed image', signed)
345 return signed
346
Doug Anderson86ce5f42011-07-27 10:40:18 -0700347 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700348 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700349
350 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700351 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700352 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700353 """
Simon Glass468d8752012-09-19 16:36:19 -0700354 if bootcmd is not None:
355 if bootcmd == 'none':
356 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800357 self.fdt.PutString('/config', 'bootcmd', bootcmd)
358 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700359 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700360
Simon Glassa4934b72012-05-09 13:35:02 -0700361 def SetNodeEnabled(self, node_name, enabled):
362 """Set whether an node is enabled or disabled.
363
364 This simply sets the 'status' property of a node to "ok", or "disabled".
365
366 The node should either be a full path to the node (like '/uart@10200000')
367 or an alias property.
368
369 Aliases are supported like this:
370
371 aliases {
372 console = "/uart@10200000";
373 };
374
375 pointing to a node:
376
377 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700378 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700379 };
380
381 In this case, this function takes the name of the alias ('console' in
382 this case) and updates the status of the node that is pointed to, to
383 either ok or disabled. If the alias does not exist, a warning is
384 displayed.
385
386 Args:
387 node_name: Name of node (e.g. '/uart@10200000') or alias alias
388 (e.g. 'console') to adjust
389 enabled: True to enable, False to disable
390 """
391 # Look up the alias if this is an alias reference
392 if not node_name.startswith('/'):
393 lookup = self.fdt.GetString('/aliases', node_name, '')
394 if not lookup:
395 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
396 return
397 node_name = lookup
398 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700399 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700400 else:
401 status = 'disabled'
402 self.fdt.PutString(node_name, 'status', status)
403
404 def AddEnableList(self, enable_list):
405 """Process a list of nodes to enable/disable.
406
407 Args:
408 config_list: List of (node, value) tuples to add to the fdt. For each
409 tuple:
410 node: The fdt node to write to will be <node> or pointed to by
411 /aliases/<node>. We can tell which
412 value: 0 to disable the node, 1 to enable it
413 """
414 if enable_list:
415 for node_name, enabled in enable_list:
416 try:
417 enabled = int(enabled)
418 if enabled not in (0, 1):
419 raise ValueError
420 except ValueError as str:
421 raise CmdError("Invalid enable option value '%s' "
422 "(should be 0 or 1)" % enabled)
423 self.SetNodeEnabled(node_name, enabled)
424
Simon Glass290a1802011-07-17 13:54:32 -0700425 def AddConfigList(self, config_list, use_int=False):
426 """Add a list of config items to the fdt.
427
428 Normally these values are written to the fdt as strings, but integers
429 are also supported, in which case the values will be converted to integers
430 (if necessary) before being stored.
431
432 Args:
433 config_list: List of (config, value) tuples to add to the fdt. For each
434 tuple:
435 config: The fdt node to write to will be /config/<config>.
436 value: An integer or string value to write.
437 use_int: True to only write integer values.
438
439 Raises:
440 CmdError: if a value is required to be converted to integer but can't be.
441 """
442 if config_list:
443 for config in config_list:
444 value = config[1]
445 if use_int:
446 try:
447 value = int(value)
448 except ValueError as str:
449 raise CmdError("Cannot convert config option '%s' to integer" %
450 value)
451 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800452 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700453 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800454 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700455
Simon Glass7c2d5572011-11-15 14:47:08 -0800456 def DecodeTextBase(self, data):
457 """Look at a U-Boot image and try to decode its TEXT_BASE.
458
459 This works because U-Boot has a header with the value 0x12345678
460 immediately followed by the TEXT_BASE value. We can therefore read this
461 from the image with some certainty. We check only the first 40 words
462 since the header should be within that region.
463
Simon Glass96b50302012-07-20 06:55:28 +0100464 Since upstream Tegra has moved to having a 16KB SPL region at the start,
465 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
466 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
467
Simon Glass7c2d5572011-11-15 14:47:08 -0800468 Args:
469 data: U-Boot binary data
470
471 Returns:
472 Text base (integer) or None if none was found
473 """
474 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100475 for start in (0, 0x4000):
476 for i in range(start, start + 160, 4):
477 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800478
Simon Glass96b50302012-07-20 06:55:28 +0100479 # TODO(sjg): This does not cope with a big-endian target
480 value = struct.unpack('<I', word)[0]
481 if found:
482 return value - start
483 if value == 0x12345678:
484 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800485
486 return None
487
488 def CalcTextBase(self, name, fdt, fname):
489 """Calculate the TEXT_BASE to use for U-Boot.
490
491 Normally this value is in the fdt, so we just read it from there. But as
492 a second check we look at the image itself in case this is different, and
493 switch to that if it is.
494
495 This allows us to flash any U-Boot even if its TEXT_BASE is different.
496 This is particularly useful with upstream U-Boot which uses a different
497 value (which we will move to).
498 """
499 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200500 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800501 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100502 text_base_str = '%#x' % text_base if text_base else 'None'
503 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
504 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800505
506 # If they are different, issue a warning and switch over.
507 if text_base and text_base != fdt_text_base:
508 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
509 "fdt value of %x. Using %x" % (text_base, name,
510 fdt_text_base, text_base))
511 fdt_text_base = text_base
512 return fdt_text_base
513
Simon Glass6dcc2f22011-07-28 15:26:49 +1200514 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700515 """Create a boot stub and a signed boot stub.
516
Simon Glass6dcc2f22011-07-28 15:26:49 +1200517 For postload:
518 We add a /config/postload-text-offset entry to the signed bootstub's
519 fdt so that U-Boot can find the postload code.
520
521 The raw (unsigned) bootstub will have a value of -1 for this since we will
522 simply append the postload code to the bootstub and it can find it there.
523 This will be used for RW A/B firmware.
524
525 For the signed case this value will specify where in the flash to find
526 the postload code. This will be used for RO firmware.
527
Simon Glass89b86b82011-07-17 23:49:49 -0700528 Args:
529 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800530 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200531 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700532
533 Returns:
534 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200535 Full path to bootstub (uboot + fdt(-1) + postload).
536 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700537
538 Raises:
539 CmdError if a command fails.
540 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200541 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800542 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700543 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200544
545 # Make a copy of the fdt for the bootstub
546 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800547 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700548 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200549
Simon Glass89b86b82011-07-17 23:49:49 -0700550 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700551 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
552 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700553 self._tools.OutputSize('Combined binary', bootstub)
554
Simon Glasse13ee2c2011-07-28 08:12:28 +1200555 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700556 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700557 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200558 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200559
560 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
561 data = self._tools.ReadFile(signed)
562
563 if postload:
564 # We must add postload to the bootstub since A and B will need to
565 # be able to find it without the /config/postload-text-offset mechanism.
566 bs_data = self._tools.ReadFile(bootstub)
567 bs_data += self._tools.ReadFile(postload)
568 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
569 self._tools.WriteFile(bootstub, bs_data)
570 self._tools.OutputSize('Combined binary with postload', bootstub)
571
572 # Now that we know the file size, adjust the fdt and re-sign
573 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800574 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200575 fdt_data = self._tools.ReadFile(fdt.fname)
576 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
577 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
578 postload_bootstub, text_base)
579 if len(data) != os.path.getsize(signed):
580 raise CmdError('Signed file size changed from %d to %d after updating '
581 'fdt' % (len(data), os.path.getsize(signed)))
582
583 # Re-read the signed image, and add the post-load binary.
584 data = self._tools.ReadFile(signed)
585 data += self._tools.ReadFile(postload)
586 self._tools.OutputSize('Post-load binary', postload)
587
588 self._tools.WriteFile(signed_postload, data)
589 self._tools.OutputSize('Final bootstub with postload', signed_postload)
590
591 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700592
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700593 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700594 """Create a coreboot boot stub.
595
596 Args:
597 uboot: Path to u-boot.bin (may be chroot-relative)
598 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700599 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700600
601 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100602 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700603
604 Raises:
605 CmdError if a command fails.
606 """
607 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700608
609 # U-Boot itself does not put a .elf extension on the elf file.
610 # The U-Boot ebuild does, but we shouldn't actually require it since
611 # devs may want to just use what U-Boot creates.
612 uboot_elf = uboot.replace('.bin', '')
613 if not os.path.exists(self._tools.Filename(uboot_elf)):
614 uboot_elf = uboot.replace('.bin', '.elf')
615 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700616 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700617 'fallback/payload', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100618
619 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700620 return bootstub
621
Simon Glass3b404092012-05-23 13:10:36 -0700622 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700623 """Update the parameters in a BL2 blob.
624
625 We look at the list in the parameter block, extract the value of each
626 from the device tree, and write that value to the parameter block.
627
628 Args:
629 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700630 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700631 data: The BL2 data.
632 pos: The position of the start of the parameter block.
633
634 Returns:
635 The new contents of the parameter block, after updating.
636 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700637 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
638 if version != 1:
639 raise CmdError("Cannot update machine parameter block version '%d'" %
640 version)
641 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700642 raise CmdError("Machine parameter block size %d is invalid: "
643 "pos=%d, size=%d, space=%d, len=%d" %
644 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700645
646 # Move past the header and read the parameter list, which is terminated
647 # with \0.
648 pos += 12
649 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
650 param_len = param_list.find('\0')
651 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700652 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700653
654 # Work through the parameters one at a time, adding each value
655 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700656 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700657 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700658 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700659 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700660 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700661 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
662 if not mem_type in mem_types:
663 raise CmdError("Unknown memory type '%s'" % mem_type)
664 value = mem_types.index(mem_type)
665 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700666 elif param == 'M' :
667 mem_manuf = fdt.GetString('/dmc', 'mem-manuf')
668 mem_manufs = ['autodetect', 'elpida', 'samsung']
669 if not mem_manuf in mem_manufs:
670 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
671 value = mem_manufs.index(mem_manuf)
672 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700673 elif param == 'f' :
674 mem_freq = fdt.GetInt('/dmc', 'clock-frequency') / 1000000
675 if not mem_freq in [533, 667, 800]:
676 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
677 value = mem_freq
678 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700679 elif param == 'v':
680 value = 31
681 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700682 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700683 value = (spl_load_size + 0xfff) & ~0xfff
684 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
685 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700686 elif param == 'b':
687 # These values come from enum boot_mode in U-Boot's cpu.h
688 if self.spl_source == 'straps':
689 value = 32
690 elif self.spl_source == 'emmc':
691 value = 4
692 elif self.spl_source == 'spi':
693 value = 20
694 elif self.spl_source == 'usb':
695 value = 33
696 else:
697 raise CmdError("Invalid boot source '%s'" % self.spl_source)
698 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700699 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700700 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700701 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700702 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700703 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700704
705 # Put the data into our block.
706 data = data[:pos] + new_data + data[pos + len(new_data):]
707 self._out.Info('BL2 configuration complete')
708 return data
709
Simon Glasse5e8afb2012-05-23 11:19:23 -0700710 def _UpdateChecksum(self, data):
711 """Update the BL2 checksum.
712
713 The checksum is a 4 byte sum of all the bytes in the image before the
714 last 4 bytes (which hold the checksum).
715
716 Args:
717 data: The BL2 data to update.
718
719 Returns:
720 The new contents of the BL2 data, after updating the checksum.
721 """
722 checksum = 0
723 for ch in data[:-4]:
724 checksum += ord(ch)
725 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
726
Simon Glass559b6612012-05-23 13:28:45 -0700727 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700728 """Configure an Exynos BL2 binary for our needs.
729
730 We create a new modified BL2 and return its filename.
731
732 Args:
733 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700734 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700735 orig_bl2: Filename of original BL2 file to modify.
736 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700737 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700738 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700739 data = self._tools.ReadFile(orig_bl2)
740 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700741
742 # Locate the parameter block
743 data = self._tools.ReadFile(bl2)
744 marker = struct.pack('<L', 0xdeadbeef)
745 pos = data.rfind(marker)
746 if not pos:
747 raise CmdError("Could not find machine parameter block in '%s'" %
748 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700749 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700750 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700751 self._tools.WriteFile(bl2, data)
752 return bl2
753
Simon Glass89b86b82011-07-17 23:49:49 -0700754 def _PackOutput(self, msg):
755 """Helper function to write output from PackFirmware (verbose level 2).
756
757 This is passed to PackFirmware for it to use to write output.
758
759 Args:
760 msg: Message to display.
761 """
762 self._out.Notice(msg)
763
Simon Glass439fe7a2012-03-09 16:19:34 -0800764 def _BuildBlob(self, pack, fdt, blob_type):
765 """Build the blob data for a particular blob type.
766
767 Args:
768 blob_type: The type of blob to create data for. Supported types are:
769 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
770 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
771 """
772 if blob_type == 'coreboot':
773 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700774 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800775 pack.AddProperty('coreboot', coreboot)
776 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700777 elif blob_type == 'legacy':
778 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800779 elif blob_type == 'signed':
780 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
781 self.postload_fname)
782 pack.AddProperty('bootstub', bootstub)
783 pack.AddProperty('signed', signed)
784 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700785 elif blob_type == 'exynos-bl1':
786 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700787
788 # TODO(sjg@chromium.org): Deprecate ecbin
789 elif blob_type in ['ecrw', 'ecbin']:
790 pack.AddProperty('ecrw', self.ecrw_fname)
791 pack.AddProperty('ecbin', self.ecrw_fname)
792 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700793 # crosbug.com/p/13143
794 # We cannot have an fmap in the EC image since there can be only one,
795 # which is the main fmap describing the whole image.
796 # Ultimately the EC will not have an fmap, since with software sync
797 # there is no flashrom involvement in updating the EC flash, and thus
798 # no need for the fmap.
799 # For now, mangle the fmap name to avoid problems.
800 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
801 data = self._tools.ReadFile(self.ecro_fname)
802 data = re.sub('__FMAP__', '__fMAP__', data)
803 self._tools.WriteFile(updated_ecro, data)
804 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700805 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700806 spl_payload = pack.GetBlobParams(blob_type)
807
808 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
809 # from all flash map files.
810 if not spl_payload:
811 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
812 prop_list = 'boot+dtb'
813
814 # Do this later, when we remove boot+dtb.
815 # raise CmdError("No parameters provided for blob type '%s'" %
816 # blob_type)
817 else:
818 prop_list = spl_payload[0].split(',')
819 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
820 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
821 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700822 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700823 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800824 elif pack.GetProperty(blob_type):
825 pass
826 else:
827 raise CmdError("Unknown blob type '%s' required in flash map" %
828 blob_type)
829
Simon Glass290a1802011-07-17 13:54:32 -0700830 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700831 """Create a full firmware image, along with various by-products.
832
833 This uses the provided u-boot.bin, fdt and bct to create a firmware
834 image containing all the required parts. If the GBB is not supplied
835 then this will just return a signed U-Boot as the image.
836
837 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200838 gbb: Full path to the GBB file, or empty if a GBB is not required.
839 fdt: Fdt object containing required information.
840
841 Returns:
842 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700843
844 Raises:
845 CmdError if a command fails.
846 """
Simon Glass02d124a2012-03-02 14:47:20 -0800847 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700848
Simon Glass439fe7a2012-03-09 16:19:34 -0800849 # Get the flashmap so we know what to build
850 pack = PackFirmware(self._tools, self._out)
851 pack.SelectFdt(fdt)
852
853 # Get all our blobs ready
854 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700855 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700856 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700857
Simon Glass47817052012-10-20 13:30:07 -0700858 # Let's create some copies of the fdt for vboot. These can be used to
859 # pass a different fdt to each firmware type. For now it is just used to
860 # check that the right fdt comes through.
861 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
862 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
863 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
864 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
865 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
866 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
867 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
868
Simon Glassde9c8072012-07-02 22:29:02 -0700869 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
870 if self.kernel_fname:
871 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
872
Simon Glass50f74602012-03-15 21:04:25 -0700873 # Make a copy of the fdt for the bootstub
874 fdt_data = self._tools.ReadFile(fdt.fname)
875 uboot_data = self._tools.ReadFile(self.uboot_fname)
876 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
877 self._tools.WriteFile(uboot_copy, uboot_data)
878
879 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
880 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700881
882 # TODO(sjg@chromium.org): Deprecate this property when all boards
883 # use a comma-separated list for section contents. We will then
884 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700885 pack.AddProperty('boot+dtb', bootstub)
886
Simon Glass439fe7a2012-03-09 16:19:34 -0800887 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100888 blob_list = pack.GetBlobList()
889 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700890 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800891 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700892
893 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700894 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800895 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800896 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800897 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700898 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800899 pack.AddProperty('fwid', fwid)
900 pack.AddProperty('gbb', gbb)
901 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700902
903 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700904
905 # Record position and size of all blob members in the FDT
906 pack.UpdateBlobPositions(fdt)
907
Simon Glasscbc83552012-07-23 15:26:22 +0100908 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
909 # has created a rom file without the dtb, because until now it is not
910 # complete. Add the dtb here.
911 # A better anwer might be to put the dtb in memory immediately after
912 # U-Boot as is done for ARM and have coreboot load it as a binary file
913 # instead of an elf. However, I need to check whether coreboot supports
914 # this, and whether this is desirable for other reasons.
915 if 'coreboot' in blob_list:
916 bootstub = pack.GetProperty('coreboot')
917 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
918 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
919 '0xac'])
Stefan Reinauer728be822012-10-02 16:54:09 -0700920 bootstub_tmp = bootstub + '.tmp'
921 self._tools.Run('dd', ['if=' + bootstub, 'of=' + bootstub_tmp,
922 'bs=1M', 'skip=7'])
923 shutil.move(bootstub_tmp, bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100924
Simon Glassc90cf582012-03-13 15:40:47 -0700925 image = os.path.join(self._tools.outdir, 'image.bin')
926 pack.PackImage(self._tools.outdir, image)
927 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700928
Simon Glass439fe7a2012-03-09 16:19:34 -0800929 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700930 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700931 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700932
Simon Glass290a1802011-07-17 13:54:32 -0700933 def SelectFdt(self, fdt_fname):
934 """Select an FDT to control the firmware bundling
935
936 Args:
937 fdt_fname: The filename of the fdt to use.
938
Simon Glassc0f3dc62011-08-09 14:19:05 -0700939 Returns:
940 The Fdt object of the original fdt file, which we will not modify.
941
Simon Glass290a1802011-07-17 13:54:32 -0700942 We make a copy of this which will include any on-the-fly changes we want
943 to make.
944 """
945 self._fdt_fname = fdt_fname
946 self.CheckOptions()
947 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800948 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700949 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700950 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700951
Simon Glassc90cf582012-03-13 15:40:47 -0700952 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -0700953 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700954
955 - Checks options, tools, output directory, fdt.
956 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700957
958 Args:
Simon Glass56577572011-07-19 11:08:06 +1200959 hardware_id: Hardware ID to use for this board. If None, then the
960 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700961 output_fname: Output filename for the image. If this is not None, then
962 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -0700963 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -0700964
965 Returns:
966 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700967 """
Simon Glass89b86b82011-07-17 23:49:49 -0700968 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700969 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200970 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700971
972 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -0700973 image, pack = self._CreateImage(gbb, self.fdt)
974 if show_map:
975 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -0700976 if output_fname:
977 shutil.copyfile(image, output_fname)
978 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -0700979 return image, pack.props