blob: 51364431bc6a67188463b66d3c8cf64e8d2a90e5 [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
19import os
20import re
21
22import cros_output
23from fdt import Fdt
24from pack_firmware import PackFirmware
25import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080026import struct
Simon Glass89b86b82011-07-17 23:49:49 -070027import tempfile
Simon Glass439fe7a2012-03-09 16:19:34 -080028from tools import CmdError
Simon Glass89b86b82011-07-17 23:49:49 -070029from tools import Tools
30from write_firmware import WriteFirmware
31
32# This data is required by bmpblk_utility. Does it ever change?
33# It was stored with the chromeos-bootimage ebuild, but we want
34# this utility to work outside the chroot.
35yaml_data = '''
36bmpblock: 1.0
37
38images:
39 devmode: DeveloperBmp/DeveloperBmp.bmp
40 recovery: RecoveryBmp/RecoveryBmp.bmp
41 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
42 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
43
44screens:
45 dev_en:
46 - [0, 0, devmode]
47 rec_en:
48 - [0, 0, recovery]
49 yuck_en:
50 - [0, 0, rec_yuck]
51 ins_en:
52 - [0, 0, rec_insert]
53
54localizations:
55 - [ dev_en, rec_en, yuck_en, ins_en ]
56'''
57
58class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070059 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070060
Simon Glass290a1802011-07-17 13:54:32 -070061 Sequence of events:
62 bundle = Bundle(tools.Tools(), cros_output.Output())
63 bundle.SetDirs(...)
64 bundle.SetFiles(...)
65 bundle.SetOptions(...)
66 bundle.SelectFdt(fdt.Fdt('filename.dtb')
67 .. can call bundle.AddConfigList() if required
68 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070069
Simon Glass290a1802011-07-17 13:54:32 -070070 Public properties:
71 fdt: The fdt object that we use for building our image. This wil be the
72 one specified by the user, except that we might add config options
73 to it. This is set up by SelectFdt() which must be called before
74 bundling starts.
75 uboot_fname: Full filename of the U-Boot binary we use.
76 bct_fname: Full filename of the BCT file we use.
77 """
Simon Glass89b86b82011-07-17 23:49:49 -070078
Simon Glass290a1802011-07-17 13:54:32 -070079 def __init__(self, tools, output):
80 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -070081
Simon Glass290a1802011-07-17 13:54:32 -070082 Args:
83 tools: A tools.Tools object to use for external tools.
84 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -070085 """
Simon Glass290a1802011-07-17 13:54:32 -070086 self._tools = tools
87 self._out = output
88
89 # Set up the things we need to know in order to operate.
90 self._board = None # Board name, e.g. tegra2_seaboard.
91 self._fdt_fname = None # Filename of our FDT.
92 self.uboot_fname = None # Filename of our U-Boot binary.
93 self.bct_fname = None # Filename of our BCT file.
94 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +080095 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -070096 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -070097 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -070098 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
99 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass290a1802011-07-17 13:54:32 -0700100
101 def SetDirs(self, keydir):
102 """Set up directories required for Bundle.
103
104 Args:
105 keydir: Directory containing keys to use for signing firmware.
106 """
107 self._keydir = keydir
108
Simon Glass6dcc2f22011-07-28 15:26:49 +1200109 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glass7e199222012-03-13 15:51:18 -0700110 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None):
Simon Glass290a1802011-07-17 13:54:32 -0700111 """Set up files required for Bundle.
112
113 Args:
114 board: The name of the board to target (e.g. tegra2_seaboard).
115 uboot: The filename of the u-boot.bin image to use.
116 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800117 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700118 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200119 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700120 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass290a1802011-07-17 13:54:32 -0700121 """
122 self._board = board
123 self.uboot_fname = uboot
124 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800125 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700126 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200127 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700128 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700129 self.exynos_bl1 = exynos_bl1
130 self.exynos_bl2 = exynos_bl2
Simon Glass290a1802011-07-17 13:54:32 -0700131
132 def SetOptions(self, small):
133 """Set up options supported by Bundle.
134
135 Args:
136 small: Only create a signed U-Boot - don't produce the full packed
137 firmware image. This is useful for devs who want to replace just the
138 U-Boot part while keeping the keys, gbb, etc. the same.
139 """
140 self._small = small
141
142 def CheckOptions(self):
143 """Check provided options and select defaults."""
144 if not self._board:
145 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700146 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass290a1802011-07-17 13:54:32 -0700147 if not self._fdt_fname:
Simon Glass29b96ad2012-03-09 15:34:33 -0800148 self._fdt_fname = os.path.join(build_root, 'dts', '%s.dts' %
Simon Glass290a1802011-07-17 13:54:32 -0700149 re.sub('_', '-', self._board))
150 if not self.uboot_fname:
151 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
152 if not self.bct_fname:
153 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700154 if not self.bmpblk_fname:
155 self.bmpblk_fname = os.path.join(build_root, 'default.bmpblk')
Simon Glass89b86b82011-07-17 23:49:49 -0700156
Simon Glass56577572011-07-19 11:08:06 +1200157 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700158 """Create a GBB for the image.
159
Simon Glass56577572011-07-19 11:08:06 +1200160 Args:
161 hardware_id: Hardware ID to use for this board. If None, then the
162 default from the Fdt will be used
163
Simon Glass89b86b82011-07-17 23:49:49 -0700164 Returns:
165 Path of the created GBB file.
166
167 Raises:
168 CmdError if a command fails.
169 """
Simon Glass56577572011-07-19 11:08:06 +1200170 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800171 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700172 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700173 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700174
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800175 chromeos_config = self.fdt.GetProps("/chromeos-config")
176 if 'fast-developer-mode' not in chromeos_config:
177 gbb_flags = 0
178 else:
179 self._out.Notice("Enabling fast-developer-mode.")
180 gbb_flags = 1
181
Simon Glass89b86b82011-07-17 23:49:49 -0700182 self._out.Progress('Creating GBB')
183 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
184 sizes = ['%#x' % size for size in sizes]
185 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700186 keydir = self._tools.Filename(self._keydir)
187 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700188 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200189 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700190 '--rootkey=%s/root_key.vbpubk' % keydir,
191 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700192 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800193 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700194 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700195 cwd=odir)
196 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700197
Simon Glasse13ee2c2011-07-28 08:12:28 +1200198 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700199 """Sign an image so that the Tegra SOC will boot it.
200
201 Args:
202 bct: BCT file to use.
203 bootstub: Boot stub (U-Boot + fdt) file to sign.
204 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700205
206 Returns:
207 filename of signed image.
208
209 Raises:
210 CmdError if a command fails.
211 """
212 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200213 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700214 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200215 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700216 fd = open(config, 'w')
217 fd.write('Version = 1;\n')
218 fd.write('Redundancy = 1;\n')
219 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700220
221 # TODO(dianders): Right now, we don't have enough space in our flash map
222 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
223 # sure what this does for reliability, but at least things will fit...
224 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
225 if is_nand:
226 fd.write('Bctcopy = 1;\n')
227
Simon Glass89b86b82011-07-17 23:49:49 -0700228 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
229 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700230
Simon Glass89b86b82011-07-17 23:49:49 -0700231 fd.close()
232
233 self._tools.Run('cbootimage', [config, signed])
234 self._tools.OutputSize('BCT', bct)
235 self._tools.OutputSize('Signed image', signed)
236 return signed
237
Doug Anderson86ce5f42011-07-27 10:40:18 -0700238 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700239 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700240
241 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700242 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700243 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700244 """
Simon Glass290a1802011-07-17 13:54:32 -0700245 if bootcmd:
Simon Glass02d124a2012-03-02 14:47:20 -0800246 self.fdt.PutString('/config', 'bootcmd', bootcmd)
247 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700248 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700249
Simon Glass290a1802011-07-17 13:54:32 -0700250 def AddConfigList(self, config_list, use_int=False):
251 """Add a list of config items to the fdt.
252
253 Normally these values are written to the fdt as strings, but integers
254 are also supported, in which case the values will be converted to integers
255 (if necessary) before being stored.
256
257 Args:
258 config_list: List of (config, value) tuples to add to the fdt. For each
259 tuple:
260 config: The fdt node to write to will be /config/<config>.
261 value: An integer or string value to write.
262 use_int: True to only write integer values.
263
264 Raises:
265 CmdError: if a value is required to be converted to integer but can't be.
266 """
267 if config_list:
268 for config in config_list:
269 value = config[1]
270 if use_int:
271 try:
272 value = int(value)
273 except ValueError as str:
274 raise CmdError("Cannot convert config option '%s' to integer" %
275 value)
276 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800277 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700278 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800279 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700280
Simon Glass7c2d5572011-11-15 14:47:08 -0800281 def DecodeTextBase(self, data):
282 """Look at a U-Boot image and try to decode its TEXT_BASE.
283
284 This works because U-Boot has a header with the value 0x12345678
285 immediately followed by the TEXT_BASE value. We can therefore read this
286 from the image with some certainty. We check only the first 40 words
287 since the header should be within that region.
288
289 Args:
290 data: U-Boot binary data
291
292 Returns:
293 Text base (integer) or None if none was found
294 """
295 found = False
296 for i in range(0, 160, 4):
297 word = data[i:i + 4]
298
299 # TODO(sjg): This does not cope with a big-endian target
300 value = struct.unpack('<I', word)[0]
301 if found:
302 return value
303 if value == 0x12345678:
304 found = True
305
306 return None
307
308 def CalcTextBase(self, name, fdt, fname):
309 """Calculate the TEXT_BASE to use for U-Boot.
310
311 Normally this value is in the fdt, so we just read it from there. But as
312 a second check we look at the image itself in case this is different, and
313 switch to that if it is.
314
315 This allows us to flash any U-Boot even if its TEXT_BASE is different.
316 This is particularly useful with upstream U-Boot which uses a different
317 value (which we will move to).
318 """
319 data = self._tools.ReadFile(fname)
Simon Glass02d124a2012-03-02 14:47:20 -0800320 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase')
Simon Glass7c2d5572011-11-15 14:47:08 -0800321 text_base = self.DecodeTextBase(data)
322
323 # If they are different, issue a warning and switch over.
324 if text_base and text_base != fdt_text_base:
325 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
326 "fdt value of %x. Using %x" % (text_base, name,
327 fdt_text_base, text_base))
328 fdt_text_base = text_base
329 return fdt_text_base
330
Simon Glass6dcc2f22011-07-28 15:26:49 +1200331 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700332 """Create a boot stub and a signed boot stub.
333
Simon Glass6dcc2f22011-07-28 15:26:49 +1200334 For postload:
335 We add a /config/postload-text-offset entry to the signed bootstub's
336 fdt so that U-Boot can find the postload code.
337
338 The raw (unsigned) bootstub will have a value of -1 for this since we will
339 simply append the postload code to the bootstub and it can find it there.
340 This will be used for RW A/B firmware.
341
342 For the signed case this value will specify where in the flash to find
343 the postload code. This will be used for RO firmware.
344
Simon Glass89b86b82011-07-17 23:49:49 -0700345 Args:
346 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800347 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200348 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700349
350 Returns:
351 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200352 Full path to bootstub (uboot + fdt(-1) + postload).
353 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700354
355 Raises:
356 CmdError if a command fails.
357 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200358 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800359 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700360 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200361
362 # Make a copy of the fdt for the bootstub
363 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800364 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700365 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200366
Simon Glass89b86b82011-07-17 23:49:49 -0700367 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700368 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
369 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700370 self._tools.OutputSize('Combined binary', bootstub)
371
Simon Glasse13ee2c2011-07-28 08:12:28 +1200372 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700373 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700374 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200375 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200376
377 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
378 data = self._tools.ReadFile(signed)
379
380 if postload:
381 # We must add postload to the bootstub since A and B will need to
382 # be able to find it without the /config/postload-text-offset mechanism.
383 bs_data = self._tools.ReadFile(bootstub)
384 bs_data += self._tools.ReadFile(postload)
385 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
386 self._tools.WriteFile(bootstub, bs_data)
387 self._tools.OutputSize('Combined binary with postload', bootstub)
388
389 # Now that we know the file size, adjust the fdt and re-sign
390 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800391 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200392 fdt_data = self._tools.ReadFile(fdt.fname)
393 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
394 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
395 postload_bootstub, text_base)
396 if len(data) != os.path.getsize(signed):
397 raise CmdError('Signed file size changed from %d to %d after updating '
398 'fdt' % (len(data), os.path.getsize(signed)))
399
400 # Re-read the signed image, and add the post-load binary.
401 data = self._tools.ReadFile(signed)
402 data += self._tools.ReadFile(postload)
403 self._tools.OutputSize('Post-load binary', postload)
404
405 self._tools.WriteFile(signed_postload, data)
406 self._tools.OutputSize('Final bootstub with postload', signed_postload)
407
408 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700409
Vincent Palatinf7286772011-10-12 14:31:53 -0700410 def _CreateCorebootStub(self, uboot, coreboot, fdt, seabios):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700411 """Create a coreboot boot stub.
412
413 Args:
414 uboot: Path to u-boot.bin (may be chroot-relative)
415 coreboot: Path to coreboot.rom
416 fdt: Device Tree
Vincent Palatinf7286772011-10-12 14:31:53 -0700417 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700418
419 Returns:
420 Full path to bootstub (coreboot + uboot + fdt).
421
422 Raises:
423 CmdError if a command fails.
424 """
425 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700426 uboot_elf = uboot.replace(".bin", ".elf")
427 shutil.copyfile(coreboot, bootstub)
Vincent Palatinf7286772011-10-12 14:31:53 -0700428 if seabios:
Simon Glass146cb8e2012-03-09 15:51:24 -0800429 self._tools.Run('cbfstool', [bootstub, 'add-payload', seabios,
Vincent Palatinf7286772011-10-12 14:31:53 -0700430 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800431 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700432 'img/U-Boot', 'lzma'])
433 else:
Simon Glass146cb8e2012-03-09 15:51:24 -0800434 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700435 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800436 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700437 '0xac'])
438 return bootstub
439
Simon Glassdf95dd22012-03-13 15:46:16 -0700440 def _UpdateBl2Parameters(self, fdt, data, pos):
441 """Update the parameters in a BL2 blob.
442
443 We look at the list in the parameter block, extract the value of each
444 from the device tree, and write that value to the parameter block.
445
446 Args:
447 fdt: Device tree containing the parameter values.
448 data: The BL2 data.
449 pos: The position of the start of the parameter block.
450
451 Returns:
452 The new contents of the parameter block, after updating.
453 """
454 self._out.Info('Configuring BL2')
455 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
456 if version != 1:
457 raise CmdError("Cannot update machine parameter block version '%d'" %
458 version)
459 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700460 raise CmdError("Machine parameter block size %d is invalid: "
461 "pos=%d, size=%d, space=%d, len=%d" %
462 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700463
464 # Move past the header and read the parameter list, which is terminated
465 # with \0.
466 pos += 12
467 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
468 param_len = param_list.find('\0')
469 param_list = param_list[:param_len]
470 pos += (param_len + 3) & ~3
471
472 # Work through the parameters one at a time, adding each value
473 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700474 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700475 for param in param_list:
476 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700477 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700478 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
479 if not mem_type in mem_types:
480 raise CmdError("Unknown memory type '%s'" % mem_type)
481 value = mem_types.index(mem_type)
482 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
483 elif param == 'v':
484 value = 31
485 self._out.Info(' Memory interleave: %#0x' % value)
486 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700487 self._out.Warning("Unknown machine parameter type '%s'" % param)
488 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700489 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700490 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700491
492 # Put the data into our block.
493 data = data[:pos] + new_data + data[pos + len(new_data):]
494 self._out.Info('BL2 configuration complete')
495 return data
496
Simon Glass7e199222012-03-13 15:51:18 -0700497 def _ConfigureExynosBl2(self, fdt, orig_bl2):
498 """Configure an Exynos BL2 binary for our needs.
499
500 We create a new modified BL2 and return its filename.
501
502 Args:
503 fdt: Device tree containing the parameter values.
504 orig_bl2: Filename of original BL2 file to modify.
505 """
506 bl2 = os.path.join(self._tools.outdir, 'updated-spl.bin')
507 shutil.copyfile(orig_bl2, bl2)
508
509 # Locate the parameter block
510 data = self._tools.ReadFile(bl2)
511 marker = struct.pack('<L', 0xdeadbeef)
512 pos = data.rfind(marker)
513 if not pos:
514 raise CmdError("Could not find machine parameter block in '%s'" %
515 orig_bl2)
Simon Glassdf95dd22012-03-13 15:46:16 -0700516 self._UpdateBl2Parameters(fdt, data, pos)
Simon Glass7e199222012-03-13 15:51:18 -0700517 self._tools.WriteFile(bl2, data)
518 return bl2
519
Simon Glass89b86b82011-07-17 23:49:49 -0700520 def _PackOutput(self, msg):
521 """Helper function to write output from PackFirmware (verbose level 2).
522
523 This is passed to PackFirmware for it to use to write output.
524
525 Args:
526 msg: Message to display.
527 """
528 self._out.Notice(msg)
529
Simon Glass439fe7a2012-03-09 16:19:34 -0800530 def _BuildBlob(self, pack, fdt, blob_type):
531 """Build the blob data for a particular blob type.
532
533 Args:
534 blob_type: The type of blob to create data for. Supported types are:
535 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
536 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
537 """
538 if blob_type == 'coreboot':
539 coreboot = self._CreateCorebootStub(self.uboot_fname,
540 self.coreboot_fname, fdt, self.seabios_fname)
541 pack.AddProperty('coreboot', coreboot)
542 pack.AddProperty('image', coreboot)
543 elif blob_type == 'signed':
544 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
545 self.postload_fname)
546 pack.AddProperty('bootstub', bootstub)
547 pack.AddProperty('signed', signed)
548 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700549 elif blob_type == 'exynos-bl1':
550 pack.AddProperty(blob_type, self.exynos_bl1)
551 elif blob_type == 'exynos-bl2':
552 bl2 = self._ConfigureExynosBl2(fdt, self.exynos_bl2)
553 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800554 elif pack.GetProperty(blob_type):
555 pass
556 else:
557 raise CmdError("Unknown blob type '%s' required in flash map" %
558 blob_type)
559
Simon Glass290a1802011-07-17 13:54:32 -0700560 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700561 """Create a full firmware image, along with various by-products.
562
563 This uses the provided u-boot.bin, fdt and bct to create a firmware
564 image containing all the required parts. If the GBB is not supplied
565 then this will just return a signed U-Boot as the image.
566
567 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200568 gbb: Full path to the GBB file, or empty if a GBB is not required.
569 fdt: Fdt object containing required information.
570
571 Returns:
572 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700573
574 Raises:
575 CmdError if a command fails.
576 """
Simon Glass02d124a2012-03-02 14:47:20 -0800577 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700578
Simon Glass439fe7a2012-03-09 16:19:34 -0800579 # Get the flashmap so we know what to build
580 pack = PackFirmware(self._tools, self._out)
581 pack.SelectFdt(fdt)
582
583 # Get all our blobs ready
584 pack.AddProperty('boot', self.uboot_fname)
Simon Glass50f74602012-03-15 21:04:25 -0700585
586 # Make a copy of the fdt for the bootstub
587 fdt_data = self._tools.ReadFile(fdt.fname)
588 uboot_data = self._tools.ReadFile(self.uboot_fname)
589 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
590 self._tools.WriteFile(uboot_copy, uboot_data)
591
592 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
593 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
594 pack.AddProperty('boot+dtb', bootstub)
595
Simon Glass439fe7a2012-03-09 16:19:34 -0800596 pack.AddProperty('gbb', self.uboot_fname)
597 for blob_type in pack.GetBlobList(self.coreboot_fname is not None):
598 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700599
600 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700601 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800602 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800603 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800604 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700605 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800606 pack.AddProperty('fwid', fwid)
607 pack.AddProperty('gbb', gbb)
608 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700609
610 pack.CheckProperties()
611 image = os.path.join(self._tools.outdir, 'image.bin')
612 pack.PackImage(self._tools.outdir, image)
613 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700614
Simon Glass439fe7a2012-03-09 16:19:34 -0800615 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700616 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700617 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700618
Simon Glass290a1802011-07-17 13:54:32 -0700619 def SelectFdt(self, fdt_fname):
620 """Select an FDT to control the firmware bundling
621
622 Args:
623 fdt_fname: The filename of the fdt to use.
624
Simon Glassc0f3dc62011-08-09 14:19:05 -0700625 Returns:
626 The Fdt object of the original fdt file, which we will not modify.
627
Simon Glass290a1802011-07-17 13:54:32 -0700628 We make a copy of this which will include any on-the-fly changes we want
629 to make.
630 """
631 self._fdt_fname = fdt_fname
632 self.CheckOptions()
633 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800634 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700635 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700636 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700637
Simon Glassc90cf582012-03-13 15:40:47 -0700638 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -0700639 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700640
641 - Checks options, tools, output directory, fdt.
642 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700643
644 Args:
Simon Glass56577572011-07-19 11:08:06 +1200645 hardware_id: Hardware ID to use for this board. If None, then the
646 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700647 output_fname: Output filename for the image. If this is not None, then
648 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -0700649 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -0700650
651 Returns:
652 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700653 """
Simon Glass89b86b82011-07-17 23:49:49 -0700654 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700655 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200656 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700657
658 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -0700659 image, pack = self._CreateImage(gbb, self.fdt)
660 if show_map:
661 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -0700662 if output_fname:
663 shutil.copyfile(image, output_fname)
664 self._out.Notice("Output image '%s'" % output_fname)
665 return image