blob: a159aa4b9c77a4a446a862117a2538e0b41d7bed [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
Simon Glass89b86b82011-07-17 23:49:49 -070029
Simon Glass4a887b12012-10-23 16:29:03 -070030# Build GBB flags.
31# (src/platform/vboot_reference/firmware/include/gbb_header.h)
32gbb_flag_properties = {
33 'dev-screen-short-delay': 0x00000001,
34 'load-option-roms': 0x00000002,
35 'enable-alternate-os': 0x00000004,
36 'force-dev-switch-on': 0x00000008,
37 'force-dev-boot-usb': 0x00000010,
38 'disable-fw-rollback-check': 0x00000020,
39 'enter-triggers-tonorm': 0x00000040,
40 'force-dev-boot-legacy': 0x00000080,
Shawn Nematbakhsh07c19882014-08-19 10:21:59 -070041 'faft-key-overide': 0x00000100,
42 'disable-ec-software-sync': 0x00000200,
43 'default-dev-boot-legacy': 0x00000400,
44 'disable-pd-software-sync': 0x00000800,
Furquan Shaikhd4eac3b2015-05-15 18:05:09 -070045 'force-dev-boot-fastboot-full-cap': 0x00002000,
Mary Ruthvena759c322015-11-16 08:23:26 -080046 'enable-serial': 0x00004000,
Simon Glass4a887b12012-10-23 16:29:03 -070047}
48
Simon Glass49b026b2013-04-26 16:38:42 -070049# Maps board name to Exynos product number
50type_to_model = {
51 'peach' : '5420',
52 'daisy' : '5250'
53}
54
Simon Glass5076a7f2012-10-23 16:31:54 -070055def ListGoogleBinaryBlockFlags():
56 """Print out a list of GBB flags."""
57 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
58 for name, value in gbb_flag_properties.iteritems():
59 print ' %-30s %02x' % (name, value)
60
Simon Glass89b86b82011-07-17 23:49:49 -070061class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070062 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070063
Simon Glass290a1802011-07-17 13:54:32 -070064 Sequence of events:
65 bundle = Bundle(tools.Tools(), cros_output.Output())
66 bundle.SetDirs(...)
67 bundle.SetFiles(...)
68 bundle.SetOptions(...)
69 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070070 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070071 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070072
Simon Glass290a1802011-07-17 13:54:32 -070073 Public properties:
74 fdt: The fdt object that we use for building our image. This wil be the
75 one specified by the user, except that we might add config options
76 to it. This is set up by SelectFdt() which must be called before
77 bundling starts.
78 uboot_fname: Full filename of the U-Boot binary we use.
79 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -070080 spl_source: Source device to load U-Boot from, in SPL:
81 straps: Select device according to CPU strap pins
82 spi: Boot from SPI
83 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -070084
85 Private attributes:
86 _small: True to create a 'small' signed U-Boot, False to produce a
87 full image. The small U-Boot is enough to boot but will not have
88 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -070089 """
Simon Glass89b86b82011-07-17 23:49:49 -070090
Simon Glass290a1802011-07-17 13:54:32 -070091 def __init__(self, tools, output):
92 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -070093
Simon Glass290a1802011-07-17 13:54:32 -070094 Args:
95 tools: A tools.Tools object to use for external tools.
96 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -070097 """
Simon Glass290a1802011-07-17 13:54:32 -070098 self._tools = tools
99 self._out = output
100
101 # Set up the things we need to know in order to operate.
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500102 self._board = None # Board name, e.g. nyan.
Simon Glass290a1802011-07-17 13:54:32 -0700103 self._fdt_fname = None # Filename of our FDT.
Simon Glass00d027e2013-07-20 14:51:12 -0600104 self._force_efs = None
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700105 self._gbb_flags = None
106 self._keydir = None
107 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700108 self.bct_fname = None # Filename of our BCT file.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700109 self.blobs = {} # Table of (type, filename) of arbitrary blobs
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700110 self.coreboot_elf = None
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700111 self.coreboot_fname = None # Filename of our coreboot binary.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700112 self.ecro_fname = None # Filename of EC read-only file
113 self.ecrw_fname = None # Filename of EC file
Randall Spangler7307da92014-07-18 12:47:34 -0700114 self.pdrw_fname = None # Filename of PD file
Simon Glass7e199222012-03-13 15:51:18 -0700115 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
116 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700117 self.fdt = None # Our Fdt object.
118 self.kernel_fname = None
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700119 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass07267952012-06-08 12:45:13 -0700120 self.skeleton_fname = None # Filename of Coreboot skeleton file
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700121 self.uboot_fname = None # Filename of our U-Boot binary.
Patrick Georgi29d2eed2016-10-12 15:45:08 +0200122 self.bootstub = None
123 self.cb_copy = None
Simon Glass290a1802011-07-17 13:54:32 -0700124
125 def SetDirs(self, keydir):
126 """Set up directories required for Bundle.
127
128 Args:
129 keydir: Directory containing keys to use for signing firmware.
130 """
131 self._keydir = keydir
132
Patrick Georgi48030572016-09-09 22:55:46 +0200133 def SetFiles(self, board, bct, uboot=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800134 coreboot_elf=None,
Simon Glass942bedb2016-05-14 16:19:59 -0600135 seabios=None, exynos_bl1=None, exynos_bl2=None,
Randall Spangler7307da92014-07-18 12:47:34 -0700136 skeleton=None, ecrw=None, ecro=None, pdrw=None,
Patrick Georgi48030572016-09-09 22:55:46 +0200137 kernel=None, blobs=None, cbfs_files=None,
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600138 rocbfs_files=None):
Simon Glass290a1802011-07-17 13:54:32 -0700139 """Set up files required for Bundle.
140
141 Args:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500142 board: The name of the board to target (e.g. nyan).
Simon Glass290a1802011-07-17 13:54:32 -0700143 uboot: The filename of the u-boot.bin image to use.
144 bct: The filename of the binary BCT file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800145 coreboot: The filename of the coreboot image to use (on x86).
146 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Vincent Palatinf7286772011-10-12 14:31:53 -0700147 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700148 exynos_bl1: The filename of the exynos BL1 file
149 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
150 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700151 ecrw: The filename of the EC (Embedded Controller) read-write file.
152 ecro: The filename of the EC (Embedded Controller) read-only file.
Randall Spangler7307da92014-07-18 12:47:34 -0700153 pdrw: The filename of the PD (PD embedded controller) read-write file.
Simon Glassde9c8072012-07-02 22:29:02 -0700154 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800155 blobs: List of (type, filename) of arbitrary blobs.
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600156 cbfs_files: Root directory of files to be stored in RO and RW CBFS
157 rocbfs_files: Root directory of files to be stored in RO CBFS
Simon Glass290a1802011-07-17 13:54:32 -0700158 """
159 self._board = board
160 self.uboot_fname = uboot
161 self.bct_fname = bct
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700162 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800163 self.coreboot_elf = coreboot_elf
Vincent Palatinf7286772011-10-12 14:31:53 -0700164 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700165 self.exynos_bl1 = exynos_bl1
166 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700167 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700168 self.ecrw_fname = ecrw
169 self.ecro_fname = ecro
Randall Spangler7307da92014-07-18 12:47:34 -0700170 self.pdrw_fname = pdrw
Simon Glassde9c8072012-07-02 22:29:02 -0700171 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800172 self.blobs = dict(blobs or ())
Daisuke Nojiri69662892015-09-25 15:24:04 -0700173 self.cbfs_files = cbfs_files
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600174 self.rocbfs_files = rocbfs_files
Simon Glass290a1802011-07-17 13:54:32 -0700175
Patrick Georgi450204a2016-08-15 19:13:29 +0200176 def SetOptions(self, small, gbb_flags, force_efs=False):
Simon Glass290a1802011-07-17 13:54:32 -0700177 """Set up options supported by Bundle.
178
179 Args:
180 small: Only create a signed U-Boot - don't produce the full packed
181 firmware image. This is useful for devs who want to replace just the
182 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700183 gbb_flags: Specification for string containing adjustments to make.
Simon Glass00d027e2013-07-20 14:51:12 -0600184 force_efs: Force firmware to use 'early firmware selection' feature,
185 where RW firmware is selected before SDRAM is initialized.
Simon Glass290a1802011-07-17 13:54:32 -0700186 """
187 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700188 self._gbb_flags = gbb_flags
Simon Glass00d027e2013-07-20 14:51:12 -0600189 self._force_efs = force_efs
Simon Glass290a1802011-07-17 13:54:32 -0700190
Simon Glass22f39fb2013-02-09 13:44:14 -0800191 def _GetBuildRoot(self):
192 """Get the path to this board's 'firmware' directory.
193
194 Returns:
195 Path to firmware directory, with ## representing the path to the
196 chroot.
197 """
Simon Glass290a1802011-07-17 13:54:32 -0700198 if not self._board:
199 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800200 return os.path.join('##', 'build', self._board, 'firmware')
201
202 def _CheckFdtFilename(self, fname):
203 """Check provided FDT filename and return the correct name if needed.
204
205 Where the filename lacks a path, add a default path for this board.
206 Where no FDT filename is provided, select a default one for this board.
207
208 Args:
209 fname: Proposed FDT filename.
210
211 Returns:
212 Selected FDT filename, after validation.
213 """
214 build_root = self._GetBuildRoot()
Julius Wernerb4b14392013-08-09 14:41:40 -0700215 dir_name = os.path.join(build_root, 'dtb')
Simon Glass22f39fb2013-02-09 13:44:14 -0800216 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700217 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700218 base_name = re.sub('_', '-', self._board)
219
220 # In case the name exists with a prefix or suffix, find it.
Julius Wernerb4b14392013-08-09 14:41:40 -0700221 wildcard = os.path.join(dir_name, '*%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700222 found_list = glob.glob(self._tools.Filename(wildcard))
223 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800224 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700225 else:
226 # We didn't find anything definite, so set up our expected name.
Julius Wernerb4b14392013-08-09 14:41:40 -0700227 fname = os.path.join(dir_name, '%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700228
Simon Glass881964d2012-04-04 11:34:09 -0700229 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800230 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700231 if not ext and not os.path.dirname(root):
Julius Wernerb4b14392013-08-09 14:41:40 -0700232 fname = os.path.join(dir_name, '%s.dtb' % root)
Simon Glass22f39fb2013-02-09 13:44:14 -0800233 return fname
234
235 def CheckOptions(self):
236 """Check provided options and select defaults."""
237 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700238
Simon Glass49b026b2013-04-26 16:38:42 -0700239 board_type = self._board.split('_')[0]
240 model = type_to_model.get(board_type)
241
Simon Glass290a1802011-07-17 13:54:32 -0700242 if not self.uboot_fname:
243 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
244 if not self.bct_fname:
245 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass49b026b2013-04-26 16:38:42 -0700246 if model:
247 if not self.exynos_bl1:
Simon Glassd05696e2013-06-13 20:14:00 -0700248 self.exynos_bl1 = os.path.join(build_root, 'u-boot.bl1.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700249 if not self.exynos_bl2:
Julius Wernerb12c0052013-08-14 13:57:04 -0700250 self.exynos_bl2 = os.path.join(build_root, 'u-boot-spl.wrapped.bin')
Simon Glass07267952012-06-08 12:45:13 -0700251 if not self.coreboot_fname:
252 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
253 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700254 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Simon Glassbe0bc002012-08-16 12:50:48 -0700255 if not self.ecrw_fname:
256 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
Randall Spangler7307da92014-07-18 12:47:34 -0700257 if not self.pdrw_fname:
258 self.pdrw_fname = os.path.join(build_root, 'pd.RW.bin')
Simon Glassbe0bc002012-08-16 12:50:48 -0700259 if not self.ecro_fname:
260 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700261
Simon Glass75759302012-03-15 20:26:53 -0700262 def GetFiles(self):
263 """Get a list of files that we know about.
264
265 This is the opposite of SetFiles except that we may have put in some
266 default names. It returns a dictionary containing the filename for
267 each of a number of pre-defined files.
268
269 Returns:
270 Dictionary, with one entry for each file.
271 """
272 file_list = {
273 'bct' : self.bct_fname,
274 'exynos-bl1' : self.exynos_bl1,
275 'exynos-bl2' : self.exynos_bl2,
276 }
277 return file_list
278
Simon Glass4a887b12012-10-23 16:29:03 -0700279 def DecodeGBBFlagsFromFdt(self):
280 """Get Google Binary Block flags from the FDT.
281
282 These should be in the chromeos-config node, like this:
283
284 chromeos-config {
285 gbb-flag-dev-screen-short-delay;
286 gbb-flag-force-dev-switch-on;
287 gbb-flag-force-dev-boot-usb;
288 gbb-flag-disable-fw-rollback-check;
289 };
290
291 Returns:
292 GBB flags value from FDT.
293 """
294 chromeos_config = self.fdt.GetProps("/chromeos-config")
295 gbb_flags = 0
296 for name in chromeos_config:
297 if name.startswith('gbb-flag-'):
298 flag_value = gbb_flag_properties.get(name[9:])
299 if flag_value:
300 gbb_flags |= flag_value
301 self._out.Notice("FDT: Enabling %s." % name)
302 else:
303 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
304 return gbb_flags
305
Simon Glass157c0662012-10-23 13:52:42 -0700306 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
307 """Decode ajustments to the provided GBB flags.
308
309 We support three options:
310
311 hex value: c2
312 defined value: force-dev-boot-usb,load-option-roms
313 adjust default value: -load-option-roms,+force-dev-boot-usb
314
315 The last option starts from the passed-in GBB flags and adds or removes
316 flags.
317
318 Args:
319 gbb_flags: Base (default) FDT flags.
320 adjustments: String containing adjustments to make.
321
322 Returns:
323 Updated FDT flags.
324 """
325 use_base_value = True
326 if adjustments:
327 try:
328 return int(adjustments, base=16)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700329 except (ValueError, TypeError):
Simon Glass157c0662012-10-23 13:52:42 -0700330 pass
331 for flag in adjustments.split(','):
332 oper = None
333 if flag[0] in ['-', '+']:
334 oper = flag[0]
335 flag = flag[1:]
336 value = gbb_flag_properties.get(flag)
337 if not value:
338 raise ValueError("Invalid GBB flag '%s'" % flag)
339 if oper == '+':
340 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800341 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700342 elif oper == '-':
343 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800344 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700345 else:
346 if use_base_value:
347 gbb_flags = 0
348 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800349 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700350 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800351 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700352
353 return gbb_flags
354
Simon Glass56577572011-07-19 11:08:06 +1200355 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700356 """Create a GBB for the image.
357
Simon Glass56577572011-07-19 11:08:06 +1200358 Args:
359 hardware_id: Hardware ID to use for this board. If None, then the
360 default from the Fdt will be used
361
Simon Glass89b86b82011-07-17 23:49:49 -0700362 Returns:
363 Path of the created GBB file.
Simon Glass89b86b82011-07-17 23:49:49 -0700364 """
Simon Glass56577572011-07-19 11:08:06 +1200365 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800366 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700367 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700368 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700369
Simon Glass4a887b12012-10-23 16:29:03 -0700370 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800371
Simon Glass157c0662012-10-23 13:52:42 -0700372 # Allow command line to override flags
373 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
374
Simon Glass4a887b12012-10-23 16:29:03 -0700375 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700376 self._out.Progress('Creating GBB')
Patrick Georgi48030572016-09-09 22:55:46 +0200377 sizes = [0x100, 0x1000, 0, 0x1000]
Simon Glass89b86b82011-07-17 23:49:49 -0700378 sizes = ['%#x' % size for size in sizes]
379 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700380 keydir = self._tools.Filename(self._keydir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800381
382 gbb_set_command = ['-s',
383 '--hwid=%s' % hardware_id,
384 '--rootkey=%s/root_key.vbpubk' % keydir,
385 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
386 '--flags=%d' % gbb_flags,
387 gbb]
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800388
Simon Glass290a1802011-07-17 13:54:32 -0700389 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800390 self._tools.Run('gbb_utility', gbb_set_command, cwd=odir)
Simon Glass290a1802011-07-17 13:54:32 -0700391 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700392
Simon Glasse13ee2c2011-07-28 08:12:28 +1200393 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700394 """Sign an image so that the Tegra SOC will boot it.
395
396 Args:
397 bct: BCT file to use.
398 bootstub: Boot stub (U-Boot + fdt) file to sign.
399 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700400
401 Returns:
402 filename of signed image.
Simon Glass89b86b82011-07-17 23:49:49 -0700403 """
404 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200405 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700406 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200407 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700408 fd = open(config, 'w')
409 fd.write('Version = 1;\n')
410 fd.write('Redundancy = 1;\n')
411 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700412
413 # TODO(dianders): Right now, we don't have enough space in our flash map
414 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
415 # sure what this does for reliability, but at least things will fit...
416 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
417 if is_nand:
418 fd.write('Bctcopy = 1;\n')
419
Simon Glass89b86b82011-07-17 23:49:49 -0700420 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
421 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700422
Simon Glass89b86b82011-07-17 23:49:49 -0700423 fd.close()
424
425 self._tools.Run('cbootimage', [config, signed])
426 self._tools.OutputSize('BCT', bct)
427 self._tools.OutputSize('Signed image', signed)
428 return signed
429
Doug Anderson86ce5f42011-07-27 10:40:18 -0700430 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700431 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700432
433 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700434 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700435 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700436 """
Simon Glass468d8752012-09-19 16:36:19 -0700437 if bootcmd is not None:
438 if bootcmd == 'none':
439 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800440 self.fdt.PutString('/config', 'bootcmd', bootcmd)
441 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700442 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700443
Simon Glassa4934b72012-05-09 13:35:02 -0700444 def SetNodeEnabled(self, node_name, enabled):
445 """Set whether an node is enabled or disabled.
446
447 This simply sets the 'status' property of a node to "ok", or "disabled".
448
449 The node should either be a full path to the node (like '/uart@10200000')
450 or an alias property.
451
452 Aliases are supported like this:
453
454 aliases {
455 console = "/uart@10200000";
456 };
457
458 pointing to a node:
459
460 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700461 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700462 };
463
464 In this case, this function takes the name of the alias ('console' in
465 this case) and updates the status of the node that is pointed to, to
466 either ok or disabled. If the alias does not exist, a warning is
467 displayed.
468
469 Args:
470 node_name: Name of node (e.g. '/uart@10200000') or alias alias
471 (e.g. 'console') to adjust
472 enabled: True to enable, False to disable
473 """
474 # Look up the alias if this is an alias reference
475 if not node_name.startswith('/'):
476 lookup = self.fdt.GetString('/aliases', node_name, '')
477 if not lookup:
478 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
479 return
480 node_name = lookup
481 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700482 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700483 else:
484 status = 'disabled'
485 self.fdt.PutString(node_name, 'status', status)
486
487 def AddEnableList(self, enable_list):
488 """Process a list of nodes to enable/disable.
489
490 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700491 enable_list: List of (node, value) tuples to add to the fdt. For each
Simon Glassa4934b72012-05-09 13:35:02 -0700492 tuple:
493 node: The fdt node to write to will be <node> or pointed to by
494 /aliases/<node>. We can tell which
495 value: 0 to disable the node, 1 to enable it
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700496
Vadim Bendebury507c0012013-06-09 12:49:25 -0700497 Raises:
498 CmdError if a command fails.
Simon Glassa4934b72012-05-09 13:35:02 -0700499 """
500 if enable_list:
501 for node_name, enabled in enable_list:
502 try:
503 enabled = int(enabled)
504 if enabled not in (0, 1):
505 raise ValueError
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700506 except ValueError:
Simon Glassa4934b72012-05-09 13:35:02 -0700507 raise CmdError("Invalid enable option value '%s' "
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700508 "(should be 0 or 1)" % str(enabled))
Simon Glassa4934b72012-05-09 13:35:02 -0700509 self.SetNodeEnabled(node_name, enabled)
510
Simon Glass290a1802011-07-17 13:54:32 -0700511 def AddConfigList(self, config_list, use_int=False):
512 """Add a list of config items to the fdt.
513
514 Normally these values are written to the fdt as strings, but integers
515 are also supported, in which case the values will be converted to integers
516 (if necessary) before being stored.
517
518 Args:
519 config_list: List of (config, value) tuples to add to the fdt. For each
520 tuple:
521 config: The fdt node to write to will be /config/<config>.
522 value: An integer or string value to write.
523 use_int: True to only write integer values.
524
525 Raises:
526 CmdError: if a value is required to be converted to integer but can't be.
527 """
528 if config_list:
529 for config in config_list:
530 value = config[1]
531 if use_int:
532 try:
533 value = int(value)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700534 except ValueError:
Simon Glass290a1802011-07-17 13:54:32 -0700535 raise CmdError("Cannot convert config option '%s' to integer" %
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700536 str(value))
Simon Glass290a1802011-07-17 13:54:32 -0700537 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800538 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700539 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800540 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700541
Simon Glass7c2d5572011-11-15 14:47:08 -0800542 def DecodeTextBase(self, data):
543 """Look at a U-Boot image and try to decode its TEXT_BASE.
544
545 This works because U-Boot has a header with the value 0x12345678
546 immediately followed by the TEXT_BASE value. We can therefore read this
547 from the image with some certainty. We check only the first 40 words
548 since the header should be within that region.
549
Simon Glass96b50302012-07-20 06:55:28 +0100550 Since upstream Tegra has moved to having a 16KB SPL region at the start,
551 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
552 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
553
Simon Glass7c2d5572011-11-15 14:47:08 -0800554 Args:
555 data: U-Boot binary data
556
557 Returns:
558 Text base (integer) or None if none was found
559 """
560 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100561 for start in (0, 0x4000):
562 for i in range(start, start + 160, 4):
563 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800564
Simon Glass96b50302012-07-20 06:55:28 +0100565 # TODO(sjg): This does not cope with a big-endian target
566 value = struct.unpack('<I', word)[0]
567 if found:
568 return value - start
569 if value == 0x12345678:
570 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800571
572 return None
573
574 def CalcTextBase(self, name, fdt, fname):
575 """Calculate the TEXT_BASE to use for U-Boot.
576
577 Normally this value is in the fdt, so we just read it from there. But as
578 a second check we look at the image itself in case this is different, and
579 switch to that if it is.
580
581 This allows us to flash any U-Boot even if its TEXT_BASE is different.
582 This is particularly useful with upstream U-Boot which uses a different
583 value (which we will move to).
584 """
585 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800586 # The value that comes back from fdt.GetInt is signed, which makes no
587 # sense for an address base. Force it to unsigned.
588 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800589 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100590 text_base_str = '%#x' % text_base if text_base else 'None'
591 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
592 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800593
594 # If they are different, issue a warning and switch over.
595 if text_base and text_base != fdt_text_base:
596 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
597 "fdt value of %x. Using %x" % (text_base, name,
598 fdt_text_base, text_base))
599 fdt_text_base = text_base
600 return fdt_text_base
601
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600602 def _AddCbfsFiles(self, bootstub, cbfs_files):
603 for dir, subs, files in os.walk(cbfs_files):
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600604 for file in files:
605 file = os.path.join(dir, file)
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600606 cbfs_name = file.replace(cbfs_files, '', 1).strip('/')
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600607 self._tools.Run('cbfstool', [bootstub, 'add', '-f', file,
608 '-n', cbfs_name, '-t', 'raw', '-c', 'lzma'])
609
Patrick Georgi29d2eed2016-10-12 15:45:08 +0200610 def _CreateCorebootStub(self, coreboot):
611 """Create a coreboot boot stub.
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700612
613 Args:
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700614 coreboot: Path to coreboot.rom
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700615 """
616 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700617 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100618
Patrick Georgi29d2eed2016-10-12 15:45:08 +0200619 self.bootstub = bootstub
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700620
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600621 # Add files to to RO and RW CBFS if provided.
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600622 if self.cbfs_files:
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600623 self._AddCbfsFiles(bootstub, self.cbfs_files)
Simon Glass7e199222012-03-13 15:51:18 -0700624
Aaron Durbina113f522016-01-05 09:09:55 -0600625 # Create a coreboot copy to use as a scratch pad. Order matters. The
626 # cbfs_files were added prior to this action. That's so the RW CBFS
Patrick Georgi45b64b82016-10-05 16:35:27 +0200627 # regions inherit the files from the RO CBFS region.
Patrick Georgi3a332672015-11-20 10:02:51 +0100628 cb_copy = os.path.abspath(os.path.join(self._tools.outdir, 'cb_with_fmap'))
Aaron Durbina113f522016-01-05 09:09:55 -0600629 self._tools.WriteFile(cb_copy, self._tools.ReadFile(bootstub))
Patrick Georgi3a332672015-11-20 10:02:51 +0100630 binary = self._tools.ReadFile(bootstub)
Patrick Georgi3a332672015-11-20 10:02:51 +0100631 self._tools.WriteFile(cb_copy, binary)
Patrick Georgi29d2eed2016-10-12 15:45:08 +0200632
633 self.cb_copy = cb_copy
Aaron Durbina113f522016-01-05 09:09:55 -0600634
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600635 # Add files to to RO CBFS if provided. This done here such that the
636 # copy above does not contain the RO CBFS files.
637 if self.rocbfs_files:
638 self._AddCbfsFiles(bootstub, self.rocbfs_files)
639
Aaron Durbina113f522016-01-05 09:09:55 -0600640
Simon Glass89b86b82011-07-17 23:49:49 -0700641 def _PackOutput(self, msg):
642 """Helper function to write output from PackFirmware (verbose level 2).
643
644 This is passed to PackFirmware for it to use to write output.
645
646 Args:
647 msg: Message to display.
648 """
649 self._out.Notice(msg)
650
Patrick Georgic1064f42016-10-12 11:34:24 +0200651 def _FdtNameToFmap(self, fdtstr):
652 return re.sub('-', '_', fdtstr).upper()
653
Aaron Durbin80564452015-12-21 15:25:06 -0600654 def _FmapNameByPath(self, path):
655 """ Take list of names to form node path. Return FMAP name.
656
657 Obtain the FMAP name described by the node path.
658
659 Args:
660 path: list forming a node path.
661
662 Returns:
663 FMAP name of fdt node.
664
665 Raises:
666 CmdError if path not found.
667 """
668 lbl = self.fdt.GetLabel(self.fdt.GetFlashNode(*path))
Patrick Georgic1064f42016-10-12 11:34:24 +0200669 return self._FdtNameToFmap(lbl)
Aaron Durbin80564452015-12-21 15:25:06 -0600670
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800671 def _PrepareCbfs(self, pack, blob_name):
672 """Create CBFS blob in rw-boot-{a,b} FMAP sections.
673
674 When the blob name is defined as cbfs#<section>#<subsection>, fill the
675 <section>_<subsection> area in the flash map with a CBFS copy, putting the
676 CBFS header of the copy at the base of the section.
677
678 If --coreboot-elf parameter was specified during cros_bumdle_firmware
679 invocation, add the parameter of this option as the payload to the new
680 CBFS instance.
681
682 Args:
683 pack: a PackFirmware object describing the firmware image to build.
684 blob_name: a string, blob name describing what FMAP section this CBFS
685 copy is destined to
686 Raises:
Patrick Georgi3a332672015-11-20 10:02:51 +0100687 CmdError if cbfs-files node has incorrect parameters.
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800688 """
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800689 part_sections = blob_name.split('/')[1:]
Aaron Durbin80564452015-12-21 15:25:06 -0600690 fmap_dst = self._FmapNameByPath(part_sections)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800691
692 # Base address and size of the desitnation partition
693 base, size = self.fdt.GetFlashPart(*part_sections)
694
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800695 # Add coreboot payload if so requested. Note that the some images use
696 # different payload for the rw sections, which is passed in as the value
697 # of the --uboot option in the command line.
698 if self.uboot_fname:
699 payload_fname = self.uboot_fname
700 elif self.coreboot_elf:
701 payload_fname = self.coreboot_elf
702 else:
703 payload_fname = None
704
705 if payload_fname:
706 self._tools.Run('cbfstool', [
Patrick Georgi69d47622016-10-12 15:53:06 +0200707 self.cb_copy, 'add-payload', '-f', payload_fname,
Patrick Georgi10690b42015-11-20 22:06:38 +0100708 '-n', 'fallback/payload', '-c', 'lzma' , '-r', fmap_dst])
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800709
Patrick Georgi964fb542015-10-16 16:52:03 +0200710 if self.ecrw_fname:
711 self._tools.Run('cbfstool', [
Patrick Georgi69d47622016-10-12 15:53:06 +0200712 self.cb_copy, 'add', '-f', self.ecrw_fname, '-t', 'raw',
Patrick Georgi10690b42015-11-20 22:06:38 +0100713 '-n', 'ecrw', '-A', 'sha256', '-r', fmap_dst ])
Patrick Georgi964fb542015-10-16 16:52:03 +0200714
715 if self.pdrw_fname:
716 self._tools.Run('cbfstool', [
Patrick Georgi69d47622016-10-12 15:53:06 +0200717 self.cb_copy, 'add', '-f', self.pdrw_fname, '-t', 'raw',
Patrick Georgi10690b42015-11-20 22:06:38 +0100718 '-n', 'pdrw', '-A', 'sha256', '-r', fmap_dst ])
Patrick Georgi964fb542015-10-16 16:52:03 +0200719
Aaron Durbin880cf952016-01-27 14:11:38 -0600720 # Parse the file list to obtain the last entry. If its empty use its
721 # offset as the size of the CBFS to hash.
722 stdout = self._tools.Run('cbfstool',
Patrick Georgi69d47622016-10-12 15:53:06 +0200723 [ self.cb_copy, 'print', '-k', '-r', fmap_dst ])
Aaron Durbin880cf952016-01-27 14:11:38 -0600724 # Fields are tab separated in the following order.
725 # Name Offset Type Metadata Size Data Size Total Size
726 last_entry = stdout.strip().splitlines()[-1].split('\t')
727 if last_entry[0] == '(empty)' and last_entry[2] == 'null':
728 size = int(last_entry[1], 16)
729
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800730 # And extract the blob for the FW section
731 rw_section = os.path.join(self._tools.outdir, '_'.join(part_sections))
732 self._tools.WriteFile(rw_section,
Patrick Georgi69d47622016-10-12 15:53:06 +0200733 self._tools.ReadFile(self.cb_copy)[base:base+size])
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800734
735 pack.AddProperty(blob_name, rw_section)
736
Patrick Georgidf772712016-10-05 16:24:20 +0200737 def _PrepareBootblock(self, pack):
738 """Copy bootblock into blob file for packaging
739
740 Args:
741 pack: a PackFirmware object describing the firmware image to build.
742 Raises:
743 CmdError if cbfs-files node has incorrect parameters.
744 """
Patrick Georgidf772712016-10-05 16:24:20 +0200745 bootblock_section = os.path.join(self._tools.outdir, 'bootblock.section')
746
747 self._tools.Run('cbfstool', [
Patrick Georgi69d47622016-10-12 15:53:06 +0200748 self.cb_copy, 'read', '-r', 'BOOTBLOCK', '-f', bootblock_section])
Patrick Georgidf772712016-10-05 16:24:20 +0200749
750 pack.AddProperty('bootblock', bootblock_section)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800751
Simon Glass439fe7a2012-03-09 16:19:34 -0800752 def _BuildBlob(self, pack, fdt, blob_type):
753 """Build the blob data for a particular blob type.
754
755 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700756 pack: a PackFirmware object describing the firmware image to build.
757 fdt: an fdt object including image layout information
Simon Glass439fe7a2012-03-09 16:19:34 -0800758 blob_type: The type of blob to create data for. Supported types are:
759 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
760 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
Vadim Bendebury507c0012013-06-09 12:49:25 -0700761
762 Raises:
763 CmdError if a command fails.
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':
Patrick Georgi69d47622016-10-12 15:53:06 +0200768 self._tools.Run('cbfstool', [self.cb_copy, 'write',
Patrick Georgi44092222016-10-12 12:15:48 +0200769 '-f', self.seabios_fname,
770 '--force',
771 '-r', 'RW_LEGACY'])
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700772 pack.AddProperty('legacy', self.seabios_fname)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800773 elif blob_type.startswith('cbfs'):
774 self._PrepareCbfs(pack, blob_type)
Patrick Georgidf772712016-10-05 16:24:20 +0200775 elif blob_type == 'bootblock':
776 self._PrepareBootblock(pack)
Simon Glass439fe7a2012-03-09 16:19:34 -0800777 elif pack.GetProperty(blob_type):
778 pass
Furquan Shaikh95ee50c2016-05-29 09:46:41 -0700779 elif blob_type == 'ifwi' or blob_type == 'sig2':
780 # Copy IFWI/CSE_SIGN(sig2) regions from coreboot copy and build a blob
781 # for the blob_type
Furquan Shaikh95ee50c2016-05-29 09:46:41 -0700782 blob_start, blob_size = fdt.GetFlashPart('ro', blob_type)
783 blob_file = blob_type + '.bin'
784 blob_path = os.path.join(self._tools.outdir, blob_file)
Patrick Georgi69d47622016-10-12 15:53:06 +0200785 data = self._tools.ReadFile(self.cb_copy)
Furquan Shaikh95ee50c2016-05-29 09:46:41 -0700786 self._tools.WriteFile(blob_path, data[blob_start:blob_start+blob_size])
787 pack.AddProperty(blob_type, blob_path)
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800788 elif blob_type in self.blobs:
Patrick Georgi69d47622016-10-12 15:53:06 +0200789 self._tools.Run('cbfstool', [self.cb_copy, 'write',
Patrick Georgi44092222016-10-12 12:15:48 +0200790 '--fill-upward',
791 '-f', self.blobs[blob_type],
792 '-r', _FdtNameToFmap(blob_type)])
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800793 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -0800794 else:
795 raise CmdError("Unknown blob type '%s' required in flash map" %
796 blob_type)
797
Aaron Durbin41c85b62015-12-17 17:40:29 -0600798 def _BuildBlobs(self, pack, fdt):
799 """Build the blob data for the list of blobs in the pack.
800
801 Args:
802 pack: a PackFirmware object describing the firmware image to build.
803 fdt: an fdt object including image layout information
804
805 Raises:
806 CmdError if a command fails.
Aaron Durbin41c85b62015-12-17 17:40:29 -0600807 """
808 blob_list = pack.GetBlobList()
809 self._out.Info('Building blobs %s\n' % blob_list)
810
811 complete = False
812 deferred_list = []
813
Patrick Georgifa20ddc2016-09-27 14:10:51 +0200814 # We always have a coreboot blob, and some other components rely on it, so
815 # make sure it's ready when the others come in.
816 blob_list.remove('coreboot')
Patrick Georgi29d2eed2016-10-12 15:45:08 +0200817 self._CreateCorebootStub(self.coreboot_fname)
818
819 pack.AddProperty('coreboot', self.bootstub)
820 pack.AddProperty('image', self.bootstub)
Patrick Georgifa20ddc2016-09-27 14:10:51 +0200821
Patrick Georgi49cf7b22016-09-27 14:25:03 +0200822 for blob_type in blob_list:
823 self._BuildBlob(pack, fdt, blob_type)
Aaron Durbin41c85b62015-12-17 17:40:29 -0600824
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200825 def _BuildKeyblocks(self, pack):
826 """Compute vblocks and write them into their FMAP regions.
827 Works for the (VBLOCK_?,FW_MAIN_?) pairs
828 """
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200829 fmap_blob = open(self.coreboot_fname).read()
830 f = fmap.fmap_decode(fmap_blob)
831 for area in f['areas']:
832 label = area['name']
833 slot = label[-1]
834 if label[:-1] == 'VBLOCK_':
835 region_in = 'FW_MAIN_' + slot
836 region_out = label
837
838 input_data = os.path.join(self._tools.outdir, 'input.%s' % region_in)
839 output_data = os.path.join(self._tools.outdir, 'vblock.%s' % region_out)
840 self._tools.Run('cbfstool', [
Patrick Georgi69d47622016-10-12 15:53:06 +0200841 self.cb_copy, 'read', '-r', region_in, '-f', input_data])
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200842
843 # Parse the file list to obtain the last entry. If its empty use
844 # its offset as the size of the CBFS to hash.
845 stdout = self._tools.Run('cbfstool',
Patrick Georgi69d47622016-10-12 15:53:06 +0200846 [ self.cb_copy, 'print', '-k', '-r', region_in ])
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200847 # Fields are tab separated in the following order.
848 # Name Offset Type Metadata Size Data Size Total Size
849 last_entry = stdout.strip().splitlines()[-1].split('\t')
850 if last_entry[0] == '(empty)' and last_entry[2] == 'null':
851 size = int(last_entry[1], 16)
852 self._tools.Run('truncate', [
853 '--no-create', '--size', str(size), input_data])
854 self._out.Info('truncated FW_MAIN_%s to %d bytes' %
855 (slot, size))
856
857 try:
858 prefix = self._keydir + '/'
859
860 self._tools.Run('vbutil_firmware', [
861 '--vblock', output_data,
862 '--keyblock', prefix + 'firmware.keyblock',
863 '--signprivate', prefix + 'firmware_data_key.vbprivk',
864 '--version', '1',
865 '--fv', input_data,
866 '--kernelkey', prefix + 'kernel_subkey.vbpubk',
867 '--flags', '0',
868 ])
869
870 except CmdError as err:
871 raise PackError('Cannot make key block: vbutil_firmware failed\n%s' %
872 err)
Patrick Georgi69d47622016-10-12 15:53:06 +0200873 self._tools.Run('cbfstool', [self.cb_copy, 'write',
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200874 '--fill-upward',
875 '-f', output_data,
876 '-r', label])
877
Simon Glass290a1802011-07-17 13:54:32 -0700878 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700879 """Create a full firmware image, along with various by-products.
880
881 This uses the provided u-boot.bin, fdt and bct to create a firmware
882 image containing all the required parts. If the GBB is not supplied
883 then this will just return a signed U-Boot as the image.
884
885 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700886 gbb: a string, full path to the GBB file, or empty if a GBB is not
887 required.
888 fdt: an fdt object containing required information.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200889
890 Returns:
891 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700892 """
Simon Glass02d124a2012-03-02 14:47:20 -0800893 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700894
Simon Glass439fe7a2012-03-09 16:19:34 -0800895 pack = PackFirmware(self._tools, self._out)
Simon Glass00d027e2013-07-20 14:51:12 -0600896 if self._force_efs:
897 fdt.PutInteger('/chromeos-config', 'early-firmware-selection', 1)
Simon Glassa7e66e22013-07-23 07:21:16 -0600898 pack.use_efs = fdt.GetInt('/chromeos-config', 'early-firmware-selection',
899 0)
Simon Glassb8c6d952012-12-01 06:14:35 -0800900
Simon Glass4f318912013-07-20 16:13:06 -0600901 pack.SelectFdt(fdt, self._board)
Simon Glass439fe7a2012-03-09 16:19:34 -0800902
903 # Get all our blobs ready
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800904 if self.uboot_fname:
905 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -0800906 if self.skeleton_fname:
907 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700908 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700909
Simon Glassde9c8072012-07-02 22:29:02 -0700910 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
911 if self.kernel_fname:
912 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
913
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800914 if gbb:
915 pack.AddProperty('gbb', gbb)
Aaron Durbin41c85b62015-12-17 17:40:29 -0600916
917 # Build the blobs out.
918 self._BuildBlobs(pack, fdt)
Simon Glass89b86b82011-07-17 23:49:49 -0700919
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200920 # Now that blobs are built (and written into cb_with_fmap),
921 # create the vblocks
922 self._BuildKeyblocks(pack)
923
Simon Glass7306b902012-12-17 15:06:21 -0800924 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -0700925 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700926 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800927 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800928 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800929 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700930 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800931 pack.AddProperty('fwid', fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800932 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700933
934 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700935
936 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -0800937 pack.UpdateBlobPositionsAndHashes(fdt)
Simon Glass8884b982012-06-21 12:41:41 -0700938
Simon Glass6207efe2012-12-17 15:04:36 -0800939 # Make a copy of the fdt for the bootstub
940 fdt_data = self._tools.ReadFile(fdt.fname)
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800941 if self.uboot_fname:
942 uboot_data = self._tools.ReadFile(self.uboot_fname)
943 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
944 self._tools.WriteFile(uboot_copy, uboot_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800945
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800946 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
947 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800948
Simon Glassa10282a2013-01-08 17:06:41 -0800949 # Fix up the coreboot image here, since we can't do this until we have
950 # a final device tree binary.
Patrick Georgi50561e82016-10-06 18:45:05 +0200951 bootstub = pack.GetProperty('coreboot')
952 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
953 if self.coreboot_elf:
954 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
955 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
956 elif self.uboot_fname:
957 text_base = 0x1110000
Simon Glass0a7cf112013-05-21 23:08:21 -0700958
Patrick Georgi50561e82016-10-06 18:45:05 +0200959 # This is the the 'movw $GD_FLG_COLD_BOOT, %bx' instruction
960 # 1110015: 66 bb 00 01 mov $0x100,%bx
961 marker = struct.pack('<L', 0x0100bb66)
962 pos = uboot_data.find(marker)
963 if pos == -1 or pos > 0x100:
964 raise ValueError('Cannot find U-Boot cold boot entry point')
965 entry = text_base + pos
966 self._out.Notice('U-Boot entry point %#08x' % entry)
967 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
968 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
969 '-l', '%#x' % text_base, '-e', '%#x' % entry])
970 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
971 '-n', 'u-boot.dtb', '-t', '0xac'])
972 data = self._tools.ReadFile(bootstub)
973 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
974 self._tools.WriteFile(bootstub_copy, data)
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700975
Patrick Georgi50561e82016-10-06 18:45:05 +0200976 # Use offset and size from fmap.dts to extract CBFS area from coreboot.rom
977 cbfs_offset, cbfs_size = fdt.GetFlashPart('ro', 'boot')
978 self._tools.WriteFile(bootstub, data[cbfs_offset:cbfs_offset+cbfs_size])
Simon Glasscbc83552012-07-23 15:26:22 +0100979
Simon Glass208ad952013-02-10 11:16:46 -0800980 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -0700981 image = os.path.join(self._tools.outdir, 'image.bin')
982 pack.PackImage(self._tools.outdir, image)
983 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700984
Simon Glass439fe7a2012-03-09 16:19:34 -0800985 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700986 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700987 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700988
Simon Glassdedda6f2013-02-09 13:44:14 -0800989 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -0700990 """Select an FDT to control the firmware bundling
991
Simon Glassdedda6f2013-02-09 13:44:14 -0800992 We make a copy of this which will include any on-the-fly changes we want
993 to make.
994
Simon Glass290a1802011-07-17 13:54:32 -0700995 Args:
996 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -0800997 use_defaults: True to use a default FDT name if available, and to add
998 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -0700999
Simon Glassc0f3dc62011-08-09 14:19:05 -07001000 Returns:
1001 The Fdt object of the original fdt file, which we will not modify.
1002
Simon Glassdedda6f2013-02-09 13:44:14 -08001003 Raises:
1004 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
1005 False).
Simon Glass290a1802011-07-17 13:54:32 -07001006 """
Simon Glassdedda6f2013-02-09 13:44:14 -08001007 if use_defaults:
1008 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -08001009 if not fdt_fname:
1010 raise ValueError('Please provide an FDT filename')
1011 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -07001012 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -08001013
Patrick Georgi81263072016-09-09 22:33:06 +02001014 fdt.Compile(None)
Simon Glasse53abbc2013-08-21 22:29:55 -06001015 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
1016
Patrick Georgicebb5a22016-08-15 19:07:02 +02001017 if fdt.GetProp('/flash', 'reg', ''):
1018 raise ValueError('fmap.dts /flash is deprecated. Use chromeos.fmd')
1019
1020 # fill in /flash from binary fmap
1021 # ignore "read-only" attribute, that isn't used anywhere
1022 fmap_blob = open(self.coreboot_fname).read()
1023 f = fmap.fmap_decode(fmap_blob)
1024 fdt.PutString('/flash', 'compatible', 'chromeos,flashmap')
1025 fdt.PutIntList('/flash', 'reg', [f['base'], f['size']])
1026 for area in f['areas']:
1027 label = re.sub('_', '-', area['name']).lower()
1028 fdt_path = '/flash/' + label
1029 slot=label[-1]
1030 if label == 'gbb':
1031 fdt_path = '/flash/ro-gbb'
1032 fdt.PutString(fdt_path, 'type', 'blob gbb')
1033 elif label == 'fmap':
1034 fdt_path = '/flash/ro-fmap'
1035 fdt.PutString(fdt_path, 'type', 'fmap')
1036 fdt.PutIntList(fdt_path, 'ver-major', [1])
1037 fdt.PutIntList(fdt_path, 'ver-minor', [0])
Julius Wernerbcf0c942016-09-07 16:57:40 -07001038 elif label == 'bootblock':
Patrick Georgidf772712016-10-05 16:24:20 +02001039 fdt.PutString(fdt_path, 'type', 'blob bootblock')
Patrick Georgicebb5a22016-08-15 19:07:02 +02001040 elif label == 'coreboot':
Patrick Georgidf772712016-10-05 16:24:20 +02001041 fdt_path = '/flash/ro-boot'
1042 fdt.PutString(fdt_path, 'type', 'blob coreboot')
Patrick Georgicebb5a22016-08-15 19:07:02 +02001043 elif label == 'si-desc':
1044 fdt.PutString(fdt_path, 'type', 'ifd')
1045 elif label == 'rw-shared':
1046 fdt_path = '/flash/shared-section'
1047 elif label == 'rw-section-'+slot:
1048 fdt_path = '/flash/rw-'+slot
1049 elif label == 'rw-legacy' and self.seabios_fname:
1050 fdt.PutString(fdt_path, 'type', 'blob legacy')
1051 elif label in ['rw-mrc-cache', 'rw-elog', 'rw-legacy',
1052 'rw-vpd', 'rw-unused', 'ro-vpd', 'ro-unused',
1053 'ro-frid-pad', 'bios-unusable', 'device-extension',
1054 'unused-hole', 'rw-gpt-primary', 'rw-gpt-secondary',
1055 'rw-nvram', 'ro-unused-1', 'ro-unused-2']:
1056 fdt.PutString(fdt_path, 'type', 'wiped')
1057 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
1058 elif label == 'shared-data':
1059 fdt.PutString(fdt_path, 'type', 'wiped')
1060 fdt.PutIntList(fdt_path, 'wipe-value', [0])
1061 elif label == 'vblock-dev':
1062 fdt_path = '/flash/rw-vblock-dev'
1063 fdt.PutString(fdt_path, 'type', 'wiped')
1064 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
1065 elif label[:-1] == 'vblock-':
1066 fdt_path = '/flash/rw-'+slot+'-vblock'
1067 fdt.PutString(fdt_path, 'type', 'keyblock cbfs/rw/'+slot+'-boot')
1068 fdt.PutString(fdt_path, 'keyblock', 'firmware.keyblock')
1069 fdt.PutString(fdt_path, 'signprivate', 'firmware_data_key.vbprivk')
1070 fdt.PutString(fdt_path, 'kernelkey', 'kernel_subkey.vbpubk')
1071 fdt.PutIntList(fdt_path, 'version', [1])
1072 fdt.PutIntList(fdt_path, 'preamble-flags', [0])
1073 elif label[:-1] == 'fw-main-':
1074 fdt_path = '/flash/rw-'+slot+'-boot'
1075 fdt.PutString(fdt_path, 'type', 'blob cbfs/rw/'+slot+'-boot')
1076 elif label[:-1] == 'rw-fwid-':
1077 fdt_path = '/flash/rw-'+slot+'-firmware-id'
1078 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1079 elif label == 'ro-frid':
1080 fdt_path = '/flash/ro-firmware-id'
1081 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1082 elif label == 'ifwi':
1083 fdt_path = '/flash/ro-ifwi'
1084 fdt.PutString(fdt_path, 'type', 'blob ifwi')
1085 elif label == 'sign-cse':
1086 fdt_path = '/flash/ro-sig'
1087 fdt.PutString(fdt_path, 'type', 'blob sig2')
1088 # white list for empty regions
Patrick Georgi56dc9202016-09-07 21:12:04 +02001089 elif label in ['bootblock', 'misc-rw', 'ro-section', 'rw-environment',
1090 'rw-gpt', 'si-all', 'si-bios', 'si-me', 'wp-ro']:
Patrick Georgicebb5a22016-08-15 19:07:02 +02001091 pass
1092 else:
1093 raise ValueError('encountered label "'+label+'" in binary fmap. '+
1094 'Check chromeos.fmd')
1095 fdt.PutString(fdt_path, 'label', label)
1096 fdt.PutIntList(fdt_path, 'reg', [area['offset'], area['size']])
1097
Simon Glass7df773b2013-08-25 18:02:29 -06001098 # Remember our board type.
1099 fdt.PutString('/chromeos-config', 'board', self._board)
1100
Simon Glasse53abbc2013-08-21 22:29:55 -06001101 self.fdt = fdt
1102 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001103
Simon Glassc90cf582012-03-13 15:40:47 -07001104 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001105 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001106
1107 - Checks options, tools, output directory, fdt.
1108 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001109
1110 Args:
Simon Glass56577572011-07-19 11:08:06 +12001111 hardware_id: Hardware ID to use for this board. If None, then the
1112 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001113 output_fname: Output filename for the image. If this is not None, then
1114 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001115 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001116
1117 Returns:
1118 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001119 """
Vadim Bendebury5baeec12013-04-02 13:01:22 -07001120 if self._small or self.fdt.GetProp('/config', 'nogbb', 'any') != 'any':
1121 gbb = '' # Building a small image or `nogbb' is requested in device tree.
1122 else:
Simon Glass56577572011-07-19 11:08:06 +12001123 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001124
1125 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001126 image, pack = self._CreateImage(gbb, self.fdt)
1127 if show_map:
1128 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001129 if output_fname:
1130 shutil.copyfile(image, output_fname)
1131 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001132 return image, pack.props