blob: 4aa4123dfb136bb0b48d7af7b68731722d713c73 [file] [log] [blame]
Simon Glass89b86b82011-07-17 23:49:49 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This module builds a firmware image for a tegra-based board.
6
7This modules uses a few rudimentary other libraries for its activity.
8
9Here are the names we give to the various files we deal with. It is important
10to keep these consistent!
11
12 uboot u-boot.bin (with no device tree)
13 fdt the fdt blob
14 bct the BCT file
15 bootstub uboot + fdt
16 signed (uboot + fdt + bct) signed blob
17"""
18
Simon Glassceff3ff2012-04-04 11:23:45 -070019import glob
Simon Glass89b86b82011-07-17 23:49:49 -070020import os
21import re
22
23import cros_output
24from fdt import Fdt
25from pack_firmware import PackFirmware
26import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080027import struct
Simon Glass89b86b82011-07-17 23:49:49 -070028import tempfile
Simon Glass439fe7a2012-03-09 16:19:34 -080029from tools import CmdError
Simon Glass89b86b82011-07-17 23:49:49 -070030from tools import Tools
31from write_firmware import WriteFirmware
32
33# This data is required by bmpblk_utility. Does it ever change?
34# It was stored with the chromeos-bootimage ebuild, but we want
35# this utility to work outside the chroot.
36yaml_data = '''
37bmpblock: 1.0
38
39images:
40 devmode: DeveloperBmp/DeveloperBmp.bmp
41 recovery: RecoveryBmp/RecoveryBmp.bmp
42 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
43 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
44
45screens:
46 dev_en:
47 - [0, 0, devmode]
48 rec_en:
49 - [0, 0, recovery]
50 yuck_en:
51 - [0, 0, rec_yuck]
52 ins_en:
53 - [0, 0, rec_insert]
54
55localizations:
56 - [ dev_en, rec_en, yuck_en, ins_en ]
57'''
58
59class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070060 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070061
Simon Glass290a1802011-07-17 13:54:32 -070062 Sequence of events:
63 bundle = Bundle(tools.Tools(), cros_output.Output())
64 bundle.SetDirs(...)
65 bundle.SetFiles(...)
66 bundle.SetOptions(...)
67 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070068 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070069 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070070
Simon Glass290a1802011-07-17 13:54:32 -070071 Public properties:
72 fdt: The fdt object that we use for building our image. This wil be the
73 one specified by the user, except that we might add config options
74 to it. This is set up by SelectFdt() which must be called before
75 bundling starts.
76 uboot_fname: Full filename of the U-Boot binary we use.
77 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -070078 spl_source: Source device to load U-Boot from, in SPL:
79 straps: Select device according to CPU strap pins
80 spi: Boot from SPI
81 emmc: Boot from eMMC
Simon Glass290a1802011-07-17 13:54:32 -070082 """
Simon Glass89b86b82011-07-17 23:49:49 -070083
Simon Glass290a1802011-07-17 13:54:32 -070084 def __init__(self, tools, output):
85 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -070086
Simon Glass290a1802011-07-17 13:54:32 -070087 Args:
88 tools: A tools.Tools object to use for external tools.
89 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -070090 """
Simon Glass290a1802011-07-17 13:54:32 -070091 self._tools = tools
92 self._out = output
93
94 # Set up the things we need to know in order to operate.
95 self._board = None # Board name, e.g. tegra2_seaboard.
96 self._fdt_fname = None # Filename of our FDT.
97 self.uboot_fname = None # Filename of our U-Boot binary.
98 self.bct_fname = None # Filename of our BCT file.
99 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800100 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700101 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -0700102 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -0700103 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
104 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass559b6612012-05-23 13:28:45 -0700105 self.spl_source = 'straps' # SPL boot according to board settings
Simon Glass07267952012-06-08 12:45:13 -0700106 self.skeleton_fname = None # Filename of Coreboot skeleton file
Simon Glassf0cf8b92012-06-21 08:17:30 -0700107 self.ecbin_fname = None # Filename of EC file
Simon Glass290a1802011-07-17 13:54:32 -0700108
109 def SetDirs(self, keydir):
110 """Set up directories required for Bundle.
111
112 Args:
113 keydir: Directory containing keys to use for signing firmware.
114 """
115 self._keydir = keydir
116
Simon Glass6dcc2f22011-07-28 15:26:49 +1200117 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glass07267952012-06-08 12:45:13 -0700118 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassf0cf8b92012-06-21 08:17:30 -0700119 skeleton=None, ecbin=None):
Simon Glass290a1802011-07-17 13:54:32 -0700120 """Set up files required for Bundle.
121
122 Args:
123 board: The name of the board to target (e.g. tegra2_seaboard).
124 uboot: The filename of the u-boot.bin image to use.
125 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800126 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700127 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200128 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700129 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700130 exynos_bl1: The filename of the exynos BL1 file
131 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
132 skeleton: The filename of the coreboot skeleton file.
Simon Glassf0cf8b92012-06-21 08:17:30 -0700133 ecbin: The filename of the EC (Embedded Controller) file.
Simon Glass290a1802011-07-17 13:54:32 -0700134 """
135 self._board = board
136 self.uboot_fname = uboot
137 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800138 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700139 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200140 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700141 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700142 self.exynos_bl1 = exynos_bl1
143 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700144 self.skeleton_fname = skeleton
Simon Glassf0cf8b92012-06-21 08:17:30 -0700145 self.ecbin_fname = ecbin
Simon Glass290a1802011-07-17 13:54:32 -0700146
147 def SetOptions(self, small):
148 """Set up options supported by Bundle.
149
150 Args:
151 small: Only create a signed U-Boot - don't produce the full packed
152 firmware image. This is useful for devs who want to replace just the
153 U-Boot part while keeping the keys, gbb, etc. the same.
154 """
155 self._small = small
156
157 def CheckOptions(self):
158 """Check provided options and select defaults."""
159 if not self._board:
160 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700161 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700162 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700163 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700164 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700165 base_name = re.sub('_', '-', self._board)
166
167 # In case the name exists with a prefix or suffix, find it.
168 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
169 found_list = glob.glob(self._tools.Filename(wildcard))
170 if len(found_list) == 1:
171 self._fdt_fname = found_list[0]
172 else:
173 # We didn't find anything definite, so set up our expected name.
174 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
175
Simon Glass881964d2012-04-04 11:34:09 -0700176 # Convert things like 'exynos5250-daisy' into a full path.
177 root, ext = os.path.splitext(self._fdt_fname)
178 if not ext and not os.path.dirname(root):
179 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
180
Simon Glass290a1802011-07-17 13:54:32 -0700181 if not self.uboot_fname:
182 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
183 if not self.bct_fname:
184 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700185 if not self.bmpblk_fname:
186 self.bmpblk_fname = os.path.join(build_root, 'default.bmpblk')
Simon Glass1d376832012-03-15 20:50:54 -0700187 if not self.exynos_bl1:
188 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
189 if not self.exynos_bl2:
190 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700191 if not self.coreboot_fname:
192 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
193 if not self.skeleton_fname:
194 self.skeleton_fname = os.path.join(build_root, 'skeleton.bin')
Simon Glassf0cf8b92012-06-21 08:17:30 -0700195 if not self.ecbin_fname:
196 self.ecbin_fname = os.path.join(build_root, 'ec.RW.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700197
Simon Glass75759302012-03-15 20:26:53 -0700198 def GetFiles(self):
199 """Get a list of files that we know about.
200
201 This is the opposite of SetFiles except that we may have put in some
202 default names. It returns a dictionary containing the filename for
203 each of a number of pre-defined files.
204
205 Returns:
206 Dictionary, with one entry for each file.
207 """
208 file_list = {
209 'bct' : self.bct_fname,
210 'exynos-bl1' : self.exynos_bl1,
211 'exynos-bl2' : self.exynos_bl2,
212 }
213 return file_list
214
Simon Glass56577572011-07-19 11:08:06 +1200215 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700216 """Create a GBB for the image.
217
Simon Glass56577572011-07-19 11:08:06 +1200218 Args:
219 hardware_id: Hardware ID to use for this board. If None, then the
220 default from the Fdt will be used
221
Simon Glass89b86b82011-07-17 23:49:49 -0700222 Returns:
223 Path of the created GBB file.
224
225 Raises:
226 CmdError if a command fails.
227 """
Simon Glass56577572011-07-19 11:08:06 +1200228 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800229 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700230 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700231 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700232
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800233 chromeos_config = self.fdt.GetProps("/chromeos-config")
234 if 'fast-developer-mode' not in chromeos_config:
235 gbb_flags = 0
236 else:
237 self._out.Notice("Enabling fast-developer-mode.")
238 gbb_flags = 1
239
Simon Glass89b86b82011-07-17 23:49:49 -0700240 self._out.Progress('Creating GBB')
241 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
242 sizes = ['%#x' % size for size in sizes]
243 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700244 keydir = self._tools.Filename(self._keydir)
245 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700246 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200247 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700248 '--rootkey=%s/root_key.vbpubk' % keydir,
249 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700250 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800251 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700252 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700253 cwd=odir)
254 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700255
Simon Glasse13ee2c2011-07-28 08:12:28 +1200256 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700257 """Sign an image so that the Tegra SOC will boot it.
258
259 Args:
260 bct: BCT file to use.
261 bootstub: Boot stub (U-Boot + fdt) file to sign.
262 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700263
264 Returns:
265 filename of signed image.
266
267 Raises:
268 CmdError if a command fails.
269 """
270 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200271 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700272 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200273 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700274 fd = open(config, 'w')
275 fd.write('Version = 1;\n')
276 fd.write('Redundancy = 1;\n')
277 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700278
279 # TODO(dianders): Right now, we don't have enough space in our flash map
280 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
281 # sure what this does for reliability, but at least things will fit...
282 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
283 if is_nand:
284 fd.write('Bctcopy = 1;\n')
285
Simon Glass89b86b82011-07-17 23:49:49 -0700286 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
287 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700288
Simon Glass89b86b82011-07-17 23:49:49 -0700289 fd.close()
290
291 self._tools.Run('cbootimage', [config, signed])
292 self._tools.OutputSize('BCT', bct)
293 self._tools.OutputSize('Signed image', signed)
294 return signed
295
Doug Anderson86ce5f42011-07-27 10:40:18 -0700296 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700297 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700298
299 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700300 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700301 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700302 """
Simon Glass290a1802011-07-17 13:54:32 -0700303 if bootcmd:
Simon Glass02d124a2012-03-02 14:47:20 -0800304 self.fdt.PutString('/config', 'bootcmd', bootcmd)
305 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700306 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700307
Simon Glassa4934b72012-05-09 13:35:02 -0700308 def SetNodeEnabled(self, node_name, enabled):
309 """Set whether an node is enabled or disabled.
310
311 This simply sets the 'status' property of a node to "ok", or "disabled".
312
313 The node should either be a full path to the node (like '/uart@10200000')
314 or an alias property.
315
316 Aliases are supported like this:
317
318 aliases {
319 console = "/uart@10200000";
320 };
321
322 pointing to a node:
323
324 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700325 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700326 };
327
328 In this case, this function takes the name of the alias ('console' in
329 this case) and updates the status of the node that is pointed to, to
330 either ok or disabled. If the alias does not exist, a warning is
331 displayed.
332
333 Args:
334 node_name: Name of node (e.g. '/uart@10200000') or alias alias
335 (e.g. 'console') to adjust
336 enabled: True to enable, False to disable
337 """
338 # Look up the alias if this is an alias reference
339 if not node_name.startswith('/'):
340 lookup = self.fdt.GetString('/aliases', node_name, '')
341 if not lookup:
342 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
343 return
344 node_name = lookup
345 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700346 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700347 else:
348 status = 'disabled'
349 self.fdt.PutString(node_name, 'status', status)
350
351 def AddEnableList(self, enable_list):
352 """Process a list of nodes to enable/disable.
353
354 Args:
355 config_list: List of (node, value) tuples to add to the fdt. For each
356 tuple:
357 node: The fdt node to write to will be <node> or pointed to by
358 /aliases/<node>. We can tell which
359 value: 0 to disable the node, 1 to enable it
360 """
361 if enable_list:
362 for node_name, enabled in enable_list:
363 try:
364 enabled = int(enabled)
365 if enabled not in (0, 1):
366 raise ValueError
367 except ValueError as str:
368 raise CmdError("Invalid enable option value '%s' "
369 "(should be 0 or 1)" % enabled)
370 self.SetNodeEnabled(node_name, enabled)
371
Simon Glass290a1802011-07-17 13:54:32 -0700372 def AddConfigList(self, config_list, use_int=False):
373 """Add a list of config items to the fdt.
374
375 Normally these values are written to the fdt as strings, but integers
376 are also supported, in which case the values will be converted to integers
377 (if necessary) before being stored.
378
379 Args:
380 config_list: List of (config, value) tuples to add to the fdt. For each
381 tuple:
382 config: The fdt node to write to will be /config/<config>.
383 value: An integer or string value to write.
384 use_int: True to only write integer values.
385
386 Raises:
387 CmdError: if a value is required to be converted to integer but can't be.
388 """
389 if config_list:
390 for config in config_list:
391 value = config[1]
392 if use_int:
393 try:
394 value = int(value)
395 except ValueError as str:
396 raise CmdError("Cannot convert config option '%s' to integer" %
397 value)
398 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800399 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700400 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800401 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700402
Simon Glass7c2d5572011-11-15 14:47:08 -0800403 def DecodeTextBase(self, data):
404 """Look at a U-Boot image and try to decode its TEXT_BASE.
405
406 This works because U-Boot has a header with the value 0x12345678
407 immediately followed by the TEXT_BASE value. We can therefore read this
408 from the image with some certainty. We check only the first 40 words
409 since the header should be within that region.
410
411 Args:
412 data: U-Boot binary data
413
414 Returns:
415 Text base (integer) or None if none was found
416 """
417 found = False
418 for i in range(0, 160, 4):
419 word = data[i:i + 4]
420
421 # TODO(sjg): This does not cope with a big-endian target
422 value = struct.unpack('<I', word)[0]
423 if found:
424 return value
425 if value == 0x12345678:
426 found = True
427
428 return None
429
430 def CalcTextBase(self, name, fdt, fname):
431 """Calculate the TEXT_BASE to use for U-Boot.
432
433 Normally this value is in the fdt, so we just read it from there. But as
434 a second check we look at the image itself in case this is different, and
435 switch to that if it is.
436
437 This allows us to flash any U-Boot even if its TEXT_BASE is different.
438 This is particularly useful with upstream U-Boot which uses a different
439 value (which we will move to).
440 """
441 data = self._tools.ReadFile(fname)
Simon Glass02d124a2012-03-02 14:47:20 -0800442 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase')
Simon Glass7c2d5572011-11-15 14:47:08 -0800443 text_base = self.DecodeTextBase(data)
Simon Glass60a40af2012-06-07 11:54:17 -0700444 self._out.Info('TEXT_BASE: fdt says %#x, %s says %#x' % (fdt_text_base,
445 fname, text_base))
Simon Glass7c2d5572011-11-15 14:47:08 -0800446
447 # If they are different, issue a warning and switch over.
448 if text_base and text_base != fdt_text_base:
449 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
450 "fdt value of %x. Using %x" % (text_base, name,
451 fdt_text_base, text_base))
452 fdt_text_base = text_base
453 return fdt_text_base
454
Simon Glass6dcc2f22011-07-28 15:26:49 +1200455 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700456 """Create a boot stub and a signed boot stub.
457
Simon Glass6dcc2f22011-07-28 15:26:49 +1200458 For postload:
459 We add a /config/postload-text-offset entry to the signed bootstub's
460 fdt so that U-Boot can find the postload code.
461
462 The raw (unsigned) bootstub will have a value of -1 for this since we will
463 simply append the postload code to the bootstub and it can find it there.
464 This will be used for RW A/B firmware.
465
466 For the signed case this value will specify where in the flash to find
467 the postload code. This will be used for RO firmware.
468
Simon Glass89b86b82011-07-17 23:49:49 -0700469 Args:
470 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800471 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200472 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700473
474 Returns:
475 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200476 Full path to bootstub (uboot + fdt(-1) + postload).
477 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700478
479 Raises:
480 CmdError if a command fails.
481 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200482 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800483 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700484 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200485
486 # Make a copy of the fdt for the bootstub
487 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800488 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700489 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200490
Simon Glass89b86b82011-07-17 23:49:49 -0700491 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700492 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
493 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700494 self._tools.OutputSize('Combined binary', bootstub)
495
Simon Glasse13ee2c2011-07-28 08:12:28 +1200496 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700497 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700498 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200499 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200500
501 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
502 data = self._tools.ReadFile(signed)
503
504 if postload:
505 # We must add postload to the bootstub since A and B will need to
506 # be able to find it without the /config/postload-text-offset mechanism.
507 bs_data = self._tools.ReadFile(bootstub)
508 bs_data += self._tools.ReadFile(postload)
509 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
510 self._tools.WriteFile(bootstub, bs_data)
511 self._tools.OutputSize('Combined binary with postload', bootstub)
512
513 # Now that we know the file size, adjust the fdt and re-sign
514 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800515 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200516 fdt_data = self._tools.ReadFile(fdt.fname)
517 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
518 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
519 postload_bootstub, text_base)
520 if len(data) != os.path.getsize(signed):
521 raise CmdError('Signed file size changed from %d to %d after updating '
522 'fdt' % (len(data), os.path.getsize(signed)))
523
524 # Re-read the signed image, and add the post-load binary.
525 data = self._tools.ReadFile(signed)
526 data += self._tools.ReadFile(postload)
527 self._tools.OutputSize('Post-load binary', postload)
528
529 self._tools.WriteFile(signed_postload, data)
530 self._tools.OutputSize('Final bootstub with postload', signed_postload)
531
532 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700533
Vincent Palatinf7286772011-10-12 14:31:53 -0700534 def _CreateCorebootStub(self, uboot, coreboot, fdt, seabios):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700535 """Create a coreboot boot stub.
536
537 Args:
538 uboot: Path to u-boot.bin (may be chroot-relative)
539 coreboot: Path to coreboot.rom
540 fdt: Device Tree
Vincent Palatinf7286772011-10-12 14:31:53 -0700541 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700542
543 Returns:
544 Full path to bootstub (coreboot + uboot + fdt).
545
546 Raises:
547 CmdError if a command fails.
548 """
549 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700550
551 # U-Boot itself does not put a .elf extension on the elf file.
552 # The U-Boot ebuild does, but we shouldn't actually require it since
553 # devs may want to just use what U-Boot creates.
554 uboot_elf = uboot.replace('.bin', '')
555 if not os.path.exists(self._tools.Filename(uboot_elf)):
556 uboot_elf = uboot.replace('.bin', '.elf')
557 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Vincent Palatinf7286772011-10-12 14:31:53 -0700558 if seabios:
Simon Glass146cb8e2012-03-09 15:51:24 -0800559 self._tools.Run('cbfstool', [bootstub, 'add-payload', seabios,
Vincent Palatinf7286772011-10-12 14:31:53 -0700560 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800561 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700562 'img/U-Boot', 'lzma'])
563 else:
Simon Glass146cb8e2012-03-09 15:51:24 -0800564 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700565 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800566 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700567 '0xac'])
568 return bootstub
569
Simon Glass3b404092012-05-23 13:10:36 -0700570 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700571 """Update the parameters in a BL2 blob.
572
573 We look at the list in the parameter block, extract the value of each
574 from the device tree, and write that value to the parameter block.
575
576 Args:
577 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700578 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700579 data: The BL2 data.
580 pos: The position of the start of the parameter block.
581
582 Returns:
583 The new contents of the parameter block, after updating.
584 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700585 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
586 if version != 1:
587 raise CmdError("Cannot update machine parameter block version '%d'" %
588 version)
589 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700590 raise CmdError("Machine parameter block size %d is invalid: "
591 "pos=%d, size=%d, space=%d, len=%d" %
592 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700593
594 # Move past the header and read the parameter list, which is terminated
595 # with \0.
596 pos += 12
597 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
598 param_len = param_list.find('\0')
599 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700600 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700601
602 # Work through the parameters one at a time, adding each value
603 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700604 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700605 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700606 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700607 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700608 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700609 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
610 if not mem_type in mem_types:
611 raise CmdError("Unknown memory type '%s'" % mem_type)
612 value = mem_types.index(mem_type)
613 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700614 elif param == 'M' :
615 mem_manuf = fdt.GetString('/dmc', 'mem-manuf')
616 mem_manufs = ['autodetect', 'elpida', 'samsung']
617 if not mem_manuf in mem_manufs:
618 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
619 value = mem_manufs.index(mem_manuf)
620 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glassdf95dd22012-03-13 15:46:16 -0700621 elif param == 'v':
622 value = 31
623 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700624 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700625 value = (spl_load_size + 0xfff) & ~0xfff
626 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
627 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700628 elif param == 'b':
629 # These values come from enum boot_mode in U-Boot's cpu.h
630 if self.spl_source == 'straps':
631 value = 32
632 elif self.spl_source == 'emmc':
633 value = 4
634 elif self.spl_source == 'spi':
635 value = 20
636 elif self.spl_source == 'usb':
637 value = 33
638 else:
639 raise CmdError("Invalid boot source '%s'" % self.spl_source)
640 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700641 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700642 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700643 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700644 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700645 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700646
647 # Put the data into our block.
648 data = data[:pos] + new_data + data[pos + len(new_data):]
649 self._out.Info('BL2 configuration complete')
650 return data
651
Simon Glasse5e8afb2012-05-23 11:19:23 -0700652 def _UpdateChecksum(self, data):
653 """Update the BL2 checksum.
654
655 The checksum is a 4 byte sum of all the bytes in the image before the
656 last 4 bytes (which hold the checksum).
657
658 Args:
659 data: The BL2 data to update.
660
661 Returns:
662 The new contents of the BL2 data, after updating the checksum.
663 """
664 checksum = 0
665 for ch in data[:-4]:
666 checksum += ord(ch)
667 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
668
Simon Glass559b6612012-05-23 13:28:45 -0700669 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700670 """Configure an Exynos BL2 binary for our needs.
671
672 We create a new modified BL2 and return its filename.
673
674 Args:
675 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700676 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700677 orig_bl2: Filename of original BL2 file to modify.
678 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700679 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700680 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700681 data = self._tools.ReadFile(orig_bl2)
682 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700683
684 # Locate the parameter block
685 data = self._tools.ReadFile(bl2)
686 marker = struct.pack('<L', 0xdeadbeef)
687 pos = data.rfind(marker)
688 if not pos:
689 raise CmdError("Could not find machine parameter block in '%s'" %
690 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700691 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700692 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700693 self._tools.WriteFile(bl2, data)
694 return bl2
695
Simon Glass89b86b82011-07-17 23:49:49 -0700696 def _PackOutput(self, msg):
697 """Helper function to write output from PackFirmware (verbose level 2).
698
699 This is passed to PackFirmware for it to use to write output.
700
701 Args:
702 msg: Message to display.
703 """
704 self._out.Notice(msg)
705
Simon Glass439fe7a2012-03-09 16:19:34 -0800706 def _BuildBlob(self, pack, fdt, blob_type):
707 """Build the blob data for a particular blob type.
708
709 Args:
710 blob_type: The type of blob to create data for. Supported types are:
711 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
712 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
713 """
714 if blob_type == 'coreboot':
715 coreboot = self._CreateCorebootStub(self.uboot_fname,
716 self.coreboot_fname, fdt, self.seabios_fname)
717 pack.AddProperty('coreboot', coreboot)
718 pack.AddProperty('image', coreboot)
719 elif blob_type == 'signed':
720 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
721 self.postload_fname)
722 pack.AddProperty('bootstub', bootstub)
723 pack.AddProperty('signed', signed)
724 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700725 elif blob_type == 'exynos-bl1':
726 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassf0cf8b92012-06-21 08:17:30 -0700727 elif blob_type == 'ecbin':
728 pack.AddProperty(blob_type, self.ecbin_fname)
Simon Glass7e199222012-03-13 15:51:18 -0700729 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700730 spl_payload = pack.GetBlobParams(blob_type)
731
732 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
733 # from all flash map files.
734 if not spl_payload:
735 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
736 prop_list = 'boot+dtb'
737
738 # Do this later, when we remove boot+dtb.
739 # raise CmdError("No parameters provided for blob type '%s'" %
740 # blob_type)
741 else:
742 prop_list = spl_payload[0].split(',')
743 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
744 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
745 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700746 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700747 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800748 elif pack.GetProperty(blob_type):
749 pass
750 else:
751 raise CmdError("Unknown blob type '%s' required in flash map" %
752 blob_type)
753
Simon Glass290a1802011-07-17 13:54:32 -0700754 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700755 """Create a full firmware image, along with various by-products.
756
757 This uses the provided u-boot.bin, fdt and bct to create a firmware
758 image containing all the required parts. If the GBB is not supplied
759 then this will just return a signed U-Boot as the image.
760
761 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200762 gbb: Full path to the GBB file, or empty if a GBB is not required.
763 fdt: Fdt object containing required information.
764
765 Returns:
766 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700767
768 Raises:
769 CmdError if a command fails.
770 """
Simon Glass02d124a2012-03-02 14:47:20 -0800771 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700772
Simon Glass439fe7a2012-03-09 16:19:34 -0800773 # Get the flashmap so we know what to build
774 pack = PackFirmware(self._tools, self._out)
775 pack.SelectFdt(fdt)
776
777 # Get all our blobs ready
778 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700779 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700780 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700781
782 # Make a copy of the fdt for the bootstub
783 fdt_data = self._tools.ReadFile(fdt.fname)
784 uboot_data = self._tools.ReadFile(self.uboot_fname)
785 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
786 self._tools.WriteFile(uboot_copy, uboot_data)
787
788 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
789 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700790
791 # TODO(sjg@chromium.org): Deprecate this property when all boards
792 # use a comma-separated list for section contents. We will then
793 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700794 pack.AddProperty('boot+dtb', bootstub)
795
Simon Glass439fe7a2012-03-09 16:19:34 -0800796 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700797 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800798 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700799
800 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700801 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800802 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800803 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800804 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700805 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800806 pack.AddProperty('fwid', fwid)
807 pack.AddProperty('gbb', gbb)
808 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700809
810 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700811
812 # Record position and size of all blob members in the FDT
813 pack.UpdateBlobPositions(fdt)
814
Simon Glassc90cf582012-03-13 15:40:47 -0700815 image = os.path.join(self._tools.outdir, 'image.bin')
816 pack.PackImage(self._tools.outdir, image)
817 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700818
Simon Glass439fe7a2012-03-09 16:19:34 -0800819 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700820 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700821 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700822
Simon Glass290a1802011-07-17 13:54:32 -0700823 def SelectFdt(self, fdt_fname):
824 """Select an FDT to control the firmware bundling
825
826 Args:
827 fdt_fname: The filename of the fdt to use.
828
Simon Glassc0f3dc62011-08-09 14:19:05 -0700829 Returns:
830 The Fdt object of the original fdt file, which we will not modify.
831
Simon Glass290a1802011-07-17 13:54:32 -0700832 We make a copy of this which will include any on-the-fly changes we want
833 to make.
834 """
835 self._fdt_fname = fdt_fname
836 self.CheckOptions()
837 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800838 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700839 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700840 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700841
Simon Glassc90cf582012-03-13 15:40:47 -0700842 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -0700843 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700844
845 - Checks options, tools, output directory, fdt.
846 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700847
848 Args:
Simon Glass56577572011-07-19 11:08:06 +1200849 hardware_id: Hardware ID to use for this board. If None, then the
850 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700851 output_fname: Output filename for the image. If this is not None, then
852 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -0700853 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -0700854
855 Returns:
856 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700857 """
Simon Glass89b86b82011-07-17 23:49:49 -0700858 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700859 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200860 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700861
862 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -0700863 image, pack = self._CreateImage(gbb, self.fdt)
864 if show_map:
865 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -0700866 if output_fname:
867 shutil.copyfile(image, output_fname)
868 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -0700869 return image, pack.props