blob: ad8d80392aa1d6636a13519dd58cf7027640120d [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 Glassde9c8072012-07-02 22:29:02 -0700119 skeleton=None, ecbin=None, kernel=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 Glassde9c8072012-07-02 22:29:02 -0700134 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700135 """
136 self._board = board
137 self.uboot_fname = uboot
138 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800139 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700140 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200141 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700142 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700143 self.exynos_bl1 = exynos_bl1
144 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700145 self.skeleton_fname = skeleton
Simon Glassf0cf8b92012-06-21 08:17:30 -0700146 self.ecbin_fname = ecbin
Simon Glassde9c8072012-07-02 22:29:02 -0700147 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700148
149 def SetOptions(self, small):
150 """Set up options supported by Bundle.
151
152 Args:
153 small: Only create a signed U-Boot - don't produce the full packed
154 firmware image. This is useful for devs who want to replace just the
155 U-Boot part while keeping the keys, gbb, etc. the same.
156 """
157 self._small = small
158
159 def CheckOptions(self):
160 """Check provided options and select defaults."""
161 if not self._board:
162 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700163 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700164 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700165 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700166 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700167 base_name = re.sub('_', '-', self._board)
168
169 # In case the name exists with a prefix or suffix, find it.
170 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
171 found_list = glob.glob(self._tools.Filename(wildcard))
172 if len(found_list) == 1:
173 self._fdt_fname = found_list[0]
174 else:
175 # We didn't find anything definite, so set up our expected name.
176 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
177
Simon Glass881964d2012-04-04 11:34:09 -0700178 # Convert things like 'exynos5250-daisy' into a full path.
179 root, ext = os.path.splitext(self._fdt_fname)
180 if not ext and not os.path.dirname(root):
181 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
182
Simon Glass290a1802011-07-17 13:54:32 -0700183 if not self.uboot_fname:
184 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
185 if not self.bct_fname:
186 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700187 if not self.bmpblk_fname:
188 self.bmpblk_fname = os.path.join(build_root, 'default.bmpblk')
Simon Glass1d376832012-03-15 20:50:54 -0700189 if not self.exynos_bl1:
190 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
191 if not self.exynos_bl2:
192 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700193 if not self.coreboot_fname:
194 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
195 if not self.skeleton_fname:
196 self.skeleton_fname = os.path.join(build_root, 'skeleton.bin')
Simon Glassf0cf8b92012-06-21 08:17:30 -0700197 if not self.ecbin_fname:
198 self.ecbin_fname = os.path.join(build_root, 'ec.RW.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700199
Simon Glass75759302012-03-15 20:26:53 -0700200 def GetFiles(self):
201 """Get a list of files that we know about.
202
203 This is the opposite of SetFiles except that we may have put in some
204 default names. It returns a dictionary containing the filename for
205 each of a number of pre-defined files.
206
207 Returns:
208 Dictionary, with one entry for each file.
209 """
210 file_list = {
211 'bct' : self.bct_fname,
212 'exynos-bl1' : self.exynos_bl1,
213 'exynos-bl2' : self.exynos_bl2,
214 }
215 return file_list
216
Simon Glass56577572011-07-19 11:08:06 +1200217 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700218 """Create a GBB for the image.
219
Simon Glass56577572011-07-19 11:08:06 +1200220 Args:
221 hardware_id: Hardware ID to use for this board. If None, then the
222 default from the Fdt will be used
223
Simon Glass89b86b82011-07-17 23:49:49 -0700224 Returns:
225 Path of the created GBB file.
226
227 Raises:
228 CmdError if a command fails.
229 """
Simon Glass56577572011-07-19 11:08:06 +1200230 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800231 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700232 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700233 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700234
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800235 chromeos_config = self.fdt.GetProps("/chromeos-config")
236 if 'fast-developer-mode' not in chromeos_config:
237 gbb_flags = 0
238 else:
239 self._out.Notice("Enabling fast-developer-mode.")
240 gbb_flags = 1
241
Simon Glass89b86b82011-07-17 23:49:49 -0700242 self._out.Progress('Creating GBB')
243 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
244 sizes = ['%#x' % size for size in sizes]
245 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700246 keydir = self._tools.Filename(self._keydir)
247 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700248 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200249 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700250 '--rootkey=%s/root_key.vbpubk' % keydir,
251 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700252 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800253 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700254 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700255 cwd=odir)
256 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700257
Simon Glasse13ee2c2011-07-28 08:12:28 +1200258 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700259 """Sign an image so that the Tegra SOC will boot it.
260
261 Args:
262 bct: BCT file to use.
263 bootstub: Boot stub (U-Boot + fdt) file to sign.
264 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700265
266 Returns:
267 filename of signed image.
268
269 Raises:
270 CmdError if a command fails.
271 """
272 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200273 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700274 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200275 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700276 fd = open(config, 'w')
277 fd.write('Version = 1;\n')
278 fd.write('Redundancy = 1;\n')
279 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700280
281 # TODO(dianders): Right now, we don't have enough space in our flash map
282 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
283 # sure what this does for reliability, but at least things will fit...
284 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
285 if is_nand:
286 fd.write('Bctcopy = 1;\n')
287
Simon Glass89b86b82011-07-17 23:49:49 -0700288 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
289 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700290
Simon Glass89b86b82011-07-17 23:49:49 -0700291 fd.close()
292
293 self._tools.Run('cbootimage', [config, signed])
294 self._tools.OutputSize('BCT', bct)
295 self._tools.OutputSize('Signed image', signed)
296 return signed
297
Doug Anderson86ce5f42011-07-27 10:40:18 -0700298 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700299 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700300
301 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700302 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700303 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700304 """
Simon Glass290a1802011-07-17 13:54:32 -0700305 if bootcmd:
Simon Glass02d124a2012-03-02 14:47:20 -0800306 self.fdt.PutString('/config', 'bootcmd', bootcmd)
307 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700308 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700309
Simon Glassa4934b72012-05-09 13:35:02 -0700310 def SetNodeEnabled(self, node_name, enabled):
311 """Set whether an node is enabled or disabled.
312
313 This simply sets the 'status' property of a node to "ok", or "disabled".
314
315 The node should either be a full path to the node (like '/uart@10200000')
316 or an alias property.
317
318 Aliases are supported like this:
319
320 aliases {
321 console = "/uart@10200000";
322 };
323
324 pointing to a node:
325
326 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700327 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700328 };
329
330 In this case, this function takes the name of the alias ('console' in
331 this case) and updates the status of the node that is pointed to, to
332 either ok or disabled. If the alias does not exist, a warning is
333 displayed.
334
335 Args:
336 node_name: Name of node (e.g. '/uart@10200000') or alias alias
337 (e.g. 'console') to adjust
338 enabled: True to enable, False to disable
339 """
340 # Look up the alias if this is an alias reference
341 if not node_name.startswith('/'):
342 lookup = self.fdt.GetString('/aliases', node_name, '')
343 if not lookup:
344 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
345 return
346 node_name = lookup
347 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700348 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700349 else:
350 status = 'disabled'
351 self.fdt.PutString(node_name, 'status', status)
352
353 def AddEnableList(self, enable_list):
354 """Process a list of nodes to enable/disable.
355
356 Args:
357 config_list: List of (node, value) tuples to add to the fdt. For each
358 tuple:
359 node: The fdt node to write to will be <node> or pointed to by
360 /aliases/<node>. We can tell which
361 value: 0 to disable the node, 1 to enable it
362 """
363 if enable_list:
364 for node_name, enabled in enable_list:
365 try:
366 enabled = int(enabled)
367 if enabled not in (0, 1):
368 raise ValueError
369 except ValueError as str:
370 raise CmdError("Invalid enable option value '%s' "
371 "(should be 0 or 1)" % enabled)
372 self.SetNodeEnabled(node_name, enabled)
373
Simon Glass290a1802011-07-17 13:54:32 -0700374 def AddConfigList(self, config_list, use_int=False):
375 """Add a list of config items to the fdt.
376
377 Normally these values are written to the fdt as strings, but integers
378 are also supported, in which case the values will be converted to integers
379 (if necessary) before being stored.
380
381 Args:
382 config_list: List of (config, value) tuples to add to the fdt. For each
383 tuple:
384 config: The fdt node to write to will be /config/<config>.
385 value: An integer or string value to write.
386 use_int: True to only write integer values.
387
388 Raises:
389 CmdError: if a value is required to be converted to integer but can't be.
390 """
391 if config_list:
392 for config in config_list:
393 value = config[1]
394 if use_int:
395 try:
396 value = int(value)
397 except ValueError as str:
398 raise CmdError("Cannot convert config option '%s' to integer" %
399 value)
400 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800401 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700402 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800403 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700404
Simon Glass7c2d5572011-11-15 14:47:08 -0800405 def DecodeTextBase(self, data):
406 """Look at a U-Boot image and try to decode its TEXT_BASE.
407
408 This works because U-Boot has a header with the value 0x12345678
409 immediately followed by the TEXT_BASE value. We can therefore read this
410 from the image with some certainty. We check only the first 40 words
411 since the header should be within that region.
412
413 Args:
414 data: U-Boot binary data
415
416 Returns:
417 Text base (integer) or None if none was found
418 """
419 found = False
420 for i in range(0, 160, 4):
421 word = data[i:i + 4]
422
423 # TODO(sjg): This does not cope with a big-endian target
424 value = struct.unpack('<I', word)[0]
425 if found:
426 return value
427 if value == 0x12345678:
428 found = True
429
430 return None
431
432 def CalcTextBase(self, name, fdt, fname):
433 """Calculate the TEXT_BASE to use for U-Boot.
434
435 Normally this value is in the fdt, so we just read it from there. But as
436 a second check we look at the image itself in case this is different, and
437 switch to that if it is.
438
439 This allows us to flash any U-Boot even if its TEXT_BASE is different.
440 This is particularly useful with upstream U-Boot which uses a different
441 value (which we will move to).
442 """
443 data = self._tools.ReadFile(fname)
Simon Glass02d124a2012-03-02 14:47:20 -0800444 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase')
Simon Glass7c2d5572011-11-15 14:47:08 -0800445 text_base = self.DecodeTextBase(data)
Simon Glass60a40af2012-06-07 11:54:17 -0700446 self._out.Info('TEXT_BASE: fdt says %#x, %s says %#x' % (fdt_text_base,
447 fname, text_base))
Simon Glass7c2d5572011-11-15 14:47:08 -0800448
449 # If they are different, issue a warning and switch over.
450 if text_base and text_base != fdt_text_base:
451 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
452 "fdt value of %x. Using %x" % (text_base, name,
453 fdt_text_base, text_base))
454 fdt_text_base = text_base
455 return fdt_text_base
456
Simon Glass6dcc2f22011-07-28 15:26:49 +1200457 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700458 """Create a boot stub and a signed boot stub.
459
Simon Glass6dcc2f22011-07-28 15:26:49 +1200460 For postload:
461 We add a /config/postload-text-offset entry to the signed bootstub's
462 fdt so that U-Boot can find the postload code.
463
464 The raw (unsigned) bootstub will have a value of -1 for this since we will
465 simply append the postload code to the bootstub and it can find it there.
466 This will be used for RW A/B firmware.
467
468 For the signed case this value will specify where in the flash to find
469 the postload code. This will be used for RO firmware.
470
Simon Glass89b86b82011-07-17 23:49:49 -0700471 Args:
472 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800473 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200474 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700475
476 Returns:
477 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200478 Full path to bootstub (uboot + fdt(-1) + postload).
479 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700480
481 Raises:
482 CmdError if a command fails.
483 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200484 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800485 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700486 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200487
488 # Make a copy of the fdt for the bootstub
489 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800490 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700491 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200492
Simon Glass89b86b82011-07-17 23:49:49 -0700493 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700494 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
495 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700496 self._tools.OutputSize('Combined binary', bootstub)
497
Simon Glasse13ee2c2011-07-28 08:12:28 +1200498 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700499 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700500 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200501 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200502
503 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
504 data = self._tools.ReadFile(signed)
505
506 if postload:
507 # We must add postload to the bootstub since A and B will need to
508 # be able to find it without the /config/postload-text-offset mechanism.
509 bs_data = self._tools.ReadFile(bootstub)
510 bs_data += self._tools.ReadFile(postload)
511 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
512 self._tools.WriteFile(bootstub, bs_data)
513 self._tools.OutputSize('Combined binary with postload', bootstub)
514
515 # Now that we know the file size, adjust the fdt and re-sign
516 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800517 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200518 fdt_data = self._tools.ReadFile(fdt.fname)
519 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
520 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
521 postload_bootstub, text_base)
522 if len(data) != os.path.getsize(signed):
523 raise CmdError('Signed file size changed from %d to %d after updating '
524 'fdt' % (len(data), os.path.getsize(signed)))
525
526 # Re-read the signed image, and add the post-load binary.
527 data = self._tools.ReadFile(signed)
528 data += self._tools.ReadFile(postload)
529 self._tools.OutputSize('Post-load binary', postload)
530
531 self._tools.WriteFile(signed_postload, data)
532 self._tools.OutputSize('Final bootstub with postload', signed_postload)
533
534 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700535
Vincent Palatinf7286772011-10-12 14:31:53 -0700536 def _CreateCorebootStub(self, uboot, coreboot, fdt, seabios):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700537 """Create a coreboot boot stub.
538
539 Args:
540 uboot: Path to u-boot.bin (may be chroot-relative)
541 coreboot: Path to coreboot.rom
542 fdt: Device Tree
Vincent Palatinf7286772011-10-12 14:31:53 -0700543 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700544
545 Returns:
546 Full path to bootstub (coreboot + uboot + fdt).
547
548 Raises:
549 CmdError if a command fails.
550 """
551 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700552
553 # U-Boot itself does not put a .elf extension on the elf file.
554 # The U-Boot ebuild does, but we shouldn't actually require it since
555 # devs may want to just use what U-Boot creates.
556 uboot_elf = uboot.replace('.bin', '')
557 if not os.path.exists(self._tools.Filename(uboot_elf)):
558 uboot_elf = uboot.replace('.bin', '.elf')
559 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Vincent Palatinf7286772011-10-12 14:31:53 -0700560 if seabios:
Simon Glass146cb8e2012-03-09 15:51:24 -0800561 self._tools.Run('cbfstool', [bootstub, 'add-payload', seabios,
Vincent Palatinf7286772011-10-12 14:31:53 -0700562 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800563 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700564 'img/U-Boot', 'lzma'])
565 else:
Simon Glass146cb8e2012-03-09 15:51:24 -0800566 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700567 'fallback/payload', 'lzma'])
Simon Glass146cb8e2012-03-09 15:51:24 -0800568 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700569 '0xac'])
570 return bootstub
571
Simon Glass3b404092012-05-23 13:10:36 -0700572 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700573 """Update the parameters in a BL2 blob.
574
575 We look at the list in the parameter block, extract the value of each
576 from the device tree, and write that value to the parameter block.
577
578 Args:
579 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700580 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700581 data: The BL2 data.
582 pos: The position of the start of the parameter block.
583
584 Returns:
585 The new contents of the parameter block, after updating.
586 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700587 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
588 if version != 1:
589 raise CmdError("Cannot update machine parameter block version '%d'" %
590 version)
591 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700592 raise CmdError("Machine parameter block size %d is invalid: "
593 "pos=%d, size=%d, space=%d, len=%d" %
594 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700595
596 # Move past the header and read the parameter list, which is terminated
597 # with \0.
598 pos += 12
599 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
600 param_len = param_list.find('\0')
601 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700602 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700603
604 # Work through the parameters one at a time, adding each value
605 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700606 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700607 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700608 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700609 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700610 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700611 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
612 if not mem_type in mem_types:
613 raise CmdError("Unknown memory type '%s'" % mem_type)
614 value = mem_types.index(mem_type)
615 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700616 elif param == 'M' :
617 mem_manuf = fdt.GetString('/dmc', 'mem-manuf')
618 mem_manufs = ['autodetect', 'elpida', 'samsung']
619 if not mem_manuf in mem_manufs:
620 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
621 value = mem_manufs.index(mem_manuf)
622 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glassdf95dd22012-03-13 15:46:16 -0700623 elif param == 'v':
624 value = 31
625 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700626 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700627 value = (spl_load_size + 0xfff) & ~0xfff
628 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
629 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700630 elif param == 'b':
631 # These values come from enum boot_mode in U-Boot's cpu.h
632 if self.spl_source == 'straps':
633 value = 32
634 elif self.spl_source == 'emmc':
635 value = 4
636 elif self.spl_source == 'spi':
637 value = 20
638 elif self.spl_source == 'usb':
639 value = 33
640 else:
641 raise CmdError("Invalid boot source '%s'" % self.spl_source)
642 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700643 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700644 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700645 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700646 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700647 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700648
649 # Put the data into our block.
650 data = data[:pos] + new_data + data[pos + len(new_data):]
651 self._out.Info('BL2 configuration complete')
652 return data
653
Simon Glasse5e8afb2012-05-23 11:19:23 -0700654 def _UpdateChecksum(self, data):
655 """Update the BL2 checksum.
656
657 The checksum is a 4 byte sum of all the bytes in the image before the
658 last 4 bytes (which hold the checksum).
659
660 Args:
661 data: The BL2 data to update.
662
663 Returns:
664 The new contents of the BL2 data, after updating the checksum.
665 """
666 checksum = 0
667 for ch in data[:-4]:
668 checksum += ord(ch)
669 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
670
Simon Glass559b6612012-05-23 13:28:45 -0700671 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700672 """Configure an Exynos BL2 binary for our needs.
673
674 We create a new modified BL2 and return its filename.
675
676 Args:
677 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700678 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700679 orig_bl2: Filename of original BL2 file to modify.
680 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700681 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700682 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700683 data = self._tools.ReadFile(orig_bl2)
684 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700685
686 # Locate the parameter block
687 data = self._tools.ReadFile(bl2)
688 marker = struct.pack('<L', 0xdeadbeef)
689 pos = data.rfind(marker)
690 if not pos:
691 raise CmdError("Could not find machine parameter block in '%s'" %
692 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700693 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700694 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700695 self._tools.WriteFile(bl2, data)
696 return bl2
697
Simon Glass89b86b82011-07-17 23:49:49 -0700698 def _PackOutput(self, msg):
699 """Helper function to write output from PackFirmware (verbose level 2).
700
701 This is passed to PackFirmware for it to use to write output.
702
703 Args:
704 msg: Message to display.
705 """
706 self._out.Notice(msg)
707
Simon Glass439fe7a2012-03-09 16:19:34 -0800708 def _BuildBlob(self, pack, fdt, blob_type):
709 """Build the blob data for a particular blob type.
710
711 Args:
712 blob_type: The type of blob to create data for. Supported types are:
713 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
714 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
715 """
716 if blob_type == 'coreboot':
717 coreboot = self._CreateCorebootStub(self.uboot_fname,
718 self.coreboot_fname, fdt, self.seabios_fname)
719 pack.AddProperty('coreboot', coreboot)
720 pack.AddProperty('image', coreboot)
721 elif blob_type == 'signed':
722 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
723 self.postload_fname)
724 pack.AddProperty('bootstub', bootstub)
725 pack.AddProperty('signed', signed)
726 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700727 elif blob_type == 'exynos-bl1':
728 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassf0cf8b92012-06-21 08:17:30 -0700729 elif blob_type == 'ecbin':
730 pack.AddProperty(blob_type, self.ecbin_fname)
Simon Glass7e199222012-03-13 15:51:18 -0700731 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700732 spl_payload = pack.GetBlobParams(blob_type)
733
734 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
735 # from all flash map files.
736 if not spl_payload:
737 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
738 prop_list = 'boot+dtb'
739
740 # Do this later, when we remove boot+dtb.
741 # raise CmdError("No parameters provided for blob type '%s'" %
742 # blob_type)
743 else:
744 prop_list = spl_payload[0].split(',')
745 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
746 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
747 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700748 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700749 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800750 elif pack.GetProperty(blob_type):
751 pass
752 else:
753 raise CmdError("Unknown blob type '%s' required in flash map" %
754 blob_type)
755
Simon Glass290a1802011-07-17 13:54:32 -0700756 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700757 """Create a full firmware image, along with various by-products.
758
759 This uses the provided u-boot.bin, fdt and bct to create a firmware
760 image containing all the required parts. If the GBB is not supplied
761 then this will just return a signed U-Boot as the image.
762
763 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200764 gbb: Full path to the GBB file, or empty if a GBB is not required.
765 fdt: Fdt object containing required information.
766
767 Returns:
768 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700769
770 Raises:
771 CmdError if a command fails.
772 """
Simon Glass02d124a2012-03-02 14:47:20 -0800773 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700774
Simon Glass439fe7a2012-03-09 16:19:34 -0800775 # Get the flashmap so we know what to build
776 pack = PackFirmware(self._tools, self._out)
777 pack.SelectFdt(fdt)
778
779 # Get all our blobs ready
780 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700781 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700782 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700783
Simon Glassde9c8072012-07-02 22:29:02 -0700784 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
785 if self.kernel_fname:
786 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
787
Simon Glass50f74602012-03-15 21:04:25 -0700788 # Make a copy of the fdt for the bootstub
789 fdt_data = self._tools.ReadFile(fdt.fname)
790 uboot_data = self._tools.ReadFile(self.uboot_fname)
791 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
792 self._tools.WriteFile(uboot_copy, uboot_data)
793
794 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
795 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700796
797 # TODO(sjg@chromium.org): Deprecate this property when all boards
798 # use a comma-separated list for section contents. We will then
799 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700800 pack.AddProperty('boot+dtb', bootstub)
801
Simon Glass439fe7a2012-03-09 16:19:34 -0800802 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700803 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800804 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700805
806 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700807 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800808 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800809 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800810 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700811 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800812 pack.AddProperty('fwid', fwid)
813 pack.AddProperty('gbb', gbb)
814 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700815
816 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700817
818 # Record position and size of all blob members in the FDT
819 pack.UpdateBlobPositions(fdt)
820
Simon Glassc90cf582012-03-13 15:40:47 -0700821 image = os.path.join(self._tools.outdir, 'image.bin')
822 pack.PackImage(self._tools.outdir, image)
823 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700824
Simon Glass439fe7a2012-03-09 16:19:34 -0800825 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700826 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700827 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700828
Simon Glass290a1802011-07-17 13:54:32 -0700829 def SelectFdt(self, fdt_fname):
830 """Select an FDT to control the firmware bundling
831
832 Args:
833 fdt_fname: The filename of the fdt to use.
834
Simon Glassc0f3dc62011-08-09 14:19:05 -0700835 Returns:
836 The Fdt object of the original fdt file, which we will not modify.
837
Simon Glass290a1802011-07-17 13:54:32 -0700838 We make a copy of this which will include any on-the-fly changes we want
839 to make.
840 """
841 self._fdt_fname = fdt_fname
842 self.CheckOptions()
843 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -0800844 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -0700845 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -0700846 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700847
Simon Glassc90cf582012-03-13 15:40:47 -0700848 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -0700849 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -0700850
851 - Checks options, tools, output directory, fdt.
852 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -0700853
854 Args:
Simon Glass56577572011-07-19 11:08:06 +1200855 hardware_id: Hardware ID to use for this board. If None, then the
856 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -0700857 output_fname: Output filename for the image. If this is not None, then
858 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -0700859 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -0700860
861 Returns:
862 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -0700863 """
Simon Glass89b86b82011-07-17 23:49:49 -0700864 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -0700865 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +1200866 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -0700867
868 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -0700869 image, pack = self._CreateImage(gbb, self.fdt)
870 if show_map:
871 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -0700872 if output_fname:
873 shutil.copyfile(image, output_fname)
874 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -0700875 return image, pack.props