blob: defcd797b7f0a4b0f1b813c47efda213d0ee7e7c [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):
460 raise CmdError("Machine parameter block size %d is invalid" % size)
461
462 # Move past the header and read the parameter list, which is terminated
463 # with \0.
464 pos += 12
465 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
466 param_len = param_list.find('\0')
467 param_list = param_list[:param_len]
468 pos += (param_len + 3) & ~3
469
470 # Work through the parameters one at a time, adding each value
471 new_data = ''
472 for param in param_list:
473 if param == 'm' :
474 mem_type = fdt.GetString('/memory', 'samsung,memtype')
475 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
476 if not mem_type in mem_types:
477 raise CmdError("Unknown memory type '%s'" % mem_type)
478 value = mem_types.index(mem_type)
479 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
480 elif param == 'v':
481 value = 31
482 self._out.Info(' Memory interleave: %#0x' % value)
483 else:
484 raise CmdError("Machine parameter block size %d is invalid" % size)
485 new_data += struct.pack('<L', value)
486
487 # Put the data into our block.
488 data = data[:pos] + new_data + data[pos + len(new_data):]
489 self._out.Info('BL2 configuration complete')
490 return data
491
Simon Glass7e199222012-03-13 15:51:18 -0700492 def _ConfigureExynosBl2(self, fdt, orig_bl2):
493 """Configure an Exynos BL2 binary for our needs.
494
495 We create a new modified BL2 and return its filename.
496
497 Args:
498 fdt: Device tree containing the parameter values.
499 orig_bl2: Filename of original BL2 file to modify.
500 """
501 bl2 = os.path.join(self._tools.outdir, 'updated-spl.bin')
502 shutil.copyfile(orig_bl2, bl2)
503
504 # Locate the parameter block
505 data = self._tools.ReadFile(bl2)
506 marker = struct.pack('<L', 0xdeadbeef)
507 pos = data.rfind(marker)
508 if not pos:
509 raise CmdError("Could not find machine parameter block in '%s'" %
510 orig_bl2)
Simon Glassdf95dd22012-03-13 15:46:16 -0700511 self._UpdateBl2Parameters(fdt, data, pos)
Simon Glass7e199222012-03-13 15:51:18 -0700512 self._tools.WriteFile(bl2, data)
513 return bl2
514
Simon Glass89b86b82011-07-17 23:49:49 -0700515 def _PackOutput(self, msg):
516 """Helper function to write output from PackFirmware (verbose level 2).
517
518 This is passed to PackFirmware for it to use to write output.
519
520 Args:
521 msg: Message to display.
522 """
523 self._out.Notice(msg)
524
Simon Glass439fe7a2012-03-09 16:19:34 -0800525 def _BuildBlob(self, pack, fdt, blob_type):
526 """Build the blob data for a particular blob type.
527
528 Args:
529 blob_type: The type of blob to create data for. Supported types are:
530 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
531 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
532 """
533 if blob_type == 'coreboot':
534 coreboot = self._CreateCorebootStub(self.uboot_fname,
535 self.coreboot_fname, fdt, self.seabios_fname)
536 pack.AddProperty('coreboot', coreboot)
537 pack.AddProperty('image', coreboot)
538 elif blob_type == 'signed':
539 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
540 self.postload_fname)
541 pack.AddProperty('bootstub', bootstub)
542 pack.AddProperty('signed', signed)
543 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700544 elif blob_type == 'exynos-bl1':
545 pack.AddProperty(blob_type, self.exynos_bl1)
546 elif blob_type == 'exynos-bl2':
547 bl2 = self._ConfigureExynosBl2(fdt, self.exynos_bl2)
548 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800549 elif pack.GetProperty(blob_type):
550 pass
551 else:
552 raise CmdError("Unknown blob type '%s' required in flash map" %
553 blob_type)
554
Simon Glass290a1802011-07-17 13:54:32 -0700555 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700556 """Create a full firmware image, along with various by-products.
557
558 This uses the provided u-boot.bin, fdt and bct to create a firmware
559 image containing all the required parts. If the GBB is not supplied
560 then this will just return a signed U-Boot as the image.
561
562 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200563 gbb: Full path to the GBB file, or empty if a GBB is not required.
564 fdt: Fdt object containing required information.
565
566 Returns:
567 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700568
569 Raises:
570 CmdError if a command fails.
571 """
Simon Glass02d124a2012-03-02 14:47:20 -0800572 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700573
Simon Glass439fe7a2012-03-09 16:19:34 -0800574 # Get the flashmap so we know what to build
575 pack = PackFirmware(self._tools, self._out)
576 pack.SelectFdt(fdt)
577
578 # Get all our blobs ready
579 pack.AddProperty('boot', self.uboot_fname)
Simon Glass50f74602012-03-15 21:04:25 -0700580
581 # Make a copy of the fdt for the bootstub
582 fdt_data = self._tools.ReadFile(fdt.fname)
583 uboot_data = self._tools.ReadFile(self.uboot_fname)
584 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
585 self._tools.WriteFile(uboot_copy, uboot_data)
586
587 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
588 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
589 pack.AddProperty('boot+dtb', bootstub)
590
Simon Glass439fe7a2012-03-09 16:19:34 -0800591 pack.AddProperty('gbb', self.uboot_fname)
592 for blob_type in pack.GetBlobList(self.coreboot_fname is not None):
593 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700594
595 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700596 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800597 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800598 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800599 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700600 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800601 pack.AddProperty('fwid', fwid)
602 pack.AddProperty('gbb', gbb)
603 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700604
605 pack.CheckProperties()
606 image = os.path.join(self._tools.outdir, 'image.bin')
607 pack.PackImage(self._tools.outdir, image)
608 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700609
Simon Glass439fe7a2012-03-09 16:19:34 -0800610 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700611 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700612 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700613
Simon Glass290a1802011-07-17 13:54:32 -0700614 def SelectFdt(self, fdt_fname):
615 """Select an FDT to control the firmware bundling
616
617 Args:
618 fdt_fname: The filename of the fdt to use.
619
Simon Glassc0f3dc62011-08-09 14:19:05 -0700620 Returns:
621 The Fdt object of the original fdt file, which we will not modify.
622
Simon Glass290a1802011-07-17 13:54:32 -0700623 We make a copy of this which will include any on-the-fly changes we want
624 to make.
625 """
626 self._fdt_fname = fdt_fname
627 self.CheckOptions()
628 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800629 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700630 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700631 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700632
Simon Glassc90cf582012-03-13 15:40:47 -0700633 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -0700634 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700635
636 - Checks options, tools, output directory, fdt.
637 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700638
639 Args:
Simon Glass56577572011-07-19 11:08:06 +1200640 hardware_id: Hardware ID to use for this board. If None, then the
641 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700642 output_fname: Output filename for the image. If this is not None, then
643 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -0700644 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -0700645
646 Returns:
647 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700648 """
Simon Glass89b86b82011-07-17 23:49:49 -0700649 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700650 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200651 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700652
653 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -0700654 image, pack = self._CreateImage(gbb, self.fdt)
655 if show_map:
656 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -0700657 if output_fname:
658 shutil.copyfile(image, output_fname)
659 self._out.Notice("Output image '%s'" % output_fname)
660 return image