blob: bf17a16d6031783e558224fee10bb7ba6e48af39 [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
Gabe Blackcdbdfe12013-02-06 05:37:52 -080020import hashlib
Simon Glass89b86b82011-07-17 23:49:49 -070021import os
22import re
23
Simon Glass89b86b82011-07-17 23:49:49 -070024from fdt import Fdt
25from pack_firmware import PackFirmware
26import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080027import struct
Vadim Bendebury8c35e2e2014-05-06 12:55:50 -070028from flashmaps import default_flashmaps
Simon Glass439fe7a2012-03-09 16:19:34 -080029from tools import CmdError
Vadim Bendeburyb12e3352013-06-08 17:25:19 -070030from exynos import ExynosBl2
Simon Glass89b86b82011-07-17 23:49:49 -070031
32# This data is required by bmpblk_utility. Does it ever change?
33# It was stored with the chromeos-bootimage ebuild, but we want
34# this utility to work outside the chroot.
35yaml_data = '''
36bmpblock: 1.0
37
38images:
39 devmode: DeveloperBmp/DeveloperBmp.bmp
40 recovery: RecoveryBmp/RecoveryBmp.bmp
41 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
42 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
43
44screens:
45 dev_en:
46 - [0, 0, devmode]
47 rec_en:
48 - [0, 0, recovery]
49 yuck_en:
50 - [0, 0, rec_yuck]
51 ins_en:
52 - [0, 0, rec_insert]
53
54localizations:
55 - [ dev_en, rec_en, yuck_en, ins_en ]
56'''
57
Simon Glass4a887b12012-10-23 16:29:03 -070058# Build GBB flags.
59# (src/platform/vboot_reference/firmware/include/gbb_header.h)
60gbb_flag_properties = {
61 'dev-screen-short-delay': 0x00000001,
62 'load-option-roms': 0x00000002,
63 'enable-alternate-os': 0x00000004,
64 'force-dev-switch-on': 0x00000008,
65 'force-dev-boot-usb': 0x00000010,
66 'disable-fw-rollback-check': 0x00000020,
67 'enter-triggers-tonorm': 0x00000040,
68 'force-dev-boot-legacy': 0x00000080,
Shawn Nematbakhsh07c19882014-08-19 10:21:59 -070069 'faft-key-overide': 0x00000100,
70 'disable-ec-software-sync': 0x00000200,
71 'default-dev-boot-legacy': 0x00000400,
72 'disable-pd-software-sync': 0x00000800,
Furquan Shaikhd4eac3b2015-05-15 18:05:09 -070073 'force-dev-boot-fastboot-full-cap': 0x00002000,
Simon Glass4a887b12012-10-23 16:29:03 -070074}
75
Simon Glass49b026b2013-04-26 16:38:42 -070076# Maps board name to Exynos product number
77type_to_model = {
78 'peach' : '5420',
79 'daisy' : '5250'
80}
81
Simon Glass5076a7f2012-10-23 16:31:54 -070082def ListGoogleBinaryBlockFlags():
83 """Print out a list of GBB flags."""
84 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
85 for name, value in gbb_flag_properties.iteritems():
86 print ' %-30s %02x' % (name, value)
87
Simon Glass89b86b82011-07-17 23:49:49 -070088class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070089 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070090
Simon Glass290a1802011-07-17 13:54:32 -070091 Sequence of events:
92 bundle = Bundle(tools.Tools(), cros_output.Output())
93 bundle.SetDirs(...)
94 bundle.SetFiles(...)
95 bundle.SetOptions(...)
96 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070097 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070098 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070099
Simon Glass290a1802011-07-17 13:54:32 -0700100 Public properties:
101 fdt: The fdt object that we use for building our image. This wil be the
102 one specified by the user, except that we might add config options
103 to it. This is set up by SelectFdt() which must be called before
104 bundling starts.
105 uboot_fname: Full filename of the U-Boot binary we use.
106 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -0700107 spl_source: Source device to load U-Boot from, in SPL:
108 straps: Select device according to CPU strap pins
109 spi: Boot from SPI
110 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -0700111
112 Private attributes:
113 _small: True to create a 'small' signed U-Boot, False to produce a
114 full image. The small U-Boot is enough to boot but will not have
115 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700116 """
Simon Glass89b86b82011-07-17 23:49:49 -0700117
Simon Glass290a1802011-07-17 13:54:32 -0700118 def __init__(self, tools, output):
119 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700120
Simon Glass290a1802011-07-17 13:54:32 -0700121 Args:
122 tools: A tools.Tools object to use for external tools.
123 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700124 """
Simon Glass290a1802011-07-17 13:54:32 -0700125 self._tools = tools
126 self._out = output
127
128 # Set up the things we need to know in order to operate.
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500129 self._board = None # Board name, e.g. nyan.
Simon Glass290a1802011-07-17 13:54:32 -0700130 self._fdt_fname = None # Filename of our FDT.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700131 self._force_rw = None
Simon Glass00d027e2013-07-20 14:51:12 -0600132 self._force_efs = None
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700133 self._gbb_flags = None
134 self._keydir = None
135 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700136 self.bct_fname = None # Filename of our BCT file.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700137 self.blobs = {} # Table of (type, filename) of arbitrary blobs
Hung-Te Lin5b649382011-08-03 15:01:16 +0800138 self.bmpblk_fname = None # Filename of our Bitmap Block
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700139 self.coreboot_elf = None
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700140 self.coreboot_fname = None # Filename of our coreboot binary.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700141 self.ecro_fname = None # Filename of EC read-only file
142 self.ecrw_fname = None # Filename of EC file
Randall Spangler7307da92014-07-18 12:47:34 -0700143 self.pdrw_fname = None # Filename of PD file
Simon Glass7e199222012-03-13 15:51:18 -0700144 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
145 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700146 self.fdt = None # Our Fdt object.
147 self.kernel_fname = None
148 self.postload_fname = None
149 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass07267952012-06-08 12:45:13 -0700150 self.skeleton_fname = None # Filename of Coreboot skeleton file
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700151 self.uboot_fname = None # Filename of our U-Boot binary.
Simon Glass290a1802011-07-17 13:54:32 -0700152
153 def SetDirs(self, keydir):
154 """Set up directories required for Bundle.
155
156 Args:
157 keydir: Directory containing keys to use for signing firmware.
158 """
159 self._keydir = keydir
160
Simon Glass6dcc2f22011-07-28 15:26:49 +1200161 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800162 coreboot_elf=None,
Simon Glass07267952012-06-08 12:45:13 -0700163 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Randall Spangler7307da92014-07-18 12:47:34 -0700164 skeleton=None, ecrw=None, ecro=None, pdrw=None,
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800165 kernel=None, blobs=None, skip_bmpblk=False):
Simon Glass290a1802011-07-17 13:54:32 -0700166 """Set up files required for Bundle.
167
168 Args:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500169 board: The name of the board to target (e.g. nyan).
Simon Glass290a1802011-07-17 13:54:32 -0700170 uboot: The filename of the u-boot.bin image to use.
171 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800172 bmpblk: The filename of bitmap block file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800173 coreboot: The filename of the coreboot image to use (on x86).
174 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200175 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700176 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700177 exynos_bl1: The filename of the exynos BL1 file
178 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
179 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700180 ecrw: The filename of the EC (Embedded Controller) read-write file.
181 ecro: The filename of the EC (Embedded Controller) read-only file.
Randall Spangler7307da92014-07-18 12:47:34 -0700182 pdrw: The filename of the PD (PD embedded controller) read-write file.
Simon Glassde9c8072012-07-02 22:29:02 -0700183 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800184 blobs: List of (type, filename) of arbitrary blobs.
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800185 skip_bmpblk: True if no bmpblk is required
Simon Glass290a1802011-07-17 13:54:32 -0700186 """
187 self._board = board
188 self.uboot_fname = uboot
189 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800190 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700191 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800192 self.coreboot_elf = coreboot_elf
Simon Glass6dcc2f22011-07-28 15:26:49 +1200193 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700194 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700195 self.exynos_bl1 = exynos_bl1
196 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700197 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700198 self.ecrw_fname = ecrw
199 self.ecro_fname = ecro
Randall Spangler7307da92014-07-18 12:47:34 -0700200 self.pdrw_fname = pdrw
Simon Glassde9c8072012-07-02 22:29:02 -0700201 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800202 self.blobs = dict(blobs or ())
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800203 self.skip_bmpblk = skip_bmpblk
Simon Glass290a1802011-07-17 13:54:32 -0700204
Simon Glass00d027e2013-07-20 14:51:12 -0600205 def SetOptions(self, small, gbb_flags, force_rw=False, force_efs=False):
Simon Glass290a1802011-07-17 13:54:32 -0700206 """Set up options supported by Bundle.
207
208 Args:
209 small: Only create a signed U-Boot - don't produce the full packed
210 firmware image. This is useful for devs who want to replace just the
211 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700212 gbb_flags: Specification for string containing adjustments to make.
213 force_rw: Force firmware into RW mode.
Simon Glass00d027e2013-07-20 14:51:12 -0600214 force_efs: Force firmware to use 'early firmware selection' feature,
215 where RW firmware is selected before SDRAM is initialized.
Simon Glass290a1802011-07-17 13:54:32 -0700216 """
217 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700218 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700219 self._force_rw = force_rw
Simon Glass00d027e2013-07-20 14:51:12 -0600220 self._force_efs = force_efs
Simon Glass290a1802011-07-17 13:54:32 -0700221
Simon Glass22f39fb2013-02-09 13:44:14 -0800222 def _GetBuildRoot(self):
223 """Get the path to this board's 'firmware' directory.
224
225 Returns:
226 Path to firmware directory, with ## representing the path to the
227 chroot.
228 """
Simon Glass290a1802011-07-17 13:54:32 -0700229 if not self._board:
230 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800231 return os.path.join('##', 'build', self._board, 'firmware')
232
233 def _CheckFdtFilename(self, fname):
234 """Check provided FDT filename and return the correct name if needed.
235
236 Where the filename lacks a path, add a default path for this board.
237 Where no FDT filename is provided, select a default one for this board.
238
239 Args:
240 fname: Proposed FDT filename.
241
242 Returns:
243 Selected FDT filename, after validation.
244 """
245 build_root = self._GetBuildRoot()
Julius Wernerb4b14392013-08-09 14:41:40 -0700246 dir_name = os.path.join(build_root, 'dtb')
Simon Glass22f39fb2013-02-09 13:44:14 -0800247 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700248 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700249 base_name = re.sub('_', '-', self._board)
250
251 # In case the name exists with a prefix or suffix, find it.
Julius Wernerb4b14392013-08-09 14:41:40 -0700252 wildcard = os.path.join(dir_name, '*%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700253 found_list = glob.glob(self._tools.Filename(wildcard))
254 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800255 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700256 else:
257 # We didn't find anything definite, so set up our expected name.
Julius Wernerb4b14392013-08-09 14:41:40 -0700258 fname = os.path.join(dir_name, '%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700259
Simon Glass881964d2012-04-04 11:34:09 -0700260 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800261 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700262 if not ext and not os.path.dirname(root):
Julius Wernerb4b14392013-08-09 14:41:40 -0700263 fname = os.path.join(dir_name, '%s.dtb' % root)
Simon Glass22f39fb2013-02-09 13:44:14 -0800264 return fname
265
266 def CheckOptions(self):
267 """Check provided options and select defaults."""
268 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700269
Simon Glass49b026b2013-04-26 16:38:42 -0700270 board_type = self._board.split('_')[0]
271 model = type_to_model.get(board_type)
272
Simon Glass290a1802011-07-17 13:54:32 -0700273 if not self.uboot_fname:
274 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
275 if not self.bct_fname:
276 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700277 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700278 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700279 if model:
280 if not self.exynos_bl1:
Simon Glassd05696e2013-06-13 20:14:00 -0700281 self.exynos_bl1 = os.path.join(build_root, 'u-boot.bl1.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700282 if not self.exynos_bl2:
Julius Wernerb12c0052013-08-14 13:57:04 -0700283 self.exynos_bl2 = os.path.join(build_root, 'u-boot-spl.wrapped.bin')
Simon Glass07267952012-06-08 12:45:13 -0700284 if not self.coreboot_fname:
285 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
286 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700287 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700288 if not self.seabios_fname:
289 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700290 if not self.ecrw_fname:
291 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
Randall Spangler7307da92014-07-18 12:47:34 -0700292 if not self.pdrw_fname:
293 self.pdrw_fname = os.path.join(build_root, 'pd.RW.bin')
Simon Glassbe0bc002012-08-16 12:50:48 -0700294 if not self.ecro_fname:
295 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700296
Simon Glass75759302012-03-15 20:26:53 -0700297 def GetFiles(self):
298 """Get a list of files that we know about.
299
300 This is the opposite of SetFiles except that we may have put in some
301 default names. It returns a dictionary containing the filename for
302 each of a number of pre-defined files.
303
304 Returns:
305 Dictionary, with one entry for each file.
306 """
307 file_list = {
308 'bct' : self.bct_fname,
309 'exynos-bl1' : self.exynos_bl1,
310 'exynos-bl2' : self.exynos_bl2,
311 }
312 return file_list
313
Simon Glass4a887b12012-10-23 16:29:03 -0700314 def DecodeGBBFlagsFromFdt(self):
315 """Get Google Binary Block flags from the FDT.
316
317 These should be in the chromeos-config node, like this:
318
319 chromeos-config {
320 gbb-flag-dev-screen-short-delay;
321 gbb-flag-force-dev-switch-on;
322 gbb-flag-force-dev-boot-usb;
323 gbb-flag-disable-fw-rollback-check;
324 };
325
326 Returns:
327 GBB flags value from FDT.
328 """
329 chromeos_config = self.fdt.GetProps("/chromeos-config")
330 gbb_flags = 0
331 for name in chromeos_config:
332 if name.startswith('gbb-flag-'):
333 flag_value = gbb_flag_properties.get(name[9:])
334 if flag_value:
335 gbb_flags |= flag_value
336 self._out.Notice("FDT: Enabling %s." % name)
337 else:
338 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
339 return gbb_flags
340
Simon Glass157c0662012-10-23 13:52:42 -0700341 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
342 """Decode ajustments to the provided GBB flags.
343
344 We support three options:
345
346 hex value: c2
347 defined value: force-dev-boot-usb,load-option-roms
348 adjust default value: -load-option-roms,+force-dev-boot-usb
349
350 The last option starts from the passed-in GBB flags and adds or removes
351 flags.
352
353 Args:
354 gbb_flags: Base (default) FDT flags.
355 adjustments: String containing adjustments to make.
356
357 Returns:
358 Updated FDT flags.
359 """
360 use_base_value = True
361 if adjustments:
362 try:
363 return int(adjustments, base=16)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700364 except (ValueError, TypeError):
Simon Glass157c0662012-10-23 13:52:42 -0700365 pass
366 for flag in adjustments.split(','):
367 oper = None
368 if flag[0] in ['-', '+']:
369 oper = flag[0]
370 flag = flag[1:]
371 value = gbb_flag_properties.get(flag)
372 if not value:
373 raise ValueError("Invalid GBB flag '%s'" % flag)
374 if oper == '+':
375 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800376 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700377 elif oper == '-':
378 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800379 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700380 else:
381 if use_base_value:
382 gbb_flags = 0
383 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800384 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700385 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800386 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700387
388 return gbb_flags
389
Simon Glass56577572011-07-19 11:08:06 +1200390 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700391 """Create a GBB for the image.
392
Simon Glass56577572011-07-19 11:08:06 +1200393 Args:
394 hardware_id: Hardware ID to use for this board. If None, then the
395 default from the Fdt will be used
396
Simon Glass89b86b82011-07-17 23:49:49 -0700397 Returns:
398 Path of the created GBB file.
Simon Glass89b86b82011-07-17 23:49:49 -0700399 """
Simon Glass56577572011-07-19 11:08:06 +1200400 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800401 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700402 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700403 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700404
Simon Glass4a887b12012-10-23 16:29:03 -0700405 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800406
Simon Glass157c0662012-10-23 13:52:42 -0700407 # Allow command line to override flags
408 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
409
Simon Glass4a887b12012-10-23 16:29:03 -0700410 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700411 self._out.Progress('Creating GBB')
412 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
413 sizes = ['%#x' % size for size in sizes]
414 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700415 keydir = self._tools.Filename(self._keydir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800416
417 gbb_set_command = ['-s',
418 '--hwid=%s' % hardware_id,
419 '--rootkey=%s/root_key.vbpubk' % keydir,
420 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
421 '--flags=%d' % gbb_flags,
422 gbb]
423 if not self.skip_bmpblk:
424 gbb_set_command[-1:-1] = ['--bmpfv=%s' % self._tools.Filename(
425 self.bmpblk_fname),]
426
Simon Glass290a1802011-07-17 13:54:32 -0700427 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Vadim Bendeburybfd227f2014-11-28 22:14:24 -0800428 self._tools.Run('gbb_utility', gbb_set_command, cwd=odir)
Simon Glass290a1802011-07-17 13:54:32 -0700429 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700430
Simon Glasse13ee2c2011-07-28 08:12:28 +1200431 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700432 """Sign an image so that the Tegra SOC will boot it.
433
434 Args:
435 bct: BCT file to use.
436 bootstub: Boot stub (U-Boot + fdt) file to sign.
437 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700438
439 Returns:
440 filename of signed image.
Simon Glass89b86b82011-07-17 23:49:49 -0700441 """
442 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200443 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700444 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200445 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700446 fd = open(config, 'w')
447 fd.write('Version = 1;\n')
448 fd.write('Redundancy = 1;\n')
449 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700450
451 # TODO(dianders): Right now, we don't have enough space in our flash map
452 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
453 # sure what this does for reliability, but at least things will fit...
454 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
455 if is_nand:
456 fd.write('Bctcopy = 1;\n')
457
Simon Glass89b86b82011-07-17 23:49:49 -0700458 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
459 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700460
Simon Glass89b86b82011-07-17 23:49:49 -0700461 fd.close()
462
463 self._tools.Run('cbootimage', [config, signed])
464 self._tools.OutputSize('BCT', bct)
465 self._tools.OutputSize('Signed image', signed)
466 return signed
467
Doug Anderson86ce5f42011-07-27 10:40:18 -0700468 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700469 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700470
471 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700472 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700473 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700474 """
Simon Glass468d8752012-09-19 16:36:19 -0700475 if bootcmd is not None:
476 if bootcmd == 'none':
477 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800478 self.fdt.PutString('/config', 'bootcmd', bootcmd)
479 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700480 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700481
Simon Glassa4934b72012-05-09 13:35:02 -0700482 def SetNodeEnabled(self, node_name, enabled):
483 """Set whether an node is enabled or disabled.
484
485 This simply sets the 'status' property of a node to "ok", or "disabled".
486
487 The node should either be a full path to the node (like '/uart@10200000')
488 or an alias property.
489
490 Aliases are supported like this:
491
492 aliases {
493 console = "/uart@10200000";
494 };
495
496 pointing to a node:
497
498 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700499 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700500 };
501
502 In this case, this function takes the name of the alias ('console' in
503 this case) and updates the status of the node that is pointed to, to
504 either ok or disabled. If the alias does not exist, a warning is
505 displayed.
506
507 Args:
508 node_name: Name of node (e.g. '/uart@10200000') or alias alias
509 (e.g. 'console') to adjust
510 enabled: True to enable, False to disable
511 """
512 # Look up the alias if this is an alias reference
513 if not node_name.startswith('/'):
514 lookup = self.fdt.GetString('/aliases', node_name, '')
515 if not lookup:
516 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
517 return
518 node_name = lookup
519 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700520 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700521 else:
522 status = 'disabled'
523 self.fdt.PutString(node_name, 'status', status)
524
525 def AddEnableList(self, enable_list):
526 """Process a list of nodes to enable/disable.
527
528 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700529 enable_list: List of (node, value) tuples to add to the fdt. For each
Simon Glassa4934b72012-05-09 13:35:02 -0700530 tuple:
531 node: The fdt node to write to will be <node> or pointed to by
532 /aliases/<node>. We can tell which
533 value: 0 to disable the node, 1 to enable it
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700534
Vadim Bendebury507c0012013-06-09 12:49:25 -0700535 Raises:
536 CmdError if a command fails.
Simon Glassa4934b72012-05-09 13:35:02 -0700537 """
538 if enable_list:
539 for node_name, enabled in enable_list:
540 try:
541 enabled = int(enabled)
542 if enabled not in (0, 1):
543 raise ValueError
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700544 except ValueError:
Simon Glassa4934b72012-05-09 13:35:02 -0700545 raise CmdError("Invalid enable option value '%s' "
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700546 "(should be 0 or 1)" % str(enabled))
Simon Glassa4934b72012-05-09 13:35:02 -0700547 self.SetNodeEnabled(node_name, enabled)
548
Simon Glass290a1802011-07-17 13:54:32 -0700549 def AddConfigList(self, config_list, use_int=False):
550 """Add a list of config items to the fdt.
551
552 Normally these values are written to the fdt as strings, but integers
553 are also supported, in which case the values will be converted to integers
554 (if necessary) before being stored.
555
556 Args:
557 config_list: List of (config, value) tuples to add to the fdt. For each
558 tuple:
559 config: The fdt node to write to will be /config/<config>.
560 value: An integer or string value to write.
561 use_int: True to only write integer values.
562
563 Raises:
564 CmdError: if a value is required to be converted to integer but can't be.
565 """
566 if config_list:
567 for config in config_list:
568 value = config[1]
569 if use_int:
570 try:
571 value = int(value)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700572 except ValueError:
Simon Glass290a1802011-07-17 13:54:32 -0700573 raise CmdError("Cannot convert config option '%s' to integer" %
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700574 str(value))
Simon Glass290a1802011-07-17 13:54:32 -0700575 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800576 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700577 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800578 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700579
Simon Glass7c2d5572011-11-15 14:47:08 -0800580 def DecodeTextBase(self, data):
581 """Look at a U-Boot image and try to decode its TEXT_BASE.
582
583 This works because U-Boot has a header with the value 0x12345678
584 immediately followed by the TEXT_BASE value. We can therefore read this
585 from the image with some certainty. We check only the first 40 words
586 since the header should be within that region.
587
Simon Glass96b50302012-07-20 06:55:28 +0100588 Since upstream Tegra has moved to having a 16KB SPL region at the start,
589 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
590 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
591
Simon Glass7c2d5572011-11-15 14:47:08 -0800592 Args:
593 data: U-Boot binary data
594
595 Returns:
596 Text base (integer) or None if none was found
597 """
598 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100599 for start in (0, 0x4000):
600 for i in range(start, start + 160, 4):
601 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800602
Simon Glass96b50302012-07-20 06:55:28 +0100603 # TODO(sjg): This does not cope with a big-endian target
604 value = struct.unpack('<I', word)[0]
605 if found:
606 return value - start
607 if value == 0x12345678:
608 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800609
610 return None
611
612 def CalcTextBase(self, name, fdt, fname):
613 """Calculate the TEXT_BASE to use for U-Boot.
614
615 Normally this value is in the fdt, so we just read it from there. But as
616 a second check we look at the image itself in case this is different, and
617 switch to that if it is.
618
619 This allows us to flash any U-Boot even if its TEXT_BASE is different.
620 This is particularly useful with upstream U-Boot which uses a different
621 value (which we will move to).
622 """
623 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800624 # The value that comes back from fdt.GetInt is signed, which makes no
625 # sense for an address base. Force it to unsigned.
626 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800627 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100628 text_base_str = '%#x' % text_base if text_base else 'None'
629 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
630 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800631
632 # If they are different, issue a warning and switch over.
633 if text_base and text_base != fdt_text_base:
634 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
635 "fdt value of %x. Using %x" % (text_base, name,
636 fdt_text_base, text_base))
637 fdt_text_base = text_base
638 return fdt_text_base
639
Simon Glass6dcc2f22011-07-28 15:26:49 +1200640 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700641 """Create a boot stub and a signed boot stub.
642
Simon Glass6dcc2f22011-07-28 15:26:49 +1200643 For postload:
644 We add a /config/postload-text-offset entry to the signed bootstub's
645 fdt so that U-Boot can find the postload code.
646
647 The raw (unsigned) bootstub will have a value of -1 for this since we will
648 simply append the postload code to the bootstub and it can find it there.
649 This will be used for RW A/B firmware.
650
651 For the signed case this value will specify where in the flash to find
652 the postload code. This will be used for RO firmware.
653
Simon Glass89b86b82011-07-17 23:49:49 -0700654 Args:
655 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800656 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200657 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700658
659 Returns:
660 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200661 Full path to bootstub (uboot + fdt(-1) + postload).
662 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700663
664 Raises:
665 CmdError if a command fails.
666 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200667 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800668 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700669 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200670
671 # Make a copy of the fdt for the bootstub
672 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700673 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff)
Simon Glass290a1802011-07-17 13:54:32 -0700674 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200675
Simon Glass89b86b82011-07-17 23:49:49 -0700676 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700677 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
678 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700679 self._tools.OutputSize('Combined binary', bootstub)
680
Simon Glasse13ee2c2011-07-28 08:12:28 +1200681 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700682 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700683 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200684 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200685
686 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
687 data = self._tools.ReadFile(signed)
688
689 if postload:
690 # We must add postload to the bootstub since A and B will need to
691 # be able to find it without the /config/postload-text-offset mechanism.
692 bs_data = self._tools.ReadFile(bootstub)
693 bs_data += self._tools.ReadFile(postload)
694 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
695 self._tools.WriteFile(bootstub, bs_data)
696 self._tools.OutputSize('Combined binary with postload', bootstub)
697
698 # Now that we know the file size, adjust the fdt and re-sign
699 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800700 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200701 fdt_data = self._tools.ReadFile(fdt.fname)
702 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
703 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
704 postload_bootstub, text_base)
705 if len(data) != os.path.getsize(signed):
706 raise CmdError('Signed file size changed from %d to %d after updating '
707 'fdt' % (len(data), os.path.getsize(signed)))
708
709 # Re-read the signed image, and add the post-load binary.
710 data = self._tools.ReadFile(signed)
711 data += self._tools.ReadFile(postload)
712 self._tools.OutputSize('Post-load binary', postload)
713
714 self._tools.WriteFile(signed_postload, data)
715 self._tools.OutputSize('Final bootstub with postload', signed_postload)
716
717 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700718
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700719 def _CreateCorebootStub(self, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700720 """Create a coreboot boot stub.
721
722 Args:
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700723 coreboot: Path to coreboot.rom
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700724
725 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100726 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700727 """
728 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700729 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100730
731 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700732 return bootstub
733
Simon Glass7e199222012-03-13 15:51:18 -0700734
Simon Glass89b86b82011-07-17 23:49:49 -0700735 def _PackOutput(self, msg):
736 """Helper function to write output from PackFirmware (verbose level 2).
737
738 This is passed to PackFirmware for it to use to write output.
739
740 Args:
741 msg: Message to display.
742 """
743 self._out.Notice(msg)
744
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800745 def _PrepareCbfs(self, pack, blob_name):
746 """Create CBFS blob in rw-boot-{a,b} FMAP sections.
747
748 When the blob name is defined as cbfs#<section>#<subsection>, fill the
749 <section>_<subsection> area in the flash map with a CBFS copy, putting the
750 CBFS header of the copy at the base of the section.
751
752 If --coreboot-elf parameter was specified during cros_bumdle_firmware
753 invocation, add the parameter of this option as the payload to the new
754 CBFS instance.
755
756 Args:
757 pack: a PackFirmware object describing the firmware image to build.
758 blob_name: a string, blob name describing what FMAP section this CBFS
759 copy is destined to
760 Raises:
761 CmdError if base coreboot image does not contain CBFS
762 """
763
764 if not self.coreboot_fname:
765 raise CmdError("coreboot file needed for blob % s", blob_name)
766
767 part_sections = blob_name.split('/')[1:]
768
769 # Base address and size of the desitnation partition
770 base, size = self.fdt.GetFlashPart(*part_sections)
771
772 # Create a coreboot copy to use as a scratch pad.
773 cb_copy = os.path.join(self._tools.outdir, 'cb_copy')
774 if not os.path.exists(cb_copy):
775 self._tools.WriteFile(cb_copy, self._tools.ReadFile(self.coreboot_fname))
776
777 # Copy CBFS to the required offset
778 self._tools.Run('cbfstool', [cb_copy, 'copy', '-D',
779 '%d' % base, '-s', '%d' % size])
780
781 # Add coreboot payload if so requested. Note that the some images use
782 # different payload for the rw sections, which is passed in as the value
783 # of the --uboot option in the command line.
784 if self.uboot_fname:
785 payload_fname = self.uboot_fname
786 elif self.coreboot_elf:
787 payload_fname = self.coreboot_elf
788 else:
789 payload_fname = None
790
791 if payload_fname:
792 self._tools.Run('cbfstool', [
793 cb_copy, 'add-payload', '-f', payload_fname,
794 '-n', 'fallback/payload', '-c', 'lzma' , '-H', '%d' % base])
795
796 # And extract the blob for the FW section
797 rw_section = os.path.join(self._tools.outdir, '_'.join(part_sections))
798 self._tools.WriteFile(rw_section,
799 self._tools.ReadFile(cb_copy)[base:base+size])
800
801 pack.AddProperty(blob_name, rw_section)
802
803
Simon Glass439fe7a2012-03-09 16:19:34 -0800804 def _BuildBlob(self, pack, fdt, blob_type):
805 """Build the blob data for a particular blob type.
806
807 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700808 pack: a PackFirmware object describing the firmware image to build.
809 fdt: an fdt object including image layout information
Simon Glass439fe7a2012-03-09 16:19:34 -0800810 blob_type: The type of blob to create data for. Supported types are:
811 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
812 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
Vadim Bendebury507c0012013-06-09 12:49:25 -0700813
814 Raises:
815 CmdError if a command fails.
Simon Glass439fe7a2012-03-09 16:19:34 -0800816 """
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700817 # stupid pylint insists that sha256 is not in hashlib.
818 # pylint: disable=E1101
Simon Glass439fe7a2012-03-09 16:19:34 -0800819 if blob_type == 'coreboot':
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700820 coreboot = self._CreateCorebootStub(self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800821 pack.AddProperty('coreboot', coreboot)
822 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700823 elif blob_type == 'legacy':
824 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800825 elif blob_type == 'signed':
826 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
827 self.postload_fname)
828 pack.AddProperty('bootstub', bootstub)
829 pack.AddProperty('signed', signed)
830 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700831 elif blob_type == 'exynos-bl1':
832 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700833
834 # TODO(sjg@chromium.org): Deprecate ecbin
835 elif blob_type in ['ecrw', 'ecbin']:
836 pack.AddProperty('ecrw', self.ecrw_fname)
837 pack.AddProperty('ecbin', self.ecrw_fname)
Randall Spangler7307da92014-07-18 12:47:34 -0700838 elif blob_type == 'pdrw':
839 pack.AddProperty('pdrw', self.pdrw_fname)
Gabe Blackcdbdfe12013-02-06 05:37:52 -0800840 elif blob_type == 'ecrwhash':
841 ec_hash_file = os.path.join(self._tools.outdir, 'ec_hash.bin')
842 ecrw = self._tools.ReadFile(self.ecrw_fname)
843 hasher = hashlib.sha256()
844 hasher.update(ecrw)
845 self._tools.WriteFile(ec_hash_file, hasher.digest())
846 pack.AddProperty(blob_type, ec_hash_file)
Randall Spangler7307da92014-07-18 12:47:34 -0700847 elif blob_type == 'pdrwhash':
848 pd_hash_file = os.path.join(self._tools.outdir, 'pd_hash.bin')
849 pdrw = self._tools.ReadFile(self.pdrw_fname)
850 hasher = hashlib.sha256()
851 hasher.update(pdrw)
852 self._tools.WriteFile(pd_hash_file, hasher.digest())
853 pack.AddProperty(blob_type, pd_hash_file)
Simon Glassbe0bc002012-08-16 12:50:48 -0700854 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700855 # crosbug.com/p/13143
856 # We cannot have an fmap in the EC image since there can be only one,
857 # which is the main fmap describing the whole image.
858 # Ultimately the EC will not have an fmap, since with software sync
859 # there is no flashrom involvement in updating the EC flash, and thus
860 # no need for the fmap.
861 # For now, mangle the fmap name to avoid problems.
862 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
863 data = self._tools.ReadFile(self.ecro_fname)
864 data = re.sub('__FMAP__', '__fMAP__', data)
865 self._tools.WriteFile(updated_ecro, data)
866 pack.AddProperty(blob_type, updated_ecro)
Simon Glass0a047bc2013-07-19 15:44:43 -0600867 elif blob_type.startswith('exynos-bl2'):
868 # We need to configure this per node, so do it later
869 pass
Vadim Bendeburyc9600c62014-12-22 16:31:13 -0800870 elif blob_type.startswith('cbfs'):
871 self._PrepareCbfs(pack, blob_type)
Simon Glass439fe7a2012-03-09 16:19:34 -0800872 elif pack.GetProperty(blob_type):
873 pass
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800874 elif blob_type in self.blobs:
875 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -0800876 else:
877 raise CmdError("Unknown blob type '%s' required in flash map" %
878 blob_type)
879
Simon Glass290a1802011-07-17 13:54:32 -0700880 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700881 """Create a full firmware image, along with various by-products.
882
883 This uses the provided u-boot.bin, fdt and bct to create a firmware
884 image containing all the required parts. If the GBB is not supplied
885 then this will just return a signed U-Boot as the image.
886
887 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700888 gbb: a string, full path to the GBB file, or empty if a GBB is not
889 required.
890 fdt: an fdt object containing required information.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200891
892 Returns:
893 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700894 """
Simon Glass02d124a2012-03-02 14:47:20 -0800895 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700896
Simon Glass439fe7a2012-03-09 16:19:34 -0800897 pack = PackFirmware(self._tools, self._out)
Simon Glassb8c6d952012-12-01 06:14:35 -0800898 if self._force_rw:
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700899 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
900 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
Simon Glass00d027e2013-07-20 14:51:12 -0600901 if self._force_efs:
902 fdt.PutInteger('/chromeos-config', 'early-firmware-selection', 1)
Simon Glassa7e66e22013-07-23 07:21:16 -0600903 pack.use_efs = fdt.GetInt('/chromeos-config', 'early-firmware-selection',
904 0)
Simon Glassb8c6d952012-12-01 06:14:35 -0800905
Simon Glass4f318912013-07-20 16:13:06 -0600906 pack.SelectFdt(fdt, self._board)
Simon Glass439fe7a2012-03-09 16:19:34 -0800907
908 # Get all our blobs ready
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800909 if self.uboot_fname:
910 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -0800911 if self.skeleton_fname:
912 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700913 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700914
Simon Glassde9c8072012-07-02 22:29:02 -0700915 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
916 if self.kernel_fname:
917 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
918
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800919 if gbb:
920 pack.AddProperty('gbb', gbb)
Simon Glass9d088d92012-07-16 16:27:11 +0100921 blob_list = pack.GetBlobList()
922 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700923 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800924 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700925
Simon Glass7306b902012-12-17 15:06:21 -0800926 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -0700927 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700928 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800929 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800930 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800931 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700932 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800933 pack.AddProperty('fwid', fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800934 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700935
Simon Glass0a047bc2013-07-19 15:44:43 -0600936 # Some blobs need to be configured according to the node they are in.
Simon Glass4c24f662013-07-19 15:53:02 -0600937 todo = pack.GetMissingBlobs()
938 for blob in todo:
Simon Glass0a047bc2013-07-19 15:44:43 -0600939 if blob.key.startswith('exynos-bl2'):
940 bl2 = ExynosBl2(self._tools, self._out)
941 pack.AddProperty(blob.key, bl2.MakeSpl(pack, fdt, blob,
942 self.exynos_bl2))
943
Simon Glassc90cf582012-03-13 15:40:47 -0700944 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700945
946 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -0800947 pack.UpdateBlobPositionsAndHashes(fdt)
Simon Glass8884b982012-06-21 12:41:41 -0700948
Simon Glass4c24f662013-07-19 15:53:02 -0600949 # Recalculate the Exynos BL2, since it may have a hash. The call to
950 # UpdateBlobPositionsAndHashes() may have updated the hash-target so we
951 # need to recalculate the hash.
952 for blob in todo:
953 if blob.key.startswith('exynos-bl2'):
954 bl2 = ExynosBl2(self._tools, self._out)
955 pack.AddProperty(blob.key, bl2.MakeSpl(pack, fdt, blob,
956 self.exynos_bl2))
957
Simon Glass6207efe2012-12-17 15:04:36 -0800958 # Make a copy of the fdt for the bootstub
959 fdt_data = self._tools.ReadFile(fdt.fname)
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800960 if self.uboot_fname:
961 uboot_data = self._tools.ReadFile(self.uboot_fname)
962 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
963 self._tools.WriteFile(uboot_copy, uboot_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800964
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800965 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
966 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
Simon Glass6207efe2012-12-17 15:04:36 -0800967
Simon Glassa10282a2013-01-08 17:06:41 -0800968 # Fix up the coreboot image here, since we can't do this until we have
969 # a final device tree binary.
Simon Glasscbc83552012-07-23 15:26:22 +0100970 if 'coreboot' in blob_list:
971 bootstub = pack.GetProperty('coreboot')
972 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -0800973 if self.coreboot_elf:
974 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
975 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
Vadim Bendebury466a7d82014-12-22 10:08:58 -0800976 elif self.uboot_fname:
Simon Glass0a7cf112013-05-21 23:08:21 -0700977 text_base = 0x1110000
978
979 # This is the the 'movw $GD_FLG_COLD_BOOT, %bx' instruction
980 # 1110015: 66 bb 00 01 mov $0x100,%bx
981 marker = struct.pack('<L', 0x0100bb66)
982 pos = uboot_data.find(marker)
983 if pos == -1 or pos > 0x100:
984 raise ValueError('Cannot find U-Boot cold boot entry point')
985 entry = text_base + pos
986 self._out.Notice('U-Boot entry point %#08x' % entry)
Simon Glassa10282a2013-01-08 17:06:41 -0800987 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
988 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
Simon Glass0a7cf112013-05-21 23:08:21 -0700989 '-l', '%#x' % text_base, '-e', '%#x' % entry])
Stefan Reinauer1502ea62012-11-01 10:15:38 -0700990 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
991 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -0800992 data = self._tools.ReadFile(bootstub)
993 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
994 self._tools.WriteFile(bootstub_copy, data)
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700995
Julius Werneraa1fe942014-11-21 17:16:11 -0800996 # Use offset and size from fmap.dts to extract CBFS area from coreboot.rom
997 cbfs_offset, cbfs_size = fdt.GetFlashPart('ro', 'boot')
998 self._tools.WriteFile(bootstub, data[cbfs_offset:cbfs_offset+cbfs_size])
Simon Glasscbc83552012-07-23 15:26:22 +0100999
Simon Glass208ad952013-02-10 11:16:46 -08001000 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -07001001 image = os.path.join(self._tools.outdir, 'image.bin')
1002 pack.PackImage(self._tools.outdir, image)
1003 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -07001004
Simon Glass439fe7a2012-03-09 16:19:34 -08001005 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -07001006 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001007 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001008
Simon Glassdedda6f2013-02-09 13:44:14 -08001009 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -07001010 """Select an FDT to control the firmware bundling
1011
Simon Glassdedda6f2013-02-09 13:44:14 -08001012 We make a copy of this which will include any on-the-fly changes we want
1013 to make.
1014
Simon Glass290a1802011-07-17 13:54:32 -07001015 Args:
1016 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -08001017 use_defaults: True to use a default FDT name if available, and to add
1018 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -07001019
Simon Glassc0f3dc62011-08-09 14:19:05 -07001020 Returns:
1021 The Fdt object of the original fdt file, which we will not modify.
1022
Simon Glassdedda6f2013-02-09 13:44:14 -08001023 Raises:
1024 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
1025 False).
Simon Glass290a1802011-07-17 13:54:32 -07001026 """
Simon Glassdedda6f2013-02-09 13:44:14 -08001027 if use_defaults:
1028 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -08001029 if not fdt_fname:
1030 raise ValueError('Please provide an FDT filename')
1031 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -07001032 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -08001033
1034 # For upstream, select the correct architecture .dtsi manually.
1035 if self._board == 'link' or 'x86' in self._board:
1036 arch_dts = 'coreboot.dtsi'
1037 elif self._board == 'daisy':
1038 arch_dts = 'exynos5250.dtsi'
1039 else:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -05001040 arch_dts = 'tegra124.dtsi'
Simon Glassc3e42c32012-12-17 15:00:04 -08001041
1042 fdt.Compile(arch_dts)
Simon Glasse53abbc2013-08-21 22:29:55 -06001043 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
1044
1045 # Get the flashmap so we know what to build. For board variants use the
1046 # main board name as the key (drop the _<variant> suffix).
1047 default_flashmap = default_flashmaps.get(self._board.split('_')[0], [])
1048
1049 if not fdt.GetProp('/flash', 'reg', ''):
1050 fdt.InsertNodes(default_flashmap)
1051
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -05001052 # Only check for /iram and /config nodes for boards that require it.
1053 if self._board in ('daisy', 'peach'):
1054 # Insert default values for any essential properties that are missing.
1055 # This should only happen for upstream U-Boot, until our changes are
1056 # upstreamed.
1057 if not fdt.GetProp('/iram', 'reg', ''):
1058 self._out.Warning('Cannot find /iram, using default')
1059 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/iram'])
Simon Glasse53abbc2013-08-21 22:29:55 -06001060
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -05001061 # Sadly the pit branch has an invalid /memory node. Work around it
1062 # for now. crosbug.com/p/22184
1063 if (not fdt.GetProp('/memory', 'reg', '') or
1064 fdt.GetIntList('/memory', 'reg')[0] == 0):
1065 self._out.Warning('Cannot find /memory, using default')
1066 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/memory'])
Simon Glasse53abbc2013-08-21 22:29:55 -06001067
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -05001068 if not fdt.GetProp('/config', 'samsung,bl1-offset', ''):
1069 self._out.Warning('Missing properties in /config, using defaults')
1070 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/config'])
Simon Glasse53abbc2013-08-21 22:29:55 -06001071
Simon Glass7df773b2013-08-25 18:02:29 -06001072 # Remember our board type.
1073 fdt.PutString('/chromeos-config', 'board', self._board)
1074
Simon Glasse53abbc2013-08-21 22:29:55 -06001075 self.fdt = fdt
1076 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001077
Simon Glassc90cf582012-03-13 15:40:47 -07001078 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001079 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001080
1081 - Checks options, tools, output directory, fdt.
1082 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001083
1084 Args:
Simon Glass56577572011-07-19 11:08:06 +12001085 hardware_id: Hardware ID to use for this board. If None, then the
1086 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001087 output_fname: Output filename for the image. If this is not None, then
1088 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001089 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001090
1091 Returns:
1092 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001093 """
Vadim Bendebury5baeec12013-04-02 13:01:22 -07001094 if self._small or self.fdt.GetProp('/config', 'nogbb', 'any') != 'any':
1095 gbb = '' # Building a small image or `nogbb' is requested in device tree.
1096 else:
Simon Glass56577572011-07-19 11:08:06 +12001097 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001098
1099 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001100 image, pack = self._CreateImage(gbb, self.fdt)
1101 if show_map:
1102 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001103 if output_fname:
1104 shutil.copyfile(image, output_fname)
1105 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001106 return image, pack.props