blob: 48c61d7fdab05749bc908e4e46eef0b1242bfcdb [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.
Simon Glass290a1802011-07-17 13:54:32 -0700122
123 def SetDirs(self, keydir):
124 """Set up directories required for Bundle.
125
126 Args:
127 keydir: Directory containing keys to use for signing firmware.
128 """
129 self._keydir = keydir
130
Patrick Georgi48030572016-09-09 22:55:46 +0200131 def SetFiles(self, board, bct, uboot=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800132 coreboot_elf=None,
Simon Glass942bedb2016-05-14 16:19:59 -0600133 seabios=None, exynos_bl1=None, exynos_bl2=None,
Randall Spangler7307da92014-07-18 12:47:34 -0700134 skeleton=None, ecrw=None, ecro=None, pdrw=None,
Patrick Georgi48030572016-09-09 22:55:46 +0200135 kernel=None, blobs=None, cbfs_files=None,
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600136 rocbfs_files=None):
Simon Glass290a1802011-07-17 13:54:32 -0700137 """Set up files required for Bundle.
138
139 Args:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500140 board: The name of the board to target (e.g. nyan).
Simon Glass290a1802011-07-17 13:54:32 -0700141 uboot: The filename of the u-boot.bin image to use.
142 bct: The filename of the binary BCT file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800143 coreboot: The filename of the coreboot image to use (on x86).
144 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Vincent Palatinf7286772011-10-12 14:31:53 -0700145 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700146 exynos_bl1: The filename of the exynos BL1 file
147 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
148 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700149 ecrw: The filename of the EC (Embedded Controller) read-write file.
150 ecro: The filename of the EC (Embedded Controller) read-only file.
Randall Spangler7307da92014-07-18 12:47:34 -0700151 pdrw: The filename of the PD (PD embedded controller) read-write file.
Simon Glassde9c8072012-07-02 22:29:02 -0700152 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800153 blobs: List of (type, filename) of arbitrary blobs.
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600154 cbfs_files: Root directory of files to be stored in RO and RW CBFS
155 rocbfs_files: Root directory of files to be stored in RO CBFS
Simon Glass290a1802011-07-17 13:54:32 -0700156 """
157 self._board = board
158 self.uboot_fname = uboot
159 self.bct_fname = bct
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700160 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800161 self.coreboot_elf = coreboot_elf
Vincent Palatinf7286772011-10-12 14:31:53 -0700162 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700163 self.exynos_bl1 = exynos_bl1
164 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700165 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700166 self.ecrw_fname = ecrw
167 self.ecro_fname = ecro
Randall Spangler7307da92014-07-18 12:47:34 -0700168 self.pdrw_fname = pdrw
Simon Glassde9c8072012-07-02 22:29:02 -0700169 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800170 self.blobs = dict(blobs or ())
Daisuke Nojiri69662892015-09-25 15:24:04 -0700171 self.cbfs_files = cbfs_files
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600172 self.rocbfs_files = rocbfs_files
Simon Glass290a1802011-07-17 13:54:32 -0700173
Patrick Georgi450204a2016-08-15 19:13:29 +0200174 def SetOptions(self, small, gbb_flags, force_efs=False):
Simon Glass290a1802011-07-17 13:54:32 -0700175 """Set up options supported by Bundle.
176
177 Args:
178 small: Only create a signed U-Boot - don't produce the full packed
179 firmware image. This is useful for devs who want to replace just the
180 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700181 gbb_flags: Specification for string containing adjustments to make.
Simon Glass00d027e2013-07-20 14:51:12 -0600182 force_efs: Force firmware to use 'early firmware selection' feature,
183 where RW firmware is selected before SDRAM is initialized.
Simon Glass290a1802011-07-17 13:54:32 -0700184 """
185 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700186 self._gbb_flags = gbb_flags
Simon Glass00d027e2013-07-20 14:51:12 -0600187 self._force_efs = force_efs
Simon Glass290a1802011-07-17 13:54:32 -0700188
Simon Glass22f39fb2013-02-09 13:44:14 -0800189 def _GetBuildRoot(self):
190 """Get the path to this board's 'firmware' directory.
191
192 Returns:
193 Path to firmware directory, with ## representing the path to the
194 chroot.
195 """
Simon Glass290a1802011-07-17 13:54:32 -0700196 if not self._board:
197 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800198 return os.path.join('##', 'build', self._board, 'firmware')
199
200 def _CheckFdtFilename(self, fname):
201 """Check provided FDT filename and return the correct name if needed.
202
203 Where the filename lacks a path, add a default path for this board.
204 Where no FDT filename is provided, select a default one for this board.
205
206 Args:
207 fname: Proposed FDT filename.
208
209 Returns:
210 Selected FDT filename, after validation.
211 """
212 build_root = self._GetBuildRoot()
Julius Wernerb4b14392013-08-09 14:41:40 -0700213 dir_name = os.path.join(build_root, 'dtb')
Simon Glass22f39fb2013-02-09 13:44:14 -0800214 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700215 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700216 base_name = re.sub('_', '-', self._board)
217
218 # In case the name exists with a prefix or suffix, find it.
Julius Wernerb4b14392013-08-09 14:41:40 -0700219 wildcard = os.path.join(dir_name, '*%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700220 found_list = glob.glob(self._tools.Filename(wildcard))
221 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800222 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700223 else:
224 # We didn't find anything definite, so set up our expected name.
Julius Wernerb4b14392013-08-09 14:41:40 -0700225 fname = os.path.join(dir_name, '%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700226
Simon Glass881964d2012-04-04 11:34:09 -0700227 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800228 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700229 if not ext and not os.path.dirname(root):
Julius Wernerb4b14392013-08-09 14:41:40 -0700230 fname = os.path.join(dir_name, '%s.dtb' % root)
Simon Glass22f39fb2013-02-09 13:44:14 -0800231 return fname
232
233 def CheckOptions(self):
234 """Check provided options and select defaults."""
235 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700236
Simon Glass49b026b2013-04-26 16:38:42 -0700237 board_type = self._board.split('_')[0]
238 model = type_to_model.get(board_type)
239
Simon Glass290a1802011-07-17 13:54:32 -0700240 if not self.uboot_fname:
241 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
242 if not self.bct_fname:
243 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass49b026b2013-04-26 16:38:42 -0700244 if model:
245 if not self.exynos_bl1:
Simon Glassd05696e2013-06-13 20:14:00 -0700246 self.exynos_bl1 = os.path.join(build_root, 'u-boot.bl1.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700247 if not self.exynos_bl2:
Julius Wernerb12c0052013-08-14 13:57:04 -0700248 self.exynos_bl2 = os.path.join(build_root, 'u-boot-spl.wrapped.bin')
Simon Glass07267952012-06-08 12:45:13 -0700249 if not self.coreboot_fname:
250 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
251 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700252 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Simon Glassbe0bc002012-08-16 12:50:48 -0700253 if not self.ecrw_fname:
254 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
Randall Spangler7307da92014-07-18 12:47:34 -0700255 if not self.pdrw_fname:
256 self.pdrw_fname = os.path.join(build_root, 'pd.RW.bin')
Simon Glassbe0bc002012-08-16 12:50:48 -0700257 if not self.ecro_fname:
258 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700259
Simon Glass75759302012-03-15 20:26:53 -0700260 def GetFiles(self):
261 """Get a list of files that we know about.
262
263 This is the opposite of SetFiles except that we may have put in some
264 default names. It returns a dictionary containing the filename for
265 each of a number of pre-defined files.
266
267 Returns:
268 Dictionary, with one entry for each file.
269 """
270 file_list = {
271 'bct' : self.bct_fname,
272 'exynos-bl1' : self.exynos_bl1,
273 'exynos-bl2' : self.exynos_bl2,
274 }
275 return file_list
276
Simon Glass4a887b12012-10-23 16:29:03 -0700277 def DecodeGBBFlagsFromFdt(self):
278 """Get Google Binary Block flags from the FDT.
279
280 These should be in the chromeos-config node, like this:
281
282 chromeos-config {
283 gbb-flag-dev-screen-short-delay;
284 gbb-flag-force-dev-switch-on;
285 gbb-flag-force-dev-boot-usb;
286 gbb-flag-disable-fw-rollback-check;
287 };
288
289 Returns:
290 GBB flags value from FDT.
291 """
292 chromeos_config = self.fdt.GetProps("/chromeos-config")
293 gbb_flags = 0
294 for name in chromeos_config:
295 if name.startswith('gbb-flag-'):
296 flag_value = gbb_flag_properties.get(name[9:])
297 if flag_value:
298 gbb_flags |= flag_value
299 self._out.Notice("FDT: Enabling %s." % name)
300 else:
301 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
302 return gbb_flags
303
Simon Glass157c0662012-10-23 13:52:42 -0700304 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
305 """Decode ajustments to the provided GBB flags.
306
307 We support three options:
308
309 hex value: c2
310 defined value: force-dev-boot-usb,load-option-roms
311 adjust default value: -load-option-roms,+force-dev-boot-usb
312
313 The last option starts from the passed-in GBB flags and adds or removes
314 flags.
315
316 Args:
317 gbb_flags: Base (default) FDT flags.
318 adjustments: String containing adjustments to make.
319
320 Returns:
321 Updated FDT flags.
322 """
323 use_base_value = True
324 if adjustments:
325 try:
326 return int(adjustments, base=16)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700327 except (ValueError, TypeError):
Simon Glass157c0662012-10-23 13:52:42 -0700328 pass
329 for flag in adjustments.split(','):
330 oper = None
331 if flag[0] in ['-', '+']:
332 oper = flag[0]
333 flag = flag[1:]
334 value = gbb_flag_properties.get(flag)
335 if not value:
336 raise ValueError("Invalid GBB flag '%s'" % flag)
337 if oper == '+':
338 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800339 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700340 elif oper == '-':
341 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800342 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700343 else:
344 if use_base_value:
345 gbb_flags = 0
346 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800347 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700348 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800349 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700350
351 return gbb_flags
352
Simon Glass56577572011-07-19 11:08:06 +1200353 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700354 """Create a GBB for the image.
355
Simon Glass56577572011-07-19 11:08:06 +1200356 Args:
357 hardware_id: Hardware ID to use for this board. If None, then the
358 default from the Fdt will be used
359
Simon Glass89b86b82011-07-17 23:49:49 -0700360 Returns:
361 Path of the created GBB file.
Simon Glass89b86b82011-07-17 23:49:49 -0700362 """
Simon Glass56577572011-07-19 11:08:06 +1200363 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800364 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700365 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700366 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700367
Simon Glass4a887b12012-10-23 16:29:03 -0700368 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800369
Simon Glass157c0662012-10-23 13:52:42 -0700370 # Allow command line to override flags
371 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
372
Simon Glass4a887b12012-10-23 16:29:03 -0700373 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700374 self._out.Progress('Creating GBB')
Patrick Georgi48030572016-09-09 22:55:46 +0200375 sizes = [0x100, 0x1000, 0, 0x1000]
Simon Glass89b86b82011-07-17 23:49:49 -0700376 sizes = ['%#x' % size for size in sizes]
377 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700378 keydir = self._tools.Filename(self._keydir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800379
380 gbb_set_command = ['-s',
381 '--hwid=%s' % hardware_id,
382 '--rootkey=%s/root_key.vbpubk' % keydir,
383 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
384 '--flags=%d' % gbb_flags,
385 gbb]
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800386
Simon Glass290a1802011-07-17 13:54:32 -0700387 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800388 self._tools.Run('gbb_utility', gbb_set_command, cwd=odir)
Simon Glass290a1802011-07-17 13:54:32 -0700389 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700390
Simon Glasse13ee2c2011-07-28 08:12:28 +1200391 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700392 """Sign an image so that the Tegra SOC will boot it.
393
394 Args:
395 bct: BCT file to use.
396 bootstub: Boot stub (U-Boot + fdt) file to sign.
397 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700398
399 Returns:
400 filename of signed image.
Simon Glass89b86b82011-07-17 23:49:49 -0700401 """
402 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200403 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700404 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200405 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700406 fd = open(config, 'w')
407 fd.write('Version = 1;\n')
408 fd.write('Redundancy = 1;\n')
409 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700410
411 # TODO(dianders): Right now, we don't have enough space in our flash map
412 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
413 # sure what this does for reliability, but at least things will fit...
414 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
415 if is_nand:
416 fd.write('Bctcopy = 1;\n')
417
Simon Glass89b86b82011-07-17 23:49:49 -0700418 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
419 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700420
Simon Glass89b86b82011-07-17 23:49:49 -0700421 fd.close()
422
423 self._tools.Run('cbootimage', [config, signed])
424 self._tools.OutputSize('BCT', bct)
425 self._tools.OutputSize('Signed image', signed)
426 return signed
427
Doug Anderson86ce5f42011-07-27 10:40:18 -0700428 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700429 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700430
431 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700432 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700433 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700434 """
Simon Glass468d8752012-09-19 16:36:19 -0700435 if bootcmd is not None:
436 if bootcmd == 'none':
437 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800438 self.fdt.PutString('/config', 'bootcmd', bootcmd)
439 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700440 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700441
Simon Glassa4934b72012-05-09 13:35:02 -0700442 def SetNodeEnabled(self, node_name, enabled):
443 """Set whether an node is enabled or disabled.
444
445 This simply sets the 'status' property of a node to "ok", or "disabled".
446
447 The node should either be a full path to the node (like '/uart@10200000')
448 or an alias property.
449
450 Aliases are supported like this:
451
452 aliases {
453 console = "/uart@10200000";
454 };
455
456 pointing to a node:
457
458 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700459 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700460 };
461
462 In this case, this function takes the name of the alias ('console' in
463 this case) and updates the status of the node that is pointed to, to
464 either ok or disabled. If the alias does not exist, a warning is
465 displayed.
466
467 Args:
468 node_name: Name of node (e.g. '/uart@10200000') or alias alias
469 (e.g. 'console') to adjust
470 enabled: True to enable, False to disable
471 """
472 # Look up the alias if this is an alias reference
473 if not node_name.startswith('/'):
474 lookup = self.fdt.GetString('/aliases', node_name, '')
475 if not lookup:
476 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
477 return
478 node_name = lookup
479 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700480 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700481 else:
482 status = 'disabled'
483 self.fdt.PutString(node_name, 'status', status)
484
485 def AddEnableList(self, enable_list):
486 """Process a list of nodes to enable/disable.
487
488 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700489 enable_list: List of (node, value) tuples to add to the fdt. For each
Simon Glassa4934b72012-05-09 13:35:02 -0700490 tuple:
491 node: The fdt node to write to will be <node> or pointed to by
492 /aliases/<node>. We can tell which
493 value: 0 to disable the node, 1 to enable it
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700494
Vadim Bendebury507c0012013-06-09 12:49:25 -0700495 Raises:
496 CmdError if a command fails.
Simon Glassa4934b72012-05-09 13:35:02 -0700497 """
498 if enable_list:
499 for node_name, enabled in enable_list:
500 try:
501 enabled = int(enabled)
502 if enabled not in (0, 1):
503 raise ValueError
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700504 except ValueError:
Simon Glassa4934b72012-05-09 13:35:02 -0700505 raise CmdError("Invalid enable option value '%s' "
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700506 "(should be 0 or 1)" % str(enabled))
Simon Glassa4934b72012-05-09 13:35:02 -0700507 self.SetNodeEnabled(node_name, enabled)
508
Simon Glass290a1802011-07-17 13:54:32 -0700509 def AddConfigList(self, config_list, use_int=False):
510 """Add a list of config items to the fdt.
511
512 Normally these values are written to the fdt as strings, but integers
513 are also supported, in which case the values will be converted to integers
514 (if necessary) before being stored.
515
516 Args:
517 config_list: List of (config, value) tuples to add to the fdt. For each
518 tuple:
519 config: The fdt node to write to will be /config/<config>.
520 value: An integer or string value to write.
521 use_int: True to only write integer values.
522
523 Raises:
524 CmdError: if a value is required to be converted to integer but can't be.
525 """
526 if config_list:
527 for config in config_list:
528 value = config[1]
529 if use_int:
530 try:
531 value = int(value)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700532 except ValueError:
Simon Glass290a1802011-07-17 13:54:32 -0700533 raise CmdError("Cannot convert config option '%s' to integer" %
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700534 str(value))
Simon Glass290a1802011-07-17 13:54:32 -0700535 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800536 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700537 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800538 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700539
Simon Glass7c2d5572011-11-15 14:47:08 -0800540 def DecodeTextBase(self, data):
541 """Look at a U-Boot image and try to decode its TEXT_BASE.
542
543 This works because U-Boot has a header with the value 0x12345678
544 immediately followed by the TEXT_BASE value. We can therefore read this
545 from the image with some certainty. We check only the first 40 words
546 since the header should be within that region.
547
Simon Glass96b50302012-07-20 06:55:28 +0100548 Since upstream Tegra has moved to having a 16KB SPL region at the start,
549 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
550 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
551
Simon Glass7c2d5572011-11-15 14:47:08 -0800552 Args:
553 data: U-Boot binary data
554
555 Returns:
556 Text base (integer) or None if none was found
557 """
558 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100559 for start in (0, 0x4000):
560 for i in range(start, start + 160, 4):
561 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800562
Simon Glass96b50302012-07-20 06:55:28 +0100563 # TODO(sjg): This does not cope with a big-endian target
564 value = struct.unpack('<I', word)[0]
565 if found:
566 return value - start
567 if value == 0x12345678:
568 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800569
570 return None
571
572 def CalcTextBase(self, name, fdt, fname):
573 """Calculate the TEXT_BASE to use for U-Boot.
574
575 Normally this value is in the fdt, so we just read it from there. But as
576 a second check we look at the image itself in case this is different, and
577 switch to that if it is.
578
579 This allows us to flash any U-Boot even if its TEXT_BASE is different.
580 This is particularly useful with upstream U-Boot which uses a different
581 value (which we will move to).
582 """
583 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800584 # The value that comes back from fdt.GetInt is signed, which makes no
585 # sense for an address base. Force it to unsigned.
586 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800587 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100588 text_base_str = '%#x' % text_base if text_base else 'None'
589 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
590 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800591
592 # If they are different, issue a warning and switch over.
593 if text_base and text_base != fdt_text_base:
594 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
595 "fdt value of %x. Using %x" % (text_base, name,
596 fdt_text_base, text_base))
597 fdt_text_base = text_base
598 return fdt_text_base
599
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600600 def _AddCbfsFiles(self, bootstub, cbfs_files):
601 for dir, subs, files in os.walk(cbfs_files):
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600602 for file in files:
603 file = os.path.join(dir, file)
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600604 cbfs_name = file.replace(cbfs_files, '', 1).strip('/')
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600605 self._tools.Run('cbfstool', [bootstub, 'add', '-f', file,
606 '-n', cbfs_name, '-t', 'raw', '-c', 'lzma'])
607
608 def _CreateCorebootStub(self, pack, coreboot):
609 """Create a coreboot boot stub and add pack properties.
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700610
611 Args:
Aaron Durbina113f522016-01-05 09:09:55 -0600612 pack: a PackFirmware object describing the firmware image to build.
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700613 coreboot: Path to coreboot.rom
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700614 """
615 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700616 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100617
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600618 pack.AddProperty('coreboot', bootstub)
619 pack.AddProperty('image', bootstub)
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700620
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600621 # Add files to to RO and RW CBFS if provided.
Aaron Durbin5751c3e2016-01-04 11:45:22 -0600622 if self.cbfs_files:
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600623 self._AddCbfsFiles(bootstub, self.cbfs_files)
Simon Glass7e199222012-03-13 15:51:18 -0700624
Aaron Durbina113f522016-01-05 09:09:55 -0600625 # Create a coreboot copy to use as a scratch pad. Order matters. The
626 # cbfs_files were added prior to this action. That's so the RW CBFS
Patrick Georgi45b64b82016-10-05 16:35:27 +0200627 # regions inherit the files from the RO CBFS region.
Patrick Georgi3a332672015-11-20 10:02:51 +0100628 cb_copy = os.path.abspath(os.path.join(self._tools.outdir, 'cb_with_fmap'))
Aaron Durbina113f522016-01-05 09:09:55 -0600629 self._tools.WriteFile(cb_copy, self._tools.ReadFile(bootstub))
Patrick Georgi3a332672015-11-20 10:02:51 +0100630 binary = self._tools.ReadFile(bootstub)
Patrick Georgi3a332672015-11-20 10:02:51 +0100631 self._tools.WriteFile(cb_copy, binary)
632 # Publish where coreboot is with the FMAP data.
633 pack.AddProperty('cb_with_fmap', cb_copy)
Aaron Durbina113f522016-01-05 09:09:55 -0600634
Aaron Durbin95ef60c2016-01-06 09:17:21 -0600635 # Add files to to RO CBFS if provided. This done here such that the
636 # copy above does not contain the RO CBFS files.
637 if self.rocbfs_files:
638 self._AddCbfsFiles(bootstub, self.rocbfs_files)
639
Aaron Durbina113f522016-01-05 09:09:55 -0600640
Simon Glass89b86b82011-07-17 23:49:49 -0700641 def _PackOutput(self, msg):
642 """Helper function to write output from PackFirmware (verbose level 2).
643
644 This is passed to PackFirmware for it to use to write output.
645
646 Args:
647 msg: Message to display.
648 """
649 self._out.Notice(msg)
650
Patrick Georgic1064f42016-10-12 11:34:24 +0200651 def _FdtNameToFmap(self, fdtstr):
652 return re.sub('-', '_', fdtstr).upper()
653
Aaron Durbin80564452015-12-21 15:25:06 -0600654 def _FmapNameByPath(self, path):
655 """ Take list of names to form node path. Return FMAP name.
656
657 Obtain the FMAP name described by the node path.
658
659 Args:
660 path: list forming a node path.
661
662 Returns:
663 FMAP name of fdt node.
664
665 Raises:
666 CmdError if path not found.
667 """
668 lbl = self.fdt.GetLabel(self.fdt.GetFlashNode(*path))
Patrick Georgic1064f42016-10-12 11:34:24 +0200669 return self._FdtNameToFmap(lbl)
Aaron Durbin80564452015-12-21 15:25:06 -0600670
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800671 def _PrepareCbfs(self, pack, blob_name):
672 """Create CBFS blob in rw-boot-{a,b} FMAP sections.
673
674 When the blob name is defined as cbfs#<section>#<subsection>, fill the
675 <section>_<subsection> area in the flash map with a CBFS copy, putting the
676 CBFS header of the copy at the base of the section.
677
678 If --coreboot-elf parameter was specified during cros_bumdle_firmware
679 invocation, add the parameter of this option as the payload to the new
680 CBFS instance.
681
682 Args:
683 pack: a PackFirmware object describing the firmware image to build.
684 blob_name: a string, blob name describing what FMAP section this CBFS
685 copy is destined to
686 Raises:
Patrick Georgi3a332672015-11-20 10:02:51 +0100687 CmdError if cbfs-files node has incorrect parameters.
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800688 """
Patrick Georgi3a332672015-11-20 10:02:51 +0100689 cb_copy = pack.GetProperty('cb_with_fmap')
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800690
691 part_sections = blob_name.split('/')[1:]
Aaron Durbin80564452015-12-21 15:25:06 -0600692 fmap_dst = self._FmapNameByPath(part_sections)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800693
694 # Base address and size of the desitnation partition
695 base, size = self.fdt.GetFlashPart(*part_sections)
696
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800697 # Add coreboot payload if so requested. Note that the some images use
698 # different payload for the rw sections, which is passed in as the value
699 # of the --uboot option in the command line.
700 if self.uboot_fname:
701 payload_fname = self.uboot_fname
702 elif self.coreboot_elf:
703 payload_fname = self.coreboot_elf
704 else:
705 payload_fname = None
706
707 if payload_fname:
708 self._tools.Run('cbfstool', [
709 cb_copy, 'add-payload', '-f', payload_fname,
Patrick Georgi10690b42015-11-20 22:06:38 +0100710 '-n', 'fallback/payload', '-c', 'lzma' , '-r', fmap_dst])
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800711
Patrick Georgi964fb542015-10-16 16:52:03 +0200712 if self.ecrw_fname:
713 self._tools.Run('cbfstool', [
714 cb_copy, 'add', '-f', self.ecrw_fname, '-t', 'raw',
Patrick Georgi10690b42015-11-20 22:06:38 +0100715 '-n', 'ecrw', '-A', 'sha256', '-r', fmap_dst ])
Patrick Georgi964fb542015-10-16 16:52:03 +0200716
717 if self.pdrw_fname:
718 self._tools.Run('cbfstool', [
719 cb_copy, 'add', '-f', self.pdrw_fname, '-t', 'raw',
Patrick Georgi10690b42015-11-20 22:06:38 +0100720 '-n', 'pdrw', '-A', 'sha256', '-r', fmap_dst ])
Patrick Georgi964fb542015-10-16 16:52:03 +0200721
Aaron Durbin880cf952016-01-27 14:11:38 -0600722 # Parse the file list to obtain the last entry. If its empty use its
723 # offset as the size of the CBFS to hash.
724 stdout = self._tools.Run('cbfstool',
725 [ cb_copy, 'print', '-k', '-r', fmap_dst ])
726 # Fields are tab separated in the following order.
727 # Name Offset Type Metadata Size Data Size Total Size
728 last_entry = stdout.strip().splitlines()[-1].split('\t')
729 if last_entry[0] == '(empty)' and last_entry[2] == 'null':
730 size = int(last_entry[1], 16)
731
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800732 # And extract the blob for the FW section
733 rw_section = os.path.join(self._tools.outdir, '_'.join(part_sections))
734 self._tools.WriteFile(rw_section,
735 self._tools.ReadFile(cb_copy)[base:base+size])
736
737 pack.AddProperty(blob_name, rw_section)
738
Patrick Georgidf772712016-10-05 16:24:20 +0200739 def _PrepareBootblock(self, pack):
740 """Copy bootblock into blob file for packaging
741
742 Args:
743 pack: a PackFirmware object describing the firmware image to build.
744 Raises:
745 CmdError if cbfs-files node has incorrect parameters.
746 """
747 cb_copy = pack.GetProperty('cb_with_fmap')
748
749 bootblock_section = os.path.join(self._tools.outdir, 'bootblock.section')
750
751 self._tools.Run('cbfstool', [
752 cb_copy, 'read', '-r', 'BOOTBLOCK', '-f', bootblock_section])
753
754 pack.AddProperty('bootblock', bootblock_section)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800755
Simon Glass439fe7a2012-03-09 16:19:34 -0800756 def _BuildBlob(self, pack, fdt, blob_type):
757 """Build the blob data for a particular blob type.
758
759 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700760 pack: a PackFirmware object describing the firmware image to build.
761 fdt: an fdt object including image layout information
Simon Glass439fe7a2012-03-09 16:19:34 -0800762 blob_type: The type of blob to create data for. Supported types are:
763 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
764 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
Vadim Bendebury507c0012013-06-09 12:49:25 -0700765
766 Raises:
767 CmdError if a command fails.
Simon Glass439fe7a2012-03-09 16:19:34 -0800768 """
769 if blob_type == 'coreboot':
Patrick Georgifa20ddc2016-09-27 14:10:51 +0200770 pass
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700771 elif blob_type == 'legacy':
772 pack.AddProperty('legacy', self.seabios_fname)
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800773 elif blob_type.startswith('cbfs'):
774 self._PrepareCbfs(pack, blob_type)
Patrick Georgidf772712016-10-05 16:24:20 +0200775 elif blob_type == 'bootblock':
776 self._PrepareBootblock(pack)
Simon Glass439fe7a2012-03-09 16:19:34 -0800777 elif pack.GetProperty(blob_type):
778 pass
Furquan Shaikh95ee50c2016-05-29 09:46:41 -0700779 elif blob_type == 'ifwi' or blob_type == 'sig2':
780 # Copy IFWI/CSE_SIGN(sig2) regions from coreboot copy and build a blob
781 # for the blob_type
782 cb_copy = pack.GetProperty('cb_with_fmap')
Furquan Shaikh95ee50c2016-05-29 09:46:41 -0700783 blob_start, blob_size = fdt.GetFlashPart('ro', blob_type)
784 blob_file = blob_type + '.bin'
785 blob_path = os.path.join(self._tools.outdir, blob_file)
786 data = self._tools.ReadFile(cb_copy)
787 self._tools.WriteFile(blob_path, data[blob_start:blob_start+blob_size])
788 pack.AddProperty(blob_type, blob_path)
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800789 elif blob_type in self.blobs:
790 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -0800791 else:
792 raise CmdError("Unknown blob type '%s' required in flash map" %
793 blob_type)
794
Aaron Durbin41c85b62015-12-17 17:40:29 -0600795 def _BuildBlobs(self, pack, fdt):
796 """Build the blob data for the list of blobs in the pack.
797
798 Args:
799 pack: a PackFirmware object describing the firmware image to build.
800 fdt: an fdt object including image layout information
801
802 Raises:
803 CmdError if a command fails.
Aaron Durbin41c85b62015-12-17 17:40:29 -0600804 """
805 blob_list = pack.GetBlobList()
806 self._out.Info('Building blobs %s\n' % blob_list)
807
808 complete = False
809 deferred_list = []
810
Patrick Georgifa20ddc2016-09-27 14:10:51 +0200811 # We always have a coreboot blob, and some other components rely on it, so
812 # make sure it's ready when the others come in.
813 blob_list.remove('coreboot')
814 self._CreateCorebootStub(pack, self.coreboot_fname)
815
Patrick Georgi49cf7b22016-09-27 14:25:03 +0200816 for blob_type in blob_list:
817 self._BuildBlob(pack, fdt, blob_type)
Aaron Durbin41c85b62015-12-17 17:40:29 -0600818
Simon Glass290a1802011-07-17 13:54:32 -0700819 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700820 """Create a full firmware image, along with various by-products.
821
822 This uses the provided u-boot.bin, fdt and bct to create a firmware
823 image containing all the required parts. If the GBB is not supplied
824 then this will just return a signed U-Boot as the image.
825
826 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700827 gbb: a string, full path to the GBB file, or empty if a GBB is not
828 required.
829 fdt: an fdt object containing required information.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200830
831 Returns:
832 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700833 """
Simon Glass02d124a2012-03-02 14:47:20 -0800834 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700835
Simon Glass439fe7a2012-03-09 16:19:34 -0800836 pack = PackFirmware(self._tools, self._out)
Simon Glass00d027e2013-07-20 14:51:12 -0600837 if self._force_efs:
838 fdt.PutInteger('/chromeos-config', 'early-firmware-selection', 1)
Simon Glassa7e66e22013-07-23 07:21:16 -0600839 pack.use_efs = fdt.GetInt('/chromeos-config', 'early-firmware-selection',
840 0)
Simon Glassb8c6d952012-12-01 06:14:35 -0800841
Simon Glass4f318912013-07-20 16:13:06 -0600842 pack.SelectFdt(fdt, self._board)
Simon Glass439fe7a2012-03-09 16:19:34 -0800843
844 # Get all our blobs ready
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800845 if self.uboot_fname:
846 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -0800847 if self.skeleton_fname:
848 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700849 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700850
Simon Glassde9c8072012-07-02 22:29:02 -0700851 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
852 if self.kernel_fname:
853 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
854
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800855 if gbb:
856 pack.AddProperty('gbb', gbb)
Aaron Durbin41c85b62015-12-17 17:40:29 -0600857
858 # Build the blobs out.
859 self._BuildBlobs(pack, fdt)
Simon Glass89b86b82011-07-17 23:49:49 -0700860
Simon Glass7306b902012-12-17 15:06:21 -0800861 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -0700862 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700863 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800864 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800865 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800866 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700867 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800868 pack.AddProperty('fwid', fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800869 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700870
871 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700872
873 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -0800874 pack.UpdateBlobPositionsAndHashes(fdt)
Simon Glass8884b982012-06-21 12:41:41 -0700875
Simon Glass6207efe2012-12-17 15:04:36 -0800876 # Make a copy of the fdt for the bootstub
877 fdt_data = self._tools.ReadFile(fdt.fname)
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800878 if self.uboot_fname:
879 uboot_data = self._tools.ReadFile(self.uboot_fname)
880 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
881 self._tools.WriteFile(uboot_copy, uboot_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800882
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800883 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
884 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800885
Simon Glassa10282a2013-01-08 17:06:41 -0800886 # Fix up the coreboot image here, since we can't do this until we have
887 # a final device tree binary.
Patrick Georgi50561e82016-10-06 18:45:05 +0200888 bootstub = pack.GetProperty('coreboot')
889 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
890 if self.coreboot_elf:
891 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
892 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
893 elif self.uboot_fname:
894 text_base = 0x1110000
Simon Glass0a7cf112013-05-21 23:08:21 -0700895
Patrick Georgi50561e82016-10-06 18:45:05 +0200896 # This is the the 'movw $GD_FLG_COLD_BOOT, %bx' instruction
897 # 1110015: 66 bb 00 01 mov $0x100,%bx
898 marker = struct.pack('<L', 0x0100bb66)
899 pos = uboot_data.find(marker)
900 if pos == -1 or pos > 0x100:
901 raise ValueError('Cannot find U-Boot cold boot entry point')
902 entry = text_base + pos
903 self._out.Notice('U-Boot entry point %#08x' % entry)
904 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
905 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
906 '-l', '%#x' % text_base, '-e', '%#x' % entry])
907 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
908 '-n', 'u-boot.dtb', '-t', '0xac'])
909 data = self._tools.ReadFile(bootstub)
910 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
911 self._tools.WriteFile(bootstub_copy, data)
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700912
Patrick Georgi50561e82016-10-06 18:45:05 +0200913 # Use offset and size from fmap.dts to extract CBFS area from coreboot.rom
914 cbfs_offset, cbfs_size = fdt.GetFlashPart('ro', 'boot')
915 self._tools.WriteFile(bootstub, data[cbfs_offset:cbfs_offset+cbfs_size])
Simon Glasscbc83552012-07-23 15:26:22 +0100916
Simon Glass208ad952013-02-10 11:16:46 -0800917 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -0700918 image = os.path.join(self._tools.outdir, 'image.bin')
919 pack.PackImage(self._tools.outdir, image)
920 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700921
Simon Glass439fe7a2012-03-09 16:19:34 -0800922 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700923 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700924 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700925
Simon Glassdedda6f2013-02-09 13:44:14 -0800926 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -0700927 """Select an FDT to control the firmware bundling
928
Simon Glassdedda6f2013-02-09 13:44:14 -0800929 We make a copy of this which will include any on-the-fly changes we want
930 to make.
931
Simon Glass290a1802011-07-17 13:54:32 -0700932 Args:
933 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -0800934 use_defaults: True to use a default FDT name if available, and to add
935 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -0700936
Simon Glassc0f3dc62011-08-09 14:19:05 -0700937 Returns:
938 The Fdt object of the original fdt file, which we will not modify.
939
Simon Glassdedda6f2013-02-09 13:44:14 -0800940 Raises:
941 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
942 False).
Simon Glass290a1802011-07-17 13:54:32 -0700943 """
Simon Glassdedda6f2013-02-09 13:44:14 -0800944 if use_defaults:
945 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -0800946 if not fdt_fname:
947 raise ValueError('Please provide an FDT filename')
948 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -0700949 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -0800950
Patrick Georgi81263072016-09-09 22:33:06 +0200951 fdt.Compile(None)
Simon Glasse53abbc2013-08-21 22:29:55 -0600952 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
953
Patrick Georgicebb5a22016-08-15 19:07:02 +0200954 if fdt.GetProp('/flash', 'reg', ''):
955 raise ValueError('fmap.dts /flash is deprecated. Use chromeos.fmd')
956
957 # fill in /flash from binary fmap
958 # ignore "read-only" attribute, that isn't used anywhere
959 fmap_blob = open(self.coreboot_fname).read()
960 f = fmap.fmap_decode(fmap_blob)
961 fdt.PutString('/flash', 'compatible', 'chromeos,flashmap')
962 fdt.PutIntList('/flash', 'reg', [f['base'], f['size']])
963 for area in f['areas']:
964 label = re.sub('_', '-', area['name']).lower()
965 fdt_path = '/flash/' + label
966 slot=label[-1]
967 if label == 'gbb':
968 fdt_path = '/flash/ro-gbb'
969 fdt.PutString(fdt_path, 'type', 'blob gbb')
970 elif label == 'fmap':
971 fdt_path = '/flash/ro-fmap'
972 fdt.PutString(fdt_path, 'type', 'fmap')
973 fdt.PutIntList(fdt_path, 'ver-major', [1])
974 fdt.PutIntList(fdt_path, 'ver-minor', [0])
Julius Wernerbcf0c942016-09-07 16:57:40 -0700975 elif label == 'bootblock':
Patrick Georgidf772712016-10-05 16:24:20 +0200976 fdt.PutString(fdt_path, 'type', 'blob bootblock')
Patrick Georgicebb5a22016-08-15 19:07:02 +0200977 elif label == 'coreboot':
Patrick Georgidf772712016-10-05 16:24:20 +0200978 fdt_path = '/flash/ro-boot'
979 fdt.PutString(fdt_path, 'type', 'blob coreboot')
Patrick Georgicebb5a22016-08-15 19:07:02 +0200980 elif label == 'si-desc':
981 fdt.PutString(fdt_path, 'type', 'ifd')
982 elif label == 'rw-shared':
983 fdt_path = '/flash/shared-section'
984 elif label == 'rw-section-'+slot:
985 fdt_path = '/flash/rw-'+slot
986 elif label == 'rw-legacy' and self.seabios_fname:
987 fdt.PutString(fdt_path, 'type', 'blob legacy')
988 elif label in ['rw-mrc-cache', 'rw-elog', 'rw-legacy',
989 'rw-vpd', 'rw-unused', 'ro-vpd', 'ro-unused',
990 'ro-frid-pad', 'bios-unusable', 'device-extension',
991 'unused-hole', 'rw-gpt-primary', 'rw-gpt-secondary',
992 'rw-nvram', 'ro-unused-1', 'ro-unused-2']:
993 fdt.PutString(fdt_path, 'type', 'wiped')
994 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
995 elif label == 'shared-data':
996 fdt.PutString(fdt_path, 'type', 'wiped')
997 fdt.PutIntList(fdt_path, 'wipe-value', [0])
998 elif label == 'vblock-dev':
999 fdt_path = '/flash/rw-vblock-dev'
1000 fdt.PutString(fdt_path, 'type', 'wiped')
1001 fdt.PutIntList(fdt_path, 'wipe-value', [0xff])
1002 elif label[:-1] == 'vblock-':
1003 fdt_path = '/flash/rw-'+slot+'-vblock'
1004 fdt.PutString(fdt_path, 'type', 'keyblock cbfs/rw/'+slot+'-boot')
1005 fdt.PutString(fdt_path, 'keyblock', 'firmware.keyblock')
1006 fdt.PutString(fdt_path, 'signprivate', 'firmware_data_key.vbprivk')
1007 fdt.PutString(fdt_path, 'kernelkey', 'kernel_subkey.vbpubk')
1008 fdt.PutIntList(fdt_path, 'version', [1])
1009 fdt.PutIntList(fdt_path, 'preamble-flags', [0])
1010 elif label[:-1] == 'fw-main-':
1011 fdt_path = '/flash/rw-'+slot+'-boot'
1012 fdt.PutString(fdt_path, 'type', 'blob cbfs/rw/'+slot+'-boot')
1013 elif label[:-1] == 'rw-fwid-':
1014 fdt_path = '/flash/rw-'+slot+'-firmware-id'
1015 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1016 elif label == 'ro-frid':
1017 fdt_path = '/flash/ro-firmware-id'
1018 fdt.PutString(fdt_path, 'type', 'blobstring fwid')
1019 elif label == 'ifwi':
1020 fdt_path = '/flash/ro-ifwi'
1021 fdt.PutString(fdt_path, 'type', 'blob ifwi')
1022 elif label == 'sign-cse':
1023 fdt_path = '/flash/ro-sig'
1024 fdt.PutString(fdt_path, 'type', 'blob sig2')
1025 # white list for empty regions
Patrick Georgi56dc9202016-09-07 21:12:04 +02001026 elif label in ['bootblock', 'misc-rw', 'ro-section', 'rw-environment',
1027 'rw-gpt', 'si-all', 'si-bios', 'si-me', 'wp-ro']:
Patrick Georgicebb5a22016-08-15 19:07:02 +02001028 pass
1029 else:
1030 raise ValueError('encountered label "'+label+'" in binary fmap. '+
1031 'Check chromeos.fmd')
1032 fdt.PutString(fdt_path, 'label', label)
1033 fdt.PutIntList(fdt_path, 'reg', [area['offset'], area['size']])
1034
Simon Glass7df773b2013-08-25 18:02:29 -06001035 # Remember our board type.
1036 fdt.PutString('/chromeos-config', 'board', self._board)
1037
Simon Glasse53abbc2013-08-21 22:29:55 -06001038 self.fdt = fdt
1039 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001040
Simon Glassc90cf582012-03-13 15:40:47 -07001041 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001042 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001043
1044 - Checks options, tools, output directory, fdt.
1045 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001046
1047 Args:
Simon Glass56577572011-07-19 11:08:06 +12001048 hardware_id: Hardware ID to use for this board. If None, then the
1049 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001050 output_fname: Output filename for the image. If this is not None, then
1051 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001052 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001053
1054 Returns:
1055 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001056 """
Vadim Bendebury5baeec12013-04-02 13:01:22 -07001057 if self._small or self.fdt.GetProp('/config', 'nogbb', 'any') != 'any':
1058 gbb = '' # Building a small image or `nogbb' is requested in device tree.
1059 else:
Simon Glass56577572011-07-19 11:08:06 +12001060 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001061
1062 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001063 image, pack = self._CreateImage(gbb, self.fdt)
1064 if show_map:
1065 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001066 if output_fname:
1067 shutil.copyfile(image, output_fname)
1068 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001069 return image, pack.props