blob: e5287e6dd04c28d66487fe03fc4a15e56278a4cf [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
Simon Glass157c0662012-10-23 13:52:42 -0700171 def SetOptions(self, small, gbb_flags):
Simon Glass290a1802011-07-17 13:54:32 -0700172 """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
Simon Glass157c0662012-10-23 13:52:42 -0700180 self._gbb_flags = gbb_flags
Simon Glass290a1802011-07-17 13:54:32 -0700181
182 def CheckOptions(self):
183 """Check provided options and select defaults."""
184 if not self._board:
185 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700186 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700187 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700188 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700189 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700190 base_name = re.sub('_', '-', self._board)
191
192 # In case the name exists with a prefix or suffix, find it.
193 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
194 found_list = glob.glob(self._tools.Filename(wildcard))
195 if len(found_list) == 1:
196 self._fdt_fname = found_list[0]
197 else:
198 # We didn't find anything definite, so set up our expected name.
199 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
200
Simon Glass881964d2012-04-04 11:34:09 -0700201 # Convert things like 'exynos5250-daisy' into a full path.
202 root, ext = os.path.splitext(self._fdt_fname)
203 if not ext and not os.path.dirname(root):
204 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
205
Simon Glass290a1802011-07-17 13:54:32 -0700206 if not self.uboot_fname:
207 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
208 if not self.bct_fname:
209 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700210 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700211 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700212 if not self.exynos_bl1:
213 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
214 if not self.exynos_bl2:
215 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700216 if not self.coreboot_fname:
217 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
218 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700219 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700220 if not self.seabios_fname:
221 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700222 if not self.ecrw_fname:
223 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
224 if not self.ecro_fname:
225 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700226
Simon Glass75759302012-03-15 20:26:53 -0700227 def GetFiles(self):
228 """Get a list of files that we know about.
229
230 This is the opposite of SetFiles except that we may have put in some
231 default names. It returns a dictionary containing the filename for
232 each of a number of pre-defined files.
233
234 Returns:
235 Dictionary, with one entry for each file.
236 """
237 file_list = {
238 'bct' : self.bct_fname,
239 'exynos-bl1' : self.exynos_bl1,
240 'exynos-bl2' : self.exynos_bl2,
241 }
242 return file_list
243
Simon Glass4a887b12012-10-23 16:29:03 -0700244 def DecodeGBBFlagsFromFdt(self):
245 """Get Google Binary Block flags from the FDT.
246
247 These should be in the chromeos-config node, like this:
248
249 chromeos-config {
250 gbb-flag-dev-screen-short-delay;
251 gbb-flag-force-dev-switch-on;
252 gbb-flag-force-dev-boot-usb;
253 gbb-flag-disable-fw-rollback-check;
254 };
255
256 Returns:
257 GBB flags value from FDT.
258 """
259 chromeos_config = self.fdt.GetProps("/chromeos-config")
260 gbb_flags = 0
261 for name in chromeos_config:
262 if name.startswith('gbb-flag-'):
263 flag_value = gbb_flag_properties.get(name[9:])
264 if flag_value:
265 gbb_flags |= flag_value
266 self._out.Notice("FDT: Enabling %s." % name)
267 else:
268 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
269 return gbb_flags
270
Simon Glass157c0662012-10-23 13:52:42 -0700271 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
272 """Decode ajustments to the provided GBB flags.
273
274 We support three options:
275
276 hex value: c2
277 defined value: force-dev-boot-usb,load-option-roms
278 adjust default value: -load-option-roms,+force-dev-boot-usb
279
280 The last option starts from the passed-in GBB flags and adds or removes
281 flags.
282
283 Args:
284 gbb_flags: Base (default) FDT flags.
285 adjustments: String containing adjustments to make.
286
287 Returns:
288 Updated FDT flags.
289 """
290 use_base_value = True
291 if adjustments:
292 try:
293 return int(adjustments, base=16)
294 except:
295 pass
296 for flag in adjustments.split(','):
297 oper = None
298 if flag[0] in ['-', '+']:
299 oper = flag[0]
300 flag = flag[1:]
301 value = gbb_flag_properties.get(flag)
302 if not value:
303 raise ValueError("Invalid GBB flag '%s'" % flag)
304 if oper == '+':
305 gbb_flags |= value
306 elif oper == '-':
307 gbb_flags &= ~value
308 else:
309 if use_base_value:
310 gbb_flags = 0
311 use_base_value = False
312 gbb_flags |= value
313
314 return gbb_flags
315
Simon Glass56577572011-07-19 11:08:06 +1200316 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700317 """Create a GBB for the image.
318
Simon Glass56577572011-07-19 11:08:06 +1200319 Args:
320 hardware_id: Hardware ID to use for this board. If None, then the
321 default from the Fdt will be used
322
Simon Glass89b86b82011-07-17 23:49:49 -0700323 Returns:
324 Path of the created GBB file.
325
326 Raises:
327 CmdError if a command fails.
328 """
Simon Glass56577572011-07-19 11:08:06 +1200329 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800330 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700331 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700332 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700333
Simon Glass4a887b12012-10-23 16:29:03 -0700334 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800335
Simon Glass157c0662012-10-23 13:52:42 -0700336 # Allow command line to override flags
337 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
338
Simon Glass4a887b12012-10-23 16:29:03 -0700339 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700340 self._out.Progress('Creating GBB')
341 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
342 sizes = ['%#x' % size for size in sizes]
343 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700344 keydir = self._tools.Filename(self._keydir)
345 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700346 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200347 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700348 '--rootkey=%s/root_key.vbpubk' % keydir,
349 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700350 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800351 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700352 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700353 cwd=odir)
354 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700355
Simon Glasse13ee2c2011-07-28 08:12:28 +1200356 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700357 """Sign an image so that the Tegra SOC will boot it.
358
359 Args:
360 bct: BCT file to use.
361 bootstub: Boot stub (U-Boot + fdt) file to sign.
362 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700363
364 Returns:
365 filename of signed image.
366
367 Raises:
368 CmdError if a command fails.
369 """
370 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200371 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700372 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200373 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700374 fd = open(config, 'w')
375 fd.write('Version = 1;\n')
376 fd.write('Redundancy = 1;\n')
377 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700378
379 # TODO(dianders): Right now, we don't have enough space in our flash map
380 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
381 # sure what this does for reliability, but at least things will fit...
382 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
383 if is_nand:
384 fd.write('Bctcopy = 1;\n')
385
Simon Glass89b86b82011-07-17 23:49:49 -0700386 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
387 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700388
Simon Glass89b86b82011-07-17 23:49:49 -0700389 fd.close()
390
391 self._tools.Run('cbootimage', [config, signed])
392 self._tools.OutputSize('BCT', bct)
393 self._tools.OutputSize('Signed image', signed)
394 return signed
395
Doug Anderson86ce5f42011-07-27 10:40:18 -0700396 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700397 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700398
399 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700400 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700401 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700402 """
Simon Glass468d8752012-09-19 16:36:19 -0700403 if bootcmd is not None:
404 if bootcmd == 'none':
405 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800406 self.fdt.PutString('/config', 'bootcmd', bootcmd)
407 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700408 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700409
Simon Glassa4934b72012-05-09 13:35:02 -0700410 def SetNodeEnabled(self, node_name, enabled):
411 """Set whether an node is enabled or disabled.
412
413 This simply sets the 'status' property of a node to "ok", or "disabled".
414
415 The node should either be a full path to the node (like '/uart@10200000')
416 or an alias property.
417
418 Aliases are supported like this:
419
420 aliases {
421 console = "/uart@10200000";
422 };
423
424 pointing to a node:
425
426 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700427 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700428 };
429
430 In this case, this function takes the name of the alias ('console' in
431 this case) and updates the status of the node that is pointed to, to
432 either ok or disabled. If the alias does not exist, a warning is
433 displayed.
434
435 Args:
436 node_name: Name of node (e.g. '/uart@10200000') or alias alias
437 (e.g. 'console') to adjust
438 enabled: True to enable, False to disable
439 """
440 # Look up the alias if this is an alias reference
441 if not node_name.startswith('/'):
442 lookup = self.fdt.GetString('/aliases', node_name, '')
443 if not lookup:
444 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
445 return
446 node_name = lookup
447 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700448 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700449 else:
450 status = 'disabled'
451 self.fdt.PutString(node_name, 'status', status)
452
453 def AddEnableList(self, enable_list):
454 """Process a list of nodes to enable/disable.
455
456 Args:
457 config_list: List of (node, value) tuples to add to the fdt. For each
458 tuple:
459 node: The fdt node to write to will be <node> or pointed to by
460 /aliases/<node>. We can tell which
461 value: 0 to disable the node, 1 to enable it
462 """
463 if enable_list:
464 for node_name, enabled in enable_list:
465 try:
466 enabled = int(enabled)
467 if enabled not in (0, 1):
468 raise ValueError
469 except ValueError as str:
470 raise CmdError("Invalid enable option value '%s' "
471 "(should be 0 or 1)" % enabled)
472 self.SetNodeEnabled(node_name, enabled)
473
Simon Glass290a1802011-07-17 13:54:32 -0700474 def AddConfigList(self, config_list, use_int=False):
475 """Add a list of config items to the fdt.
476
477 Normally these values are written to the fdt as strings, but integers
478 are also supported, in which case the values will be converted to integers
479 (if necessary) before being stored.
480
481 Args:
482 config_list: List of (config, value) tuples to add to the fdt. For each
483 tuple:
484 config: The fdt node to write to will be /config/<config>.
485 value: An integer or string value to write.
486 use_int: True to only write integer values.
487
488 Raises:
489 CmdError: if a value is required to be converted to integer but can't be.
490 """
491 if config_list:
492 for config in config_list:
493 value = config[1]
494 if use_int:
495 try:
496 value = int(value)
497 except ValueError as str:
498 raise CmdError("Cannot convert config option '%s' to integer" %
499 value)
500 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800501 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700502 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800503 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700504
Simon Glass7c2d5572011-11-15 14:47:08 -0800505 def DecodeTextBase(self, data):
506 """Look at a U-Boot image and try to decode its TEXT_BASE.
507
508 This works because U-Boot has a header with the value 0x12345678
509 immediately followed by the TEXT_BASE value. We can therefore read this
510 from the image with some certainty. We check only the first 40 words
511 since the header should be within that region.
512
Simon Glass96b50302012-07-20 06:55:28 +0100513 Since upstream Tegra has moved to having a 16KB SPL region at the start,
514 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
515 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
516
Simon Glass7c2d5572011-11-15 14:47:08 -0800517 Args:
518 data: U-Boot binary data
519
520 Returns:
521 Text base (integer) or None if none was found
522 """
523 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100524 for start in (0, 0x4000):
525 for i in range(start, start + 160, 4):
526 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800527
Simon Glass96b50302012-07-20 06:55:28 +0100528 # TODO(sjg): This does not cope with a big-endian target
529 value = struct.unpack('<I', word)[0]
530 if found:
531 return value - start
532 if value == 0x12345678:
533 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800534
535 return None
536
537 def CalcTextBase(self, name, fdt, fname):
538 """Calculate the TEXT_BASE to use for U-Boot.
539
540 Normally this value is in the fdt, so we just read it from there. But as
541 a second check we look at the image itself in case this is different, and
542 switch to that if it is.
543
544 This allows us to flash any U-Boot even if its TEXT_BASE is different.
545 This is particularly useful with upstream U-Boot which uses a different
546 value (which we will move to).
547 """
548 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200549 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800550 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100551 text_base_str = '%#x' % text_base if text_base else 'None'
552 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
553 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800554
555 # If they are different, issue a warning and switch over.
556 if text_base and text_base != fdt_text_base:
557 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
558 "fdt value of %x. Using %x" % (text_base, name,
559 fdt_text_base, text_base))
560 fdt_text_base = text_base
561 return fdt_text_base
562
Simon Glass6dcc2f22011-07-28 15:26:49 +1200563 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700564 """Create a boot stub and a signed boot stub.
565
Simon Glass6dcc2f22011-07-28 15:26:49 +1200566 For postload:
567 We add a /config/postload-text-offset entry to the signed bootstub's
568 fdt so that U-Boot can find the postload code.
569
570 The raw (unsigned) bootstub will have a value of -1 for this since we will
571 simply append the postload code to the bootstub and it can find it there.
572 This will be used for RW A/B firmware.
573
574 For the signed case this value will specify where in the flash to find
575 the postload code. This will be used for RO firmware.
576
Simon Glass89b86b82011-07-17 23:49:49 -0700577 Args:
578 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800579 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200580 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700581
582 Returns:
583 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200584 Full path to bootstub (uboot + fdt(-1) + postload).
585 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700586
587 Raises:
588 CmdError if a command fails.
589 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200590 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800591 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700592 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200593
594 # Make a copy of the fdt for the bootstub
595 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800596 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700597 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200598
Simon Glass89b86b82011-07-17 23:49:49 -0700599 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700600 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
601 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700602 self._tools.OutputSize('Combined binary', bootstub)
603
Simon Glasse13ee2c2011-07-28 08:12:28 +1200604 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700605 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700606 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200607 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200608
609 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
610 data = self._tools.ReadFile(signed)
611
612 if postload:
613 # We must add postload to the bootstub since A and B will need to
614 # be able to find it without the /config/postload-text-offset mechanism.
615 bs_data = self._tools.ReadFile(bootstub)
616 bs_data += self._tools.ReadFile(postload)
617 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
618 self._tools.WriteFile(bootstub, bs_data)
619 self._tools.OutputSize('Combined binary with postload', bootstub)
620
621 # Now that we know the file size, adjust the fdt and re-sign
622 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800623 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200624 fdt_data = self._tools.ReadFile(fdt.fname)
625 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
626 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
627 postload_bootstub, text_base)
628 if len(data) != os.path.getsize(signed):
629 raise CmdError('Signed file size changed from %d to %d after updating '
630 'fdt' % (len(data), os.path.getsize(signed)))
631
632 # Re-read the signed image, and add the post-load binary.
633 data = self._tools.ReadFile(signed)
634 data += self._tools.ReadFile(postload)
635 self._tools.OutputSize('Post-load binary', postload)
636
637 self._tools.WriteFile(signed_postload, data)
638 self._tools.OutputSize('Final bootstub with postload', signed_postload)
639
640 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700641
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700642 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700643 """Create a coreboot boot stub.
644
645 Args:
646 uboot: Path to u-boot.bin (may be chroot-relative)
647 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700648 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700649
650 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100651 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700652
653 Raises:
654 CmdError if a command fails.
655 """
656 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700657
658 # U-Boot itself does not put a .elf extension on the elf file.
659 # The U-Boot ebuild does, but we shouldn't actually require it since
660 # devs may want to just use what U-Boot creates.
661 uboot_elf = uboot.replace('.bin', '')
662 if not os.path.exists(self._tools.Filename(uboot_elf)):
663 uboot_elf = uboot.replace('.bin', '.elf')
664 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700665 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700666 'fallback/payload', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100667
668 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700669 return bootstub
670
Simon Glass3b404092012-05-23 13:10:36 -0700671 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700672 """Update the parameters in a BL2 blob.
673
674 We look at the list in the parameter block, extract the value of each
675 from the device tree, and write that value to the parameter block.
676
677 Args:
678 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700679 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700680 data: The BL2 data.
681 pos: The position of the start of the parameter block.
682
683 Returns:
684 The new contents of the parameter block, after updating.
685 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700686 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
687 if version != 1:
688 raise CmdError("Cannot update machine parameter block version '%d'" %
689 version)
690 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700691 raise CmdError("Machine parameter block size %d is invalid: "
692 "pos=%d, size=%d, space=%d, len=%d" %
693 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700694
695 # Move past the header and read the parameter list, which is terminated
696 # with \0.
697 pos += 12
698 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
699 param_len = param_list.find('\0')
700 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700701 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700702
703 # Work through the parameters one at a time, adding each value
704 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700705 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700706 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700707 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700708 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700709 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700710 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
711 if not mem_type in mem_types:
712 raise CmdError("Unknown memory type '%s'" % mem_type)
713 value = mem_types.index(mem_type)
714 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700715 elif param == 'M' :
716 mem_manuf = fdt.GetString('/dmc', 'mem-manuf')
717 mem_manufs = ['autodetect', 'elpida', 'samsung']
718 if not mem_manuf in mem_manufs:
719 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
720 value = mem_manufs.index(mem_manuf)
721 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700722 elif param == 'f' :
723 mem_freq = fdt.GetInt('/dmc', 'clock-frequency') / 1000000
724 if not mem_freq in [533, 667, 800]:
725 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
726 value = mem_freq
727 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700728 elif param == 'v':
729 value = 31
730 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700731 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700732 value = (spl_load_size + 0xfff) & ~0xfff
733 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
734 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700735 elif param == 'b':
736 # These values come from enum boot_mode in U-Boot's cpu.h
737 if self.spl_source == 'straps':
738 value = 32
739 elif self.spl_source == 'emmc':
740 value = 4
741 elif self.spl_source == 'spi':
742 value = 20
743 elif self.spl_source == 'usb':
744 value = 33
745 else:
746 raise CmdError("Invalid boot source '%s'" % self.spl_source)
747 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700748 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700749 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700750 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700751 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700752 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700753
754 # Put the data into our block.
755 data = data[:pos] + new_data + data[pos + len(new_data):]
756 self._out.Info('BL2 configuration complete')
757 return data
758
Simon Glasse5e8afb2012-05-23 11:19:23 -0700759 def _UpdateChecksum(self, data):
760 """Update the BL2 checksum.
761
762 The checksum is a 4 byte sum of all the bytes in the image before the
763 last 4 bytes (which hold the checksum).
764
765 Args:
766 data: The BL2 data to update.
767
768 Returns:
769 The new contents of the BL2 data, after updating the checksum.
770 """
771 checksum = 0
772 for ch in data[:-4]:
773 checksum += ord(ch)
774 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
775
Simon Glass559b6612012-05-23 13:28:45 -0700776 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700777 """Configure an Exynos BL2 binary for our needs.
778
779 We create a new modified BL2 and return its filename.
780
781 Args:
782 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700783 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700784 orig_bl2: Filename of original BL2 file to modify.
785 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700786 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700787 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700788 data = self._tools.ReadFile(orig_bl2)
789 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700790
791 # Locate the parameter block
792 data = self._tools.ReadFile(bl2)
793 marker = struct.pack('<L', 0xdeadbeef)
794 pos = data.rfind(marker)
795 if not pos:
796 raise CmdError("Could not find machine parameter block in '%s'" %
797 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700798 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700799 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700800 self._tools.WriteFile(bl2, data)
801 return bl2
802
Simon Glass89b86b82011-07-17 23:49:49 -0700803 def _PackOutput(self, msg):
804 """Helper function to write output from PackFirmware (verbose level 2).
805
806 This is passed to PackFirmware for it to use to write output.
807
808 Args:
809 msg: Message to display.
810 """
811 self._out.Notice(msg)
812
Simon Glass439fe7a2012-03-09 16:19:34 -0800813 def _BuildBlob(self, pack, fdt, blob_type):
814 """Build the blob data for a particular blob type.
815
816 Args:
817 blob_type: The type of blob to create data for. Supported types are:
818 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
819 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
820 """
821 if blob_type == 'coreboot':
822 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700823 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800824 pack.AddProperty('coreboot', coreboot)
825 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700826 elif blob_type == 'legacy':
827 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800828 elif blob_type == 'signed':
829 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
830 self.postload_fname)
831 pack.AddProperty('bootstub', bootstub)
832 pack.AddProperty('signed', signed)
833 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700834 elif blob_type == 'exynos-bl1':
835 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700836
837 # TODO(sjg@chromium.org): Deprecate ecbin
838 elif blob_type in ['ecrw', 'ecbin']:
839 pack.AddProperty('ecrw', self.ecrw_fname)
840 pack.AddProperty('ecbin', self.ecrw_fname)
841 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700842 # crosbug.com/p/13143
843 # We cannot have an fmap in the EC image since there can be only one,
844 # which is the main fmap describing the whole image.
845 # Ultimately the EC will not have an fmap, since with software sync
846 # there is no flashrom involvement in updating the EC flash, and thus
847 # no need for the fmap.
848 # For now, mangle the fmap name to avoid problems.
849 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
850 data = self._tools.ReadFile(self.ecro_fname)
851 data = re.sub('__FMAP__', '__fMAP__', data)
852 self._tools.WriteFile(updated_ecro, data)
853 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700854 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700855 spl_payload = pack.GetBlobParams(blob_type)
856
857 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
858 # from all flash map files.
859 if not spl_payload:
860 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
861 prop_list = 'boot+dtb'
862
863 # Do this later, when we remove boot+dtb.
864 # raise CmdError("No parameters provided for blob type '%s'" %
865 # blob_type)
866 else:
867 prop_list = spl_payload[0].split(',')
868 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
869 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
870 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700871 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700872 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800873 elif pack.GetProperty(blob_type):
874 pass
875 else:
876 raise CmdError("Unknown blob type '%s' required in flash map" %
877 blob_type)
878
Simon Glass290a1802011-07-17 13:54:32 -0700879 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700880 """Create a full firmware image, along with various by-products.
881
882 This uses the provided u-boot.bin, fdt and bct to create a firmware
883 image containing all the required parts. If the GBB is not supplied
884 then this will just return a signed U-Boot as the image.
885
886 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200887 gbb: Full path to the GBB file, or empty if a GBB is not required.
888 fdt: Fdt object containing required information.
889
890 Returns:
891 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700892
893 Raises:
894 CmdError if a command fails.
895 """
Simon Glass02d124a2012-03-02 14:47:20 -0800896 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700897
Simon Glass439fe7a2012-03-09 16:19:34 -0800898 # Get the flashmap so we know what to build
899 pack = PackFirmware(self._tools, self._out)
900 pack.SelectFdt(fdt)
901
902 # Get all our blobs ready
903 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700904 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700905 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700906
Simon Glass47817052012-10-20 13:30:07 -0700907 # Let's create some copies of the fdt for vboot. These can be used to
908 # pass a different fdt to each firmware type. For now it is just used to
909 # check that the right fdt comes through.
910 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
911 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
912 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
913 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
914 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
915 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
916 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
917
Simon Glassde9c8072012-07-02 22:29:02 -0700918 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
919 if self.kernel_fname:
920 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
921
Simon Glass50f74602012-03-15 21:04:25 -0700922 # Make a copy of the fdt for the bootstub
923 fdt_data = self._tools.ReadFile(fdt.fname)
924 uboot_data = self._tools.ReadFile(self.uboot_fname)
925 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
926 self._tools.WriteFile(uboot_copy, uboot_data)
927
928 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
929 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700930
931 # TODO(sjg@chromium.org): Deprecate this property when all boards
932 # use a comma-separated list for section contents. We will then
933 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700934 pack.AddProperty('boot+dtb', bootstub)
935
Simon Glass439fe7a2012-03-09 16:19:34 -0800936 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100937 blob_list = pack.GetBlobList()
938 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700939 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800940 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700941
942 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700943 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800944 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800945 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800946 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700947 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800948 pack.AddProperty('fwid', fwid)
949 pack.AddProperty('gbb', gbb)
950 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700951
952 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700953
954 # Record position and size of all blob members in the FDT
955 pack.UpdateBlobPositions(fdt)
956
Simon Glasscbc83552012-07-23 15:26:22 +0100957 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
958 # has created a rom file without the dtb, because until now it is not
959 # complete. Add the dtb here.
960 # A better anwer might be to put the dtb in memory immediately after
961 # U-Boot as is done for ARM and have coreboot load it as a binary file
962 # instead of an elf. However, I need to check whether coreboot supports
963 # this, and whether this is desirable for other reasons.
964 if 'coreboot' in blob_list:
965 bootstub = pack.GetProperty('coreboot')
966 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
967 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
968 '0xac'])
Stefan Reinauer728be822012-10-02 16:54:09 -0700969 bootstub_tmp = bootstub + '.tmp'
970 self._tools.Run('dd', ['if=' + bootstub, 'of=' + bootstub_tmp,
971 'bs=1M', 'skip=7'])
972 shutil.move(bootstub_tmp, bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100973
Simon Glassc90cf582012-03-13 15:40:47 -0700974 image = os.path.join(self._tools.outdir, 'image.bin')
975 pack.PackImage(self._tools.outdir, image)
976 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700977
Simon Glass439fe7a2012-03-09 16:19:34 -0800978 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700979 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700980 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700981
Simon Glass290a1802011-07-17 13:54:32 -0700982 def SelectFdt(self, fdt_fname):
983 """Select an FDT to control the firmware bundling
984
985 Args:
986 fdt_fname: The filename of the fdt to use.
987
Simon Glassc0f3dc62011-08-09 14:19:05 -0700988 Returns:
989 The Fdt object of the original fdt file, which we will not modify.
990
Simon Glass290a1802011-07-17 13:54:32 -0700991 We make a copy of this which will include any on-the-fly changes we want
992 to make.
993 """
994 self._fdt_fname = fdt_fname
995 self.CheckOptions()
996 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800997 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700998 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700999 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001000
Simon Glassc90cf582012-03-13 15:40:47 -07001001 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001002 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001003
1004 - Checks options, tools, output directory, fdt.
1005 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001006
1007 Args:
Simon Glass56577572011-07-19 11:08:06 +12001008 hardware_id: Hardware ID to use for this board. If None, then the
1009 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001010 output_fname: Output filename for the image. If this is not None, then
1011 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001012 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001013
1014 Returns:
1015 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001016 """
Simon Glass89b86b82011-07-17 23:49:49 -07001017 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -07001018 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +12001019 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001020
1021 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001022 image, pack = self._CreateImage(gbb, self.fdt)
1023 if show_map:
1024 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001025 if output_fname:
1026 shutil.copyfile(image, output_fname)
1027 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001028 return image, pack.props