blob: d75f33b2e615f1ba33ae19e04b65af92315c1cab [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 Glass290a1802011-07-17 13:54:32 -070098
99 def SetDirs(self, keydir):
100 """Set up directories required for Bundle.
101
102 Args:
103 keydir: Directory containing keys to use for signing firmware.
104 """
105 self._keydir = keydir
106
Simon Glass6dcc2f22011-07-28 15:26:49 +1200107 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Vincent Palatinf7286772011-10-12 14:31:53 -0700108 postload=None, seabios=None):
Simon Glass290a1802011-07-17 13:54:32 -0700109 """Set up files required for Bundle.
110
111 Args:
112 board: The name of the board to target (e.g. tegra2_seaboard).
113 uboot: The filename of the u-boot.bin image to use.
114 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800115 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700116 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200117 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700118 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass290a1802011-07-17 13:54:32 -0700119 """
120 self._board = board
121 self.uboot_fname = uboot
122 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800123 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700124 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200125 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700126 self.seabios_fname = seabios
Simon Glass290a1802011-07-17 13:54:32 -0700127
128 def SetOptions(self, small):
129 """Set up options supported by Bundle.
130
131 Args:
132 small: Only create a signed U-Boot - don't produce the full packed
133 firmware image. This is useful for devs who want to replace just the
134 U-Boot part while keeping the keys, gbb, etc. the same.
135 """
136 self._small = small
137
138 def CheckOptions(self):
139 """Check provided options and select defaults."""
140 if not self._board:
141 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700142 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass290a1802011-07-17 13:54:32 -0700143 if not self._fdt_fname:
Simon Glass29b96ad2012-03-09 15:34:33 -0800144 self._fdt_fname = os.path.join(build_root, 'dts', '%s.dts' %
Simon Glass290a1802011-07-17 13:54:32 -0700145 re.sub('_', '-', self._board))
146 if not self.uboot_fname:
147 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
148 if not self.bct_fname:
149 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700150 if not self.bmpblk_fname:
151 self.bmpblk_fname = os.path.join(build_root, 'default.bmpblk')
Simon Glass89b86b82011-07-17 23:49:49 -0700152
Simon Glass56577572011-07-19 11:08:06 +1200153 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700154 """Create a GBB for the image.
155
Simon Glass56577572011-07-19 11:08:06 +1200156 Args:
157 hardware_id: Hardware ID to use for this board. If None, then the
158 default from the Fdt will be used
159
Simon Glass89b86b82011-07-17 23:49:49 -0700160 Returns:
161 Path of the created GBB file.
162
163 Raises:
164 CmdError if a command fails.
165 """
Simon Glass56577572011-07-19 11:08:06 +1200166 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800167 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700168 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700169 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700170
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800171 chromeos_config = self.fdt.GetProps("/chromeos-config")
172 if 'fast-developer-mode' not in chromeos_config:
173 gbb_flags = 0
174 else:
175 self._out.Notice("Enabling fast-developer-mode.")
176 gbb_flags = 1
177
Simon Glass89b86b82011-07-17 23:49:49 -0700178 self._out.Progress('Creating GBB')
179 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
180 sizes = ['%#x' % size for size in sizes]
181 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700182 keydir = self._tools.Filename(self._keydir)
183 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700184 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200185 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700186 '--rootkey=%s/root_key.vbpubk' % keydir,
187 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700188 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800189 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700190 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700191 cwd=odir)
192 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700193
Simon Glasse13ee2c2011-07-28 08:12:28 +1200194 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700195 """Sign an image so that the Tegra SOC will boot it.
196
197 Args:
198 bct: BCT file to use.
199 bootstub: Boot stub (U-Boot + fdt) file to sign.
200 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700201
202 Returns:
203 filename of signed image.
204
205 Raises:
206 CmdError if a command fails.
207 """
208 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200209 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700210 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200211 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700212 fd = open(config, 'w')
213 fd.write('Version = 1;\n')
214 fd.write('Redundancy = 1;\n')
215 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700216
217 # TODO(dianders): Right now, we don't have enough space in our flash map
218 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
219 # sure what this does for reliability, but at least things will fit...
220 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
221 if is_nand:
222 fd.write('Bctcopy = 1;\n')
223
Simon Glass89b86b82011-07-17 23:49:49 -0700224 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
225 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700226
Simon Glass89b86b82011-07-17 23:49:49 -0700227 fd.close()
228
229 self._tools.Run('cbootimage', [config, signed])
230 self._tools.OutputSize('BCT', bct)
231 self._tools.OutputSize('Signed image', signed)
232 return signed
233
Doug Anderson86ce5f42011-07-27 10:40:18 -0700234 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700235 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700236
237 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700238 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700239 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700240 """
Simon Glass290a1802011-07-17 13:54:32 -0700241 if bootcmd:
Simon Glass02d124a2012-03-02 14:47:20 -0800242 self.fdt.PutString('/config', 'bootcmd', bootcmd)
243 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700244 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700245
Simon Glass290a1802011-07-17 13:54:32 -0700246 def AddConfigList(self, config_list, use_int=False):
247 """Add a list of config items to the fdt.
248
249 Normally these values are written to the fdt as strings, but integers
250 are also supported, in which case the values will be converted to integers
251 (if necessary) before being stored.
252
253 Args:
254 config_list: List of (config, value) tuples to add to the fdt. For each
255 tuple:
256 config: The fdt node to write to will be /config/<config>.
257 value: An integer or string value to write.
258 use_int: True to only write integer values.
259
260 Raises:
261 CmdError: if a value is required to be converted to integer but can't be.
262 """
263 if config_list:
264 for config in config_list:
265 value = config[1]
266 if use_int:
267 try:
268 value = int(value)
269 except ValueError as str:
270 raise CmdError("Cannot convert config option '%s' to integer" %
271 value)
272 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800273 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700274 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800275 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700276
Simon Glass7c2d5572011-11-15 14:47:08 -0800277 def DecodeTextBase(self, data):
278 """Look at a U-Boot image and try to decode its TEXT_BASE.
279
280 This works because U-Boot has a header with the value 0x12345678
281 immediately followed by the TEXT_BASE value. We can therefore read this
282 from the image with some certainty. We check only the first 40 words
283 since the header should be within that region.
284
285 Args:
286 data: U-Boot binary data
287
288 Returns:
289 Text base (integer) or None if none was found
290 """
291 found = False
292 for i in range(0, 160, 4):
293 word = data[i:i + 4]
294
295 # TODO(sjg): This does not cope with a big-endian target
296 value = struct.unpack('<I', word)[0]
297 if found:
298 return value
299 if value == 0x12345678:
300 found = True
301
302 return None
303
304 def CalcTextBase(self, name, fdt, fname):
305 """Calculate the TEXT_BASE to use for U-Boot.
306
307 Normally this value is in the fdt, so we just read it from there. But as
308 a second check we look at the image itself in case this is different, and
309 switch to that if it is.
310
311 This allows us to flash any U-Boot even if its TEXT_BASE is different.
312 This is particularly useful with upstream U-Boot which uses a different
313 value (which we will move to).
314 """
315 data = self._tools.ReadFile(fname)
Simon Glass02d124a2012-03-02 14:47:20 -0800316 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase')
Simon Glass7c2d5572011-11-15 14:47:08 -0800317 text_base = self.DecodeTextBase(data)
318
319 # If they are different, issue a warning and switch over.
320 if text_base and text_base != fdt_text_base:
321 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
322 "fdt value of %x. Using %x" % (text_base, name,
323 fdt_text_base, text_base))
324 fdt_text_base = text_base
325 return fdt_text_base
326
Simon Glass6dcc2f22011-07-28 15:26:49 +1200327 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700328 """Create a boot stub and a signed boot stub.
329
Simon Glass6dcc2f22011-07-28 15:26:49 +1200330 For postload:
331 We add a /config/postload-text-offset entry to the signed bootstub's
332 fdt so that U-Boot can find the postload code.
333
334 The raw (unsigned) bootstub will have a value of -1 for this since we will
335 simply append the postload code to the bootstub and it can find it there.
336 This will be used for RW A/B firmware.
337
338 For the signed case this value will specify where in the flash to find
339 the postload code. This will be used for RO firmware.
340
Simon Glass89b86b82011-07-17 23:49:49 -0700341 Args:
342 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800343 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200344 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700345
346 Returns:
347 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200348 Full path to bootstub (uboot + fdt(-1) + postload).
349 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700350
351 Raises:
352 CmdError if a command fails.
353 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200354 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800355 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700356 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200357
358 # Make a copy of the fdt for the bootstub
359 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800360 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700361 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200362
Simon Glass89b86b82011-07-17 23:49:49 -0700363 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700364 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
365 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700366 self._tools.OutputSize('Combined binary', bootstub)
367
Simon Glasse13ee2c2011-07-28 08:12:28 +1200368 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700369 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700370 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200371 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200372
373 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
374 data = self._tools.ReadFile(signed)
375
376 if postload:
377 # We must add postload to the bootstub since A and B will need to
378 # be able to find it without the /config/postload-text-offset mechanism.
379 bs_data = self._tools.ReadFile(bootstub)
380 bs_data += self._tools.ReadFile(postload)
381 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
382 self._tools.WriteFile(bootstub, bs_data)
383 self._tools.OutputSize('Combined binary with postload', bootstub)
384
385 # Now that we know the file size, adjust the fdt and re-sign
386 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800387 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200388 fdt_data = self._tools.ReadFile(fdt.fname)
389 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
390 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
391 postload_bootstub, text_base)
392 if len(data) != os.path.getsize(signed):
393 raise CmdError('Signed file size changed from %d to %d after updating '
394 'fdt' % (len(data), os.path.getsize(signed)))
395
396 # Re-read the signed image, and add the post-load binary.
397 data = self._tools.ReadFile(signed)
398 data += self._tools.ReadFile(postload)
399 self._tools.OutputSize('Post-load binary', postload)
400
401 self._tools.WriteFile(signed_postload, data)
402 self._tools.OutputSize('Final bootstub with postload', signed_postload)
403
404 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700405
Vincent Palatinf7286772011-10-12 14:31:53 -0700406 def _CreateCorebootStub(self, uboot, coreboot, fdt, seabios):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700407 """Create a coreboot boot stub.
408
409 Args:
410 uboot: Path to u-boot.bin (may be chroot-relative)
411 coreboot: Path to coreboot.rom
412 fdt: Device Tree
Vincent Palatinf7286772011-10-12 14:31:53 -0700413 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700414
415 Returns:
416 Full path to bootstub (coreboot + uboot + fdt).
417
418 Raises:
419 CmdError if a command fails.
420 """
421 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700422 uboot_elf = uboot.replace(".bin", ".elf")
423 shutil.copyfile(coreboot, bootstub)
Vincent Palatinf7286772011-10-12 14:31:53 -0700424 if seabios:
Simon Glass146cb8e2012-03-09 15:51:24 -0800425 self._tools.Run('cbfstool', [bootstub, 'add-payload', seabios,
Vincent Palatinf7286772011-10-12 14:31:53 -0700426 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800427 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700428 'img/U-Boot', 'lzma'])
429 else:
Simon Glass146cb8e2012-03-09 15:51:24 -0800430 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700431 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800432 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700433 '0xac'])
434 return bootstub
435
Simon Glass89b86b82011-07-17 23:49:49 -0700436 def _PackOutput(self, msg):
437 """Helper function to write output from PackFirmware (verbose level 2).
438
439 This is passed to PackFirmware for it to use to write output.
440
441 Args:
442 msg: Message to display.
443 """
444 self._out.Notice(msg)
445
Simon Glass439fe7a2012-03-09 16:19:34 -0800446 def _BuildBlob(self, pack, fdt, blob_type):
447 """Build the blob data for a particular blob type.
448
449 Args:
450 blob_type: The type of blob to create data for. Supported types are:
451 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
452 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
453 """
454 if blob_type == 'coreboot':
455 coreboot = self._CreateCorebootStub(self.uboot_fname,
456 self.coreboot_fname, fdt, self.seabios_fname)
457 pack.AddProperty('coreboot', coreboot)
458 pack.AddProperty('image', coreboot)
459 elif blob_type == 'signed':
460 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
461 self.postload_fname)
462 pack.AddProperty('bootstub', bootstub)
463 pack.AddProperty('signed', signed)
464 pack.AddProperty('image', signed)
465 elif pack.GetProperty(blob_type):
466 pass
467 else:
468 raise CmdError("Unknown blob type '%s' required in flash map" %
469 blob_type)
470
Simon Glass290a1802011-07-17 13:54:32 -0700471 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700472 """Create a full firmware image, along with various by-products.
473
474 This uses the provided u-boot.bin, fdt and bct to create a firmware
475 image containing all the required parts. If the GBB is not supplied
476 then this will just return a signed U-Boot as the image.
477
478 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200479 gbb: Full path to the GBB file, or empty if a GBB is not required.
480 fdt: Fdt object containing required information.
481
482 Returns:
483 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700484
485 Raises:
486 CmdError if a command fails.
487 """
Simon Glass02d124a2012-03-02 14:47:20 -0800488 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700489
Simon Glass439fe7a2012-03-09 16:19:34 -0800490 # Get the flashmap so we know what to build
491 pack = PackFirmware(self._tools, self._out)
492 pack.SelectFdt(fdt)
493
494 # Get all our blobs ready
495 pack.AddProperty('boot', self.uboot_fname)
496 pack.AddProperty('gbb', self.uboot_fname)
497 for blob_type in pack.GetBlobList(self.coreboot_fname is not None):
498 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700499
500 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700501 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800502 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800503 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800504 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700505 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800506 pack.AddProperty('fwid', fwid)
507 pack.AddProperty('gbb', gbb)
508 pack.AddProperty('keydir', self._keydir)
509 pack.CheckProperties()
510 image = os.path.join(self._tools.outdir, 'image.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700511 pack.PackImage(self._tools.outdir, image)
Simon Glass439fe7a2012-03-09 16:19:34 -0800512 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700513
Simon Glass439fe7a2012-03-09 16:19:34 -0800514 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700515 self._tools.OutputSize('Final image', image)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200516 return image
Simon Glass89b86b82011-07-17 23:49:49 -0700517
Simon Glass290a1802011-07-17 13:54:32 -0700518 def SelectFdt(self, fdt_fname):
519 """Select an FDT to control the firmware bundling
520
521 Args:
522 fdt_fname: The filename of the fdt to use.
523
Simon Glassc0f3dc62011-08-09 14:19:05 -0700524 Returns:
525 The Fdt object of the original fdt file, which we will not modify.
526
Simon Glass290a1802011-07-17 13:54:32 -0700527 We make a copy of this which will include any on-the-fly changes we want
528 to make.
529 """
530 self._fdt_fname = fdt_fname
531 self.CheckOptions()
532 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800533 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700534 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700535 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700536
Simon Glass56577572011-07-19 11:08:06 +1200537 def Start(self, hardware_id, output_fname):
Simon Glass290a1802011-07-17 13:54:32 -0700538 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700539
540 - Checks options, tools, output directory, fdt.
541 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700542
543 Args:
Simon Glass56577572011-07-19 11:08:06 +1200544 hardware_id: Hardware ID to use for this board. If None, then the
545 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700546 output_fname: Output filename for the image. If this is not None, then
547 the final image will be copied here.
548
549 Returns:
550 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700551 """
Simon Glass89b86b82011-07-17 23:49:49 -0700552 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700553 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200554 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700555
556 # This creates the actual image.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200557 image = self._CreateImage(gbb, self.fdt)
Simon Glass290a1802011-07-17 13:54:32 -0700558 if output_fname:
559 shutil.copyfile(image, output_fname)
560 self._out.Notice("Output image '%s'" % output_fname)
561 return image