blob: 53b76ee359b15639d3a8e5675da8cbb349fc38ab [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
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -05005"""This module builds a firmware image.
Simon Glass89b86b82011-07-17 23:49:49 -07006
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
Gabe Blackcdbdfe12013-02-06 05:37:52 -080020import hashlib
Simon Glass89b86b82011-07-17 23:49:49 -070021import os
22import re
23
Simon Glass89b86b82011-07-17 23:49:49 -070024from fdt import Fdt
25from pack_firmware import PackFirmware
26import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080027import struct
Vadim Bendebury8c35e2e2014-05-06 12:55:50 -070028from flashmaps import default_flashmaps
Simon Glass439fe7a2012-03-09 16:19:34 -080029from tools import CmdError
Vadim Bendeburyb12e3352013-06-08 17:25:19 -070030from exynos import ExynosBl2
Simon Glass89b86b82011-07-17 23:49:49 -070031
32# This data is required by bmpblk_utility. Does it ever change?
33# It was stored with the chromeos-bootimage ebuild, but we want
34# this utility to work outside the chroot.
35yaml_data = '''
36bmpblock: 1.0
37
38images:
39 devmode: DeveloperBmp/DeveloperBmp.bmp
40 recovery: RecoveryBmp/RecoveryBmp.bmp
41 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
42 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
43
44screens:
45 dev_en:
46 - [0, 0, devmode]
47 rec_en:
48 - [0, 0, recovery]
49 yuck_en:
50 - [0, 0, rec_yuck]
51 ins_en:
52 - [0, 0, rec_insert]
53
54localizations:
55 - [ dev_en, rec_en, yuck_en, ins_en ]
56'''
57
Simon Glass4a887b12012-10-23 16:29:03 -070058# Build GBB flags.
59# (src/platform/vboot_reference/firmware/include/gbb_header.h)
60gbb_flag_properties = {
61 'dev-screen-short-delay': 0x00000001,
62 'load-option-roms': 0x00000002,
63 'enable-alternate-os': 0x00000004,
64 'force-dev-switch-on': 0x00000008,
65 'force-dev-boot-usb': 0x00000010,
66 'disable-fw-rollback-check': 0x00000020,
67 'enter-triggers-tonorm': 0x00000040,
68 'force-dev-boot-legacy': 0x00000080,
69}
70
Simon Glass49b026b2013-04-26 16:38:42 -070071# Maps board name to Exynos product number
72type_to_model = {
73 'peach' : '5420',
74 'daisy' : '5250'
75}
76
Simon Glass5076a7f2012-10-23 16:31:54 -070077def ListGoogleBinaryBlockFlags():
78 """Print out a list of GBB flags."""
79 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
80 for name, value in gbb_flag_properties.iteritems():
81 print ' %-30s %02x' % (name, value)
82
Simon Glass89b86b82011-07-17 23:49:49 -070083class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070084 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070085
Simon Glass290a1802011-07-17 13:54:32 -070086 Sequence of events:
87 bundle = Bundle(tools.Tools(), cros_output.Output())
88 bundle.SetDirs(...)
89 bundle.SetFiles(...)
90 bundle.SetOptions(...)
91 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070092 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070093 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070094
Simon Glass290a1802011-07-17 13:54:32 -070095 Public properties:
96 fdt: The fdt object that we use for building our image. This wil be the
97 one specified by the user, except that we might add config options
98 to it. This is set up by SelectFdt() which must be called before
99 bundling starts.
100 uboot_fname: Full filename of the U-Boot binary we use.
101 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -0700102 spl_source: Source device to load U-Boot from, in SPL:
103 straps: Select device according to CPU strap pins
104 spi: Boot from SPI
105 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -0700106
107 Private attributes:
108 _small: True to create a 'small' signed U-Boot, False to produce a
109 full image. The small U-Boot is enough to boot but will not have
110 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700111 """
Simon Glass89b86b82011-07-17 23:49:49 -0700112
Simon Glass290a1802011-07-17 13:54:32 -0700113 def __init__(self, tools, output):
114 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700115
Simon Glass290a1802011-07-17 13:54:32 -0700116 Args:
117 tools: A tools.Tools object to use for external tools.
118 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700119 """
Simon Glass290a1802011-07-17 13:54:32 -0700120 self._tools = tools
121 self._out = output
122
123 # Set up the things we need to know in order to operate.
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500124 self._board = None # Board name, e.g. nyan.
Simon Glass290a1802011-07-17 13:54:32 -0700125 self._fdt_fname = None # Filename of our FDT.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700126 self._force_rw = None
Simon Glass00d027e2013-07-20 14:51:12 -0600127 self._force_efs = None
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700128 self._gbb_flags = None
129 self._keydir = None
130 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700131 self.bct_fname = None # Filename of our BCT file.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700132 self.blobs = {} # Table of (type, filename) of arbitrary blobs
Hung-Te Lin5b649382011-08-03 15:01:16 +0800133 self.bmpblk_fname = None # Filename of our Bitmap Block
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700134 self.coreboot_elf = None
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700135 self.coreboot_fname = None # Filename of our coreboot binary.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700136 self.ecro_fname = None # Filename of EC read-only file
137 self.ecrw_fname = None # Filename of EC file
Randall Spangler7307da92014-07-18 12:47:34 -0700138 self.pdrw_fname = None # Filename of PD file
Simon Glass7e199222012-03-13 15:51:18 -0700139 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
140 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700141 self.fdt = None # Our Fdt object.
142 self.kernel_fname = None
143 self.postload_fname = None
144 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass07267952012-06-08 12:45:13 -0700145 self.skeleton_fname = None # Filename of Coreboot skeleton file
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700146 self.uboot_fname = None # Filename of our U-Boot binary.
Simon Glass290a1802011-07-17 13:54:32 -0700147
148 def SetDirs(self, keydir):
149 """Set up directories required for Bundle.
150
151 Args:
152 keydir: Directory containing keys to use for signing firmware.
153 """
154 self._keydir = keydir
155
Simon Glass6dcc2f22011-07-28 15:26:49 +1200156 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800157 coreboot_elf=None,
Simon Glass07267952012-06-08 12:45:13 -0700158 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Randall Spangler7307da92014-07-18 12:47:34 -0700159 skeleton=None, ecrw=None, ecro=None, pdrw=None,
160 kernel=None, blobs=None):
Simon Glass290a1802011-07-17 13:54:32 -0700161 """Set up files required for Bundle.
162
163 Args:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500164 board: The name of the board to target (e.g. nyan).
Simon Glass290a1802011-07-17 13:54:32 -0700165 uboot: The filename of the u-boot.bin image to use.
166 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800167 bmpblk: The filename of bitmap block file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800168 coreboot: The filename of the coreboot image to use (on x86).
169 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200170 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700171 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700172 exynos_bl1: The filename of the exynos BL1 file
173 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
174 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700175 ecrw: The filename of the EC (Embedded Controller) read-write file.
176 ecro: The filename of the EC (Embedded Controller) read-only file.
Randall Spangler7307da92014-07-18 12:47:34 -0700177 pdrw: The filename of the PD (PD embedded controller) read-write file.
Simon Glassde9c8072012-07-02 22:29:02 -0700178 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800179 blobs: List of (type, filename) of arbitrary blobs.
Simon Glass290a1802011-07-17 13:54:32 -0700180 """
181 self._board = board
182 self.uboot_fname = uboot
183 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800184 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700185 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800186 self.coreboot_elf = coreboot_elf
Simon Glass6dcc2f22011-07-28 15:26:49 +1200187 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700188 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700189 self.exynos_bl1 = exynos_bl1
190 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700191 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700192 self.ecrw_fname = ecrw
193 self.ecro_fname = ecro
Randall Spangler7307da92014-07-18 12:47:34 -0700194 self.pdrw_fname = pdrw
Simon Glassde9c8072012-07-02 22:29:02 -0700195 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800196 self.blobs = dict(blobs or ())
Simon Glass290a1802011-07-17 13:54:32 -0700197
Simon Glass00d027e2013-07-20 14:51:12 -0600198 def SetOptions(self, small, gbb_flags, force_rw=False, force_efs=False):
Simon Glass290a1802011-07-17 13:54:32 -0700199 """Set up options supported by Bundle.
200
201 Args:
202 small: Only create a signed U-Boot - don't produce the full packed
203 firmware image. This is useful for devs who want to replace just the
204 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700205 gbb_flags: Specification for string containing adjustments to make.
206 force_rw: Force firmware into RW mode.
Simon Glass00d027e2013-07-20 14:51:12 -0600207 force_efs: Force firmware to use 'early firmware selection' feature,
208 where RW firmware is selected before SDRAM is initialized.
Simon Glass290a1802011-07-17 13:54:32 -0700209 """
210 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700211 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700212 self._force_rw = force_rw
Simon Glass00d027e2013-07-20 14:51:12 -0600213 self._force_efs = force_efs
Simon Glass290a1802011-07-17 13:54:32 -0700214
Simon Glass22f39fb2013-02-09 13:44:14 -0800215 def _GetBuildRoot(self):
216 """Get the path to this board's 'firmware' directory.
217
218 Returns:
219 Path to firmware directory, with ## representing the path to the
220 chroot.
221 """
Simon Glass290a1802011-07-17 13:54:32 -0700222 if not self._board:
223 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800224 return os.path.join('##', 'build', self._board, 'firmware')
225
226 def _CheckFdtFilename(self, fname):
227 """Check provided FDT filename and return the correct name if needed.
228
229 Where the filename lacks a path, add a default path for this board.
230 Where no FDT filename is provided, select a default one for this board.
231
232 Args:
233 fname: Proposed FDT filename.
234
235 Returns:
236 Selected FDT filename, after validation.
237 """
238 build_root = self._GetBuildRoot()
Julius Wernerb4b14392013-08-09 14:41:40 -0700239 dir_name = os.path.join(build_root, 'dtb')
Simon Glass22f39fb2013-02-09 13:44:14 -0800240 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700241 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700242 base_name = re.sub('_', '-', self._board)
243
244 # In case the name exists with a prefix or suffix, find it.
Julius Wernerb4b14392013-08-09 14:41:40 -0700245 wildcard = os.path.join(dir_name, '*%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700246 found_list = glob.glob(self._tools.Filename(wildcard))
247 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800248 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700249 else:
250 # We didn't find anything definite, so set up our expected name.
Julius Wernerb4b14392013-08-09 14:41:40 -0700251 fname = os.path.join(dir_name, '%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700252
Simon Glass881964d2012-04-04 11:34:09 -0700253 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800254 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700255 if not ext and not os.path.dirname(root):
Julius Wernerb4b14392013-08-09 14:41:40 -0700256 fname = os.path.join(dir_name, '%s.dtb' % root)
Simon Glass22f39fb2013-02-09 13:44:14 -0800257 return fname
258
259 def CheckOptions(self):
260 """Check provided options and select defaults."""
261 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700262
Simon Glass49b026b2013-04-26 16:38:42 -0700263 board_type = self._board.split('_')[0]
264 model = type_to_model.get(board_type)
265
Simon Glass290a1802011-07-17 13:54:32 -0700266 if not self.uboot_fname:
267 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
268 if not self.bct_fname:
269 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700270 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700271 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700272 if model:
273 if not self.exynos_bl1:
Simon Glassd05696e2013-06-13 20:14:00 -0700274 self.exynos_bl1 = os.path.join(build_root, 'u-boot.bl1.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700275 if not self.exynos_bl2:
Julius Wernerb12c0052013-08-14 13:57:04 -0700276 self.exynos_bl2 = os.path.join(build_root, 'u-boot-spl.wrapped.bin')
Simon Glass07267952012-06-08 12:45:13 -0700277 if not self.coreboot_fname:
278 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
279 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700280 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700281 if not self.seabios_fname:
282 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700283 if not self.ecrw_fname:
284 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
Randall Spangler7307da92014-07-18 12:47:34 -0700285 if not self.pdrw_fname:
286 self.pdrw_fname = os.path.join(build_root, 'pd.RW.bin')
Simon Glassbe0bc002012-08-16 12:50:48 -0700287 if not self.ecro_fname:
288 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700289
Simon Glass75759302012-03-15 20:26:53 -0700290 def GetFiles(self):
291 """Get a list of files that we know about.
292
293 This is the opposite of SetFiles except that we may have put in some
294 default names. It returns a dictionary containing the filename for
295 each of a number of pre-defined files.
296
297 Returns:
298 Dictionary, with one entry for each file.
299 """
300 file_list = {
301 'bct' : self.bct_fname,
302 'exynos-bl1' : self.exynos_bl1,
303 'exynos-bl2' : self.exynos_bl2,
304 }
305 return file_list
306
Simon Glass4a887b12012-10-23 16:29:03 -0700307 def DecodeGBBFlagsFromFdt(self):
308 """Get Google Binary Block flags from the FDT.
309
310 These should be in the chromeos-config node, like this:
311
312 chromeos-config {
313 gbb-flag-dev-screen-short-delay;
314 gbb-flag-force-dev-switch-on;
315 gbb-flag-force-dev-boot-usb;
316 gbb-flag-disable-fw-rollback-check;
317 };
318
319 Returns:
320 GBB flags value from FDT.
321 """
322 chromeos_config = self.fdt.GetProps("/chromeos-config")
323 gbb_flags = 0
324 for name in chromeos_config:
325 if name.startswith('gbb-flag-'):
326 flag_value = gbb_flag_properties.get(name[9:])
327 if flag_value:
328 gbb_flags |= flag_value
329 self._out.Notice("FDT: Enabling %s." % name)
330 else:
331 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
332 return gbb_flags
333
Simon Glass157c0662012-10-23 13:52:42 -0700334 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
335 """Decode ajustments to the provided GBB flags.
336
337 We support three options:
338
339 hex value: c2
340 defined value: force-dev-boot-usb,load-option-roms
341 adjust default value: -load-option-roms,+force-dev-boot-usb
342
343 The last option starts from the passed-in GBB flags and adds or removes
344 flags.
345
346 Args:
347 gbb_flags: Base (default) FDT flags.
348 adjustments: String containing adjustments to make.
349
350 Returns:
351 Updated FDT flags.
352 """
353 use_base_value = True
354 if adjustments:
355 try:
356 return int(adjustments, base=16)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700357 except (ValueError, TypeError):
Simon Glass157c0662012-10-23 13:52:42 -0700358 pass
359 for flag in adjustments.split(','):
360 oper = None
361 if flag[0] in ['-', '+']:
362 oper = flag[0]
363 flag = flag[1:]
364 value = gbb_flag_properties.get(flag)
365 if not value:
366 raise ValueError("Invalid GBB flag '%s'" % flag)
367 if oper == '+':
368 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800369 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700370 elif oper == '-':
371 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800372 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700373 else:
374 if use_base_value:
375 gbb_flags = 0
376 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800377 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700378 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800379 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700380
381 return gbb_flags
382
Simon Glass56577572011-07-19 11:08:06 +1200383 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700384 """Create a GBB for the image.
385
Simon Glass56577572011-07-19 11:08:06 +1200386 Args:
387 hardware_id: Hardware ID to use for this board. If None, then the
388 default from the Fdt will be used
389
Simon Glass89b86b82011-07-17 23:49:49 -0700390 Returns:
391 Path of the created GBB file.
Simon Glass89b86b82011-07-17 23:49:49 -0700392 """
Simon Glass56577572011-07-19 11:08:06 +1200393 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800394 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700395 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700396 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700397
Simon Glass4a887b12012-10-23 16:29:03 -0700398 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800399
Simon Glass157c0662012-10-23 13:52:42 -0700400 # Allow command line to override flags
401 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
402
Simon Glass4a887b12012-10-23 16:29:03 -0700403 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700404 self._out.Progress('Creating GBB')
405 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
406 sizes = ['%#x' % size for size in sizes]
407 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700408 keydir = self._tools.Filename(self._keydir)
409 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700410 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200411 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700412 '--rootkey=%s/root_key.vbpubk' % keydir,
413 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700414 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800415 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700416 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700417 cwd=odir)
418 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700419
Simon Glasse13ee2c2011-07-28 08:12:28 +1200420 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700421 """Sign an image so that the Tegra SOC will boot it.
422
423 Args:
424 bct: BCT file to use.
425 bootstub: Boot stub (U-Boot + fdt) file to sign.
426 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700427
428 Returns:
429 filename of signed image.
Simon Glass89b86b82011-07-17 23:49:49 -0700430 """
431 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200432 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700433 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200434 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700435 fd = open(config, 'w')
436 fd.write('Version = 1;\n')
437 fd.write('Redundancy = 1;\n')
438 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700439
440 # TODO(dianders): Right now, we don't have enough space in our flash map
441 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
442 # sure what this does for reliability, but at least things will fit...
443 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
444 if is_nand:
445 fd.write('Bctcopy = 1;\n')
446
Simon Glass89b86b82011-07-17 23:49:49 -0700447 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
448 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700449
Simon Glass89b86b82011-07-17 23:49:49 -0700450 fd.close()
451
452 self._tools.Run('cbootimage', [config, signed])
453 self._tools.OutputSize('BCT', bct)
454 self._tools.OutputSize('Signed image', signed)
455 return signed
456
Doug Anderson86ce5f42011-07-27 10:40:18 -0700457 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700458 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700459
460 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700461 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700462 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700463 """
Simon Glass468d8752012-09-19 16:36:19 -0700464 if bootcmd is not None:
465 if bootcmd == 'none':
466 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800467 self.fdt.PutString('/config', 'bootcmd', bootcmd)
468 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700469 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700470
Simon Glassa4934b72012-05-09 13:35:02 -0700471 def SetNodeEnabled(self, node_name, enabled):
472 """Set whether an node is enabled or disabled.
473
474 This simply sets the 'status' property of a node to "ok", or "disabled".
475
476 The node should either be a full path to the node (like '/uart@10200000')
477 or an alias property.
478
479 Aliases are supported like this:
480
481 aliases {
482 console = "/uart@10200000";
483 };
484
485 pointing to a node:
486
487 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700488 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700489 };
490
491 In this case, this function takes the name of the alias ('console' in
492 this case) and updates the status of the node that is pointed to, to
493 either ok or disabled. If the alias does not exist, a warning is
494 displayed.
495
496 Args:
497 node_name: Name of node (e.g. '/uart@10200000') or alias alias
498 (e.g. 'console') to adjust
499 enabled: True to enable, False to disable
500 """
501 # Look up the alias if this is an alias reference
502 if not node_name.startswith('/'):
503 lookup = self.fdt.GetString('/aliases', node_name, '')
504 if not lookup:
505 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
506 return
507 node_name = lookup
508 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700509 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700510 else:
511 status = 'disabled'
512 self.fdt.PutString(node_name, 'status', status)
513
514 def AddEnableList(self, enable_list):
515 """Process a list of nodes to enable/disable.
516
517 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700518 enable_list: List of (node, value) tuples to add to the fdt. For each
Simon Glassa4934b72012-05-09 13:35:02 -0700519 tuple:
520 node: The fdt node to write to will be <node> or pointed to by
521 /aliases/<node>. We can tell which
522 value: 0 to disable the node, 1 to enable it
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700523
Vadim Bendebury507c0012013-06-09 12:49:25 -0700524 Raises:
525 CmdError if a command fails.
Simon Glassa4934b72012-05-09 13:35:02 -0700526 """
527 if enable_list:
528 for node_name, enabled in enable_list:
529 try:
530 enabled = int(enabled)
531 if enabled not in (0, 1):
532 raise ValueError
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700533 except ValueError:
Simon Glassa4934b72012-05-09 13:35:02 -0700534 raise CmdError("Invalid enable option value '%s' "
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700535 "(should be 0 or 1)" % str(enabled))
Simon Glassa4934b72012-05-09 13:35:02 -0700536 self.SetNodeEnabled(node_name, enabled)
537
Simon Glass290a1802011-07-17 13:54:32 -0700538 def AddConfigList(self, config_list, use_int=False):
539 """Add a list of config items to the fdt.
540
541 Normally these values are written to the fdt as strings, but integers
542 are also supported, in which case the values will be converted to integers
543 (if necessary) before being stored.
544
545 Args:
546 config_list: List of (config, value) tuples to add to the fdt. For each
547 tuple:
548 config: The fdt node to write to will be /config/<config>.
549 value: An integer or string value to write.
550 use_int: True to only write integer values.
551
552 Raises:
553 CmdError: if a value is required to be converted to integer but can't be.
554 """
555 if config_list:
556 for config in config_list:
557 value = config[1]
558 if use_int:
559 try:
560 value = int(value)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700561 except ValueError:
Simon Glass290a1802011-07-17 13:54:32 -0700562 raise CmdError("Cannot convert config option '%s' to integer" %
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700563 str(value))
Simon Glass290a1802011-07-17 13:54:32 -0700564 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800565 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700566 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800567 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700568
Simon Glass7c2d5572011-11-15 14:47:08 -0800569 def DecodeTextBase(self, data):
570 """Look at a U-Boot image and try to decode its TEXT_BASE.
571
572 This works because U-Boot has a header with the value 0x12345678
573 immediately followed by the TEXT_BASE value. We can therefore read this
574 from the image with some certainty. We check only the first 40 words
575 since the header should be within that region.
576
Simon Glass96b50302012-07-20 06:55:28 +0100577 Since upstream Tegra has moved to having a 16KB SPL region at the start,
578 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
579 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
580
Simon Glass7c2d5572011-11-15 14:47:08 -0800581 Args:
582 data: U-Boot binary data
583
584 Returns:
585 Text base (integer) or None if none was found
586 """
587 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100588 for start in (0, 0x4000):
589 for i in range(start, start + 160, 4):
590 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800591
Simon Glass96b50302012-07-20 06:55:28 +0100592 # TODO(sjg): This does not cope with a big-endian target
593 value = struct.unpack('<I', word)[0]
594 if found:
595 return value - start
596 if value == 0x12345678:
597 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800598
599 return None
600
601 def CalcTextBase(self, name, fdt, fname):
602 """Calculate the TEXT_BASE to use for U-Boot.
603
604 Normally this value is in the fdt, so we just read it from there. But as
605 a second check we look at the image itself in case this is different, and
606 switch to that if it is.
607
608 This allows us to flash any U-Boot even if its TEXT_BASE is different.
609 This is particularly useful with upstream U-Boot which uses a different
610 value (which we will move to).
611 """
612 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800613 # The value that comes back from fdt.GetInt is signed, which makes no
614 # sense for an address base. Force it to unsigned.
615 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800616 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100617 text_base_str = '%#x' % text_base if text_base else 'None'
618 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
619 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800620
621 # If they are different, issue a warning and switch over.
622 if text_base and text_base != fdt_text_base:
623 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
624 "fdt value of %x. Using %x" % (text_base, name,
625 fdt_text_base, text_base))
626 fdt_text_base = text_base
627 return fdt_text_base
628
Simon Glass6dcc2f22011-07-28 15:26:49 +1200629 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700630 """Create a boot stub and a signed boot stub.
631
Simon Glass6dcc2f22011-07-28 15:26:49 +1200632 For postload:
633 We add a /config/postload-text-offset entry to the signed bootstub's
634 fdt so that U-Boot can find the postload code.
635
636 The raw (unsigned) bootstub will have a value of -1 for this since we will
637 simply append the postload code to the bootstub and it can find it there.
638 This will be used for RW A/B firmware.
639
640 For the signed case this value will specify where in the flash to find
641 the postload code. This will be used for RO firmware.
642
Simon Glass89b86b82011-07-17 23:49:49 -0700643 Args:
644 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800645 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200646 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700647
648 Returns:
649 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200650 Full path to bootstub (uboot + fdt(-1) + postload).
651 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700652
653 Raises:
654 CmdError if a command fails.
655 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200656 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800657 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700658 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200659
660 # Make a copy of the fdt for the bootstub
661 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700662 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff)
Simon Glass290a1802011-07-17 13:54:32 -0700663 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200664
Simon Glass89b86b82011-07-17 23:49:49 -0700665 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700666 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
667 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700668 self._tools.OutputSize('Combined binary', bootstub)
669
Simon Glasse13ee2c2011-07-28 08:12:28 +1200670 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700671 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700672 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200673 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200674
675 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
676 data = self._tools.ReadFile(signed)
677
678 if postload:
679 # We must add postload to the bootstub since A and B will need to
680 # be able to find it without the /config/postload-text-offset mechanism.
681 bs_data = self._tools.ReadFile(bootstub)
682 bs_data += self._tools.ReadFile(postload)
683 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
684 self._tools.WriteFile(bootstub, bs_data)
685 self._tools.OutputSize('Combined binary with postload', bootstub)
686
687 # Now that we know the file size, adjust the fdt and re-sign
688 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800689 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200690 fdt_data = self._tools.ReadFile(fdt.fname)
691 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
692 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
693 postload_bootstub, text_base)
694 if len(data) != os.path.getsize(signed):
695 raise CmdError('Signed file size changed from %d to %d after updating '
696 'fdt' % (len(data), os.path.getsize(signed)))
697
698 # Re-read the signed image, and add the post-load binary.
699 data = self._tools.ReadFile(signed)
700 data += self._tools.ReadFile(postload)
701 self._tools.OutputSize('Post-load binary', postload)
702
703 self._tools.WriteFile(signed_postload, data)
704 self._tools.OutputSize('Final bootstub with postload', signed_postload)
705
706 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700707
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700708 def _CreateCorebootStub(self, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700709 """Create a coreboot boot stub.
710
711 Args:
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700712 coreboot: Path to coreboot.rom
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700713
714 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100715 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700716 """
717 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700718 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100719
720 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700721 return bootstub
722
Simon Glass7e199222012-03-13 15:51:18 -0700723
Simon Glass89b86b82011-07-17 23:49:49 -0700724 def _PackOutput(self, msg):
725 """Helper function to write output from PackFirmware (verbose level 2).
726
727 This is passed to PackFirmware for it to use to write output.
728
729 Args:
730 msg: Message to display.
731 """
732 self._out.Notice(msg)
733
Simon Glass439fe7a2012-03-09 16:19:34 -0800734 def _BuildBlob(self, pack, fdt, blob_type):
735 """Build the blob data for a particular blob type.
736
737 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700738 pack: a PackFirmware object describing the firmware image to build.
739 fdt: an fdt object including image layout information
Simon Glass439fe7a2012-03-09 16:19:34 -0800740 blob_type: The type of blob to create data for. Supported types are:
741 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
742 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
Vadim Bendebury507c0012013-06-09 12:49:25 -0700743
744 Raises:
745 CmdError if a command fails.
Simon Glass439fe7a2012-03-09 16:19:34 -0800746 """
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700747 # stupid pylint insists that sha256 is not in hashlib.
748 # pylint: disable=E1101
Simon Glass439fe7a2012-03-09 16:19:34 -0800749 if blob_type == 'coreboot':
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700750 coreboot = self._CreateCorebootStub(self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800751 pack.AddProperty('coreboot', coreboot)
752 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700753 elif blob_type == 'legacy':
754 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800755 elif blob_type == 'signed':
756 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
757 self.postload_fname)
758 pack.AddProperty('bootstub', bootstub)
759 pack.AddProperty('signed', signed)
760 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700761 elif blob_type == 'exynos-bl1':
762 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700763
764 # TODO(sjg@chromium.org): Deprecate ecbin
765 elif blob_type in ['ecrw', 'ecbin']:
766 pack.AddProperty('ecrw', self.ecrw_fname)
767 pack.AddProperty('ecbin', self.ecrw_fname)
Randall Spangler7307da92014-07-18 12:47:34 -0700768 elif blob_type == 'pdrw':
769 pack.AddProperty('pdrw', self.pdrw_fname)
Gabe Blackcdbdfe12013-02-06 05:37:52 -0800770 elif blob_type == 'ecrwhash':
771 ec_hash_file = os.path.join(self._tools.outdir, 'ec_hash.bin')
772 ecrw = self._tools.ReadFile(self.ecrw_fname)
773 hasher = hashlib.sha256()
774 hasher.update(ecrw)
775 self._tools.WriteFile(ec_hash_file, hasher.digest())
776 pack.AddProperty(blob_type, ec_hash_file)
Randall Spangler7307da92014-07-18 12:47:34 -0700777 elif blob_type == 'pdrwhash':
778 pd_hash_file = os.path.join(self._tools.outdir, 'pd_hash.bin')
779 pdrw = self._tools.ReadFile(self.pdrw_fname)
780 hasher = hashlib.sha256()
781 hasher.update(pdrw)
782 self._tools.WriteFile(pd_hash_file, hasher.digest())
783 pack.AddProperty(blob_type, pd_hash_file)
Simon Glassbe0bc002012-08-16 12:50:48 -0700784 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700785 # crosbug.com/p/13143
786 # We cannot have an fmap in the EC image since there can be only one,
787 # which is the main fmap describing the whole image.
788 # Ultimately the EC will not have an fmap, since with software sync
789 # there is no flashrom involvement in updating the EC flash, and thus
790 # no need for the fmap.
791 # For now, mangle the fmap name to avoid problems.
792 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
793 data = self._tools.ReadFile(self.ecro_fname)
794 data = re.sub('__FMAP__', '__fMAP__', data)
795 self._tools.WriteFile(updated_ecro, data)
796 pack.AddProperty(blob_type, updated_ecro)
Simon Glass0a047bc2013-07-19 15:44:43 -0600797 elif blob_type.startswith('exynos-bl2'):
798 # We need to configure this per node, so do it later
799 pass
Simon Glass439fe7a2012-03-09 16:19:34 -0800800 elif pack.GetProperty(blob_type):
801 pass
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800802 elif blob_type in self.blobs:
803 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -0800804 else:
805 raise CmdError("Unknown blob type '%s' required in flash map" %
806 blob_type)
807
Simon Glass290a1802011-07-17 13:54:32 -0700808 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700809 """Create a full firmware image, along with various by-products.
810
811 This uses the provided u-boot.bin, fdt and bct to create a firmware
812 image containing all the required parts. If the GBB is not supplied
813 then this will just return a signed U-Boot as the image.
814
815 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700816 gbb: a string, full path to the GBB file, or empty if a GBB is not
817 required.
818 fdt: an fdt object containing required information.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200819
820 Returns:
821 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700822 """
Simon Glass02d124a2012-03-02 14:47:20 -0800823 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700824
Simon Glass439fe7a2012-03-09 16:19:34 -0800825 pack = PackFirmware(self._tools, self._out)
Simon Glassb8c6d952012-12-01 06:14:35 -0800826 if self._force_rw:
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700827 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
828 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
Simon Glass00d027e2013-07-20 14:51:12 -0600829 if self._force_efs:
830 fdt.PutInteger('/chromeos-config', 'early-firmware-selection', 1)
Simon Glassa7e66e22013-07-23 07:21:16 -0600831 pack.use_efs = fdt.GetInt('/chromeos-config', 'early-firmware-selection',
832 0)
Simon Glassb8c6d952012-12-01 06:14:35 -0800833
Simon Glass4f318912013-07-20 16:13:06 -0600834 pack.SelectFdt(fdt, self._board)
Simon Glass439fe7a2012-03-09 16:19:34 -0800835
836 # Get all our blobs ready
837 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -0800838 if self.skeleton_fname:
839 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700840 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700841
Simon Glassde9c8072012-07-02 22:29:02 -0700842 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
843 if self.kernel_fname:
844 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
845
Simon Glass439fe7a2012-03-09 16:19:34 -0800846 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100847 blob_list = pack.GetBlobList()
848 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700849 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800850 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700851
Simon Glass7306b902012-12-17 15:06:21 -0800852 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -0700853 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700854 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800855 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800856 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800857 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700858 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800859 pack.AddProperty('fwid', fwid)
860 pack.AddProperty('gbb', gbb)
861 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700862
Simon Glass0a047bc2013-07-19 15:44:43 -0600863 # Some blobs need to be configured according to the node they are in.
Simon Glass4c24f662013-07-19 15:53:02 -0600864 todo = pack.GetMissingBlobs()
865 for blob in todo:
Simon Glass0a047bc2013-07-19 15:44:43 -0600866 if blob.key.startswith('exynos-bl2'):
867 bl2 = ExynosBl2(self._tools, self._out)
868 pack.AddProperty(blob.key, bl2.MakeSpl(pack, fdt, blob,
869 self.exynos_bl2))
870
Simon Glassc90cf582012-03-13 15:40:47 -0700871 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700872
873 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -0800874 pack.UpdateBlobPositionsAndHashes(fdt)
Simon Glass8884b982012-06-21 12:41:41 -0700875
Simon Glass4c24f662013-07-19 15:53:02 -0600876 # Recalculate the Exynos BL2, since it may have a hash. The call to
877 # UpdateBlobPositionsAndHashes() may have updated the hash-target so we
878 # need to recalculate the hash.
879 for blob in todo:
880 if blob.key.startswith('exynos-bl2'):
881 bl2 = ExynosBl2(self._tools, self._out)
882 pack.AddProperty(blob.key, bl2.MakeSpl(pack, fdt, blob,
883 self.exynos_bl2))
884
Simon Glass6207efe2012-12-17 15:04:36 -0800885 # Make a copy of the fdt for the bootstub
886 fdt_data = self._tools.ReadFile(fdt.fname)
887 uboot_data = self._tools.ReadFile(self.uboot_fname)
888 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
889 self._tools.WriteFile(uboot_copy, uboot_data)
890
891 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
892 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
893
Simon Glassa10282a2013-01-08 17:06:41 -0800894 # Fix up the coreboot image here, since we can't do this until we have
895 # a final device tree binary.
Simon Glasscbc83552012-07-23 15:26:22 +0100896 if 'coreboot' in blob_list:
897 bootstub = pack.GetProperty('coreboot')
898 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -0800899 if self.coreboot_elf:
900 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
901 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
902 else:
Simon Glass0a7cf112013-05-21 23:08:21 -0700903 text_base = 0x1110000
904
905 # This is the the 'movw $GD_FLG_COLD_BOOT, %bx' instruction
906 # 1110015: 66 bb 00 01 mov $0x100,%bx
907 marker = struct.pack('<L', 0x0100bb66)
908 pos = uboot_data.find(marker)
909 if pos == -1 or pos > 0x100:
910 raise ValueError('Cannot find U-Boot cold boot entry point')
911 entry = text_base + pos
912 self._out.Notice('U-Boot entry point %#08x' % entry)
Simon Glassa10282a2013-01-08 17:06:41 -0800913 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
914 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
Simon Glass0a7cf112013-05-21 23:08:21 -0700915 '-l', '%#x' % text_base, '-e', '%#x' % entry])
Stefan Reinauer1502ea62012-11-01 10:15:38 -0700916 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
917 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -0800918 data = self._tools.ReadFile(bootstub)
919 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
920 self._tools.WriteFile(bootstub_copy, data)
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700921
Aaron Durbinab505932014-07-16 15:58:40 -0500922 if self._board in ('storm', 'rush', 'rush_ryu', ):
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700923 # This is a hack, as storm does not fall into any of the two
924 # categories of images covered by the [-0x100000:] range. Not applying
925 # this to all targets yet, as it is not clear that they all would fit
926 # this scheme where the /flash/ro-boot node has the 'reg' property
927 # showing the location of the ro coreboot part in the image.
928 #
929 # The upcoming refactor of this tool will have to take care of this in
930 # a more consistent way.
931 fdt_ro_boot = fdt.GetProp('/flash/ro-boot', 'reg')
932 rom_range = [int(x) for x in fdt_ro_boot.split()]
933 self._tools.WriteFile(bootstub, data[rom_range[0]:rom_range[1]])
934 else:
935 self._tools.WriteFile(bootstub, data[-0x100000:])
Simon Glasscbc83552012-07-23 15:26:22 +0100936
Simon Glass208ad952013-02-10 11:16:46 -0800937 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -0700938 image = os.path.join(self._tools.outdir, 'image.bin')
939 pack.PackImage(self._tools.outdir, image)
940 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700941
Simon Glass439fe7a2012-03-09 16:19:34 -0800942 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700943 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700944 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700945
Simon Glassdedda6f2013-02-09 13:44:14 -0800946 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -0700947 """Select an FDT to control the firmware bundling
948
Simon Glassdedda6f2013-02-09 13:44:14 -0800949 We make a copy of this which will include any on-the-fly changes we want
950 to make.
951
Simon Glass290a1802011-07-17 13:54:32 -0700952 Args:
953 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -0800954 use_defaults: True to use a default FDT name if available, and to add
955 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -0700956
Simon Glassc0f3dc62011-08-09 14:19:05 -0700957 Returns:
958 The Fdt object of the original fdt file, which we will not modify.
959
Simon Glassdedda6f2013-02-09 13:44:14 -0800960 Raises:
961 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
962 False).
Simon Glass290a1802011-07-17 13:54:32 -0700963 """
Simon Glassdedda6f2013-02-09 13:44:14 -0800964 if use_defaults:
965 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -0800966 if not fdt_fname:
967 raise ValueError('Please provide an FDT filename')
968 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -0700969 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -0800970
971 # For upstream, select the correct architecture .dtsi manually.
972 if self._board == 'link' or 'x86' in self._board:
973 arch_dts = 'coreboot.dtsi'
974 elif self._board == 'daisy':
975 arch_dts = 'exynos5250.dtsi'
976 else:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500977 arch_dts = 'tegra124.dtsi'
Simon Glassc3e42c32012-12-17 15:00:04 -0800978
979 fdt.Compile(arch_dts)
Simon Glasse53abbc2013-08-21 22:29:55 -0600980 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
981
982 # Get the flashmap so we know what to build. For board variants use the
983 # main board name as the key (drop the _<variant> suffix).
984 default_flashmap = default_flashmaps.get(self._board.split('_')[0], [])
985
986 if not fdt.GetProp('/flash', 'reg', ''):
987 fdt.InsertNodes(default_flashmap)
988
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500989 # Only check for /iram and /config nodes for boards that require it.
990 if self._board in ('daisy', 'peach'):
991 # Insert default values for any essential properties that are missing.
992 # This should only happen for upstream U-Boot, until our changes are
993 # upstreamed.
994 if not fdt.GetProp('/iram', 'reg', ''):
995 self._out.Warning('Cannot find /iram, using default')
996 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/iram'])
Simon Glasse53abbc2013-08-21 22:29:55 -0600997
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500998 # Sadly the pit branch has an invalid /memory node. Work around it
999 # for now. crosbug.com/p/22184
1000 if (not fdt.GetProp('/memory', 'reg', '') or
1001 fdt.GetIntList('/memory', 'reg')[0] == 0):
1002 self._out.Warning('Cannot find /memory, using default')
1003 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/memory'])
Simon Glasse53abbc2013-08-21 22:29:55 -06001004
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -05001005 if not fdt.GetProp('/config', 'samsung,bl1-offset', ''):
1006 self._out.Warning('Missing properties in /config, using defaults')
1007 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/config'])
Simon Glasse53abbc2013-08-21 22:29:55 -06001008
Simon Glass7df773b2013-08-25 18:02:29 -06001009 # Remember our board type.
1010 fdt.PutString('/chromeos-config', 'board', self._board)
1011
Simon Glasse53abbc2013-08-21 22:29:55 -06001012 self.fdt = fdt
1013 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001014
Simon Glassc90cf582012-03-13 15:40:47 -07001015 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001016 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001017
1018 - Checks options, tools, output directory, fdt.
1019 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001020
1021 Args:
Simon Glass56577572011-07-19 11:08:06 +12001022 hardware_id: Hardware ID to use for this board. If None, then the
1023 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001024 output_fname: Output filename for the image. If this is not None, then
1025 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001026 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001027
1028 Returns:
1029 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001030 """
Vadim Bendebury5baeec12013-04-02 13:01:22 -07001031 if self._small or self.fdt.GetProp('/config', 'nogbb', 'any') != 'any':
1032 gbb = '' # Building a small image or `nogbb' is requested in device tree.
1033 else:
Simon Glass56577572011-07-19 11:08:06 +12001034 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001035
1036 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001037 image, pack = self._CreateImage(gbb, self.fdt)
1038 if show_map:
1039 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001040 if output_fname:
1041 shutil.copyfile(image, output_fname)
1042 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001043 return image, pack.props