blob: 488eb15b43f1243e804ff5852d8d36646630465a [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
28from tools import Tools
29from write_firmware import WriteFirmware
30
31# This data is required by bmpblk_utility. Does it ever change?
32# It was stored with the chromeos-bootimage ebuild, but we want
33# this utility to work outside the chroot.
34yaml_data = '''
35bmpblock: 1.0
36
37images:
38 devmode: DeveloperBmp/DeveloperBmp.bmp
39 recovery: RecoveryBmp/RecoveryBmp.bmp
40 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
41 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
42
43screens:
44 dev_en:
45 - [0, 0, devmode]
46 rec_en:
47 - [0, 0, recovery]
48 yuck_en:
49 - [0, 0, rec_yuck]
50 ins_en:
51 - [0, 0, rec_insert]
52
53localizations:
54 - [ dev_en, rec_en, yuck_en, ins_en ]
55'''
56
57class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070058 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070059
Simon Glass290a1802011-07-17 13:54:32 -070060 Sequence of events:
61 bundle = Bundle(tools.Tools(), cros_output.Output())
62 bundle.SetDirs(...)
63 bundle.SetFiles(...)
64 bundle.SetOptions(...)
65 bundle.SelectFdt(fdt.Fdt('filename.dtb')
66 .. can call bundle.AddConfigList() if required
67 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070068
Simon Glass290a1802011-07-17 13:54:32 -070069 Public properties:
70 fdt: The fdt object that we use for building our image. This wil be the
71 one specified by the user, except that we might add config options
72 to it. This is set up by SelectFdt() which must be called before
73 bundling starts.
74 uboot_fname: Full filename of the U-Boot binary we use.
75 bct_fname: Full filename of the BCT file we use.
76 """
Simon Glass89b86b82011-07-17 23:49:49 -070077
Simon Glass290a1802011-07-17 13:54:32 -070078 def __init__(self, tools, output):
79 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -070080
Simon Glass290a1802011-07-17 13:54:32 -070081 Args:
82 tools: A tools.Tools object to use for external tools.
83 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -070084 """
Simon Glass290a1802011-07-17 13:54:32 -070085 self._tools = tools
86 self._out = output
87
88 # Set up the things we need to know in order to operate.
89 self._board = None # Board name, e.g. tegra2_seaboard.
90 self._fdt_fname = None # Filename of our FDT.
91 self.uboot_fname = None # Filename of our U-Boot binary.
92 self.bct_fname = None # Filename of our BCT file.
93 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +080094 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -070095 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -070096 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass290a1802011-07-17 13:54:32 -070097
98 def SetDirs(self, keydir):
99 """Set up directories required for Bundle.
100
101 Args:
102 keydir: Directory containing keys to use for signing firmware.
103 """
104 self._keydir = keydir
105
Simon Glass6dcc2f22011-07-28 15:26:49 +1200106 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Vincent Palatinf7286772011-10-12 14:31:53 -0700107 postload=None, seabios=None):
Simon Glass290a1802011-07-17 13:54:32 -0700108 """Set up files required for Bundle.
109
110 Args:
111 board: The name of the board to target (e.g. tegra2_seaboard).
112 uboot: The filename of the u-boot.bin image to use.
113 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800114 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700115 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200116 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700117 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass290a1802011-07-17 13:54:32 -0700118 """
119 self._board = board
120 self.uboot_fname = uboot
121 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800122 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700123 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200124 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700125 self.seabios_fname = seabios
Simon Glass290a1802011-07-17 13:54:32 -0700126
127 def SetOptions(self, small):
128 """Set up options supported by Bundle.
129
130 Args:
131 small: Only create a signed U-Boot - don't produce the full packed
132 firmware image. This is useful for devs who want to replace just the
133 U-Boot part while keeping the keys, gbb, etc. the same.
134 """
135 self._small = small
136
137 def CheckOptions(self):
138 """Check provided options and select defaults."""
139 if not self._board:
140 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700141 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass290a1802011-07-17 13:54:32 -0700142 if not self._fdt_fname:
Simon Glass29b96ad2012-03-09 15:34:33 -0800143 self._fdt_fname = os.path.join(build_root, 'dts', '%s.dts' %
Simon Glass290a1802011-07-17 13:54:32 -0700144 re.sub('_', '-', self._board))
145 if not self.uboot_fname:
146 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
147 if not self.bct_fname:
148 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700149 if not self.bmpblk_fname:
150 self.bmpblk_fname = os.path.join(build_root, 'default.bmpblk')
Simon Glass89b86b82011-07-17 23:49:49 -0700151
Simon Glass56577572011-07-19 11:08:06 +1200152 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700153 """Create a GBB for the image.
154
Simon Glass56577572011-07-19 11:08:06 +1200155 Args:
156 hardware_id: Hardware ID to use for this board. If None, then the
157 default from the Fdt will be used
158
Simon Glass89b86b82011-07-17 23:49:49 -0700159 Returns:
160 Path of the created GBB file.
161
162 Raises:
163 CmdError if a command fails.
164 """
Simon Glass56577572011-07-19 11:08:06 +1200165 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800166 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700167 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700168 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700169
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800170 chromeos_config = self.fdt.GetProps("/chromeos-config")
171 if 'fast-developer-mode' not in chromeos_config:
172 gbb_flags = 0
173 else:
174 self._out.Notice("Enabling fast-developer-mode.")
175 gbb_flags = 1
176
Simon Glass89b86b82011-07-17 23:49:49 -0700177 self._out.Progress('Creating GBB')
178 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
179 sizes = ['%#x' % size for size in sizes]
180 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700181 keydir = self._tools.Filename(self._keydir)
182 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700183 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200184 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700185 '--rootkey=%s/root_key.vbpubk' % keydir,
186 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700187 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800188 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700189 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700190 cwd=odir)
191 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700192
Simon Glasse13ee2c2011-07-28 08:12:28 +1200193 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700194 """Sign an image so that the Tegra SOC will boot it.
195
196 Args:
197 bct: BCT file to use.
198 bootstub: Boot stub (U-Boot + fdt) file to sign.
199 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700200
201 Returns:
202 filename of signed image.
203
204 Raises:
205 CmdError if a command fails.
206 """
207 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200208 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700209 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200210 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700211 fd = open(config, 'w')
212 fd.write('Version = 1;\n')
213 fd.write('Redundancy = 1;\n')
214 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700215
216 # TODO(dianders): Right now, we don't have enough space in our flash map
217 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
218 # sure what this does for reliability, but at least things will fit...
219 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
220 if is_nand:
221 fd.write('Bctcopy = 1;\n')
222
Simon Glass89b86b82011-07-17 23:49:49 -0700223 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
224 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700225
Simon Glass89b86b82011-07-17 23:49:49 -0700226 fd.close()
227
228 self._tools.Run('cbootimage', [config, signed])
229 self._tools.OutputSize('BCT', bct)
230 self._tools.OutputSize('Signed image', signed)
231 return signed
232
Doug Anderson86ce5f42011-07-27 10:40:18 -0700233 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700234 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700235
236 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700237 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700238 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700239 """
Simon Glass290a1802011-07-17 13:54:32 -0700240 if bootcmd:
Simon Glass02d124a2012-03-02 14:47:20 -0800241 self.fdt.PutString('/config', 'bootcmd', bootcmd)
242 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700243 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700244
Simon Glass290a1802011-07-17 13:54:32 -0700245 def AddConfigList(self, config_list, use_int=False):
246 """Add a list of config items to the fdt.
247
248 Normally these values are written to the fdt as strings, but integers
249 are also supported, in which case the values will be converted to integers
250 (if necessary) before being stored.
251
252 Args:
253 config_list: List of (config, value) tuples to add to the fdt. For each
254 tuple:
255 config: The fdt node to write to will be /config/<config>.
256 value: An integer or string value to write.
257 use_int: True to only write integer values.
258
259 Raises:
260 CmdError: if a value is required to be converted to integer but can't be.
261 """
262 if config_list:
263 for config in config_list:
264 value = config[1]
265 if use_int:
266 try:
267 value = int(value)
268 except ValueError as str:
269 raise CmdError("Cannot convert config option '%s' to integer" %
270 value)
271 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800272 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700273 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800274 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700275
Simon Glass7c2d5572011-11-15 14:47:08 -0800276 def DecodeTextBase(self, data):
277 """Look at a U-Boot image and try to decode its TEXT_BASE.
278
279 This works because U-Boot has a header with the value 0x12345678
280 immediately followed by the TEXT_BASE value. We can therefore read this
281 from the image with some certainty. We check only the first 40 words
282 since the header should be within that region.
283
284 Args:
285 data: U-Boot binary data
286
287 Returns:
288 Text base (integer) or None if none was found
289 """
290 found = False
291 for i in range(0, 160, 4):
292 word = data[i:i + 4]
293
294 # TODO(sjg): This does not cope with a big-endian target
295 value = struct.unpack('<I', word)[0]
296 if found:
297 return value
298 if value == 0x12345678:
299 found = True
300
301 return None
302
303 def CalcTextBase(self, name, fdt, fname):
304 """Calculate the TEXT_BASE to use for U-Boot.
305
306 Normally this value is in the fdt, so we just read it from there. But as
307 a second check we look at the image itself in case this is different, and
308 switch to that if it is.
309
310 This allows us to flash any U-Boot even if its TEXT_BASE is different.
311 This is particularly useful with upstream U-Boot which uses a different
312 value (which we will move to).
313 """
314 data = self._tools.ReadFile(fname)
Simon Glass02d124a2012-03-02 14:47:20 -0800315 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase')
Simon Glass7c2d5572011-11-15 14:47:08 -0800316 text_base = self.DecodeTextBase(data)
317
318 # If they are different, issue a warning and switch over.
319 if text_base and text_base != fdt_text_base:
320 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
321 "fdt value of %x. Using %x" % (text_base, name,
322 fdt_text_base, text_base))
323 fdt_text_base = text_base
324 return fdt_text_base
325
Simon Glass6dcc2f22011-07-28 15:26:49 +1200326 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700327 """Create a boot stub and a signed boot stub.
328
Simon Glass6dcc2f22011-07-28 15:26:49 +1200329 For postload:
330 We add a /config/postload-text-offset entry to the signed bootstub's
331 fdt so that U-Boot can find the postload code.
332
333 The raw (unsigned) bootstub will have a value of -1 for this since we will
334 simply append the postload code to the bootstub and it can find it there.
335 This will be used for RW A/B firmware.
336
337 For the signed case this value will specify where in the flash to find
338 the postload code. This will be used for RO firmware.
339
Simon Glass89b86b82011-07-17 23:49:49 -0700340 Args:
341 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800342 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200343 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700344
345 Returns:
346 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200347 Full path to bootstub (uboot + fdt(-1) + postload).
348 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700349
350 Raises:
351 CmdError if a command fails.
352 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200353 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800354 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700355 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200356
357 # Make a copy of the fdt for the bootstub
358 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800359 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700360 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200361
Simon Glass89b86b82011-07-17 23:49:49 -0700362 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700363 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
364 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700365 self._tools.OutputSize('Combined binary', bootstub)
366
Simon Glasse13ee2c2011-07-28 08:12:28 +1200367 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700368 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700369 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200370 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200371
372 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
373 data = self._tools.ReadFile(signed)
374
375 if postload:
376 # We must add postload to the bootstub since A and B will need to
377 # be able to find it without the /config/postload-text-offset mechanism.
378 bs_data = self._tools.ReadFile(bootstub)
379 bs_data += self._tools.ReadFile(postload)
380 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
381 self._tools.WriteFile(bootstub, bs_data)
382 self._tools.OutputSize('Combined binary with postload', bootstub)
383
384 # Now that we know the file size, adjust the fdt and re-sign
385 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800386 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200387 fdt_data = self._tools.ReadFile(fdt.fname)
388 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
389 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
390 postload_bootstub, text_base)
391 if len(data) != os.path.getsize(signed):
392 raise CmdError('Signed file size changed from %d to %d after updating '
393 'fdt' % (len(data), os.path.getsize(signed)))
394
395 # Re-read the signed image, and add the post-load binary.
396 data = self._tools.ReadFile(signed)
397 data += self._tools.ReadFile(postload)
398 self._tools.OutputSize('Post-load binary', postload)
399
400 self._tools.WriteFile(signed_postload, data)
401 self._tools.OutputSize('Final bootstub with postload', signed_postload)
402
403 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700404
Vincent Palatinf7286772011-10-12 14:31:53 -0700405 def _CreateCorebootStub(self, uboot, coreboot, fdt, seabios):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700406 """Create a coreboot boot stub.
407
408 Args:
409 uboot: Path to u-boot.bin (may be chroot-relative)
410 coreboot: Path to coreboot.rom
411 fdt: Device Tree
Vincent Palatinf7286772011-10-12 14:31:53 -0700412 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700413
414 Returns:
415 Full path to bootstub (coreboot + uboot + fdt).
416
417 Raises:
418 CmdError if a command fails.
419 """
420 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Stefan Reinauer17c19622011-09-16 12:47:41 -0700421 cbfstool = "/usr/bin/cbfstool"
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:
425 self._tools.Run(cbfstool, [bootstub, 'add-payload', seabios,
426 'fallback/payload', 'lzma'])
427 self._tools.Run(cbfstool, [bootstub, 'add-payload', uboot_elf,
428 'img/U-Boot', 'lzma'])
429 else:
430 self._tools.Run(cbfstool, [bootstub, 'add-payload', uboot_elf,
431 'fallback/payload', 'lzma'])
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700432 self._tools.Run(cbfstool, [bootstub, 'add', fdt.fname, 'u-boot.dtb',
433 '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 Glass290a1802011-07-17 13:54:32 -0700446 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700447 """Create a full firmware image, along with various by-products.
448
449 This uses the provided u-boot.bin, fdt and bct to create a firmware
450 image containing all the required parts. If the GBB is not supplied
451 then this will just return a signed U-Boot as the image.
452
453 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200454 gbb: Full path to the GBB file, or empty if a GBB is not required.
455 fdt: Fdt object containing required information.
456
457 Returns:
458 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700459
460 Raises:
461 CmdError if a command fails.
462 """
Simon Glass02d124a2012-03-02 14:47:20 -0800463 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700464
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700465 if self.coreboot_fname:
466 # FIXME(reinauer) the names are not too great choices.
467 # signed gets packed into the bootstub, and bootstub gets
468 # packed into the RW sections.
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700469 signed = self._CreateCorebootStub(self.uboot_fname,
Vincent Palatinf7286772011-10-12 14:31:53 -0700470 self.coreboot_fname, fdt, self.seabios_fname)
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700471 bootstub = self.uboot_fname
472 else:
473 # Create the boot stub, which is U-Boot plus an fdt and bct
Simon Glass6dcc2f22011-07-28 15:26:49 +1200474 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
475 self.postload_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700476
477 if gbb:
478 pack = PackFirmware(self._tools, self._out)
479 image = os.path.join(self._tools.outdir, 'image.bin')
Hung-Te Lina7462e72011-07-27 19:17:10 +0800480 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800481 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800482 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700483 self._out.Notice('Firmware ID: %s' % fwid)
484 pack.SetupFiles(boot=bootstub, signed=signed, gbb=gbb,
Simon Glass290a1802011-07-17 13:54:32 -0700485 fwid=fwid, keydir=self._keydir)
486 pack.SelectFdt(fdt)
Simon Glass89b86b82011-07-17 23:49:49 -0700487 pack.PackImage(self._tools.outdir, image)
488 else:
489 image = signed
490
491 self._tools.OutputSize('Final image', image)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200492 return image
Simon Glass89b86b82011-07-17 23:49:49 -0700493
Simon Glass290a1802011-07-17 13:54:32 -0700494 def SelectFdt(self, fdt_fname):
495 """Select an FDT to control the firmware bundling
496
497 Args:
498 fdt_fname: The filename of the fdt to use.
499
Simon Glassc0f3dc62011-08-09 14:19:05 -0700500 Returns:
501 The Fdt object of the original fdt file, which we will not modify.
502
Simon Glass290a1802011-07-17 13:54:32 -0700503 We make a copy of this which will include any on-the-fly changes we want
504 to make.
505 """
506 self._fdt_fname = fdt_fname
507 self.CheckOptions()
508 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800509 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700510 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700511 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700512
Simon Glass56577572011-07-19 11:08:06 +1200513 def Start(self, hardware_id, output_fname):
Simon Glass290a1802011-07-17 13:54:32 -0700514 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700515
516 - Checks options, tools, output directory, fdt.
517 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700518
519 Args:
Simon Glass56577572011-07-19 11:08:06 +1200520 hardware_id: Hardware ID to use for this board. If None, then the
521 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700522 output_fname: Output filename for the image. If this is not None, then
523 the final image will be copied here.
524
525 Returns:
526 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700527 """
Simon Glass89b86b82011-07-17 23:49:49 -0700528 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700529 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200530 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700531
532 # This creates the actual image.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200533 image = self._CreateImage(gbb, self.fdt)
Simon Glass290a1802011-07-17 13:54:32 -0700534 if output_fname:
535 shutil.copyfile(image, output_fname)
536 self._out.Notice("Output image '%s'" % output_fname)
537 return image