blob: 7615b597e158bf7fbdcb1b724cbe0e9e05fa2653 [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 Georgi5f949ad2016-10-12 16:03:13 +0200122 self.hardware_id = None
Patrick Georgi29d2eed2016-10-12 15:45:08 +0200123 self.bootstub = None
124 self.cb_copy = None
Simon Glass290a1802011-07-17 13:54:32 -0700125
126 def SetDirs(self, keydir):
127 """Set up directories required for Bundle.
128
129 Args:
130 keydir: Directory containing keys to use for signing firmware.
131 """
132 self._keydir = keydir
133
Patrick Georgi48030572016-09-09 22:55:46 +0200134 def SetFiles(self, board, bct, uboot=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800135 coreboot_elf=None,
Simon Glass942bedb2016-05-14 16:19:59 -0600136 seabios=None, exynos_bl1=None, exynos_bl2=None,
Randall Spangler7307da92014-07-18 12:47:34 -0700137 skeleton=None, ecrw=None, ecro=None, pdrw=None,
Patrick Georgi48030572016-09-09 22:55:46 +0200138 kernel=None, blobs=None, cbfs_files=None,
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600139 rocbfs_files=None):
Simon Glass290a1802011-07-17 13:54:32 -0700140 """Set up files required for Bundle.
141
142 Args:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500143 board: The name of the board to target (e.g. nyan).
Simon Glass290a1802011-07-17 13:54:32 -0700144 uboot: The filename of the u-boot.bin image to use.
145 bct: The filename of the binary BCT file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800146 coreboot: The filename of the coreboot image to use (on x86).
147 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Vincent Palatinf7286772011-10-12 14:31:53 -0700148 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700149 exynos_bl1: The filename of the exynos BL1 file
150 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
151 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700152 ecrw: The filename of the EC (Embedded Controller) read-write file.
153 ecro: The filename of the EC (Embedded Controller) read-only file.
Randall Spangler7307da92014-07-18 12:47:34 -0700154 pdrw: The filename of the PD (PD embedded controller) read-write file.
Simon Glassde9c8072012-07-02 22:29:02 -0700155 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800156 blobs: List of (type, filename) of arbitrary blobs.
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600157 cbfs_files: Root directory of files to be stored in RO and RW CBFS
158 rocbfs_files: Root directory of files to be stored in RO CBFS
Simon Glass290a1802011-07-17 13:54:32 -0700159 """
160 self._board = board
161 self.uboot_fname = uboot
162 self.bct_fname = bct
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700163 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800164 self.coreboot_elf = coreboot_elf
Vincent Palatinf7286772011-10-12 14:31:53 -0700165 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700166 self.exynos_bl1 = exynos_bl1
167 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700168 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700169 self.ecrw_fname = ecrw
170 self.ecro_fname = ecro
Randall Spangler7307da92014-07-18 12:47:34 -0700171 self.pdrw_fname = pdrw
Simon Glassde9c8072012-07-02 22:29:02 -0700172 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800173 self.blobs = dict(blobs or ())
Daisuke Nojiri69662892015-09-25 15:24:04 -0700174 self.cbfs_files = cbfs_files
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600175 self.rocbfs_files = rocbfs_files
Simon Glass290a1802011-07-17 13:54:32 -0700176
Patrick Georgi450204a2016-08-15 19:13:29 +0200177 def SetOptions(self, small, gbb_flags, force_efs=False):
Simon Glass290a1802011-07-17 13:54:32 -0700178 """Set up options supported by Bundle.
179
180 Args:
181 small: Only create a signed U-Boot - don't produce the full packed
182 firmware image. This is useful for devs who want to replace just the
183 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700184 gbb_flags: Specification for string containing adjustments to make.
Simon Glass00d027e2013-07-20 14:51:12 -0600185 force_efs: Force firmware to use 'early firmware selection' feature,
186 where RW firmware is selected before SDRAM is initialized.
Simon Glass290a1802011-07-17 13:54:32 -0700187 """
188 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700189 self._gbb_flags = gbb_flags
Simon Glass00d027e2013-07-20 14:51:12 -0600190 self._force_efs = force_efs
Simon Glass290a1802011-07-17 13:54:32 -0700191
Simon Glass22f39fb2013-02-09 13:44:14 -0800192 def _GetBuildRoot(self):
193 """Get the path to this board's 'firmware' directory.
194
195 Returns:
196 Path to firmware directory, with ## representing the path to the
197 chroot.
198 """
Simon Glass290a1802011-07-17 13:54:32 -0700199 if not self._board:
200 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800201 return os.path.join('##', 'build', self._board, 'firmware')
202
203 def _CheckFdtFilename(self, fname):
204 """Check provided FDT filename and return the correct name if needed.
205
206 Where the filename lacks a path, add a default path for this board.
207 Where no FDT filename is provided, select a default one for this board.
208
209 Args:
210 fname: Proposed FDT filename.
211
212 Returns:
213 Selected FDT filename, after validation.
214 """
215 build_root = self._GetBuildRoot()
Julius Wernerb4b14392013-08-09 14:41:40 -0700216 dir_name = os.path.join(build_root, 'dtb')
Simon Glass22f39fb2013-02-09 13:44:14 -0800217 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700218 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700219 base_name = re.sub('_', '-', self._board)
220
221 # In case the name exists with a prefix or suffix, find it.
Julius Wernerb4b14392013-08-09 14:41:40 -0700222 wildcard = os.path.join(dir_name, '*%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700223 found_list = glob.glob(self._tools.Filename(wildcard))
224 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800225 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700226 else:
227 # We didn't find anything definite, so set up our expected name.
Julius Wernerb4b14392013-08-09 14:41:40 -0700228 fname = os.path.join(dir_name, '%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700229
Simon Glass881964d2012-04-04 11:34:09 -0700230 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800231 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700232 if not ext and not os.path.dirname(root):
Julius Wernerb4b14392013-08-09 14:41:40 -0700233 fname = os.path.join(dir_name, '%s.dtb' % root)
Simon Glass22f39fb2013-02-09 13:44:14 -0800234 return fname
235
236 def CheckOptions(self):
237 """Check provided options and select defaults."""
238 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700239
Simon Glass49b026b2013-04-26 16:38:42 -0700240 board_type = self._board.split('_')[0]
241 model = type_to_model.get(board_type)
242
Simon Glass290a1802011-07-17 13:54:32 -0700243 if not self.uboot_fname:
244 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
245 if not self.bct_fname:
246 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass49b026b2013-04-26 16:38:42 -0700247 if model:
248 if not self.exynos_bl1:
Simon Glassd05696e2013-06-13 20:14:00 -0700249 self.exynos_bl1 = os.path.join(build_root, 'u-boot.bl1.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700250 if not self.exynos_bl2:
Julius Wernerb12c0052013-08-14 13:57:04 -0700251 self.exynos_bl2 = os.path.join(build_root, 'u-boot-spl.wrapped.bin')
Simon Glass07267952012-06-08 12:45:13 -0700252 if not self.coreboot_fname:
253 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
254 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700255 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Simon Glassbe0bc002012-08-16 12:50:48 -0700256 if not self.ecrw_fname:
257 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
Randall Spangler7307da92014-07-18 12:47:34 -0700258 if not self.pdrw_fname:
259 self.pdrw_fname = os.path.join(build_root, 'pd.RW.bin')
Simon Glassbe0bc002012-08-16 12:50:48 -0700260 if not self.ecro_fname:
261 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700262
Simon Glass75759302012-03-15 20:26:53 -0700263 def GetFiles(self):
264 """Get a list of files that we know about.
265
266 This is the opposite of SetFiles except that we may have put in some
267 default names. It returns a dictionary containing the filename for
268 each of a number of pre-defined files.
269
270 Returns:
271 Dictionary, with one entry for each file.
272 """
273 file_list = {
274 'bct' : self.bct_fname,
275 'exynos-bl1' : self.exynos_bl1,
276 'exynos-bl2' : self.exynos_bl2,
277 }
278 return file_list
279
Simon Glass4a887b12012-10-23 16:29:03 -0700280 def DecodeGBBFlagsFromFdt(self):
281 """Get Google Binary Block flags from the FDT.
282
283 These should be in the chromeos-config node, like this:
284
285 chromeos-config {
286 gbb-flag-dev-screen-short-delay;
287 gbb-flag-force-dev-switch-on;
288 gbb-flag-force-dev-boot-usb;
289 gbb-flag-disable-fw-rollback-check;
290 };
291
292 Returns:
293 GBB flags value from FDT.
294 """
295 chromeos_config = self.fdt.GetProps("/chromeos-config")
296 gbb_flags = 0
297 for name in chromeos_config:
298 if name.startswith('gbb-flag-'):
299 flag_value = gbb_flag_properties.get(name[9:])
300 if flag_value:
301 gbb_flags |= flag_value
302 self._out.Notice("FDT: Enabling %s." % name)
303 else:
304 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
305 return gbb_flags
306
Simon Glass157c0662012-10-23 13:52:42 -0700307 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
308 """Decode ajustments to the provided GBB flags.
309
310 We support three options:
311
312 hex value: c2
313 defined value: force-dev-boot-usb,load-option-roms
314 adjust default value: -load-option-roms,+force-dev-boot-usb
315
316 The last option starts from the passed-in GBB flags and adds or removes
317 flags.
318
319 Args:
320 gbb_flags: Base (default) FDT flags.
321 adjustments: String containing adjustments to make.
322
323 Returns:
324 Updated FDT flags.
325 """
326 use_base_value = True
327 if adjustments:
328 try:
329 return int(adjustments, base=16)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700330 except (ValueError, TypeError):
Simon Glass157c0662012-10-23 13:52:42 -0700331 pass
332 for flag in adjustments.split(','):
333 oper = None
334 if flag[0] in ['-', '+']:
335 oper = flag[0]
336 flag = flag[1:]
337 value = gbb_flag_properties.get(flag)
338 if not value:
339 raise ValueError("Invalid GBB flag '%s'" % flag)
340 if oper == '+':
341 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800342 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700343 elif oper == '-':
344 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800345 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700346 else:
347 if use_base_value:
348 gbb_flags = 0
349 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800350 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700351 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800352 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700353
354 return gbb_flags
355
Patrick Georgi5f949ad2016-10-12 16:03:13 +0200356 def _CreateGoogleBinaryBlock(self):
Simon Glass89b86b82011-07-17 23:49:49 -0700357 """Create a GBB for the image.
358
Simon Glass56577572011-07-19 11:08:06 +1200359 Args:
360 hardware_id: Hardware ID to use for this board. If None, then the
361 default from the Fdt will be used
362
Simon Glass89b86b82011-07-17 23:49:49 -0700363 Returns:
364 Path of the created GBB file.
Simon Glass89b86b82011-07-17 23:49:49 -0700365 """
Patrick Georgi5f949ad2016-10-12 16:03:13 +0200366 hardware_id = self.hardware_id
Simon Glass56577572011-07-19 11:08:06 +1200367 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800368 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass290a1802011-07-17 13:54:32 -0700369 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700370
Simon Glass4a887b12012-10-23 16:29:03 -0700371 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800372
Simon Glass157c0662012-10-23 13:52:42 -0700373 # Allow command line to override flags
374 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
375
Simon Glass4a887b12012-10-23 16:29:03 -0700376 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700377 self._out.Progress('Creating GBB')
Patrick Georgi48030572016-09-09 22:55:46 +0200378 sizes = [0x100, 0x1000, 0, 0x1000]
Simon Glass89b86b82011-07-17 23:49:49 -0700379 sizes = ['%#x' % size for size in sizes]
380 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700381 keydir = self._tools.Filename(self._keydir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800382
383 gbb_set_command = ['-s',
384 '--hwid=%s' % hardware_id,
385 '--rootkey=%s/root_key.vbpubk' % keydir,
386 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
387 '--flags=%d' % gbb_flags,
388 gbb]
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800389
Simon Glass290a1802011-07-17 13:54:32 -0700390 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800391 self._tools.Run('gbb_utility', gbb_set_command, cwd=odir)
Simon Glass290a1802011-07-17 13:54:32 -0700392 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700393
Simon Glasse13ee2c2011-07-28 08:12:28 +1200394 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700395 """Sign an image so that the Tegra SOC will boot it.
396
397 Args:
398 bct: BCT file to use.
399 bootstub: Boot stub (U-Boot + fdt) file to sign.
400 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700401
402 Returns:
403 filename of signed image.
Simon Glass89b86b82011-07-17 23:49:49 -0700404 """
405 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200406 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700407 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200408 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700409 fd = open(config, 'w')
410 fd.write('Version = 1;\n')
411 fd.write('Redundancy = 1;\n')
412 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700413
414 # TODO(dianders): Right now, we don't have enough space in our flash map
415 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
416 # sure what this does for reliability, but at least things will fit...
417 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
418 if is_nand:
419 fd.write('Bctcopy = 1;\n')
420
Simon Glass89b86b82011-07-17 23:49:49 -0700421 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
422 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700423
Simon Glass89b86b82011-07-17 23:49:49 -0700424 fd.close()
425
426 self._tools.Run('cbootimage', [config, signed])
427 self._tools.OutputSize('BCT', bct)
428 self._tools.OutputSize('Signed image', signed)
429 return signed
430
Doug Anderson86ce5f42011-07-27 10:40:18 -0700431 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700432 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700433
434 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700435 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700436 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700437 """
Simon Glass468d8752012-09-19 16:36:19 -0700438 if bootcmd is not None:
439 if bootcmd == 'none':
440 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800441 self.fdt.PutString('/config', 'bootcmd', bootcmd)
442 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700443 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700444
Simon Glassa4934b72012-05-09 13:35:02 -0700445 def SetNodeEnabled(self, node_name, enabled):
446 """Set whether an node is enabled or disabled.
447
448 This simply sets the 'status' property of a node to "ok", or "disabled".
449
450 The node should either be a full path to the node (like '/uart@10200000')
451 or an alias property.
452
453 Aliases are supported like this:
454
455 aliases {
456 console = "/uart@10200000";
457 };
458
459 pointing to a node:
460
461 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700462 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700463 };
464
465 In this case, this function takes the name of the alias ('console' in
466 this case) and updates the status of the node that is pointed to, to
467 either ok or disabled. If the alias does not exist, a warning is
468 displayed.
469
470 Args:
471 node_name: Name of node (e.g. '/uart@10200000') or alias alias
472 (e.g. 'console') to adjust
473 enabled: True to enable, False to disable
474 """
475 # Look up the alias if this is an alias reference
476 if not node_name.startswith('/'):
477 lookup = self.fdt.GetString('/aliases', node_name, '')
478 if not lookup:
479 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
480 return
481 node_name = lookup
482 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700483 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700484 else:
485 status = 'disabled'
486 self.fdt.PutString(node_name, 'status', status)
487
488 def AddEnableList(self, enable_list):
489 """Process a list of nodes to enable/disable.
490
491 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700492 enable_list: List of (node, value) tuples to add to the fdt. For each
Simon Glassa4934b72012-05-09 13:35:02 -0700493 tuple:
494 node: The fdt node to write to will be <node> or pointed to by
495 /aliases/<node>. We can tell which
496 value: 0 to disable the node, 1 to enable it
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700497
Vadim Bendebury507c0012013-06-09 12:49:25 -0700498 Raises:
499 CmdError if a command fails.
Simon Glassa4934b72012-05-09 13:35:02 -0700500 """
501 if enable_list:
502 for node_name, enabled in enable_list:
503 try:
504 enabled = int(enabled)
505 if enabled not in (0, 1):
506 raise ValueError
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700507 except ValueError:
Simon Glassa4934b72012-05-09 13:35:02 -0700508 raise CmdError("Invalid enable option value '%s' "
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700509 "(should be 0 or 1)" % str(enabled))
Simon Glassa4934b72012-05-09 13:35:02 -0700510 self.SetNodeEnabled(node_name, enabled)
511
Simon Glass290a1802011-07-17 13:54:32 -0700512 def AddConfigList(self, config_list, use_int=False):
513 """Add a list of config items to the fdt.
514
515 Normally these values are written to the fdt as strings, but integers
516 are also supported, in which case the values will be converted to integers
517 (if necessary) before being stored.
518
519 Args:
520 config_list: List of (config, value) tuples to add to the fdt. For each
521 tuple:
522 config: The fdt node to write to will be /config/<config>.
523 value: An integer or string value to write.
524 use_int: True to only write integer values.
525
526 Raises:
527 CmdError: if a value is required to be converted to integer but can't be.
528 """
529 if config_list:
530 for config in config_list:
531 value = config[1]
532 if use_int:
533 try:
534 value = int(value)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700535 except ValueError:
Simon Glass290a1802011-07-17 13:54:32 -0700536 raise CmdError("Cannot convert config option '%s' to integer" %
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700537 str(value))
Simon Glass290a1802011-07-17 13:54:32 -0700538 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800539 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700540 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800541 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700542
Simon Glass7c2d5572011-11-15 14:47:08 -0800543 def DecodeTextBase(self, data):
544 """Look at a U-Boot image and try to decode its TEXT_BASE.
545
546 This works because U-Boot has a header with the value 0x12345678
547 immediately followed by the TEXT_BASE value. We can therefore read this
548 from the image with some certainty. We check only the first 40 words
549 since the header should be within that region.
550
Simon Glass96b50302012-07-20 06:55:28 +0100551 Since upstream Tegra has moved to having a 16KB SPL region at the start,
552 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
553 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
554
Simon Glass7c2d5572011-11-15 14:47:08 -0800555 Args:
556 data: U-Boot binary data
557
558 Returns:
559 Text base (integer) or None if none was found
560 """
561 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100562 for start in (0, 0x4000):
563 for i in range(start, start + 160, 4):
564 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800565
Simon Glass96b50302012-07-20 06:55:28 +0100566 # TODO(sjg): This does not cope with a big-endian target
567 value = struct.unpack('<I', word)[0]
568 if found:
569 return value - start
570 if value == 0x12345678:
571 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800572
573 return None
574
575 def CalcTextBase(self, name, fdt, fname):
576 """Calculate the TEXT_BASE to use for U-Boot.
577
578 Normally this value is in the fdt, so we just read it from there. But as
579 a second check we look at the image itself in case this is different, and
580 switch to that if it is.
581
582 This allows us to flash any U-Boot even if its TEXT_BASE is different.
583 This is particularly useful with upstream U-Boot which uses a different
584 value (which we will move to).
585 """
586 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800587 # The value that comes back from fdt.GetInt is signed, which makes no
588 # sense for an address base. Force it to unsigned.
589 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800590 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100591 text_base_str = '%#x' % text_base if text_base else 'None'
592 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
593 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800594
595 # If they are different, issue a warning and switch over.
596 if text_base and text_base != fdt_text_base:
597 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
598 "fdt value of %x. Using %x" % (text_base, name,
599 fdt_text_base, text_base))
600 fdt_text_base = text_base
601 return fdt_text_base
602
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600603 def _AddCbfsFiles(self, bootstub, cbfs_files):
604 for dir, subs, files in os.walk(cbfs_files):
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600605 for file in files:
606 file = os.path.join(dir, file)
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600607 cbfs_name = file.replace(cbfs_files, '', 1).strip('/')
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600608 self._tools.Run('cbfstool', [bootstub, 'add', '-f', file,
609 '-n', cbfs_name, '-t', 'raw', '-c', 'lzma'])
610
Patrick Georgi29d2eed2016-10-12 15:45:08 +0200611 def _CreateCorebootStub(self, coreboot):
612 """Create a coreboot boot stub.
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700613
614 Args:
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700615 coreboot: Path to coreboot.rom
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700616 """
617 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700618 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100619
Patrick Georgi29d2eed2016-10-12 15:45:08 +0200620 self.bootstub = bootstub
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700621
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600622 # Add files to to RO and RW CBFS if provided.
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600623 if self.cbfs_files:
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600624 self._AddCbfsFiles(bootstub, self.cbfs_files)
Simon Glass7e199222012-03-13 15:51:18 -0700625
Aaron Durbina113f522016-01-05 09:09:55 -0600626 # Create a coreboot copy to use as a scratch pad. Order matters. The
627 # cbfs_files were added prior to this action. That's so the RW CBFS
Patrick Georgi45b64b82016-10-05 16:35:27 +0200628 # regions inherit the files from the RO CBFS region.
Patrick Georgi3a332672015-11-20 10:02:51 +0100629 cb_copy = os.path.abspath(os.path.join(self._tools.outdir, 'cb_with_fmap'))
Aaron Durbina113f522016-01-05 09:09:55 -0600630 self._tools.WriteFile(cb_copy, self._tools.ReadFile(bootstub))
Patrick Georgi3a332672015-11-20 10:02:51 +0100631 binary = self._tools.ReadFile(bootstub)
Patrick Georgi3a332672015-11-20 10:02:51 +0100632 self._tools.WriteFile(cb_copy, binary)
Patrick Georgi29d2eed2016-10-12 15:45:08 +0200633
634 self.cb_copy = cb_copy
Aaron Durbina113f522016-01-05 09:09:55 -0600635
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600636 # Add files to to RO CBFS if provided. This done here such that the
637 # copy above does not contain the RO CBFS files.
638 if self.rocbfs_files:
639 self._AddCbfsFiles(bootstub, self.rocbfs_files)
640
Aaron Durbina113f522016-01-05 09:09:55 -0600641
Simon Glass89b86b82011-07-17 23:49:49 -0700642 def _PackOutput(self, msg):
643 """Helper function to write output from PackFirmware (verbose level 2).
644
645 This is passed to PackFirmware for it to use to write output.
646
647 Args:
648 msg: Message to display.
649 """
650 self._out.Notice(msg)
651
Patrick Georgic1064f42016-10-12 11:34:24 +0200652 def _FdtNameToFmap(self, fdtstr):
653 return re.sub('-', '_', fdtstr).upper()
654
Aaron Durbin80564452015-12-21 15:25:06 -0600655 def _FmapNameByPath(self, path):
656 """ Take list of names to form node path. Return FMAP name.
657
658 Obtain the FMAP name described by the node path.
659
660 Args:
661 path: list forming a node path.
662
663 Returns:
664 FMAP name of fdt node.
665
666 Raises:
667 CmdError if path not found.
668 """
669 lbl = self.fdt.GetLabel(self.fdt.GetFlashNode(*path))
Patrick Georgic1064f42016-10-12 11:34:24 +0200670 return self._FdtNameToFmap(lbl)
Aaron Durbin80564452015-12-21 15:25:06 -0600671
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800672 def _PrepareCbfs(self, pack, blob_name):
673 """Create CBFS blob in rw-boot-{a,b} FMAP sections.
674
675 When the blob name is defined as cbfs#<section>#<subsection>, fill the
676 <section>_<subsection> area in the flash map with a CBFS copy, putting the
677 CBFS header of the copy at the base of the section.
678
679 If --coreboot-elf parameter was specified during cros_bumdle_firmware
680 invocation, add the parameter of this option as the payload to the new
681 CBFS instance.
682
683 Args:
684 pack: a PackFirmware object describing the firmware image to build.
685 blob_name: a string, blob name describing what FMAP section this CBFS
686 copy is destined to
687 Raises:
Patrick Georgi3a332672015-11-20 10:02:51 +0100688 CmdError if cbfs-files node has incorrect parameters.
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800689 """
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800690 part_sections = blob_name.split('/')[1:]
Aaron Durbin80564452015-12-21 15:25:06 -0600691 fmap_dst = self._FmapNameByPath(part_sections)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800692
693 # Base address and size of the desitnation partition
694 base, size = self.fdt.GetFlashPart(*part_sections)
695
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800696 # Add coreboot payload if so requested. Note that the some images use
697 # different payload for the rw sections, which is passed in as the value
698 # of the --uboot option in the command line.
699 if self.uboot_fname:
700 payload_fname = self.uboot_fname
701 elif self.coreboot_elf:
702 payload_fname = self.coreboot_elf
703 else:
704 payload_fname = None
705
706 if payload_fname:
707 self._tools.Run('cbfstool', [
Patrick Georgi69d47622016-10-12 15:53:06 +0200708 self.cb_copy, 'add-payload', '-f', payload_fname,
Patrick Georgi10690b42015-11-20 22:06:38 +0100709 '-n', 'fallback/payload', '-c', 'lzma' , '-r', fmap_dst])
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800710
Patrick Georgi964fb542015-10-16 16:52:03 +0200711 if self.ecrw_fname:
712 self._tools.Run('cbfstool', [
Patrick Georgi69d47622016-10-12 15:53:06 +0200713 self.cb_copy, 'add', '-f', self.ecrw_fname, '-t', 'raw',
Patrick Georgi10690b42015-11-20 22:06:38 +0100714 '-n', 'ecrw', '-A', 'sha256', '-r', fmap_dst ])
Patrick Georgi964fb542015-10-16 16:52:03 +0200715
716 if self.pdrw_fname:
717 self._tools.Run('cbfstool', [
Patrick Georgi69d47622016-10-12 15:53:06 +0200718 self.cb_copy, 'add', '-f', self.pdrw_fname, '-t', 'raw',
Patrick Georgi10690b42015-11-20 22:06:38 +0100719 '-n', 'pdrw', '-A', 'sha256', '-r', fmap_dst ])
Patrick Georgi964fb542015-10-16 16:52:03 +0200720
Aaron Durbin880cf952016-01-27 14:11:38 -0600721 # Parse the file list to obtain the last entry. If its empty use its
722 # offset as the size of the CBFS to hash.
723 stdout = self._tools.Run('cbfstool',
Patrick Georgi69d47622016-10-12 15:53:06 +0200724 [ self.cb_copy, 'print', '-k', '-r', fmap_dst ])
Aaron Durbin880cf952016-01-27 14:11:38 -0600725 # Fields are tab separated in the following order.
726 # Name Offset Type Metadata Size Data Size Total Size
727 last_entry = stdout.strip().splitlines()[-1].split('\t')
728 if last_entry[0] == '(empty)' and last_entry[2] == 'null':
729 size = int(last_entry[1], 16)
730
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800731 # And extract the blob for the FW section
732 rw_section = os.path.join(self._tools.outdir, '_'.join(part_sections))
733 self._tools.WriteFile(rw_section,
Patrick Georgi69d47622016-10-12 15:53:06 +0200734 self._tools.ReadFile(self.cb_copy)[base:base+size])
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800735
736 pack.AddProperty(blob_name, rw_section)
737
Patrick Georgidf772712016-10-05 16:24:20 +0200738 def _PrepareBootblock(self, pack):
739 """Copy bootblock into blob file for packaging
740
741 Args:
742 pack: a PackFirmware object describing the firmware image to build.
743 Raises:
744 CmdError if cbfs-files node has incorrect parameters.
745 """
Patrick Georgidf772712016-10-05 16:24:20 +0200746 bootblock_section = os.path.join(self._tools.outdir, 'bootblock.section')
747
748 self._tools.Run('cbfstool', [
Patrick Georgi69d47622016-10-12 15:53:06 +0200749 self.cb_copy, 'read', '-r', 'BOOTBLOCK', '-f', bootblock_section])
Patrick Georgidf772712016-10-05 16:24:20 +0200750
751 pack.AddProperty('bootblock', bootblock_section)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800752
Patrick Georgi9c2686b2016-10-12 16:36:42 +0200753 def _GenerateWiped(self, label, size, value):
754 """Fill a CBFS region in cb_with_fmap with a given value
755
756 Args:
757 label: fdt-style region name
758 size: size of region
759 value: value to fill region with (int)
760 """
761 wipedfile = os.path.join(self._tools.outdir, 'wiped.%s' % label)
762 fmaplabel = self._FdtNameToFmap(label)
763
764 self._tools.WriteFile(wipedfile, size*chr(value))
765 self._tools.Run('cbfstool', [
766 self.cb_copy, 'write',
767 '--force',
768 '-r', fmaplabel, '-f', wipedfile])
769
Simon Glass439fe7a2012-03-09 16:19:34 -0800770 def _BuildBlob(self, pack, fdt, blob_type):
771 """Build the blob data for a particular blob type.
772
773 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700774 pack: a PackFirmware object describing the firmware image to build.
775 fdt: an fdt object including image layout information
Simon Glass439fe7a2012-03-09 16:19:34 -0800776 blob_type: The type of blob to create data for. Supported types are:
777 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
778 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
Vadim Bendebury507c0012013-06-09 12:49:25 -0700779
780 Raises:
781 CmdError if a command fails.
Simon Glass439fe7a2012-03-09 16:19:34 -0800782 """
783 if blob_type == 'coreboot':
Patrick Georgifa20ddc2016-09-27 14:10:51 +0200784 pass
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700785 elif blob_type == 'legacy':
Patrick Georgi69d47622016-10-12 15:53:06 +0200786 self._tools.Run('cbfstool', [self.cb_copy, 'write',
Patrick Georgi44092222016-10-12 12:15:48 +0200787 '-f', self.seabios_fname,
788 '--force',
789 '-r', 'RW_LEGACY'])
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700790 pack.AddProperty('legacy', self.seabios_fname)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800791 elif blob_type.startswith('cbfs'):
792 self._PrepareCbfs(pack, blob_type)
Patrick Georgidf772712016-10-05 16:24:20 +0200793 elif blob_type == 'bootblock':
794 self._PrepareBootblock(pack)
Simon Glass439fe7a2012-03-09 16:19:34 -0800795 elif pack.GetProperty(blob_type):
796 pass
Furquan Shaikh95ee50c2016-05-29 09:46:41 -0700797 elif blob_type == 'ifwi' or blob_type == 'sig2':
798 # Copy IFWI/CSE_SIGN(sig2) regions from coreboot copy and build a blob
799 # for the blob_type
Furquan Shaikh95ee50c2016-05-29 09:46:41 -0700800 blob_start, blob_size = fdt.GetFlashPart('ro', blob_type)
801 blob_file = blob_type + '.bin'
802 blob_path = os.path.join(self._tools.outdir, blob_file)
Patrick Georgi69d47622016-10-12 15:53:06 +0200803 data = self._tools.ReadFile(self.cb_copy)
Furquan Shaikh95ee50c2016-05-29 09:46:41 -0700804 self._tools.WriteFile(blob_path, data[blob_start:blob_start+blob_size])
805 pack.AddProperty(blob_type, blob_path)
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800806 elif blob_type in self.blobs:
Patrick Georgi69d47622016-10-12 15:53:06 +0200807 self._tools.Run('cbfstool', [self.cb_copy, 'write',
Patrick Georgi44092222016-10-12 12:15:48 +0200808 '--fill-upward',
809 '-f', self.blobs[blob_type],
810 '-r', _FdtNameToFmap(blob_type)])
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800811 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -0800812 else:
813 raise CmdError("Unknown blob type '%s' required in flash map" %
814 blob_type)
815
Aaron Durbin41c85b62015-12-17 17:40:29 -0600816 def _BuildBlobs(self, pack, fdt):
817 """Build the blob data for the list of blobs in the pack.
818
819 Args:
820 pack: a PackFirmware object describing the firmware image to build.
821 fdt: an fdt object including image layout information
822
823 Raises:
824 CmdError if a command fails.
Aaron Durbin41c85b62015-12-17 17:40:29 -0600825 """
826 blob_list = pack.GetBlobList()
827 self._out.Info('Building blobs %s\n' % blob_list)
828
829 complete = False
830 deferred_list = []
831
Patrick Georgi29d2eed2016-10-12 15:45:08 +0200832 pack.AddProperty('coreboot', self.bootstub)
833 pack.AddProperty('image', self.bootstub)
Patrick Georgifa20ddc2016-09-27 14:10:51 +0200834
Patrick Georgi49cf7b22016-09-27 14:25:03 +0200835 for blob_type in blob_list:
836 self._BuildBlob(pack, fdt, blob_type)
Aaron Durbin41c85b62015-12-17 17:40:29 -0600837
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200838 def _BuildKeyblocks(self, pack):
839 """Compute vblocks and write them into their FMAP regions.
840 Works for the (VBLOCK_?,FW_MAIN_?) pairs
841 """
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200842 fmap_blob = open(self.coreboot_fname).read()
843 f = fmap.fmap_decode(fmap_blob)
844 for area in f['areas']:
845 label = area['name']
846 slot = label[-1]
847 if label[:-1] == 'VBLOCK_':
848 region_in = 'FW_MAIN_' + slot
849 region_out = label
850
851 input_data = os.path.join(self._tools.outdir, 'input.%s' % region_in)
852 output_data = os.path.join(self._tools.outdir, 'vblock.%s' % region_out)
853 self._tools.Run('cbfstool', [
Patrick Georgi69d47622016-10-12 15:53:06 +0200854 self.cb_copy, 'read', '-r', region_in, '-f', input_data])
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200855
856 # Parse the file list to obtain the last entry. If its empty use
857 # its offset as the size of the CBFS to hash.
858 stdout = self._tools.Run('cbfstool',
Patrick Georgi69d47622016-10-12 15:53:06 +0200859 [ self.cb_copy, 'print', '-k', '-r', region_in ])
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200860 # Fields are tab separated in the following order.
861 # Name Offset Type Metadata Size Data Size Total Size
862 last_entry = stdout.strip().splitlines()[-1].split('\t')
863 if last_entry[0] == '(empty)' and last_entry[2] == 'null':
864 size = int(last_entry[1], 16)
865 self._tools.Run('truncate', [
866 '--no-create', '--size', str(size), input_data])
867 self._out.Info('truncated FW_MAIN_%s to %d bytes' %
868 (slot, size))
869
870 try:
871 prefix = self._keydir + '/'
872
873 self._tools.Run('vbutil_firmware', [
874 '--vblock', output_data,
875 '--keyblock', prefix + 'firmware.keyblock',
876 '--signprivate', prefix + 'firmware_data_key.vbprivk',
877 '--version', '1',
878 '--fv', input_data,
879 '--kernelkey', prefix + 'kernel_subkey.vbpubk',
880 '--flags', '0',
881 ])
882
883 except CmdError as err:
884 raise PackError('Cannot make key block: vbutil_firmware failed\n%s' %
885 err)
Patrick Georgi69d47622016-10-12 15:53:06 +0200886 self._tools.Run('cbfstool', [self.cb_copy, 'write',
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200887 '--fill-upward',
888 '-f', output_data,
889 '-r', label])
890
Simon Glass290a1802011-07-17 13:54:32 -0700891 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700892 """Create a full firmware image, along with various by-products.
893
894 This uses the provided u-boot.bin, fdt and bct to create a firmware
895 image containing all the required parts. If the GBB is not supplied
896 then this will just return a signed U-Boot as the image.
897
898 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700899 gbb: a string, full path to the GBB file, or empty if a GBB is not
900 required.
901 fdt: an fdt object containing required information.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200902
903 Returns:
904 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700905 """
Simon Glass02d124a2012-03-02 14:47:20 -0800906 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700907
Simon Glass439fe7a2012-03-09 16:19:34 -0800908 pack = PackFirmware(self._tools, self._out)
Simon Glass00d027e2013-07-20 14:51:12 -0600909 if self._force_efs:
910 fdt.PutInteger('/chromeos-config', 'early-firmware-selection', 1)
Simon Glassa7e66e22013-07-23 07:21:16 -0600911 pack.use_efs = fdt.GetInt('/chromeos-config', 'early-firmware-selection',
912 0)
Simon Glassb8c6d952012-12-01 06:14:35 -0800913
Simon Glass4f318912013-07-20 16:13:06 -0600914 pack.SelectFdt(fdt, self._board)
Simon Glass439fe7a2012-03-09 16:19:34 -0800915
916 # Get all our blobs ready
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800917 if self.uboot_fname:
918 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -0800919 if self.skeleton_fname:
920 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700921 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700922
Simon Glassde9c8072012-07-02 22:29:02 -0700923 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
924 if self.kernel_fname:
925 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
926
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800927 if gbb:
928 pack.AddProperty('gbb', gbb)
Aaron Durbin41c85b62015-12-17 17:40:29 -0600929
930 # Build the blobs out.
931 self._BuildBlobs(pack, fdt)
Simon Glass89b86b82011-07-17 23:49:49 -0700932
Patrick Georgi9d57ea42016-10-12 12:23:50 +0200933 # Now that blobs are built (and written into cb_with_fmap),
934 # create the vblocks
935 self._BuildKeyblocks(pack)
936
Simon Glass7306b902012-12-17 15:06:21 -0800937 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -0700938 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700939 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800940 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800941 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800942 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700943 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800944 pack.AddProperty('fwid', fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800945 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700946
947 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700948
949 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -0800950 pack.UpdateBlobPositionsAndHashes(fdt)
Simon Glass8884b982012-06-21 12:41:41 -0700951
Simon Glass6207efe2012-12-17 15:04:36 -0800952 # Make a copy of the fdt for the bootstub
953 fdt_data = self._tools.ReadFile(fdt.fname)
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800954 if self.uboot_fname:
955 uboot_data = self._tools.ReadFile(self.uboot_fname)
956 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
957 self._tools.WriteFile(uboot_copy, uboot_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800958
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800959 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
960 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800961
Simon Glassa10282a2013-01-08 17:06:41 -0800962 # Fix up the coreboot image here, since we can't do this until we have
963 # a final device tree binary.
Patrick Georgi50561e82016-10-06 18:45:05 +0200964 bootstub = pack.GetProperty('coreboot')
965 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
966 if self.coreboot_elf:
967 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
968 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
969 elif self.uboot_fname:
970 text_base = 0x1110000
Simon Glass0a7cf112013-05-21 23:08:21 -0700971
Patrick Georgi50561e82016-10-06 18:45:05 +0200972 # This is the the 'movw $GD_FLG_COLD_BOOT, %bx' instruction
973 # 1110015: 66 bb 00 01 mov $0x100,%bx
974 marker = struct.pack('<L', 0x0100bb66)
975 pos = uboot_data.find(marker)
976 if pos == -1 or pos > 0x100:
977 raise ValueError('Cannot find U-Boot cold boot entry point')
978 entry = text_base + pos
979 self._out.Notice('U-Boot entry point %#08x' % entry)
980 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
981 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
982 '-l', '%#x' % text_base, '-e', '%#x' % entry])
983 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
984 '-n', 'u-boot.dtb', '-t', '0xac'])
985 data = self._tools.ReadFile(bootstub)
986 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
987 self._tools.WriteFile(bootstub_copy, data)
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700988
Patrick Georgi50561e82016-10-06 18:45:05 +0200989 # Use offset and size from fmap.dts to extract CBFS area from coreboot.rom
990 cbfs_offset, cbfs_size = fdt.GetFlashPart('ro', 'boot')
991 self._tools.WriteFile(bootstub, data[cbfs_offset:cbfs_offset+cbfs_size])
Simon Glasscbc83552012-07-23 15:26:22 +0100992
Simon Glass208ad952013-02-10 11:16:46 -0800993 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -0700994 image = os.path.join(self._tools.outdir, 'image.bin')
995 pack.PackImage(self._tools.outdir, image)
996 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700997
Simon Glass439fe7a2012-03-09 16:19:34 -0800998 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700999 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001000 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001001
Simon Glassdedda6f2013-02-09 13:44:14 -08001002 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -07001003 """Select an FDT to control the firmware bundling
1004
Simon Glassdedda6f2013-02-09 13:44:14 -08001005 We make a copy of this which will include any on-the-fly changes we want
1006 to make.
1007
Simon Glass290a1802011-07-17 13:54:32 -07001008 Args:
1009 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -08001010 use_defaults: True to use a default FDT name if available, and to add
1011 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -07001012
Simon Glassc0f3dc62011-08-09 14:19:05 -07001013 Returns:
1014 The Fdt object of the original fdt file, which we will not modify.
1015
Simon Glassdedda6f2013-02-09 13:44:14 -08001016 Raises:
1017 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
1018 False).
Simon Glass290a1802011-07-17 13:54:32 -07001019 """
Simon Glassdedda6f2013-02-09 13:44:14 -08001020 if use_defaults:
1021 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -08001022 if not fdt_fname:
1023 raise ValueError('Please provide an FDT filename')
1024 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -07001025 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -08001026
Patrick Georgi81263072016-09-09 22:33:06 +02001027 fdt.Compile(None)
Simon Glasse53abbc2013-08-21 22:29:55 -06001028 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
1029
Patrick Georgicebb5a22016-08-15 19:07:02 +02001030 if fdt.GetProp('/flash', 'reg', ''):
1031 raise ValueError('fmap.dts /flash is deprecated. Use chromeos.fmd')
1032
Patrick Georgic092b382016-10-12 16:35:14 +02001033 self._CreateCorebootStub(self.coreboot_fname)
1034
Patrick Georgicebb5a22016-08-15 19:07:02 +02001035 # fill in /flash from binary fmap
1036 # ignore "read-only" attribute, that isn't used anywhere
1037 fmap_blob = open(self.coreboot_fname).read()
1038 f = fmap.fmap_decode(fmap_blob)
1039 fdt.PutString('/flash', 'compatible', 'chromeos,flashmap')
1040 fdt.PutIntList('/flash', 'reg', [f['base'], f['size']])
1041 for area in f['areas']:
1042 label = re.sub('_', '-', area['name']).lower()
1043 fdt_path = '/flash/' + label
1044 slot=label[-1]
1045 if label == 'gbb':
1046 fdt_path = '/flash/ro-gbb'
1047 fdt.PutString(fdt_path, 'type', 'blob gbb')
1048 elif label == 'fmap':
1049 fdt_path = '/flash/ro-fmap'
1050 fdt.PutString(fdt_path, 'type', 'fmap')
1051 fdt.PutIntList(fdt_path, 'ver-major', [1])
1052 fdt.PutIntList(fdt_path, 'ver-minor', [0])
Julius Wernerbcf0c942016-09-07 16:57:40 -07001053 elif label == 'bootblock':
Patrick Georgidf772712016-10-05 16:24:20 +02001054 fdt.PutString(fdt_path, 'type', 'blob bootblock')
Patrick Georgicebb5a22016-08-15 19:07:02 +02001055 elif label == 'coreboot':
Patrick Georgidf772712016-10-05 16:24:20 +02001056 fdt_path = '/flash/ro-boot'
1057 fdt.PutString(fdt_path, 'type', 'blob coreboot')
Patrick Georgicebb5a22016-08-15 19:07:02 +02001058 elif label == 'si-desc':
1059 fdt.PutString(fdt_path, 'type', 'ifd')
1060 elif label == 'rw-shared':
1061 fdt_path = '/flash/shared-section'
1062 elif label == 'rw-section-'+slot:
1063 fdt_path = '/flash/rw-'+slot
1064 elif label == 'rw-legacy' and self.seabios_fname:
1065 fdt.PutString(fdt_path, 'type', 'blob legacy')
Furquan Shaikha9876542016-11-07 15:44:27 -08001066 elif label in ['rw-mrc-cache', 'recovery-mrc-cache', 'rw-elog',
1067 'rw-legacy', 'rw-vpd', 'rw-unused', 'ro-vpd',
1068 'ro-unused', 'ro-frid-pad', 'bios-unusable',
1069 'device-extension', 'unused-hole', 'rw-gpt-primary',
1070 'rw-gpt-secondary', 'rw-nvram', 'ro-unused-1',
1071 'ro-unused-2']:
Patrick Georgicebb5a22016-08-15 19:07:02 +02001072 fdt.PutString(fdt_path, 'type', 'wiped')
1073 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
Patrick Georgi9c2686b2016-10-12 16:36:42 +02001074 self._GenerateWiped(label, area['size'], 0xff)
Patrick Georgicebb5a22016-08-15 19:07:02 +02001075 elif label == 'shared-data':
1076 fdt.PutString(fdt_path, 'type', 'wiped')
1077 fdt.PutIntList(fdt_path, 'wipe-value', [0])
Patrick Georgi9c2686b2016-10-12 16:36:42 +02001078 self._GenerateWiped(label, area['size'], 0)
Patrick Georgicebb5a22016-08-15 19:07:02 +02001079 elif label == 'vblock-dev':
1080 fdt_path = '/flash/rw-vblock-dev'
1081 fdt.PutString(fdt_path, 'type', 'wiped')
1082 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
Patrick Georgi9c2686b2016-10-12 16:36:42 +02001083 self._GenerateWiped(label, area['size'], 0xff)
Patrick Georgicebb5a22016-08-15 19:07:02 +02001084 elif label[:-1] == 'vblock-':
1085 fdt_path = '/flash/rw-'+slot+'-vblock'
1086 fdt.PutString(fdt_path, 'type', 'keyblock cbfs/rw/'+slot+'-boot')
1087 fdt.PutString(fdt_path, 'keyblock', 'firmware.keyblock')
1088 fdt.PutString(fdt_path, 'signprivate', 'firmware_data_key.vbprivk')
1089 fdt.PutString(fdt_path, 'kernelkey', 'kernel_subkey.vbpubk')
1090 fdt.PutIntList(fdt_path, 'version', [1])
1091 fdt.PutIntList(fdt_path, 'preamble-flags', [0])
1092 elif label[:-1] == 'fw-main-':
1093 fdt_path = '/flash/rw-'+slot+'-boot'
1094 fdt.PutString(fdt_path, 'type', 'blob cbfs/rw/'+slot+'-boot')
1095 elif label[:-1] == 'rw-fwid-':
1096 fdt_path = '/flash/rw-'+slot+'-firmware-id'
1097 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1098 elif label == 'ro-frid':
1099 fdt_path = '/flash/ro-firmware-id'
1100 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1101 elif label == 'ifwi':
1102 fdt_path = '/flash/ro-ifwi'
1103 fdt.PutString(fdt_path, 'type', 'blob ifwi')
1104 elif label == 'sign-cse':
1105 fdt_path = '/flash/ro-sig'
1106 fdt.PutString(fdt_path, 'type', 'blob sig2')
1107 # white list for empty regions
Patrick Georgi56dc9202016-09-07 21:12:04 +02001108 elif label in ['bootblock', 'misc-rw', 'ro-section', 'rw-environment',
Furquan Shaikha9876542016-11-07 15:44:27 -08001109 'rw-gpt', 'si-all', 'si-bios', 'si-me', 'wp-ro',
1110 'unified-mrc-cache']:
Patrick Georgicebb5a22016-08-15 19:07:02 +02001111 pass
1112 else:
1113 raise ValueError('encountered label "'+label+'" in binary fmap. '+
1114 'Check chromeos.fmd')
1115 fdt.PutString(fdt_path, 'label', label)
1116 fdt.PutIntList(fdt_path, 'reg', [area['offset'], area['size']])
1117
Simon Glass7df773b2013-08-25 18:02:29 -06001118 # Remember our board type.
1119 fdt.PutString('/chromeos-config', 'board', self._board)
1120
Simon Glasse53abbc2013-08-21 22:29:55 -06001121 self.fdt = fdt
1122 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001123
Simon Glassc90cf582012-03-13 15:40:47 -07001124 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001125 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001126
1127 - Checks options, tools, output directory, fdt.
1128 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001129
1130 Args:
Simon Glass56577572011-07-19 11:08:06 +12001131 hardware_id: Hardware ID to use for this board. If None, then the
1132 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001133 output_fname: Output filename for the image. If this is not None, then
1134 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001135 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001136
1137 Returns:
1138 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001139 """
Patrick Georgi5f949ad2016-10-12 16:03:13 +02001140 self.hardware_id = hardware_id
Vadim Bendebury5baeec12013-04-02 13:01:22 -07001141 if self._small or self.fdt.GetProp('/config', 'nogbb', 'any') != 'any':
1142 gbb = '' # Building a small image or `nogbb' is requested in device tree.
1143 else:
Patrick Georgi5f949ad2016-10-12 16:03:13 +02001144 gbb = self._CreateGoogleBinaryBlock()
Simon Glass89b86b82011-07-17 23:49:49 -07001145
1146 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001147 image, pack = self._CreateImage(gbb, self.fdt)
1148 if show_map:
1149 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001150 if output_fname:
1151 shutil.copyfile(image, output_fname)
1152 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001153 return image, pack.props