blob: c4f5ca15a25a935943ad4d086302aa7e2d716ae2 [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
Simon Glass89b86b82011-07-17 23:49:49 -070020import os
21import re
22
Simon Glass89b86b82011-07-17 23:49:49 -070023from fdt import Fdt
24from pack_firmware import PackFirmware
25import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080026import struct
Patrick Georgicebb5a22016-08-15 19:07:02 +020027import fmap
Simon Glass439fe7a2012-03-09 16:19:34 -080028from tools import CmdError
Vadim Bendeburyb12e3352013-06-08 17:25:19 -070029from exynos import ExynosBl2
Simon Glass89b86b82011-07-17 23:49:49 -070030
Simon Glass4a887b12012-10-23 16:29:03 -070031# Build GBB flags.
32# (src/platform/vboot_reference/firmware/include/gbb_header.h)
33gbb_flag_properties = {
34 'dev-screen-short-delay': 0x00000001,
35 'load-option-roms': 0x00000002,
36 'enable-alternate-os': 0x00000004,
37 'force-dev-switch-on': 0x00000008,
38 'force-dev-boot-usb': 0x00000010,
39 'disable-fw-rollback-check': 0x00000020,
40 'enter-triggers-tonorm': 0x00000040,
41 'force-dev-boot-legacy': 0x00000080,
Shawn Nematbakhsh07c19882014-08-19 10:21:59 -070042 'faft-key-overide': 0x00000100,
43 'disable-ec-software-sync': 0x00000200,
44 'default-dev-boot-legacy': 0x00000400,
45 'disable-pd-software-sync': 0x00000800,
Furquan Shaikhd4eac3b2015-05-15 18:05:09 -070046 'force-dev-boot-fastboot-full-cap': 0x00002000,
Mary Ruthvena759c322015-11-16 08:23:26 -080047 'enable-serial': 0x00004000,
Simon Glass4a887b12012-10-23 16:29:03 -070048}
49
Simon Glass49b026b2013-04-26 16:38:42 -070050# Maps board name to Exynos product number
51type_to_model = {
52 'peach' : '5420',
53 'daisy' : '5250'
54}
55
Simon Glass5076a7f2012-10-23 16:31:54 -070056def ListGoogleBinaryBlockFlags():
57 """Print out a list of GBB flags."""
58 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
59 for name, value in gbb_flag_properties.iteritems():
60 print ' %-30s %02x' % (name, value)
61
Aaron Durbin41c85b62015-12-17 17:40:29 -060062class BlobDeferral(Exception):
63 """An error indicating deferal of blob generation."""
64 pass
65
Simon Glass89b86b82011-07-17 23:49:49 -070066class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070067 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070068
Simon Glass290a1802011-07-17 13:54:32 -070069 Sequence of events:
70 bundle = Bundle(tools.Tools(), cros_output.Output())
71 bundle.SetDirs(...)
72 bundle.SetFiles(...)
73 bundle.SetOptions(...)
74 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070075 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070076 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070077
Simon Glass290a1802011-07-17 13:54:32 -070078 Public properties:
79 fdt: The fdt object that we use for building our image. This wil be the
80 one specified by the user, except that we might add config options
81 to it. This is set up by SelectFdt() which must be called before
82 bundling starts.
83 uboot_fname: Full filename of the U-Boot binary we use.
84 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -070085 spl_source: Source device to load U-Boot from, in SPL:
86 straps: Select device according to CPU strap pins
87 spi: Boot from SPI
88 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -070089
90 Private attributes:
91 _small: True to create a 'small' signed U-Boot, False to produce a
92 full image. The small U-Boot is enough to boot but will not have
93 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -070094 """
Simon Glass89b86b82011-07-17 23:49:49 -070095
Simon Glass290a1802011-07-17 13:54:32 -070096 def __init__(self, tools, output):
97 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -070098
Simon Glass290a1802011-07-17 13:54:32 -070099 Args:
100 tools: A tools.Tools object to use for external tools.
101 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700102 """
Simon Glass290a1802011-07-17 13:54:32 -0700103 self._tools = tools
104 self._out = output
105
106 # Set up the things we need to know in order to operate.
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500107 self._board = None # Board name, e.g. nyan.
Simon Glass290a1802011-07-17 13:54:32 -0700108 self._fdt_fname = None # Filename of our FDT.
Simon Glass00d027e2013-07-20 14:51:12 -0600109 self._force_efs = None
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700110 self._gbb_flags = None
111 self._keydir = None
112 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700113 self.bct_fname = None # Filename of our BCT file.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700114 self.blobs = {} # Table of (type, filename) of arbitrary blobs
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700115 self.coreboot_elf = None
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700116 self.coreboot_fname = None # Filename of our coreboot binary.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700117 self.ecro_fname = None # Filename of EC read-only file
118 self.ecrw_fname = None # Filename of EC file
Randall Spangler7307da92014-07-18 12:47:34 -0700119 self.pdrw_fname = None # Filename of PD file
Simon Glass7e199222012-03-13 15:51:18 -0700120 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
121 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700122 self.fdt = None # Our Fdt object.
123 self.kernel_fname = None
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700124 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass07267952012-06-08 12:45:13 -0700125 self.skeleton_fname = None # Filename of Coreboot skeleton file
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700126 self.uboot_fname = None # Filename of our U-Boot binary.
Simon Glass290a1802011-07-17 13:54:32 -0700127
128 def SetDirs(self, keydir):
129 """Set up directories required for Bundle.
130
131 Args:
132 keydir: Directory containing keys to use for signing firmware.
133 """
134 self._keydir = keydir
135
Patrick Georgi48030572016-09-09 22:55:46 +0200136 def SetFiles(self, board, bct, uboot=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800137 coreboot_elf=None,
Simon Glass942bedb2016-05-14 16:19:59 -0600138 seabios=None, exynos_bl1=None, exynos_bl2=None,
Randall Spangler7307da92014-07-18 12:47:34 -0700139 skeleton=None, ecrw=None, ecro=None, pdrw=None,
Patrick Georgi48030572016-09-09 22:55:46 +0200140 kernel=None, blobs=None, cbfs_files=None,
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600141 rocbfs_files=None):
Simon Glass290a1802011-07-17 13:54:32 -0700142 """Set up files required for Bundle.
143
144 Args:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500145 board: The name of the board to target (e.g. nyan).
Simon Glass290a1802011-07-17 13:54:32 -0700146 uboot: The filename of the u-boot.bin image to use.
147 bct: The filename of the binary BCT file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800148 coreboot: The filename of the coreboot image to use (on x86).
149 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Vincent Palatinf7286772011-10-12 14:31:53 -0700150 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700151 exynos_bl1: The filename of the exynos BL1 file
152 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
153 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700154 ecrw: The filename of the EC (Embedded Controller) read-write file.
155 ecro: The filename of the EC (Embedded Controller) read-only file.
Randall Spangler7307da92014-07-18 12:47:34 -0700156 pdrw: The filename of the PD (PD embedded controller) read-write file.
Simon Glassde9c8072012-07-02 22:29:02 -0700157 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800158 blobs: List of (type, filename) of arbitrary blobs.
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600159 cbfs_files: Root directory of files to be stored in RO and RW CBFS
160 rocbfs_files: Root directory of files to be stored in RO CBFS
Simon Glass290a1802011-07-17 13:54:32 -0700161 """
162 self._board = board
163 self.uboot_fname = uboot
164 self.bct_fname = bct
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700165 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800166 self.coreboot_elf = coreboot_elf
Vincent Palatinf7286772011-10-12 14:31:53 -0700167 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700168 self.exynos_bl1 = exynos_bl1
169 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700170 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700171 self.ecrw_fname = ecrw
172 self.ecro_fname = ecro
Randall Spangler7307da92014-07-18 12:47:34 -0700173 self.pdrw_fname = pdrw
Simon Glassde9c8072012-07-02 22:29:02 -0700174 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800175 self.blobs = dict(blobs or ())
Daisuke Nojiri69662892015-09-25 15:24:04 -0700176 self.cbfs_files = cbfs_files
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600177 self.rocbfs_files = rocbfs_files
Simon Glass290a1802011-07-17 13:54:32 -0700178
Patrick Georgi450204a2016-08-15 19:13:29 +0200179 def SetOptions(self, small, gbb_flags, force_efs=False):
Simon Glass290a1802011-07-17 13:54:32 -0700180 """Set up options supported by Bundle.
181
182 Args:
183 small: Only create a signed U-Boot - don't produce the full packed
184 firmware image. This is useful for devs who want to replace just the
185 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700186 gbb_flags: Specification for string containing adjustments to make.
Simon Glass00d027e2013-07-20 14:51:12 -0600187 force_efs: Force firmware to use 'early firmware selection' feature,
188 where RW firmware is selected before SDRAM is initialized.
Simon Glass290a1802011-07-17 13:54:32 -0700189 """
190 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700191 self._gbb_flags = gbb_flags
Simon Glass00d027e2013-07-20 14:51:12 -0600192 self._force_efs = force_efs
Simon Glass290a1802011-07-17 13:54:32 -0700193
Simon Glass22f39fb2013-02-09 13:44:14 -0800194 def _GetBuildRoot(self):
195 """Get the path to this board's 'firmware' directory.
196
197 Returns:
198 Path to firmware directory, with ## representing the path to the
199 chroot.
200 """
Simon Glass290a1802011-07-17 13:54:32 -0700201 if not self._board:
202 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800203 return os.path.join('##', 'build', self._board, 'firmware')
204
205 def _CheckFdtFilename(self, fname):
206 """Check provided FDT filename and return the correct name if needed.
207
208 Where the filename lacks a path, add a default path for this board.
209 Where no FDT filename is provided, select a default one for this board.
210
211 Args:
212 fname: Proposed FDT filename.
213
214 Returns:
215 Selected FDT filename, after validation.
216 """
217 build_root = self._GetBuildRoot()
Julius Wernerb4b14392013-08-09 14:41:40 -0700218 dir_name = os.path.join(build_root, 'dtb')
Simon Glass22f39fb2013-02-09 13:44:14 -0800219 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700220 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700221 base_name = re.sub('_', '-', self._board)
222
223 # In case the name exists with a prefix or suffix, find it.
Julius Wernerb4b14392013-08-09 14:41:40 -0700224 wildcard = os.path.join(dir_name, '*%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700225 found_list = glob.glob(self._tools.Filename(wildcard))
226 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800227 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700228 else:
229 # We didn't find anything definite, so set up our expected name.
Julius Wernerb4b14392013-08-09 14:41:40 -0700230 fname = os.path.join(dir_name, '%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700231
Simon Glass881964d2012-04-04 11:34:09 -0700232 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800233 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700234 if not ext and not os.path.dirname(root):
Julius Wernerb4b14392013-08-09 14:41:40 -0700235 fname = os.path.join(dir_name, '%s.dtb' % root)
Simon Glass22f39fb2013-02-09 13:44:14 -0800236 return fname
237
238 def CheckOptions(self):
239 """Check provided options and select defaults."""
240 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700241
Simon Glass49b026b2013-04-26 16:38:42 -0700242 board_type = self._board.split('_')[0]
243 model = type_to_model.get(board_type)
244
Simon Glass290a1802011-07-17 13:54:32 -0700245 if not self.uboot_fname:
246 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
247 if not self.bct_fname:
248 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass49b026b2013-04-26 16:38:42 -0700249 if model:
250 if not self.exynos_bl1:
Simon Glassd05696e2013-06-13 20:14:00 -0700251 self.exynos_bl1 = os.path.join(build_root, 'u-boot.bl1.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700252 if not self.exynos_bl2:
Julius Wernerb12c0052013-08-14 13:57:04 -0700253 self.exynos_bl2 = os.path.join(build_root, 'u-boot-spl.wrapped.bin')
Simon Glass07267952012-06-08 12:45:13 -0700254 if not self.coreboot_fname:
255 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
256 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700257 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Simon Glassbe0bc002012-08-16 12:50:48 -0700258 if not self.ecrw_fname:
259 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
Randall Spangler7307da92014-07-18 12:47:34 -0700260 if not self.pdrw_fname:
261 self.pdrw_fname = os.path.join(build_root, 'pd.RW.bin')
Simon Glassbe0bc002012-08-16 12:50:48 -0700262 if not self.ecro_fname:
263 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700264
Simon Glass75759302012-03-15 20:26:53 -0700265 def GetFiles(self):
266 """Get a list of files that we know about.
267
268 This is the opposite of SetFiles except that we may have put in some
269 default names. It returns a dictionary containing the filename for
270 each of a number of pre-defined files.
271
272 Returns:
273 Dictionary, with one entry for each file.
274 """
275 file_list = {
276 'bct' : self.bct_fname,
277 'exynos-bl1' : self.exynos_bl1,
278 'exynos-bl2' : self.exynos_bl2,
279 }
280 return file_list
281
Simon Glass4a887b12012-10-23 16:29:03 -0700282 def DecodeGBBFlagsFromFdt(self):
283 """Get Google Binary Block flags from the FDT.
284
285 These should be in the chromeos-config node, like this:
286
287 chromeos-config {
288 gbb-flag-dev-screen-short-delay;
289 gbb-flag-force-dev-switch-on;
290 gbb-flag-force-dev-boot-usb;
291 gbb-flag-disable-fw-rollback-check;
292 };
293
294 Returns:
295 GBB flags value from FDT.
296 """
297 chromeos_config = self.fdt.GetProps("/chromeos-config")
298 gbb_flags = 0
299 for name in chromeos_config:
300 if name.startswith('gbb-flag-'):
301 flag_value = gbb_flag_properties.get(name[9:])
302 if flag_value:
303 gbb_flags |= flag_value
304 self._out.Notice("FDT: Enabling %s." % name)
305 else:
306 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
307 return gbb_flags
308
Simon Glass157c0662012-10-23 13:52:42 -0700309 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
310 """Decode ajustments to the provided GBB flags.
311
312 We support three options:
313
314 hex value: c2
315 defined value: force-dev-boot-usb,load-option-roms
316 adjust default value: -load-option-roms,+force-dev-boot-usb
317
318 The last option starts from the passed-in GBB flags and adds or removes
319 flags.
320
321 Args:
322 gbb_flags: Base (default) FDT flags.
323 adjustments: String containing adjustments to make.
324
325 Returns:
326 Updated FDT flags.
327 """
328 use_base_value = True
329 if adjustments:
330 try:
331 return int(adjustments, base=16)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700332 except (ValueError, TypeError):
Simon Glass157c0662012-10-23 13:52:42 -0700333 pass
334 for flag in adjustments.split(','):
335 oper = None
336 if flag[0] in ['-', '+']:
337 oper = flag[0]
338 flag = flag[1:]
339 value = gbb_flag_properties.get(flag)
340 if not value:
341 raise ValueError("Invalid GBB flag '%s'" % flag)
342 if oper == '+':
343 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800344 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700345 elif oper == '-':
346 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800347 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700348 else:
349 if use_base_value:
350 gbb_flags = 0
351 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800352 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700353 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800354 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700355
356 return gbb_flags
357
Simon Glass56577572011-07-19 11:08:06 +1200358 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700359 """Create a GBB for the image.
360
Simon Glass56577572011-07-19 11:08:06 +1200361 Args:
362 hardware_id: Hardware ID to use for this board. If None, then the
363 default from the Fdt will be used
364
Simon Glass89b86b82011-07-17 23:49:49 -0700365 Returns:
366 Path of the created GBB file.
Simon Glass89b86b82011-07-17 23:49:49 -0700367 """
Simon Glass56577572011-07-19 11:08:06 +1200368 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800369 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700370 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700371 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700372
Simon Glass4a887b12012-10-23 16:29:03 -0700373 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800374
Simon Glass157c0662012-10-23 13:52:42 -0700375 # Allow command line to override flags
376 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
377
Simon Glass4a887b12012-10-23 16:29:03 -0700378 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700379 self._out.Progress('Creating GBB')
Patrick Georgi48030572016-09-09 22:55:46 +0200380 sizes = [0x100, 0x1000, 0, 0x1000]
Simon Glass89b86b82011-07-17 23:49:49 -0700381 sizes = ['%#x' % size for size in sizes]
382 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700383 keydir = self._tools.Filename(self._keydir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800384
385 gbb_set_command = ['-s',
386 '--hwid=%s' % hardware_id,
387 '--rootkey=%s/root_key.vbpubk' % keydir,
388 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
389 '--flags=%d' % gbb_flags,
390 gbb]
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800391
Simon Glass290a1802011-07-17 13:54:32 -0700392 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800393 self._tools.Run('gbb_utility', gbb_set_command, cwd=odir)
Simon Glass290a1802011-07-17 13:54:32 -0700394 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700395
Simon Glasse13ee2c2011-07-28 08:12:28 +1200396 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700397 """Sign an image so that the Tegra SOC will boot it.
398
399 Args:
400 bct: BCT file to use.
401 bootstub: Boot stub (U-Boot + fdt) file to sign.
402 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700403
404 Returns:
405 filename of signed image.
Simon Glass89b86b82011-07-17 23:49:49 -0700406 """
407 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200408 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700409 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200410 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700411 fd = open(config, 'w')
412 fd.write('Version = 1;\n')
413 fd.write('Redundancy = 1;\n')
414 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700415
416 # TODO(dianders): Right now, we don't have enough space in our flash map
417 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
418 # sure what this does for reliability, but at least things will fit...
419 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
420 if is_nand:
421 fd.write('Bctcopy = 1;\n')
422
Simon Glass89b86b82011-07-17 23:49:49 -0700423 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
424 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700425
Simon Glass89b86b82011-07-17 23:49:49 -0700426 fd.close()
427
428 self._tools.Run('cbootimage', [config, signed])
429 self._tools.OutputSize('BCT', bct)
430 self._tools.OutputSize('Signed image', signed)
431 return signed
432
Doug Anderson86ce5f42011-07-27 10:40:18 -0700433 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700434 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700435
436 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700437 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700438 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700439 """
Simon Glass468d8752012-09-19 16:36:19 -0700440 if bootcmd is not None:
441 if bootcmd == 'none':
442 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800443 self.fdt.PutString('/config', 'bootcmd', bootcmd)
444 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700445 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700446
Simon Glassa4934b72012-05-09 13:35:02 -0700447 def SetNodeEnabled(self, node_name, enabled):
448 """Set whether an node is enabled or disabled.
449
450 This simply sets the 'status' property of a node to "ok", or "disabled".
451
452 The node should either be a full path to the node (like '/uart@10200000')
453 or an alias property.
454
455 Aliases are supported like this:
456
457 aliases {
458 console = "/uart@10200000";
459 };
460
461 pointing to a node:
462
463 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700464 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700465 };
466
467 In this case, this function takes the name of the alias ('console' in
468 this case) and updates the status of the node that is pointed to, to
469 either ok or disabled. If the alias does not exist, a warning is
470 displayed.
471
472 Args:
473 node_name: Name of node (e.g. '/uart@10200000') or alias alias
474 (e.g. 'console') to adjust
475 enabled: True to enable, False to disable
476 """
477 # Look up the alias if this is an alias reference
478 if not node_name.startswith('/'):
479 lookup = self.fdt.GetString('/aliases', node_name, '')
480 if not lookup:
481 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
482 return
483 node_name = lookup
484 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700485 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700486 else:
487 status = 'disabled'
488 self.fdt.PutString(node_name, 'status', status)
489
490 def AddEnableList(self, enable_list):
491 """Process a list of nodes to enable/disable.
492
493 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700494 enable_list: List of (node, value) tuples to add to the fdt. For each
Simon Glassa4934b72012-05-09 13:35:02 -0700495 tuple:
496 node: The fdt node to write to will be <node> or pointed to by
497 /aliases/<node>. We can tell which
498 value: 0 to disable the node, 1 to enable it
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700499
Vadim Bendebury507c0012013-06-09 12:49:25 -0700500 Raises:
501 CmdError if a command fails.
Simon Glassa4934b72012-05-09 13:35:02 -0700502 """
503 if enable_list:
504 for node_name, enabled in enable_list:
505 try:
506 enabled = int(enabled)
507 if enabled not in (0, 1):
508 raise ValueError
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700509 except ValueError:
Simon Glassa4934b72012-05-09 13:35:02 -0700510 raise CmdError("Invalid enable option value '%s' "
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700511 "(should be 0 or 1)" % str(enabled))
Simon Glassa4934b72012-05-09 13:35:02 -0700512 self.SetNodeEnabled(node_name, enabled)
513
Simon Glass290a1802011-07-17 13:54:32 -0700514 def AddConfigList(self, config_list, use_int=False):
515 """Add a list of config items to the fdt.
516
517 Normally these values are written to the fdt as strings, but integers
518 are also supported, in which case the values will be converted to integers
519 (if necessary) before being stored.
520
521 Args:
522 config_list: List of (config, value) tuples to add to the fdt. For each
523 tuple:
524 config: The fdt node to write to will be /config/<config>.
525 value: An integer or string value to write.
526 use_int: True to only write integer values.
527
528 Raises:
529 CmdError: if a value is required to be converted to integer but can't be.
530 """
531 if config_list:
532 for config in config_list:
533 value = config[1]
534 if use_int:
535 try:
536 value = int(value)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700537 except ValueError:
Simon Glass290a1802011-07-17 13:54:32 -0700538 raise CmdError("Cannot convert config option '%s' to integer" %
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700539 str(value))
Simon Glass290a1802011-07-17 13:54:32 -0700540 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800541 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700542 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800543 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700544
Simon Glass7c2d5572011-11-15 14:47:08 -0800545 def DecodeTextBase(self, data):
546 """Look at a U-Boot image and try to decode its TEXT_BASE.
547
548 This works because U-Boot has a header with the value 0x12345678
549 immediately followed by the TEXT_BASE value. We can therefore read this
550 from the image with some certainty. We check only the first 40 words
551 since the header should be within that region.
552
Simon Glass96b50302012-07-20 06:55:28 +0100553 Since upstream Tegra has moved to having a 16KB SPL region at the start,
554 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
555 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
556
Simon Glass7c2d5572011-11-15 14:47:08 -0800557 Args:
558 data: U-Boot binary data
559
560 Returns:
561 Text base (integer) or None if none was found
562 """
563 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100564 for start in (0, 0x4000):
565 for i in range(start, start + 160, 4):
566 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800567
Simon Glass96b50302012-07-20 06:55:28 +0100568 # TODO(sjg): This does not cope with a big-endian target
569 value = struct.unpack('<I', word)[0]
570 if found:
571 return value - start
572 if value == 0x12345678:
573 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800574
575 return None
576
577 def CalcTextBase(self, name, fdt, fname):
578 """Calculate the TEXT_BASE to use for U-Boot.
579
580 Normally this value is in the fdt, so we just read it from there. But as
581 a second check we look at the image itself in case this is different, and
582 switch to that if it is.
583
584 This allows us to flash any U-Boot even if its TEXT_BASE is different.
585 This is particularly useful with upstream U-Boot which uses a different
586 value (which we will move to).
587 """
588 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800589 # The value that comes back from fdt.GetInt is signed, which makes no
590 # sense for an address base. Force it to unsigned.
591 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800592 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100593 text_base_str = '%#x' % text_base if text_base else 'None'
594 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
595 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800596
597 # If they are different, issue a warning and switch over.
598 if text_base and text_base != fdt_text_base:
599 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
600 "fdt value of %x. Using %x" % (text_base, name,
601 fdt_text_base, text_base))
602 fdt_text_base = text_base
603 return fdt_text_base
604
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600605 def _AddCbfsFiles(self, bootstub, cbfs_files):
606 for dir, subs, files in os.walk(cbfs_files):
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600607 for file in files:
608 file = os.path.join(dir, file)
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600609 cbfs_name = file.replace(cbfs_files, '', 1).strip('/')
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600610 self._tools.Run('cbfstool', [bootstub, 'add', '-f', file,
611 '-n', cbfs_name, '-t', 'raw', '-c', 'lzma'])
612
613 def _CreateCorebootStub(self, pack, coreboot):
614 """Create a coreboot boot stub and add pack properties.
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700615
616 Args:
Aaron Durbina113f522016-01-05 09:09:55 -0600617 pack: a PackFirmware object describing the firmware image to build.
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700618 coreboot: Path to coreboot.rom
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700619 """
620 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700621 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100622
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600623 pack.AddProperty('coreboot', bootstub)
624 pack.AddProperty('image', bootstub)
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700625
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600626 # Add files to to RO and RW CBFS if provided.
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600627 if self.cbfs_files:
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600628 self._AddCbfsFiles(bootstub, self.cbfs_files)
Simon Glass7e199222012-03-13 15:51:18 -0700629
Aaron Durbina113f522016-01-05 09:09:55 -0600630 # Create a coreboot copy to use as a scratch pad. Order matters. The
631 # cbfs_files were added prior to this action. That's so the RW CBFS
Patrick Georgi3a332672015-11-20 10:02:51 +0100632 # regions inherit the files from the RO CBFS region. Additionally,
633 # include the full FMAP within the file.
634 cb_copy = os.path.abspath(os.path.join(self._tools.outdir, 'cb_with_fmap'))
Aaron Durbina113f522016-01-05 09:09:55 -0600635 self._tools.WriteFile(cb_copy, self._tools.ReadFile(bootstub))
Patrick Georgi3a332672015-11-20 10:02:51 +0100636 binary = self._tools.ReadFile(bootstub)
637 fmap_offset, fmap = pack.GetFmap()
638 if len(binary) < fmap_offset + len(fmap):
639 raise CmdError('FMAP will not fit')
640 # Splice in FMAP data.
641 binary = binary[:fmap_offset] + fmap + binary[fmap_offset + len(fmap):]
642 self._tools.WriteFile(cb_copy, binary)
643 # Publish where coreboot is with the FMAP data.
644 pack.AddProperty('cb_with_fmap', cb_copy)
Aaron Durbina113f522016-01-05 09:09:55 -0600645
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600646 # Add files to to RO CBFS if provided. This done here such that the
647 # copy above does not contain the RO CBFS files.
648 if self.rocbfs_files:
649 self._AddCbfsFiles(bootstub, self.rocbfs_files)
650
Aaron Durbina113f522016-01-05 09:09:55 -0600651
Simon Glass89b86b82011-07-17 23:49:49 -0700652 def _PackOutput(self, msg):
653 """Helper function to write output from PackFirmware (verbose level 2).
654
655 This is passed to PackFirmware for it to use to write output.
656
657 Args:
658 msg: Message to display.
659 """
660 self._out.Notice(msg)
661
Aaron Durbin80564452015-12-21 15:25:06 -0600662 def _FmapNameByPath(self, path):
663 """ Take list of names to form node path. Return FMAP name.
664
665 Obtain the FMAP name described by the node path.
666
667 Args:
668 path: list forming a node path.
669
670 Returns:
671 FMAP name of fdt node.
672
673 Raises:
674 CmdError if path not found.
675 """
676 lbl = self.fdt.GetLabel(self.fdt.GetFlashNode(*path))
677 return re.sub('-', '_', lbl).upper()
678
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800679 def _PrepareCbfs(self, pack, blob_name):
680 """Create CBFS blob in rw-boot-{a,b} FMAP sections.
681
682 When the blob name is defined as cbfs#<section>#<subsection>, fill the
683 <section>_<subsection> area in the flash map with a CBFS copy, putting the
684 CBFS header of the copy at the base of the section.
685
686 If --coreboot-elf parameter was specified during cros_bumdle_firmware
687 invocation, add the parameter of this option as the payload to the new
688 CBFS instance.
689
690 Args:
691 pack: a PackFirmware object describing the firmware image to build.
692 blob_name: a string, blob name describing what FMAP section this CBFS
693 copy is destined to
694 Raises:
Patrick Georgi3a332672015-11-20 10:02:51 +0100695 CmdError if cbfs-files node has incorrect parameters.
Aaron Durbina113f522016-01-05 09:09:55 -0600696 BlobDeferral if coreboot image with fmap is not available yet.
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800697 """
Patrick Georgi3a332672015-11-20 10:02:51 +0100698 cb_copy = pack.GetProperty('cb_with_fmap')
Aaron Durbina113f522016-01-05 09:09:55 -0600699 if cb_copy is None:
Patrick Georgi3a332672015-11-20 10:02:51 +0100700 raise BlobDeferral("Waiting for 'cb_with_fmap' property")
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800701
702 part_sections = blob_name.split('/')[1:]
Aaron Durbin80564452015-12-21 15:25:06 -0600703 fmap_dst = self._FmapNameByPath(part_sections)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800704
705 # Base address and size of the desitnation partition
706 base, size = self.fdt.GetFlashPart(*part_sections)
707
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800708 # Add coreboot payload if so requested. Note that the some images use
709 # different payload for the rw sections, which is passed in as the value
710 # of the --uboot option in the command line.
711 if self.uboot_fname:
712 payload_fname = self.uboot_fname
713 elif self.coreboot_elf:
714 payload_fname = self.coreboot_elf
715 else:
716 payload_fname = None
717
718 if payload_fname:
719 self._tools.Run('cbfstool', [
720 cb_copy, 'add-payload', '-f', payload_fname,
Patrick Georgi10690b42015-11-20 22:06:38 +0100721 '-n', 'fallback/payload', '-c', 'lzma' , '-r', fmap_dst])
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800722
Patrick Georgi964fb542015-10-16 16:52:03 +0200723 if self.ecrw_fname:
724 self._tools.Run('cbfstool', [
725 cb_copy, 'add', '-f', self.ecrw_fname, '-t', 'raw',
Patrick Georgi10690b42015-11-20 22:06:38 +0100726 '-n', 'ecrw', '-A', 'sha256', '-r', fmap_dst ])
Patrick Georgi964fb542015-10-16 16:52:03 +0200727
728 if self.pdrw_fname:
729 self._tools.Run('cbfstool', [
730 cb_copy, 'add', '-f', self.pdrw_fname, '-t', 'raw',
Patrick Georgi10690b42015-11-20 22:06:38 +0100731 '-n', 'pdrw', '-A', 'sha256', '-r', fmap_dst ])
Patrick Georgi964fb542015-10-16 16:52:03 +0200732
Aaron Durbin880cf952016-01-27 14:11:38 -0600733 # Parse the file list to obtain the last entry. If its empty use its
734 # offset as the size of the CBFS to hash.
735 stdout = self._tools.Run('cbfstool',
736 [ cb_copy, 'print', '-k', '-r', fmap_dst ])
737 # Fields are tab separated in the following order.
738 # Name Offset Type Metadata Size Data Size Total Size
739 last_entry = stdout.strip().splitlines()[-1].split('\t')
740 if last_entry[0] == '(empty)' and last_entry[2] == 'null':
741 size = int(last_entry[1], 16)
742
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800743 # And extract the blob for the FW section
744 rw_section = os.path.join(self._tools.outdir, '_'.join(part_sections))
745 self._tools.WriteFile(rw_section,
746 self._tools.ReadFile(cb_copy)[base:base+size])
747
748 pack.AddProperty(blob_name, rw_section)
749
750
Simon Glass439fe7a2012-03-09 16:19:34 -0800751 def _BuildBlob(self, pack, fdt, blob_type):
752 """Build the blob data for a particular blob type.
753
754 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700755 pack: a PackFirmware object describing the firmware image to build.
756 fdt: an fdt object including image layout information
Simon Glass439fe7a2012-03-09 16:19:34 -0800757 blob_type: The type of blob to create data for. Supported types are:
758 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
759 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
Vadim Bendebury507c0012013-06-09 12:49:25 -0700760
761 Raises:
762 CmdError if a command fails.
Aaron Durbin41c85b62015-12-17 17:40:29 -0600763 BlobDeferral if a blob is waiting for a dependency.
Simon Glass439fe7a2012-03-09 16:19:34 -0800764 """
765 if blob_type == 'coreboot':
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600766 self._CreateCorebootStub(pack, self.coreboot_fname)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700767 elif blob_type == 'legacy':
768 pack.AddProperty('legacy', self.seabios_fname)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800769 elif blob_type.startswith('cbfs'):
770 self._PrepareCbfs(pack, blob_type)
Simon Glass439fe7a2012-03-09 16:19:34 -0800771 elif pack.GetProperty(blob_type):
772 pass
Furquan Shaikh95ee50c2016-05-29 09:46:41 -0700773 elif blob_type == 'ifwi' or blob_type == 'sig2':
774 # Copy IFWI/CSE_SIGN(sig2) regions from coreboot copy and build a blob
775 # for the blob_type
776 cb_copy = pack.GetProperty('cb_with_fmap')
777 if cb_copy is None:
778 raise BlobDeferral("Waiting for 'cb_with_fmap' property")
779 blob_start, blob_size = fdt.GetFlashPart('ro', blob_type)
780 blob_file = blob_type + '.bin'
781 blob_path = os.path.join(self._tools.outdir, blob_file)
782 data = self._tools.ReadFile(cb_copy)
783 self._tools.WriteFile(blob_path, data[blob_start:blob_start+blob_size])
784 pack.AddProperty(blob_type, blob_path)
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800785 elif blob_type in self.blobs:
786 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -0800787 else:
788 raise CmdError("Unknown blob type '%s' required in flash map" %
789 blob_type)
790
Aaron Durbin41c85b62015-12-17 17:40:29 -0600791 def _BuildBlobs(self, pack, fdt):
792 """Build the blob data for the list of blobs in the pack.
793
794 Args:
795 pack: a PackFirmware object describing the firmware image to build.
796 fdt: an fdt object including image layout information
797
798 Raises:
799 CmdError if a command fails.
800 BlobDeferral if dependencies cannot be met because of cycles.
801 """
802 blob_list = pack.GetBlobList()
803 self._out.Info('Building blobs %s\n' % blob_list)
804
805 complete = False
806 deferred_list = []
807
808 # Build blobs allowing for dependencies between blobs. While this is
809 # an potential O(n^2) operation, in practice most blobs aren't dependent
810 # and should resolve in a few passes.
811 while not complete:
812 orig = set(blob_list)
813 for blob_type in blob_list:
814 try:
815 self._BuildBlob(pack, fdt, blob_type)
816 except (BlobDeferral):
817 deferred_list.append(blob_type)
818 if not deferred_list:
819 complete = True
820 # If deferred is the same as the original no progress is being made.
821 if not orig - set(deferred_list):
822 raise BlobDeferral("Blob cyle '%s'" % orig)
823 # Process the deferred blobs
824 blob_list = deferred_list[:]
825 deferred_list = []
826
Simon Glass290a1802011-07-17 13:54:32 -0700827 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700828 """Create a full firmware image, along with various by-products.
829
830 This uses the provided u-boot.bin, fdt and bct to create a firmware
831 image containing all the required parts. If the GBB is not supplied
832 then this will just return a signed U-Boot as the image.
833
834 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700835 gbb: a string, full path to the GBB file, or empty if a GBB is not
836 required.
837 fdt: an fdt object containing required information.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200838
839 Returns:
840 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700841 """
Simon Glass02d124a2012-03-02 14:47:20 -0800842 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700843
Simon Glass439fe7a2012-03-09 16:19:34 -0800844 pack = PackFirmware(self._tools, self._out)
Simon Glass00d027e2013-07-20 14:51:12 -0600845 if self._force_efs:
846 fdt.PutInteger('/chromeos-config', 'early-firmware-selection', 1)
Simon Glassa7e66e22013-07-23 07:21:16 -0600847 pack.use_efs = fdt.GetInt('/chromeos-config', 'early-firmware-selection',
848 0)
Simon Glassb8c6d952012-12-01 06:14:35 -0800849
Simon Glass4f318912013-07-20 16:13:06 -0600850 pack.SelectFdt(fdt, self._board)
Simon Glass439fe7a2012-03-09 16:19:34 -0800851
852 # Get all our blobs ready
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800853 if self.uboot_fname:
854 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -0800855 if self.skeleton_fname:
856 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700857 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700858
Simon Glassde9c8072012-07-02 22:29:02 -0700859 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
860 if self.kernel_fname:
861 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
862
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800863 if gbb:
864 pack.AddProperty('gbb', gbb)
Aaron Durbin41c85b62015-12-17 17:40:29 -0600865
866 # Build the blobs out.
867 self._BuildBlobs(pack, fdt)
Simon Glass89b86b82011-07-17 23:49:49 -0700868
Simon Glass7306b902012-12-17 15:06:21 -0800869 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -0700870 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700871 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800872 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800873 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800874 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700875 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800876 pack.AddProperty('fwid', fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800877 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700878
879 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700880
881 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -0800882 pack.UpdateBlobPositionsAndHashes(fdt)
Simon Glass8884b982012-06-21 12:41:41 -0700883
Simon Glass6207efe2012-12-17 15:04:36 -0800884 # Make a copy of the fdt for the bootstub
885 fdt_data = self._tools.ReadFile(fdt.fname)
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800886 if self.uboot_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)
Simon Glass6207efe2012-12-17 15:04:36 -0800890
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800891 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
892 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800893
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.
Aaron Durbin41c85b62015-12-17 17:40:29 -0600896 if 'coreboot' in pack.GetBlobList():
Simon Glasscbc83552012-07-23 15:26:22 +0100897 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'])
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800902 elif self.uboot_fname:
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
Julius Werneraa1fe942014-11-21 17:16:11 -0800922 # Use offset and size from fmap.dts to extract CBFS area from coreboot.rom
923 cbfs_offset, cbfs_size = fdt.GetFlashPart('ro', 'boot')
924 self._tools.WriteFile(bootstub, data[cbfs_offset:cbfs_offset+cbfs_size])
Simon Glasscbc83552012-07-23 15:26:22 +0100925
Simon Glass208ad952013-02-10 11:16:46 -0800926 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -0700927 image = os.path.join(self._tools.outdir, 'image.bin')
928 pack.PackImage(self._tools.outdir, image)
929 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700930
Simon Glass439fe7a2012-03-09 16:19:34 -0800931 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700932 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700933 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700934
Simon Glassdedda6f2013-02-09 13:44:14 -0800935 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -0700936 """Select an FDT to control the firmware bundling
937
Simon Glassdedda6f2013-02-09 13:44:14 -0800938 We make a copy of this which will include any on-the-fly changes we want
939 to make.
940
Simon Glass290a1802011-07-17 13:54:32 -0700941 Args:
942 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -0800943 use_defaults: True to use a default FDT name if available, and to add
944 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -0700945
Simon Glassc0f3dc62011-08-09 14:19:05 -0700946 Returns:
947 The Fdt object of the original fdt file, which we will not modify.
948
Simon Glassdedda6f2013-02-09 13:44:14 -0800949 Raises:
950 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
951 False).
Simon Glass290a1802011-07-17 13:54:32 -0700952 """
Simon Glassdedda6f2013-02-09 13:44:14 -0800953 if use_defaults:
954 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -0800955 if not fdt_fname:
956 raise ValueError('Please provide an FDT filename')
957 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -0700958 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -0800959
Patrick Georgi81263072016-09-09 22:33:06 +0200960 fdt.Compile(None)
Simon Glasse53abbc2013-08-21 22:29:55 -0600961 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
962
Patrick Georgicebb5a22016-08-15 19:07:02 +0200963 if fdt.GetProp('/flash', 'reg', ''):
964 raise ValueError('fmap.dts /flash is deprecated. Use chromeos.fmd')
965
966 # fill in /flash from binary fmap
967 # ignore "read-only" attribute, that isn't used anywhere
Julius Wernerbcf0c942016-09-07 16:57:40 -0700968 bootblock_range = None
969 coreboot_range = None
Patrick Georgicebb5a22016-08-15 19:07:02 +0200970 fmap_blob = open(self.coreboot_fname).read()
971 f = fmap.fmap_decode(fmap_blob)
972 fdt.PutString('/flash', 'compatible', 'chromeos,flashmap')
973 fdt.PutIntList('/flash', 'reg', [f['base'], f['size']])
974 for area in f['areas']:
975 label = re.sub('_', '-', area['name']).lower()
976 fdt_path = '/flash/' + label
977 slot=label[-1]
978 if label == 'gbb':
979 fdt_path = '/flash/ro-gbb'
980 fdt.PutString(fdt_path, 'type', 'blob gbb')
981 elif label == 'fmap':
982 fdt_path = '/flash/ro-fmap'
983 fdt.PutString(fdt_path, 'type', 'fmap')
984 fdt.PutIntList(fdt_path, 'ver-major', [1])
985 fdt.PutIntList(fdt_path, 'ver-minor', [0])
Julius Wernerbcf0c942016-09-07 16:57:40 -0700986 elif label == 'bootblock':
987 bootblock_range = [area['offset'], area['size']]
988 continue
Patrick Georgicebb5a22016-08-15 19:07:02 +0200989 elif label == 'coreboot':
Julius Wernerbcf0c942016-09-07 16:57:40 -0700990 coreboot_range = [area['offset'], area['size']]
991 continue
Patrick Georgicebb5a22016-08-15 19:07:02 +0200992 elif label == 'si-desc':
993 fdt.PutString(fdt_path, 'type', 'ifd')
994 elif label == 'rw-shared':
995 fdt_path = '/flash/shared-section'
996 elif label == 'rw-section-'+slot:
997 fdt_path = '/flash/rw-'+slot
998 elif label == 'rw-legacy' and self.seabios_fname:
999 fdt.PutString(fdt_path, 'type', 'blob legacy')
1000 elif label in ['rw-mrc-cache', 'rw-elog', 'rw-legacy',
1001 'rw-vpd', 'rw-unused', 'ro-vpd', 'ro-unused',
1002 'ro-frid-pad', 'bios-unusable', 'device-extension',
1003 'unused-hole', 'rw-gpt-primary', 'rw-gpt-secondary',
1004 'rw-nvram', 'ro-unused-1', 'ro-unused-2']:
1005 fdt.PutString(fdt_path, 'type', 'wiped')
1006 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
1007 elif label == 'shared-data':
1008 fdt.PutString(fdt_path, 'type', 'wiped')
1009 fdt.PutIntList(fdt_path, 'wipe-value', [0])
1010 elif label == 'vblock-dev':
1011 fdt_path = '/flash/rw-vblock-dev'
1012 fdt.PutString(fdt_path, 'type', 'wiped')
1013 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
1014 elif label[:-1] == 'vblock-':
1015 fdt_path = '/flash/rw-'+slot+'-vblock'
1016 fdt.PutString(fdt_path, 'type', 'keyblock cbfs/rw/'+slot+'-boot')
1017 fdt.PutString(fdt_path, 'keyblock', 'firmware.keyblock')
1018 fdt.PutString(fdt_path, 'signprivate', 'firmware_data_key.vbprivk')
1019 fdt.PutString(fdt_path, 'kernelkey', 'kernel_subkey.vbpubk')
1020 fdt.PutIntList(fdt_path, 'version', [1])
1021 fdt.PutIntList(fdt_path, 'preamble-flags', [0])
1022 elif label[:-1] == 'fw-main-':
1023 fdt_path = '/flash/rw-'+slot+'-boot'
1024 fdt.PutString(fdt_path, 'type', 'blob cbfs/rw/'+slot+'-boot')
1025 elif label[:-1] == 'rw-fwid-':
1026 fdt_path = '/flash/rw-'+slot+'-firmware-id'
1027 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1028 elif label == 'ro-frid':
1029 fdt_path = '/flash/ro-firmware-id'
1030 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1031 elif label == 'ifwi':
1032 fdt_path = '/flash/ro-ifwi'
1033 fdt.PutString(fdt_path, 'type', 'blob ifwi')
1034 elif label == 'sign-cse':
1035 fdt_path = '/flash/ro-sig'
1036 fdt.PutString(fdt_path, 'type', 'blob sig2')
1037 # white list for empty regions
Patrick Georgi56dc9202016-09-07 21:12:04 +02001038 elif label in ['bootblock', 'misc-rw', 'ro-section', 'rw-environment',
1039 'rw-gpt', 'si-all', 'si-bios', 'si-me', 'wp-ro']:
Patrick Georgicebb5a22016-08-15 19:07:02 +02001040 pass
1041 else:
1042 raise ValueError('encountered label "'+label+'" in binary fmap. '+
1043 'Check chromeos.fmd')
1044 fdt.PutString(fdt_path, 'label', label)
1045 fdt.PutIntList(fdt_path, 'reg', [area['offset'], area['size']])
1046
Julius Wernerbcf0c942016-09-07 16:57:40 -07001047 if coreboot_range is not None:
1048 if bootblock_range is not None:
1049 if bootblock_range[0] + bootblock_range[1] != coreboot_range[0]:
1050 raise ValueError('Cannot combine BOOTBLOCK and COREBOOT')
1051 coreboot_range[0] = bootblock_range[0]
1052 coreboot_range[1] += bootblock_range[1]
1053 fdt_path = '/flash/ro-boot'
1054 fdt.PutString(fdt_path, 'type', 'blob coreboot')
1055 fdt.PutString(fdt_path, 'label', 'coreboot')
1056 fdt.PutIntList(fdt_path, 'reg', [coreboot_range[0], coreboot_range[1]])
1057
Simon Glass7df773b2013-08-25 18:02:29 -06001058 # Remember our board type.
1059 fdt.PutString('/chromeos-config', 'board', self._board)
1060
Simon Glasse53abbc2013-08-21 22:29:55 -06001061 self.fdt = fdt
1062 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001063
Simon Glassc90cf582012-03-13 15:40:47 -07001064 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001065 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001066
1067 - Checks options, tools, output directory, fdt.
1068 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001069
1070 Args:
Simon Glass56577572011-07-19 11:08:06 +12001071 hardware_id: Hardware ID to use for this board. If None, then the
1072 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001073 output_fname: Output filename for the image. If this is not None, then
1074 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001075 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001076
1077 Returns:
1078 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001079 """
Vadim Bendebury5baeec12013-04-02 13:01:22 -07001080 if self._small or self.fdt.GetProp('/config', 'nogbb', 'any') != 'any':
1081 gbb = '' # Building a small image or `nogbb' is requested in device tree.
1082 else:
Simon Glass56577572011-07-19 11:08:06 +12001083 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001084
1085 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001086 image, pack = self._CreateImage(gbb, self.fdt)
1087 if show_map:
1088 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001089 if output_fname:
1090 shutil.copyfile(image, output_fname)
1091 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001092 return image, pack.props