blob: b93b26a75cb25c2c956642218812cf63ce0cd80e [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':
Patrick Georgifa20ddc2016-09-27 14:10:51 +0200766 pass
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
Patrick Georgifa20ddc2016-09-27 14:10:51 +0200808 # We always have a coreboot blob, and some other components rely on it, so
809 # make sure it's ready when the others come in.
810 blob_list.remove('coreboot')
811 self._CreateCorebootStub(pack, self.coreboot_fname)
812
Aaron Durbin41c85b62015-12-17 17:40:29 -0600813 # Build blobs allowing for dependencies between blobs. While this is
814 # an potential O(n^2) operation, in practice most blobs aren't dependent
815 # and should resolve in a few passes.
816 while not complete:
817 orig = set(blob_list)
818 for blob_type in blob_list:
819 try:
820 self._BuildBlob(pack, fdt, blob_type)
821 except (BlobDeferral):
822 deferred_list.append(blob_type)
823 if not deferred_list:
824 complete = True
825 # If deferred is the same as the original no progress is being made.
826 if not orig - set(deferred_list):
827 raise BlobDeferral("Blob cyle '%s'" % orig)
828 # Process the deferred blobs
829 blob_list = deferred_list[:]
830 deferred_list = []
831
Simon Glass290a1802011-07-17 13:54:32 -0700832 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700833 """Create a full firmware image, along with various by-products.
834
835 This uses the provided u-boot.bin, fdt and bct to create a firmware
836 image containing all the required parts. If the GBB is not supplied
837 then this will just return a signed U-Boot as the image.
838
839 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700840 gbb: a string, full path to the GBB file, or empty if a GBB is not
841 required.
842 fdt: an fdt object containing required information.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200843
844 Returns:
845 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700846 """
Simon Glass02d124a2012-03-02 14:47:20 -0800847 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700848
Simon Glass439fe7a2012-03-09 16:19:34 -0800849 pack = PackFirmware(self._tools, self._out)
Simon Glass00d027e2013-07-20 14:51:12 -0600850 if self._force_efs:
851 fdt.PutInteger('/chromeos-config', 'early-firmware-selection', 1)
Simon Glassa7e66e22013-07-23 07:21:16 -0600852 pack.use_efs = fdt.GetInt('/chromeos-config', 'early-firmware-selection',
853 0)
Simon Glassb8c6d952012-12-01 06:14:35 -0800854
Simon Glass4f318912013-07-20 16:13:06 -0600855 pack.SelectFdt(fdt, self._board)
Simon Glass439fe7a2012-03-09 16:19:34 -0800856
857 # Get all our blobs ready
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800858 if self.uboot_fname:
859 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -0800860 if self.skeleton_fname:
861 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700862 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700863
Simon Glassde9c8072012-07-02 22:29:02 -0700864 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
865 if self.kernel_fname:
866 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
867
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800868 if gbb:
869 pack.AddProperty('gbb', gbb)
Aaron Durbin41c85b62015-12-17 17:40:29 -0600870
871 # Build the blobs out.
872 self._BuildBlobs(pack, fdt)
Simon Glass89b86b82011-07-17 23:49:49 -0700873
Simon Glass7306b902012-12-17 15:06:21 -0800874 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -0700875 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700876 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800877 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800878 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800879 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700880 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800881 pack.AddProperty('fwid', fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800882 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700883
884 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700885
886 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -0800887 pack.UpdateBlobPositionsAndHashes(fdt)
Simon Glass8884b982012-06-21 12:41:41 -0700888
Simon Glass6207efe2012-12-17 15:04:36 -0800889 # Make a copy of the fdt for the bootstub
890 fdt_data = self._tools.ReadFile(fdt.fname)
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800891 if self.uboot_fname:
892 uboot_data = self._tools.ReadFile(self.uboot_fname)
893 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
894 self._tools.WriteFile(uboot_copy, uboot_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800895
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800896 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
897 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800898
Simon Glassa10282a2013-01-08 17:06:41 -0800899 # Fix up the coreboot image here, since we can't do this until we have
900 # a final device tree binary.
Aaron Durbin41c85b62015-12-17 17:40:29 -0600901 if 'coreboot' in pack.GetBlobList():
Simon Glasscbc83552012-07-23 15:26:22 +0100902 bootstub = pack.GetProperty('coreboot')
903 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -0800904 if self.coreboot_elf:
905 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
906 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800907 elif self.uboot_fname:
Simon Glass0a7cf112013-05-21 23:08:21 -0700908 text_base = 0x1110000
909
910 # This is the the 'movw $GD_FLG_COLD_BOOT, %bx' instruction
911 # 1110015: 66 bb 00 01 mov $0x100,%bx
912 marker = struct.pack('<L', 0x0100bb66)
913 pos = uboot_data.find(marker)
914 if pos == -1 or pos > 0x100:
915 raise ValueError('Cannot find U-Boot cold boot entry point')
916 entry = text_base + pos
917 self._out.Notice('U-Boot entry point %#08x' % entry)
Simon Glassa10282a2013-01-08 17:06:41 -0800918 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
919 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
Simon Glass0a7cf112013-05-21 23:08:21 -0700920 '-l', '%#x' % text_base, '-e', '%#x' % entry])
Stefan Reinauer1502ea62012-11-01 10:15:38 -0700921 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
922 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -0800923 data = self._tools.ReadFile(bootstub)
924 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
925 self._tools.WriteFile(bootstub_copy, data)
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700926
Julius Werneraa1fe942014-11-21 17:16:11 -0800927 # Use offset and size from fmap.dts to extract CBFS area from coreboot.rom
928 cbfs_offset, cbfs_size = fdt.GetFlashPart('ro', 'boot')
929 self._tools.WriteFile(bootstub, data[cbfs_offset:cbfs_offset+cbfs_size])
Simon Glasscbc83552012-07-23 15:26:22 +0100930
Simon Glass208ad952013-02-10 11:16:46 -0800931 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -0700932 image = os.path.join(self._tools.outdir, 'image.bin')
933 pack.PackImage(self._tools.outdir, image)
934 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700935
Simon Glass439fe7a2012-03-09 16:19:34 -0800936 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700937 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700938 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700939
Simon Glassdedda6f2013-02-09 13:44:14 -0800940 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -0700941 """Select an FDT to control the firmware bundling
942
Simon Glassdedda6f2013-02-09 13:44:14 -0800943 We make a copy of this which will include any on-the-fly changes we want
944 to make.
945
Simon Glass290a1802011-07-17 13:54:32 -0700946 Args:
947 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -0800948 use_defaults: True to use a default FDT name if available, and to add
949 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -0700950
Simon Glassc0f3dc62011-08-09 14:19:05 -0700951 Returns:
952 The Fdt object of the original fdt file, which we will not modify.
953
Simon Glassdedda6f2013-02-09 13:44:14 -0800954 Raises:
955 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
956 False).
Simon Glass290a1802011-07-17 13:54:32 -0700957 """
Simon Glassdedda6f2013-02-09 13:44:14 -0800958 if use_defaults:
959 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -0800960 if not fdt_fname:
961 raise ValueError('Please provide an FDT filename')
962 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -0700963 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -0800964
Patrick Georgi81263072016-09-09 22:33:06 +0200965 fdt.Compile(None)
Simon Glasse53abbc2013-08-21 22:29:55 -0600966 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
967
Patrick Georgicebb5a22016-08-15 19:07:02 +0200968 if fdt.GetProp('/flash', 'reg', ''):
969 raise ValueError('fmap.dts /flash is deprecated. Use chromeos.fmd')
970
971 # fill in /flash from binary fmap
972 # ignore "read-only" attribute, that isn't used anywhere
Julius Wernerbcf0c942016-09-07 16:57:40 -0700973 bootblock_range = None
974 coreboot_range = None
Patrick Georgicebb5a22016-08-15 19:07:02 +0200975 fmap_blob = open(self.coreboot_fname).read()
976 f = fmap.fmap_decode(fmap_blob)
977 fdt.PutString('/flash', 'compatible', 'chromeos,flashmap')
978 fdt.PutIntList('/flash', 'reg', [f['base'], f['size']])
979 for area in f['areas']:
980 label = re.sub('_', '-', area['name']).lower()
981 fdt_path = '/flash/' + label
982 slot=label[-1]
983 if label == 'gbb':
984 fdt_path = '/flash/ro-gbb'
985 fdt.PutString(fdt_path, 'type', 'blob gbb')
986 elif label == 'fmap':
987 fdt_path = '/flash/ro-fmap'
988 fdt.PutString(fdt_path, 'type', 'fmap')
989 fdt.PutIntList(fdt_path, 'ver-major', [1])
990 fdt.PutIntList(fdt_path, 'ver-minor', [0])
Julius Wernerbcf0c942016-09-07 16:57:40 -0700991 elif label == 'bootblock':
992 bootblock_range = [area['offset'], area['size']]
993 continue
Patrick Georgicebb5a22016-08-15 19:07:02 +0200994 elif label == 'coreboot':
Julius Wernerbcf0c942016-09-07 16:57:40 -0700995 coreboot_range = [area['offset'], area['size']]
996 continue
Patrick Georgicebb5a22016-08-15 19:07:02 +0200997 elif label == 'si-desc':
998 fdt.PutString(fdt_path, 'type', 'ifd')
999 elif label == 'rw-shared':
1000 fdt_path = '/flash/shared-section'
1001 elif label == 'rw-section-'+slot:
1002 fdt_path = '/flash/rw-'+slot
1003 elif label == 'rw-legacy' and self.seabios_fname:
1004 fdt.PutString(fdt_path, 'type', 'blob legacy')
1005 elif label in ['rw-mrc-cache', 'rw-elog', 'rw-legacy',
1006 'rw-vpd', 'rw-unused', 'ro-vpd', 'ro-unused',
1007 'ro-frid-pad', 'bios-unusable', 'device-extension',
1008 'unused-hole', 'rw-gpt-primary', 'rw-gpt-secondary',
1009 'rw-nvram', 'ro-unused-1', 'ro-unused-2']:
1010 fdt.PutString(fdt_path, 'type', 'wiped')
1011 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
1012 elif label == 'shared-data':
1013 fdt.PutString(fdt_path, 'type', 'wiped')
1014 fdt.PutIntList(fdt_path, 'wipe-value', [0])
1015 elif label == 'vblock-dev':
1016 fdt_path = '/flash/rw-vblock-dev'
1017 fdt.PutString(fdt_path, 'type', 'wiped')
1018 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
1019 elif label[:-1] == 'vblock-':
1020 fdt_path = '/flash/rw-'+slot+'-vblock'
1021 fdt.PutString(fdt_path, 'type', 'keyblock cbfs/rw/'+slot+'-boot')
1022 fdt.PutString(fdt_path, 'keyblock', 'firmware.keyblock')
1023 fdt.PutString(fdt_path, 'signprivate', 'firmware_data_key.vbprivk')
1024 fdt.PutString(fdt_path, 'kernelkey', 'kernel_subkey.vbpubk')
1025 fdt.PutIntList(fdt_path, 'version', [1])
1026 fdt.PutIntList(fdt_path, 'preamble-flags', [0])
1027 elif label[:-1] == 'fw-main-':
1028 fdt_path = '/flash/rw-'+slot+'-boot'
1029 fdt.PutString(fdt_path, 'type', 'blob cbfs/rw/'+slot+'-boot')
1030 elif label[:-1] == 'rw-fwid-':
1031 fdt_path = '/flash/rw-'+slot+'-firmware-id'
1032 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1033 elif label == 'ro-frid':
1034 fdt_path = '/flash/ro-firmware-id'
1035 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1036 elif label == 'ifwi':
1037 fdt_path = '/flash/ro-ifwi'
1038 fdt.PutString(fdt_path, 'type', 'blob ifwi')
1039 elif label == 'sign-cse':
1040 fdt_path = '/flash/ro-sig'
1041 fdt.PutString(fdt_path, 'type', 'blob sig2')
1042 # white list for empty regions
Patrick Georgi56dc9202016-09-07 21:12:04 +02001043 elif label in ['bootblock', 'misc-rw', 'ro-section', 'rw-environment',
1044 'rw-gpt', 'si-all', 'si-bios', 'si-me', 'wp-ro']:
Patrick Georgicebb5a22016-08-15 19:07:02 +02001045 pass
1046 else:
1047 raise ValueError('encountered label "'+label+'" in binary fmap. '+
1048 'Check chromeos.fmd')
1049 fdt.PutString(fdt_path, 'label', label)
1050 fdt.PutIntList(fdt_path, 'reg', [area['offset'], area['size']])
1051
Julius Wernerbcf0c942016-09-07 16:57:40 -07001052 if coreboot_range is not None:
1053 if bootblock_range is not None:
1054 if bootblock_range[0] + bootblock_range[1] != coreboot_range[0]:
1055 raise ValueError('Cannot combine BOOTBLOCK and COREBOOT')
1056 coreboot_range[0] = bootblock_range[0]
1057 coreboot_range[1] += bootblock_range[1]
1058 fdt_path = '/flash/ro-boot'
1059 fdt.PutString(fdt_path, 'type', 'blob coreboot')
1060 fdt.PutString(fdt_path, 'label', 'coreboot')
1061 fdt.PutIntList(fdt_path, 'reg', [coreboot_range[0], coreboot_range[1]])
1062
Simon Glass7df773b2013-08-25 18:02:29 -06001063 # Remember our board type.
1064 fdt.PutString('/chromeos-config', 'board', self._board)
1065
Simon Glasse53abbc2013-08-21 22:29:55 -06001066 self.fdt = fdt
1067 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001068
Simon Glassc90cf582012-03-13 15:40:47 -07001069 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001070 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001071
1072 - Checks options, tools, output directory, fdt.
1073 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001074
1075 Args:
Simon Glass56577572011-07-19 11:08:06 +12001076 hardware_id: Hardware ID to use for this board. If None, then the
1077 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001078 output_fname: Output filename for the image. If this is not None, then
1079 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001080 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001081
1082 Returns:
1083 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001084 """
Vadim Bendebury5baeec12013-04-02 13:01:22 -07001085 if self._small or self.fdt.GetProp('/config', 'nogbb', 'any') != 'any':
1086 gbb = '' # Building a small image or `nogbb' is requested in device tree.
1087 else:
Simon Glass56577572011-07-19 11:08:06 +12001088 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001089
1090 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001091 image, pack = self._CreateImage(gbb, self.fdt)
1092 if show_map:
1093 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001094 if output_fname:
1095 shutil.copyfile(image, output_fname)
1096 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001097 return image, pack.props