blob: a6c2acfde6f2fe2972185f3cfe7acb281af80fa9 [file] [log] [blame]
Simon Glass89b86b82011-07-17 23:49:49 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -05005"""This module builds a firmware image.
Simon Glass89b86b82011-07-17 23:49:49 -07006
7This modules uses a few rudimentary other libraries for its activity.
8
9Here are the names we give to the various files we deal with. It is important
10to keep these consistent!
11
12 uboot u-boot.bin (with no device tree)
13 fdt the fdt blob
14 bct the BCT file
15 bootstub uboot + fdt
16 signed (uboot + fdt + bct) signed blob
17"""
18
Simon Glassceff3ff2012-04-04 11:23:45 -070019import glob
Simon Glass89b86b82011-07-17 23:49:49 -070020import os
21import re
22
Simon Glass89b86b82011-07-17 23:49:49 -070023from fdt import Fdt
24from pack_firmware import PackFirmware
25import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080026import struct
Patrick Georgicebb5a22016-08-15 19:07:02 +020027import fmap
Simon Glass439fe7a2012-03-09 16:19:34 -080028from tools import CmdError
Vadim Bendeburyb12e3352013-06-08 17:25:19 -070029from exynos import ExynosBl2
Simon Glass89b86b82011-07-17 23:49:49 -070030
Simon Glass4a887b12012-10-23 16:29:03 -070031# Build GBB flags.
32# (src/platform/vboot_reference/firmware/include/gbb_header.h)
33gbb_flag_properties = {
34 'dev-screen-short-delay': 0x00000001,
35 'load-option-roms': 0x00000002,
36 'enable-alternate-os': 0x00000004,
37 'force-dev-switch-on': 0x00000008,
38 'force-dev-boot-usb': 0x00000010,
39 'disable-fw-rollback-check': 0x00000020,
40 'enter-triggers-tonorm': 0x00000040,
41 'force-dev-boot-legacy': 0x00000080,
Shawn Nematbakhsh07c19882014-08-19 10:21:59 -070042 'faft-key-overide': 0x00000100,
43 'disable-ec-software-sync': 0x00000200,
44 'default-dev-boot-legacy': 0x00000400,
45 'disable-pd-software-sync': 0x00000800,
Furquan Shaikhd4eac3b2015-05-15 18:05:09 -070046 'force-dev-boot-fastboot-full-cap': 0x00002000,
Mary Ruthvena759c322015-11-16 08:23:26 -080047 'enable-serial': 0x00004000,
Simon Glass4a887b12012-10-23 16:29:03 -070048}
49
Simon Glass49b026b2013-04-26 16:38:42 -070050# Maps board name to Exynos product number
51type_to_model = {
52 'peach' : '5420',
53 'daisy' : '5250'
54}
55
Simon Glass5076a7f2012-10-23 16:31:54 -070056def ListGoogleBinaryBlockFlags():
57 """Print out a list of GBB flags."""
58 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
59 for name, value in gbb_flag_properties.iteritems():
60 print ' %-30s %02x' % (name, value)
61
Simon Glass89b86b82011-07-17 23:49:49 -070062class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070063 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070064
Simon Glass290a1802011-07-17 13:54:32 -070065 Sequence of events:
66 bundle = Bundle(tools.Tools(), cros_output.Output())
67 bundle.SetDirs(...)
68 bundle.SetFiles(...)
69 bundle.SetOptions(...)
70 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070071 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070072 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070073
Simon Glass290a1802011-07-17 13:54:32 -070074 Public properties:
75 fdt: The fdt object that we use for building our image. This wil be the
76 one specified by the user, except that we might add config options
77 to it. This is set up by SelectFdt() which must be called before
78 bundling starts.
79 uboot_fname: Full filename of the U-Boot binary we use.
80 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -070081 spl_source: Source device to load U-Boot from, in SPL:
82 straps: Select device according to CPU strap pins
83 spi: Boot from SPI
84 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -070085
86 Private attributes:
87 _small: True to create a 'small' signed U-Boot, False to produce a
88 full image. The small U-Boot is enough to boot but will not have
89 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -070090 """
Simon Glass89b86b82011-07-17 23:49:49 -070091
Simon Glass290a1802011-07-17 13:54:32 -070092 def __init__(self, tools, output):
93 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -070094
Simon Glass290a1802011-07-17 13:54:32 -070095 Args:
96 tools: A tools.Tools object to use for external tools.
97 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -070098 """
Simon Glass290a1802011-07-17 13:54:32 -070099 self._tools = tools
100 self._out = output
101
102 # Set up the things we need to know in order to operate.
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500103 self._board = None # Board name, e.g. nyan.
Simon Glass290a1802011-07-17 13:54:32 -0700104 self._fdt_fname = None # Filename of our FDT.
Simon Glass00d027e2013-07-20 14:51:12 -0600105 self._force_efs = None
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700106 self._gbb_flags = None
107 self._keydir = None
108 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700109 self.bct_fname = None # Filename of our BCT file.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700110 self.blobs = {} # Table of (type, filename) of arbitrary blobs
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700111 self.coreboot_elf = None
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700112 self.coreboot_fname = None # Filename of our coreboot binary.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700113 self.ecro_fname = None # Filename of EC read-only file
114 self.ecrw_fname = None # Filename of EC file
Randall Spangler7307da92014-07-18 12:47:34 -0700115 self.pdrw_fname = None # Filename of PD file
Simon Glass7e199222012-03-13 15:51:18 -0700116 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
117 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700118 self.fdt = None # Our Fdt object.
119 self.kernel_fname = None
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700120 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass07267952012-06-08 12:45:13 -0700121 self.skeleton_fname = None # Filename of Coreboot skeleton file
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700122 self.uboot_fname = None # Filename of our U-Boot binary.
Simon Glass290a1802011-07-17 13:54:32 -0700123
124 def SetDirs(self, keydir):
125 """Set up directories required for Bundle.
126
127 Args:
128 keydir: Directory containing keys to use for signing firmware.
129 """
130 self._keydir = keydir
131
Patrick Georgi48030572016-09-09 22:55:46 +0200132 def SetFiles(self, board, bct, uboot=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800133 coreboot_elf=None,
Simon Glass942bedb2016-05-14 16:19:59 -0600134 seabios=None, exynos_bl1=None, exynos_bl2=None,
Randall Spangler7307da92014-07-18 12:47:34 -0700135 skeleton=None, ecrw=None, ecro=None, pdrw=None,
Patrick Georgi48030572016-09-09 22:55:46 +0200136 kernel=None, blobs=None, cbfs_files=None,
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600137 rocbfs_files=None):
Simon Glass290a1802011-07-17 13:54:32 -0700138 """Set up files required for Bundle.
139
140 Args:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500141 board: The name of the board to target (e.g. nyan).
Simon Glass290a1802011-07-17 13:54:32 -0700142 uboot: The filename of the u-boot.bin image to use.
143 bct: The filename of the binary BCT file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800144 coreboot: The filename of the coreboot image to use (on x86).
145 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Vincent Palatinf7286772011-10-12 14:31:53 -0700146 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700147 exynos_bl1: The filename of the exynos BL1 file
148 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
149 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700150 ecrw: The filename of the EC (Embedded Controller) read-write file.
151 ecro: The filename of the EC (Embedded Controller) read-only file.
Randall Spangler7307da92014-07-18 12:47:34 -0700152 pdrw: The filename of the PD (PD embedded controller) read-write file.
Simon Glassde9c8072012-07-02 22:29:02 -0700153 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800154 blobs: List of (type, filename) of arbitrary blobs.
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600155 cbfs_files: Root directory of files to be stored in RO and RW CBFS
156 rocbfs_files: Root directory of files to be stored in RO CBFS
Simon Glass290a1802011-07-17 13:54:32 -0700157 """
158 self._board = board
159 self.uboot_fname = uboot
160 self.bct_fname = bct
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700161 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800162 self.coreboot_elf = coreboot_elf
Vincent Palatinf7286772011-10-12 14:31:53 -0700163 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700164 self.exynos_bl1 = exynos_bl1
165 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700166 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700167 self.ecrw_fname = ecrw
168 self.ecro_fname = ecro
Randall Spangler7307da92014-07-18 12:47:34 -0700169 self.pdrw_fname = pdrw
Simon Glassde9c8072012-07-02 22:29:02 -0700170 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800171 self.blobs = dict(blobs or ())
Daisuke Nojiri69662892015-09-25 15:24:04 -0700172 self.cbfs_files = cbfs_files
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600173 self.rocbfs_files = rocbfs_files
Simon Glass290a1802011-07-17 13:54:32 -0700174
Patrick Georgi450204a2016-08-15 19:13:29 +0200175 def SetOptions(self, small, gbb_flags, force_efs=False):
Simon Glass290a1802011-07-17 13:54:32 -0700176 """Set up options supported by Bundle.
177
178 Args:
179 small: Only create a signed U-Boot - don't produce the full packed
180 firmware image. This is useful for devs who want to replace just the
181 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700182 gbb_flags: Specification for string containing adjustments to make.
Simon Glass00d027e2013-07-20 14:51:12 -0600183 force_efs: Force firmware to use 'early firmware selection' feature,
184 where RW firmware is selected before SDRAM is initialized.
Simon Glass290a1802011-07-17 13:54:32 -0700185 """
186 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700187 self._gbb_flags = gbb_flags
Simon Glass00d027e2013-07-20 14:51:12 -0600188 self._force_efs = force_efs
Simon Glass290a1802011-07-17 13:54:32 -0700189
Simon Glass22f39fb2013-02-09 13:44:14 -0800190 def _GetBuildRoot(self):
191 """Get the path to this board's 'firmware' directory.
192
193 Returns:
194 Path to firmware directory, with ## representing the path to the
195 chroot.
196 """
Simon Glass290a1802011-07-17 13:54:32 -0700197 if not self._board:
198 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800199 return os.path.join('##', 'build', self._board, 'firmware')
200
201 def _CheckFdtFilename(self, fname):
202 """Check provided FDT filename and return the correct name if needed.
203
204 Where the filename lacks a path, add a default path for this board.
205 Where no FDT filename is provided, select a default one for this board.
206
207 Args:
208 fname: Proposed FDT filename.
209
210 Returns:
211 Selected FDT filename, after validation.
212 """
213 build_root = self._GetBuildRoot()
Julius Wernerb4b14392013-08-09 14:41:40 -0700214 dir_name = os.path.join(build_root, 'dtb')
Simon Glass22f39fb2013-02-09 13:44:14 -0800215 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700216 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700217 base_name = re.sub('_', '-', self._board)
218
219 # In case the name exists with a prefix or suffix, find it.
Julius Wernerb4b14392013-08-09 14:41:40 -0700220 wildcard = os.path.join(dir_name, '*%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700221 found_list = glob.glob(self._tools.Filename(wildcard))
222 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800223 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700224 else:
225 # We didn't find anything definite, so set up our expected name.
Julius Wernerb4b14392013-08-09 14:41:40 -0700226 fname = os.path.join(dir_name, '%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700227
Simon Glass881964d2012-04-04 11:34:09 -0700228 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800229 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700230 if not ext and not os.path.dirname(root):
Julius Wernerb4b14392013-08-09 14:41:40 -0700231 fname = os.path.join(dir_name, '%s.dtb' % root)
Simon Glass22f39fb2013-02-09 13:44:14 -0800232 return fname
233
234 def CheckOptions(self):
235 """Check provided options and select defaults."""
236 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700237
Simon Glass49b026b2013-04-26 16:38:42 -0700238 board_type = self._board.split('_')[0]
239 model = type_to_model.get(board_type)
240
Simon Glass290a1802011-07-17 13:54:32 -0700241 if not self.uboot_fname:
242 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
243 if not self.bct_fname:
244 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass49b026b2013-04-26 16:38:42 -0700245 if model:
246 if not self.exynos_bl1:
Simon Glassd05696e2013-06-13 20:14:00 -0700247 self.exynos_bl1 = os.path.join(build_root, 'u-boot.bl1.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700248 if not self.exynos_bl2:
Julius Wernerb12c0052013-08-14 13:57:04 -0700249 self.exynos_bl2 = os.path.join(build_root, 'u-boot-spl.wrapped.bin')
Simon Glass07267952012-06-08 12:45:13 -0700250 if not self.coreboot_fname:
251 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
252 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700253 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Simon Glassbe0bc002012-08-16 12:50:48 -0700254 if not self.ecrw_fname:
255 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
Randall Spangler7307da92014-07-18 12:47:34 -0700256 if not self.pdrw_fname:
257 self.pdrw_fname = os.path.join(build_root, 'pd.RW.bin')
Simon Glassbe0bc002012-08-16 12:50:48 -0700258 if not self.ecro_fname:
259 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700260
Simon Glass75759302012-03-15 20:26:53 -0700261 def GetFiles(self):
262 """Get a list of files that we know about.
263
264 This is the opposite of SetFiles except that we may have put in some
265 default names. It returns a dictionary containing the filename for
266 each of a number of pre-defined files.
267
268 Returns:
269 Dictionary, with one entry for each file.
270 """
271 file_list = {
272 'bct' : self.bct_fname,
273 'exynos-bl1' : self.exynos_bl1,
274 'exynos-bl2' : self.exynos_bl2,
275 }
276 return file_list
277
Simon Glass4a887b12012-10-23 16:29:03 -0700278 def DecodeGBBFlagsFromFdt(self):
279 """Get Google Binary Block flags from the FDT.
280
281 These should be in the chromeos-config node, like this:
282
283 chromeos-config {
284 gbb-flag-dev-screen-short-delay;
285 gbb-flag-force-dev-switch-on;
286 gbb-flag-force-dev-boot-usb;
287 gbb-flag-disable-fw-rollback-check;
288 };
289
290 Returns:
291 GBB flags value from FDT.
292 """
293 chromeos_config = self.fdt.GetProps("/chromeos-config")
294 gbb_flags = 0
295 for name in chromeos_config:
296 if name.startswith('gbb-flag-'):
297 flag_value = gbb_flag_properties.get(name[9:])
298 if flag_value:
299 gbb_flags |= flag_value
300 self._out.Notice("FDT: Enabling %s." % name)
301 else:
302 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
303 return gbb_flags
304
Simon Glass157c0662012-10-23 13:52:42 -0700305 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
306 """Decode ajustments to the provided GBB flags.
307
308 We support three options:
309
310 hex value: c2
311 defined value: force-dev-boot-usb,load-option-roms
312 adjust default value: -load-option-roms,+force-dev-boot-usb
313
314 The last option starts from the passed-in GBB flags and adds or removes
315 flags.
316
317 Args:
318 gbb_flags: Base (default) FDT flags.
319 adjustments: String containing adjustments to make.
320
321 Returns:
322 Updated FDT flags.
323 """
324 use_base_value = True
325 if adjustments:
326 try:
327 return int(adjustments, base=16)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700328 except (ValueError, TypeError):
Simon Glass157c0662012-10-23 13:52:42 -0700329 pass
330 for flag in adjustments.split(','):
331 oper = None
332 if flag[0] in ['-', '+']:
333 oper = flag[0]
334 flag = flag[1:]
335 value = gbb_flag_properties.get(flag)
336 if not value:
337 raise ValueError("Invalid GBB flag '%s'" % flag)
338 if oper == '+':
339 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800340 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700341 elif oper == '-':
342 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800343 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700344 else:
345 if use_base_value:
346 gbb_flags = 0
347 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800348 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700349 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800350 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700351
352 return gbb_flags
353
Simon Glass56577572011-07-19 11:08:06 +1200354 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700355 """Create a GBB for the image.
356
Simon Glass56577572011-07-19 11:08:06 +1200357 Args:
358 hardware_id: Hardware ID to use for this board. If None, then the
359 default from the Fdt will be used
360
Simon Glass89b86b82011-07-17 23:49:49 -0700361 Returns:
362 Path of the created GBB file.
Simon Glass89b86b82011-07-17 23:49:49 -0700363 """
Simon Glass56577572011-07-19 11:08:06 +1200364 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800365 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700366 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700367 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700368
Simon Glass4a887b12012-10-23 16:29:03 -0700369 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800370
Simon Glass157c0662012-10-23 13:52:42 -0700371 # Allow command line to override flags
372 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
373
Simon Glass4a887b12012-10-23 16:29:03 -0700374 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700375 self._out.Progress('Creating GBB')
Patrick Georgi48030572016-09-09 22:55:46 +0200376 sizes = [0x100, 0x1000, 0, 0x1000]
Simon Glass89b86b82011-07-17 23:49:49 -0700377 sizes = ['%#x' % size for size in sizes]
378 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700379 keydir = self._tools.Filename(self._keydir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800380
381 gbb_set_command = ['-s',
382 '--hwid=%s' % hardware_id,
383 '--rootkey=%s/root_key.vbpubk' % keydir,
384 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
385 '--flags=%d' % gbb_flags,
386 gbb]
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800387
Simon Glass290a1802011-07-17 13:54:32 -0700388 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800389 self._tools.Run('gbb_utility', gbb_set_command, cwd=odir)
Simon Glass290a1802011-07-17 13:54:32 -0700390 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700391
Simon Glasse13ee2c2011-07-28 08:12:28 +1200392 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700393 """Sign an image so that the Tegra SOC will boot it.
394
395 Args:
396 bct: BCT file to use.
397 bootstub: Boot stub (U-Boot + fdt) file to sign.
398 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700399
400 Returns:
401 filename of signed image.
Simon Glass89b86b82011-07-17 23:49:49 -0700402 """
403 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200404 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700405 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200406 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700407 fd = open(config, 'w')
408 fd.write('Version = 1;\n')
409 fd.write('Redundancy = 1;\n')
410 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700411
412 # TODO(dianders): Right now, we don't have enough space in our flash map
413 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
414 # sure what this does for reliability, but at least things will fit...
415 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
416 if is_nand:
417 fd.write('Bctcopy = 1;\n')
418
Simon Glass89b86b82011-07-17 23:49:49 -0700419 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
420 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700421
Simon Glass89b86b82011-07-17 23:49:49 -0700422 fd.close()
423
424 self._tools.Run('cbootimage', [config, signed])
425 self._tools.OutputSize('BCT', bct)
426 self._tools.OutputSize('Signed image', signed)
427 return signed
428
Doug Anderson86ce5f42011-07-27 10:40:18 -0700429 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700430 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700431
432 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700433 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700434 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700435 """
Simon Glass468d8752012-09-19 16:36:19 -0700436 if bootcmd is not None:
437 if bootcmd == 'none':
438 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800439 self.fdt.PutString('/config', 'bootcmd', bootcmd)
440 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700441 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700442
Simon Glassa4934b72012-05-09 13:35:02 -0700443 def SetNodeEnabled(self, node_name, enabled):
444 """Set whether an node is enabled or disabled.
445
446 This simply sets the 'status' property of a node to "ok", or "disabled".
447
448 The node should either be a full path to the node (like '/uart@10200000')
449 or an alias property.
450
451 Aliases are supported like this:
452
453 aliases {
454 console = "/uart@10200000";
455 };
456
457 pointing to a node:
458
459 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700460 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700461 };
462
463 In this case, this function takes the name of the alias ('console' in
464 this case) and updates the status of the node that is pointed to, to
465 either ok or disabled. If the alias does not exist, a warning is
466 displayed.
467
468 Args:
469 node_name: Name of node (e.g. '/uart@10200000') or alias alias
470 (e.g. 'console') to adjust
471 enabled: True to enable, False to disable
472 """
473 # Look up the alias if this is an alias reference
474 if not node_name.startswith('/'):
475 lookup = self.fdt.GetString('/aliases', node_name, '')
476 if not lookup:
477 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
478 return
479 node_name = lookup
480 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700481 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700482 else:
483 status = 'disabled'
484 self.fdt.PutString(node_name, 'status', status)
485
486 def AddEnableList(self, enable_list):
487 """Process a list of nodes to enable/disable.
488
489 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700490 enable_list: List of (node, value) tuples to add to the fdt. For each
Simon Glassa4934b72012-05-09 13:35:02 -0700491 tuple:
492 node: The fdt node to write to will be <node> or pointed to by
493 /aliases/<node>. We can tell which
494 value: 0 to disable the node, 1 to enable it
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700495
Vadim Bendebury507c0012013-06-09 12:49:25 -0700496 Raises:
497 CmdError if a command fails.
Simon Glassa4934b72012-05-09 13:35:02 -0700498 """
499 if enable_list:
500 for node_name, enabled in enable_list:
501 try:
502 enabled = int(enabled)
503 if enabled not in (0, 1):
504 raise ValueError
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700505 except ValueError:
Simon Glassa4934b72012-05-09 13:35:02 -0700506 raise CmdError("Invalid enable option value '%s' "
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700507 "(should be 0 or 1)" % str(enabled))
Simon Glassa4934b72012-05-09 13:35:02 -0700508 self.SetNodeEnabled(node_name, enabled)
509
Simon Glass290a1802011-07-17 13:54:32 -0700510 def AddConfigList(self, config_list, use_int=False):
511 """Add a list of config items to the fdt.
512
513 Normally these values are written to the fdt as strings, but integers
514 are also supported, in which case the values will be converted to integers
515 (if necessary) before being stored.
516
517 Args:
518 config_list: List of (config, value) tuples to add to the fdt. For each
519 tuple:
520 config: The fdt node to write to will be /config/<config>.
521 value: An integer or string value to write.
522 use_int: True to only write integer values.
523
524 Raises:
525 CmdError: if a value is required to be converted to integer but can't be.
526 """
527 if config_list:
528 for config in config_list:
529 value = config[1]
530 if use_int:
531 try:
532 value = int(value)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700533 except ValueError:
Simon Glass290a1802011-07-17 13:54:32 -0700534 raise CmdError("Cannot convert config option '%s' to integer" %
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700535 str(value))
Simon Glass290a1802011-07-17 13:54:32 -0700536 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800537 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700538 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800539 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700540
Simon Glass7c2d5572011-11-15 14:47:08 -0800541 def DecodeTextBase(self, data):
542 """Look at a U-Boot image and try to decode its TEXT_BASE.
543
544 This works because U-Boot has a header with the value 0x12345678
545 immediately followed by the TEXT_BASE value. We can therefore read this
546 from the image with some certainty. We check only the first 40 words
547 since the header should be within that region.
548
Simon Glass96b50302012-07-20 06:55:28 +0100549 Since upstream Tegra has moved to having a 16KB SPL region at the start,
550 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
551 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
552
Simon Glass7c2d5572011-11-15 14:47:08 -0800553 Args:
554 data: U-Boot binary data
555
556 Returns:
557 Text base (integer) or None if none was found
558 """
559 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100560 for start in (0, 0x4000):
561 for i in range(start, start + 160, 4):
562 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800563
Simon Glass96b50302012-07-20 06:55:28 +0100564 # TODO(sjg): This does not cope with a big-endian target
565 value = struct.unpack('<I', word)[0]
566 if found:
567 return value - start
568 if value == 0x12345678:
569 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800570
571 return None
572
573 def CalcTextBase(self, name, fdt, fname):
574 """Calculate the TEXT_BASE to use for U-Boot.
575
576 Normally this value is in the fdt, so we just read it from there. But as
577 a second check we look at the image itself in case this is different, and
578 switch to that if it is.
579
580 This allows us to flash any U-Boot even if its TEXT_BASE is different.
581 This is particularly useful with upstream U-Boot which uses a different
582 value (which we will move to).
583 """
584 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800585 # The value that comes back from fdt.GetInt is signed, which makes no
586 # sense for an address base. Force it to unsigned.
587 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800588 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100589 text_base_str = '%#x' % text_base if text_base else 'None'
590 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
591 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800592
593 # If they are different, issue a warning and switch over.
594 if text_base and text_base != fdt_text_base:
595 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
596 "fdt value of %x. Using %x" % (text_base, name,
597 fdt_text_base, text_base))
598 fdt_text_base = text_base
599 return fdt_text_base
600
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600601 def _AddCbfsFiles(self, bootstub, cbfs_files):
602 for dir, subs, files in os.walk(cbfs_files):
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600603 for file in files:
604 file = os.path.join(dir, file)
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600605 cbfs_name = file.replace(cbfs_files, '', 1).strip('/')
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600606 self._tools.Run('cbfstool', [bootstub, 'add', '-f', file,
607 '-n', cbfs_name, '-t', 'raw', '-c', 'lzma'])
608
609 def _CreateCorebootStub(self, pack, coreboot):
610 """Create a coreboot boot stub and add pack properties.
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700611
612 Args:
Aaron Durbina113f522016-01-05 09:09:55 -0600613 pack: a PackFirmware object describing the firmware image to build.
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
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600619 pack.AddProperty('coreboot', bootstub)
620 pack.AddProperty('image', 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 Georgi3a332672015-11-20 10:02:51 +0100628 # regions inherit the files from the RO CBFS region. Additionally,
629 # include the full FMAP within the file.
630 cb_copy = os.path.abspath(os.path.join(self._tools.outdir, 'cb_with_fmap'))
Aaron Durbina113f522016-01-05 09:09:55 -0600631 self._tools.WriteFile(cb_copy, self._tools.ReadFile(bootstub))
Patrick Georgi3a332672015-11-20 10:02:51 +0100632 binary = self._tools.ReadFile(bootstub)
633 fmap_offset, fmap = pack.GetFmap()
634 if len(binary) < fmap_offset + len(fmap):
635 raise CmdError('FMAP will not fit')
636 # Splice in FMAP data.
637 binary = binary[:fmap_offset] + fmap + binary[fmap_offset + len(fmap):]
638 self._tools.WriteFile(cb_copy, binary)
639 # Publish where coreboot is with the FMAP data.
640 pack.AddProperty('cb_with_fmap', cb_copy)
Aaron Durbina113f522016-01-05 09:09:55 -0600641
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600642 # Add files to to RO CBFS if provided. This done here such that the
643 # copy above does not contain the RO CBFS files.
644 if self.rocbfs_files:
645 self._AddCbfsFiles(bootstub, self.rocbfs_files)
646
Aaron Durbina113f522016-01-05 09:09:55 -0600647
Simon Glass89b86b82011-07-17 23:49:49 -0700648 def _PackOutput(self, msg):
649 """Helper function to write output from PackFirmware (verbose level 2).
650
651 This is passed to PackFirmware for it to use to write output.
652
653 Args:
654 msg: Message to display.
655 """
656 self._out.Notice(msg)
657
Aaron Durbin80564452015-12-21 15:25:06 -0600658 def _FmapNameByPath(self, path):
659 """ Take list of names to form node path. Return FMAP name.
660
661 Obtain the FMAP name described by the node path.
662
663 Args:
664 path: list forming a node path.
665
666 Returns:
667 FMAP name of fdt node.
668
669 Raises:
670 CmdError if path not found.
671 """
672 lbl = self.fdt.GetLabel(self.fdt.GetFlashNode(*path))
673 return re.sub('-', '_', lbl).upper()
674
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800675 def _PrepareCbfs(self, pack, blob_name):
676 """Create CBFS blob in rw-boot-{a,b} FMAP sections.
677
678 When the blob name is defined as cbfs#<section>#<subsection>, fill the
679 <section>_<subsection> area in the flash map with a CBFS copy, putting the
680 CBFS header of the copy at the base of the section.
681
682 If --coreboot-elf parameter was specified during cros_bumdle_firmware
683 invocation, add the parameter of this option as the payload to the new
684 CBFS instance.
685
686 Args:
687 pack: a PackFirmware object describing the firmware image to build.
688 blob_name: a string, blob name describing what FMAP section this CBFS
689 copy is destined to
690 Raises:
Patrick Georgi3a332672015-11-20 10:02:51 +0100691 CmdError if cbfs-files node has incorrect parameters.
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800692 """
Patrick Georgi3a332672015-11-20 10:02:51 +0100693 cb_copy = pack.GetProperty('cb_with_fmap')
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800694
695 part_sections = blob_name.split('/')[1:]
Aaron Durbin80564452015-12-21 15:25:06 -0600696 fmap_dst = self._FmapNameByPath(part_sections)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800697
698 # Base address and size of the desitnation partition
699 base, size = self.fdt.GetFlashPart(*part_sections)
700
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800701 # Add coreboot payload if so requested. Note that the some images use
702 # different payload for the rw sections, which is passed in as the value
703 # of the --uboot option in the command line.
704 if self.uboot_fname:
705 payload_fname = self.uboot_fname
706 elif self.coreboot_elf:
707 payload_fname = self.coreboot_elf
708 else:
709 payload_fname = None
710
711 if payload_fname:
712 self._tools.Run('cbfstool', [
713 cb_copy, 'add-payload', '-f', payload_fname,
Patrick Georgi10690b42015-11-20 22:06:38 +0100714 '-n', 'fallback/payload', '-c', 'lzma' , '-r', fmap_dst])
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800715
Patrick Georgi964fb542015-10-16 16:52:03 +0200716 if self.ecrw_fname:
717 self._tools.Run('cbfstool', [
718 cb_copy, 'add', '-f', self.ecrw_fname, '-t', 'raw',
Patrick Georgi10690b42015-11-20 22:06:38 +0100719 '-n', 'ecrw', '-A', 'sha256', '-r', fmap_dst ])
Patrick Georgi964fb542015-10-16 16:52:03 +0200720
721 if self.pdrw_fname:
722 self._tools.Run('cbfstool', [
723 cb_copy, 'add', '-f', self.pdrw_fname, '-t', 'raw',
Patrick Georgi10690b42015-11-20 22:06:38 +0100724 '-n', 'pdrw', '-A', 'sha256', '-r', fmap_dst ])
Patrick Georgi964fb542015-10-16 16:52:03 +0200725
Aaron Durbin880cf952016-01-27 14:11:38 -0600726 # Parse the file list to obtain the last entry. If its empty use its
727 # offset as the size of the CBFS to hash.
728 stdout = self._tools.Run('cbfstool',
729 [ cb_copy, 'print', '-k', '-r', fmap_dst ])
730 # Fields are tab separated in the following order.
731 # Name Offset Type Metadata Size Data Size Total Size
732 last_entry = stdout.strip().splitlines()[-1].split('\t')
733 if last_entry[0] == '(empty)' and last_entry[2] == 'null':
734 size = int(last_entry[1], 16)
735
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800736 # And extract the blob for the FW section
737 rw_section = os.path.join(self._tools.outdir, '_'.join(part_sections))
738 self._tools.WriteFile(rw_section,
739 self._tools.ReadFile(cb_copy)[base:base+size])
740
741 pack.AddProperty(blob_name, rw_section)
742
743
Simon Glass439fe7a2012-03-09 16:19:34 -0800744 def _BuildBlob(self, pack, fdt, blob_type):
745 """Build the blob data for a particular blob type.
746
747 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700748 pack: a PackFirmware object describing the firmware image to build.
749 fdt: an fdt object including image layout information
Simon Glass439fe7a2012-03-09 16:19:34 -0800750 blob_type: The type of blob to create data for. Supported types are:
751 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
752 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
Vadim Bendebury507c0012013-06-09 12:49:25 -0700753
754 Raises:
755 CmdError if a command fails.
Simon Glass439fe7a2012-03-09 16:19:34 -0800756 """
757 if blob_type == 'coreboot':
Patrick Georgifa20ddc2016-09-27 14:10:51 +0200758 pass
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700759 elif blob_type == 'legacy':
760 pack.AddProperty('legacy', self.seabios_fname)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800761 elif blob_type.startswith('cbfs'):
762 self._PrepareCbfs(pack, blob_type)
Simon Glass439fe7a2012-03-09 16:19:34 -0800763 elif pack.GetProperty(blob_type):
764 pass
Furquan Shaikh95ee50c2016-05-29 09:46:41 -0700765 elif blob_type == 'ifwi' or blob_type == 'sig2':
766 # Copy IFWI/CSE_SIGN(sig2) regions from coreboot copy and build a blob
767 # for the blob_type
768 cb_copy = pack.GetProperty('cb_with_fmap')
Furquan Shaikh95ee50c2016-05-29 09:46:41 -0700769 blob_start, blob_size = fdt.GetFlashPart('ro', blob_type)
770 blob_file = blob_type + '.bin'
771 blob_path = os.path.join(self._tools.outdir, blob_file)
772 data = self._tools.ReadFile(cb_copy)
773 self._tools.WriteFile(blob_path, data[blob_start:blob_start+blob_size])
774 pack.AddProperty(blob_type, blob_path)
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800775 elif blob_type in self.blobs:
776 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -0800777 else:
778 raise CmdError("Unknown blob type '%s' required in flash map" %
779 blob_type)
780
Aaron Durbin41c85b62015-12-17 17:40:29 -0600781 def _BuildBlobs(self, pack, fdt):
782 """Build the blob data for the list of blobs in the pack.
783
784 Args:
785 pack: a PackFirmware object describing the firmware image to build.
786 fdt: an fdt object including image layout information
787
788 Raises:
789 CmdError if a command fails.
Aaron Durbin41c85b62015-12-17 17:40:29 -0600790 """
791 blob_list = pack.GetBlobList()
792 self._out.Info('Building blobs %s\n' % blob_list)
793
794 complete = False
795 deferred_list = []
796
Patrick Georgifa20ddc2016-09-27 14:10:51 +0200797 # We always have a coreboot blob, and some other components rely on it, so
798 # make sure it's ready when the others come in.
799 blob_list.remove('coreboot')
800 self._CreateCorebootStub(pack, self.coreboot_fname)
801
Patrick Georgi49cf7b22016-09-27 14:25:03 +0200802 for blob_type in blob_list:
803 self._BuildBlob(pack, fdt, blob_type)
Aaron Durbin41c85b62015-12-17 17:40:29 -0600804
Simon Glass290a1802011-07-17 13:54:32 -0700805 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700806 """Create a full firmware image, along with various by-products.
807
808 This uses the provided u-boot.bin, fdt and bct to create a firmware
809 image containing all the required parts. If the GBB is not supplied
810 then this will just return a signed U-Boot as the image.
811
812 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700813 gbb: a string, full path to the GBB file, or empty if a GBB is not
814 required.
815 fdt: an fdt object containing required information.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200816
817 Returns:
818 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700819 """
Simon Glass02d124a2012-03-02 14:47:20 -0800820 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700821
Simon Glass439fe7a2012-03-09 16:19:34 -0800822 pack = PackFirmware(self._tools, self._out)
Simon Glass00d027e2013-07-20 14:51:12 -0600823 if self._force_efs:
824 fdt.PutInteger('/chromeos-config', 'early-firmware-selection', 1)
Simon Glassa7e66e22013-07-23 07:21:16 -0600825 pack.use_efs = fdt.GetInt('/chromeos-config', 'early-firmware-selection',
826 0)
Simon Glassb8c6d952012-12-01 06:14:35 -0800827
Simon Glass4f318912013-07-20 16:13:06 -0600828 pack.SelectFdt(fdt, self._board)
Simon Glass439fe7a2012-03-09 16:19:34 -0800829
830 # Get all our blobs ready
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800831 if self.uboot_fname:
832 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -0800833 if self.skeleton_fname:
834 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700835 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700836
Simon Glassde9c8072012-07-02 22:29:02 -0700837 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
838 if self.kernel_fname:
839 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
840
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800841 if gbb:
842 pack.AddProperty('gbb', gbb)
Aaron Durbin41c85b62015-12-17 17:40:29 -0600843
844 # Build the blobs out.
845 self._BuildBlobs(pack, fdt)
Simon Glass89b86b82011-07-17 23:49:49 -0700846
Simon Glass7306b902012-12-17 15:06:21 -0800847 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -0700848 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700849 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800850 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800851 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800852 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700853 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800854 pack.AddProperty('fwid', fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800855 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700856
857 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700858
859 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -0800860 pack.UpdateBlobPositionsAndHashes(fdt)
Simon Glass8884b982012-06-21 12:41:41 -0700861
Simon Glass6207efe2012-12-17 15:04:36 -0800862 # Make a copy of the fdt for the bootstub
863 fdt_data = self._tools.ReadFile(fdt.fname)
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800864 if self.uboot_fname:
865 uboot_data = self._tools.ReadFile(self.uboot_fname)
866 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
867 self._tools.WriteFile(uboot_copy, uboot_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800868
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800869 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
870 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800871
Simon Glassa10282a2013-01-08 17:06:41 -0800872 # Fix up the coreboot image here, since we can't do this until we have
873 # a final device tree binary.
Aaron Durbin41c85b62015-12-17 17:40:29 -0600874 if 'coreboot' in pack.GetBlobList():
Simon Glasscbc83552012-07-23 15:26:22 +0100875 bootstub = pack.GetProperty('coreboot')
876 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -0800877 if self.coreboot_elf:
878 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
879 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800880 elif self.uboot_fname:
Simon Glass0a7cf112013-05-21 23:08:21 -0700881 text_base = 0x1110000
882
883 # This is the the 'movw $GD_FLG_COLD_BOOT, %bx' instruction
884 # 1110015: 66 bb 00 01 mov $0x100,%bx
885 marker = struct.pack('<L', 0x0100bb66)
886 pos = uboot_data.find(marker)
887 if pos == -1 or pos > 0x100:
888 raise ValueError('Cannot find U-Boot cold boot entry point')
889 entry = text_base + pos
890 self._out.Notice('U-Boot entry point %#08x' % entry)
Simon Glassa10282a2013-01-08 17:06:41 -0800891 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
892 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
Simon Glass0a7cf112013-05-21 23:08:21 -0700893 '-l', '%#x' % text_base, '-e', '%#x' % entry])
Stefan Reinauer1502ea62012-11-01 10:15:38 -0700894 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
895 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -0800896 data = self._tools.ReadFile(bootstub)
897 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
898 self._tools.WriteFile(bootstub_copy, data)
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700899
Julius Werneraa1fe942014-11-21 17:16:11 -0800900 # Use offset and size from fmap.dts to extract CBFS area from coreboot.rom
901 cbfs_offset, cbfs_size = fdt.GetFlashPart('ro', 'boot')
902 self._tools.WriteFile(bootstub, data[cbfs_offset:cbfs_offset+cbfs_size])
Simon Glasscbc83552012-07-23 15:26:22 +0100903
Simon Glass208ad952013-02-10 11:16:46 -0800904 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -0700905 image = os.path.join(self._tools.outdir, 'image.bin')
906 pack.PackImage(self._tools.outdir, image)
907 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700908
Simon Glass439fe7a2012-03-09 16:19:34 -0800909 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700910 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700911 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700912
Simon Glassdedda6f2013-02-09 13:44:14 -0800913 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -0700914 """Select an FDT to control the firmware bundling
915
Simon Glassdedda6f2013-02-09 13:44:14 -0800916 We make a copy of this which will include any on-the-fly changes we want
917 to make.
918
Simon Glass290a1802011-07-17 13:54:32 -0700919 Args:
920 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -0800921 use_defaults: True to use a default FDT name if available, and to add
922 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -0700923
Simon Glassc0f3dc62011-08-09 14:19:05 -0700924 Returns:
925 The Fdt object of the original fdt file, which we will not modify.
926
Simon Glassdedda6f2013-02-09 13:44:14 -0800927 Raises:
928 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
929 False).
Simon Glass290a1802011-07-17 13:54:32 -0700930 """
Simon Glassdedda6f2013-02-09 13:44:14 -0800931 if use_defaults:
932 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -0800933 if not fdt_fname:
934 raise ValueError('Please provide an FDT filename')
935 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -0700936 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -0800937
Patrick Georgi81263072016-09-09 22:33:06 +0200938 fdt.Compile(None)
Simon Glasse53abbc2013-08-21 22:29:55 -0600939 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
940
Patrick Georgicebb5a22016-08-15 19:07:02 +0200941 if fdt.GetProp('/flash', 'reg', ''):
942 raise ValueError('fmap.dts /flash is deprecated. Use chromeos.fmd')
943
944 # fill in /flash from binary fmap
945 # ignore "read-only" attribute, that isn't used anywhere
Julius Wernerbcf0c942016-09-07 16:57:40 -0700946 bootblock_range = None
947 coreboot_range = None
Patrick Georgicebb5a22016-08-15 19:07:02 +0200948 fmap_blob = open(self.coreboot_fname).read()
949 f = fmap.fmap_decode(fmap_blob)
950 fdt.PutString('/flash', 'compatible', 'chromeos,flashmap')
951 fdt.PutIntList('/flash', 'reg', [f['base'], f['size']])
952 for area in f['areas']:
953 label = re.sub('_', '-', area['name']).lower()
954 fdt_path = '/flash/' + label
955 slot=label[-1]
956 if label == 'gbb':
957 fdt_path = '/flash/ro-gbb'
958 fdt.PutString(fdt_path, 'type', 'blob gbb')
959 elif label == 'fmap':
960 fdt_path = '/flash/ro-fmap'
961 fdt.PutString(fdt_path, 'type', 'fmap')
962 fdt.PutIntList(fdt_path, 'ver-major', [1])
963 fdt.PutIntList(fdt_path, 'ver-minor', [0])
Julius Wernerbcf0c942016-09-07 16:57:40 -0700964 elif label == 'bootblock':
965 bootblock_range = [area['offset'], area['size']]
966 continue
Patrick Georgicebb5a22016-08-15 19:07:02 +0200967 elif label == 'coreboot':
Julius Wernerbcf0c942016-09-07 16:57:40 -0700968 coreboot_range = [area['offset'], area['size']]
969 continue
Patrick Georgicebb5a22016-08-15 19:07:02 +0200970 elif label == 'si-desc':
971 fdt.PutString(fdt_path, 'type', 'ifd')
972 elif label == 'rw-shared':
973 fdt_path = '/flash/shared-section'
974 elif label == 'rw-section-'+slot:
975 fdt_path = '/flash/rw-'+slot
976 elif label == 'rw-legacy' and self.seabios_fname:
977 fdt.PutString(fdt_path, 'type', 'blob legacy')
978 elif label in ['rw-mrc-cache', 'rw-elog', 'rw-legacy',
979 'rw-vpd', 'rw-unused', 'ro-vpd', 'ro-unused',
980 'ro-frid-pad', 'bios-unusable', 'device-extension',
981 'unused-hole', 'rw-gpt-primary', 'rw-gpt-secondary',
982 'rw-nvram', 'ro-unused-1', 'ro-unused-2']:
983 fdt.PutString(fdt_path, 'type', 'wiped')
984 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
985 elif label == 'shared-data':
986 fdt.PutString(fdt_path, 'type', 'wiped')
987 fdt.PutIntList(fdt_path, 'wipe-value', [0])
988 elif label == 'vblock-dev':
989 fdt_path = '/flash/rw-vblock-dev'
990 fdt.PutString(fdt_path, 'type', 'wiped')
991 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
992 elif label[:-1] == 'vblock-':
993 fdt_path = '/flash/rw-'+slot+'-vblock'
994 fdt.PutString(fdt_path, 'type', 'keyblock cbfs/rw/'+slot+'-boot')
995 fdt.PutString(fdt_path, 'keyblock', 'firmware.keyblock')
996 fdt.PutString(fdt_path, 'signprivate', 'firmware_data_key.vbprivk')
997 fdt.PutString(fdt_path, 'kernelkey', 'kernel_subkey.vbpubk')
998 fdt.PutIntList(fdt_path, 'version', [1])
999 fdt.PutIntList(fdt_path, 'preamble-flags', [0])
1000 elif label[:-1] == 'fw-main-':
1001 fdt_path = '/flash/rw-'+slot+'-boot'
1002 fdt.PutString(fdt_path, 'type', 'blob cbfs/rw/'+slot+'-boot')
1003 elif label[:-1] == 'rw-fwid-':
1004 fdt_path = '/flash/rw-'+slot+'-firmware-id'
1005 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1006 elif label == 'ro-frid':
1007 fdt_path = '/flash/ro-firmware-id'
1008 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1009 elif label == 'ifwi':
1010 fdt_path = '/flash/ro-ifwi'
1011 fdt.PutString(fdt_path, 'type', 'blob ifwi')
1012 elif label == 'sign-cse':
1013 fdt_path = '/flash/ro-sig'
1014 fdt.PutString(fdt_path, 'type', 'blob sig2')
1015 # white list for empty regions
Patrick Georgi56dc9202016-09-07 21:12:04 +02001016 elif label in ['bootblock', 'misc-rw', 'ro-section', 'rw-environment',
1017 'rw-gpt', 'si-all', 'si-bios', 'si-me', 'wp-ro']:
Patrick Georgicebb5a22016-08-15 19:07:02 +02001018 pass
1019 else:
1020 raise ValueError('encountered label "'+label+'" in binary fmap. '+
1021 'Check chromeos.fmd')
1022 fdt.PutString(fdt_path, 'label', label)
1023 fdt.PutIntList(fdt_path, 'reg', [area['offset'], area['size']])
1024
Julius Wernerbcf0c942016-09-07 16:57:40 -07001025 if coreboot_range is not None:
1026 if bootblock_range is not None:
1027 if bootblock_range[0] + bootblock_range[1] != coreboot_range[0]:
1028 raise ValueError('Cannot combine BOOTBLOCK and COREBOOT')
1029 coreboot_range[0] = bootblock_range[0]
1030 coreboot_range[1] += bootblock_range[1]
1031 fdt_path = '/flash/ro-boot'
1032 fdt.PutString(fdt_path, 'type', 'blob coreboot')
1033 fdt.PutString(fdt_path, 'label', 'coreboot')
1034 fdt.PutIntList(fdt_path, 'reg', [coreboot_range[0], coreboot_range[1]])
1035
Simon Glass7df773b2013-08-25 18:02:29 -06001036 # Remember our board type.
1037 fdt.PutString('/chromeos-config', 'board', self._board)
1038
Simon Glasse53abbc2013-08-21 22:29:55 -06001039 self.fdt = fdt
1040 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001041
Simon Glassc90cf582012-03-13 15:40:47 -07001042 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001043 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001044
1045 - Checks options, tools, output directory, fdt.
1046 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001047
1048 Args:
Simon Glass56577572011-07-19 11:08:06 +12001049 hardware_id: Hardware ID to use for this board. If None, then the
1050 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001051 output_fname: Output filename for the image. If this is not None, then
1052 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001053 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001054
1055 Returns:
1056 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001057 """
Vadim Bendebury5baeec12013-04-02 13:01:22 -07001058 if self._small or self.fdt.GetProp('/config', 'nogbb', 'any') != 'any':
1059 gbb = '' # Building a small image or `nogbb' is requested in device tree.
1060 else:
Simon Glass56577572011-07-19 11:08:06 +12001061 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001062
1063 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001064 image, pack = self._CreateImage(gbb, self.fdt)
1065 if show_map:
1066 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001067 if output_fname:
1068 shutil.copyfile(image, output_fname)
1069 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001070 return image, pack.props