blob: 8f535fef39d02aa2d2c0f985822ef62bbbd32b30 [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,
Simon Glass4a887b12012-10-23 16:29:03 -070073}
74
Simon Glass49b026b2013-04-26 16:38:42 -070075# Maps board name to Exynos product number
76type_to_model = {
77 'peach' : '5420',
78 'daisy' : '5250'
79}
80
Simon Glass5076a7f2012-10-23 16:31:54 -070081def ListGoogleBinaryBlockFlags():
82 """Print out a list of GBB flags."""
83 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
84 for name, value in gbb_flag_properties.iteritems():
85 print ' %-30s %02x' % (name, value)
86
Simon Glass89b86b82011-07-17 23:49:49 -070087class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070088 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070089
Simon Glass290a1802011-07-17 13:54:32 -070090 Sequence of events:
91 bundle = Bundle(tools.Tools(), cros_output.Output())
92 bundle.SetDirs(...)
93 bundle.SetFiles(...)
94 bundle.SetOptions(...)
95 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070096 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070097 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070098
Simon Glass290a1802011-07-17 13:54:32 -070099 Public properties:
100 fdt: The fdt object that we use for building our image. This wil be the
101 one specified by the user, except that we might add config options
102 to it. This is set up by SelectFdt() which must be called before
103 bundling starts.
104 uboot_fname: Full filename of the U-Boot binary we use.
105 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -0700106 spl_source: Source device to load U-Boot from, in SPL:
107 straps: Select device according to CPU strap pins
108 spi: Boot from SPI
109 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -0700110
111 Private attributes:
112 _small: True to create a 'small' signed U-Boot, False to produce a
113 full image. The small U-Boot is enough to boot but will not have
114 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700115 """
Simon Glass89b86b82011-07-17 23:49:49 -0700116
Simon Glass290a1802011-07-17 13:54:32 -0700117 def __init__(self, tools, output):
118 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700119
Simon Glass290a1802011-07-17 13:54:32 -0700120 Args:
121 tools: A tools.Tools object to use for external tools.
122 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700123 """
Simon Glass290a1802011-07-17 13:54:32 -0700124 self._tools = tools
125 self._out = output
126
127 # Set up the things we need to know in order to operate.
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500128 self._board = None # Board name, e.g. nyan.
Simon Glass290a1802011-07-17 13:54:32 -0700129 self._fdt_fname = None # Filename of our FDT.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700130 self._force_rw = None
Simon Glass00d027e2013-07-20 14:51:12 -0600131 self._force_efs = None
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700132 self._gbb_flags = None
133 self._keydir = None
134 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700135 self.bct_fname = None # Filename of our BCT file.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700136 self.blobs = {} # Table of (type, filename) of arbitrary blobs
Hung-Te Lin5b649382011-08-03 15:01:16 +0800137 self.bmpblk_fname = None # Filename of our Bitmap Block
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700138 self.coreboot_elf = None
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700139 self.coreboot_fname = None # Filename of our coreboot binary.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700140 self.ecro_fname = None # Filename of EC read-only file
141 self.ecrw_fname = None # Filename of EC file
Randall Spangler7307da92014-07-18 12:47:34 -0700142 self.pdrw_fname = None # Filename of PD file
Simon Glass7e199222012-03-13 15:51:18 -0700143 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
144 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700145 self.fdt = None # Our Fdt object.
146 self.kernel_fname = None
147 self.postload_fname = None
148 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass07267952012-06-08 12:45:13 -0700149 self.skeleton_fname = None # Filename of Coreboot skeleton file
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700150 self.uboot_fname = None # Filename of our U-Boot binary.
Simon Glass290a1802011-07-17 13:54:32 -0700151
152 def SetDirs(self, keydir):
153 """Set up directories required for Bundle.
154
155 Args:
156 keydir: Directory containing keys to use for signing firmware.
157 """
158 self._keydir = keydir
159
Simon Glass6dcc2f22011-07-28 15:26:49 +1200160 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800161 coreboot_elf=None,
Simon Glass07267952012-06-08 12:45:13 -0700162 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Randall Spangler7307da92014-07-18 12:47:34 -0700163 skeleton=None, ecrw=None, ecro=None, pdrw=None,
164 kernel=None, blobs=None):
Simon Glass290a1802011-07-17 13:54:32 -0700165 """Set up files required for Bundle.
166
167 Args:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500168 board: The name of the board to target (e.g. nyan).
Simon Glass290a1802011-07-17 13:54:32 -0700169 uboot: The filename of the u-boot.bin image to use.
170 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800171 bmpblk: The filename of bitmap block file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800172 coreboot: The filename of the coreboot image to use (on x86).
173 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200174 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700175 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700176 exynos_bl1: The filename of the exynos BL1 file
177 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
178 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700179 ecrw: The filename of the EC (Embedded Controller) read-write file.
180 ecro: The filename of the EC (Embedded Controller) read-only file.
Randall Spangler7307da92014-07-18 12:47:34 -0700181 pdrw: The filename of the PD (PD embedded controller) read-write file.
Simon Glassde9c8072012-07-02 22:29:02 -0700182 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800183 blobs: List of (type, filename) of arbitrary blobs.
Simon Glass290a1802011-07-17 13:54:32 -0700184 """
185 self._board = board
186 self.uboot_fname = uboot
187 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800188 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700189 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800190 self.coreboot_elf = coreboot_elf
Simon Glass6dcc2f22011-07-28 15:26:49 +1200191 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700192 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700193 self.exynos_bl1 = exynos_bl1
194 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700195 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700196 self.ecrw_fname = ecrw
197 self.ecro_fname = ecro
Randall Spangler7307da92014-07-18 12:47:34 -0700198 self.pdrw_fname = pdrw
Simon Glassde9c8072012-07-02 22:29:02 -0700199 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800200 self.blobs = dict(blobs or ())
Simon Glass290a1802011-07-17 13:54:32 -0700201
Simon Glass00d027e2013-07-20 14:51:12 -0600202 def SetOptions(self, small, gbb_flags, force_rw=False, force_efs=False):
Simon Glass290a1802011-07-17 13:54:32 -0700203 """Set up options supported by Bundle.
204
205 Args:
206 small: Only create a signed U-Boot - don't produce the full packed
207 firmware image. This is useful for devs who want to replace just the
208 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700209 gbb_flags: Specification for string containing adjustments to make.
210 force_rw: Force firmware into RW mode.
Simon Glass00d027e2013-07-20 14:51:12 -0600211 force_efs: Force firmware to use 'early firmware selection' feature,
212 where RW firmware is selected before SDRAM is initialized.
Simon Glass290a1802011-07-17 13:54:32 -0700213 """
214 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700215 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700216 self._force_rw = force_rw
Simon Glass00d027e2013-07-20 14:51:12 -0600217 self._force_efs = force_efs
Simon Glass290a1802011-07-17 13:54:32 -0700218
Simon Glass22f39fb2013-02-09 13:44:14 -0800219 def _GetBuildRoot(self):
220 """Get the path to this board's 'firmware' directory.
221
222 Returns:
223 Path to firmware directory, with ## representing the path to the
224 chroot.
225 """
Simon Glass290a1802011-07-17 13:54:32 -0700226 if not self._board:
227 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800228 return os.path.join('##', 'build', self._board, 'firmware')
229
230 def _CheckFdtFilename(self, fname):
231 """Check provided FDT filename and return the correct name if needed.
232
233 Where the filename lacks a path, add a default path for this board.
234 Where no FDT filename is provided, select a default one for this board.
235
236 Args:
237 fname: Proposed FDT filename.
238
239 Returns:
240 Selected FDT filename, after validation.
241 """
242 build_root = self._GetBuildRoot()
Julius Wernerb4b14392013-08-09 14:41:40 -0700243 dir_name = os.path.join(build_root, 'dtb')
Simon Glass22f39fb2013-02-09 13:44:14 -0800244 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700245 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700246 base_name = re.sub('_', '-', self._board)
247
248 # In case the name exists with a prefix or suffix, find it.
Julius Wernerb4b14392013-08-09 14:41:40 -0700249 wildcard = os.path.join(dir_name, '*%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700250 found_list = glob.glob(self._tools.Filename(wildcard))
251 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800252 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700253 else:
254 # We didn't find anything definite, so set up our expected name.
Julius Wernerb4b14392013-08-09 14:41:40 -0700255 fname = os.path.join(dir_name, '%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700256
Simon Glass881964d2012-04-04 11:34:09 -0700257 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800258 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700259 if not ext and not os.path.dirname(root):
Julius Wernerb4b14392013-08-09 14:41:40 -0700260 fname = os.path.join(dir_name, '%s.dtb' % root)
Simon Glass22f39fb2013-02-09 13:44:14 -0800261 return fname
262
263 def CheckOptions(self):
264 """Check provided options and select defaults."""
265 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700266
Simon Glass49b026b2013-04-26 16:38:42 -0700267 board_type = self._board.split('_')[0]
268 model = type_to_model.get(board_type)
269
Simon Glass290a1802011-07-17 13:54:32 -0700270 if not self.uboot_fname:
271 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
272 if not self.bct_fname:
273 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700274 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700275 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700276 if model:
277 if not self.exynos_bl1:
Simon Glassd05696e2013-06-13 20:14:00 -0700278 self.exynos_bl1 = os.path.join(build_root, 'u-boot.bl1.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700279 if not self.exynos_bl2:
Julius Wernerb12c0052013-08-14 13:57:04 -0700280 self.exynos_bl2 = os.path.join(build_root, 'u-boot-spl.wrapped.bin')
Simon Glass07267952012-06-08 12:45:13 -0700281 if not self.coreboot_fname:
282 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
283 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700284 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700285 if not self.seabios_fname:
286 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700287 if not self.ecrw_fname:
288 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
Randall Spangler7307da92014-07-18 12:47:34 -0700289 if not self.pdrw_fname:
290 self.pdrw_fname = os.path.join(build_root, 'pd.RW.bin')
Simon Glassbe0bc002012-08-16 12:50:48 -0700291 if not self.ecro_fname:
292 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700293
Simon Glass75759302012-03-15 20:26:53 -0700294 def GetFiles(self):
295 """Get a list of files that we know about.
296
297 This is the opposite of SetFiles except that we may have put in some
298 default names. It returns a dictionary containing the filename for
299 each of a number of pre-defined files.
300
301 Returns:
302 Dictionary, with one entry for each file.
303 """
304 file_list = {
305 'bct' : self.bct_fname,
306 'exynos-bl1' : self.exynos_bl1,
307 'exynos-bl2' : self.exynos_bl2,
308 }
309 return file_list
310
Simon Glass4a887b12012-10-23 16:29:03 -0700311 def DecodeGBBFlagsFromFdt(self):
312 """Get Google Binary Block flags from the FDT.
313
314 These should be in the chromeos-config node, like this:
315
316 chromeos-config {
317 gbb-flag-dev-screen-short-delay;
318 gbb-flag-force-dev-switch-on;
319 gbb-flag-force-dev-boot-usb;
320 gbb-flag-disable-fw-rollback-check;
321 };
322
323 Returns:
324 GBB flags value from FDT.
325 """
326 chromeos_config = self.fdt.GetProps("/chromeos-config")
327 gbb_flags = 0
328 for name in chromeos_config:
329 if name.startswith('gbb-flag-'):
330 flag_value = gbb_flag_properties.get(name[9:])
331 if flag_value:
332 gbb_flags |= flag_value
333 self._out.Notice("FDT: Enabling %s." % name)
334 else:
335 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
336 return gbb_flags
337
Simon Glass157c0662012-10-23 13:52:42 -0700338 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
339 """Decode ajustments to the provided GBB flags.
340
341 We support three options:
342
343 hex value: c2
344 defined value: force-dev-boot-usb,load-option-roms
345 adjust default value: -load-option-roms,+force-dev-boot-usb
346
347 The last option starts from the passed-in GBB flags and adds or removes
348 flags.
349
350 Args:
351 gbb_flags: Base (default) FDT flags.
352 adjustments: String containing adjustments to make.
353
354 Returns:
355 Updated FDT flags.
356 """
357 use_base_value = True
358 if adjustments:
359 try:
360 return int(adjustments, base=16)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700361 except (ValueError, TypeError):
Simon Glass157c0662012-10-23 13:52:42 -0700362 pass
363 for flag in adjustments.split(','):
364 oper = None
365 if flag[0] in ['-', '+']:
366 oper = flag[0]
367 flag = flag[1:]
368 value = gbb_flag_properties.get(flag)
369 if not value:
370 raise ValueError("Invalid GBB flag '%s'" % flag)
371 if oper == '+':
372 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800373 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700374 elif oper == '-':
375 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800376 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700377 else:
378 if use_base_value:
379 gbb_flags = 0
380 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800381 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700382 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800383 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700384
385 return gbb_flags
386
Simon Glass56577572011-07-19 11:08:06 +1200387 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700388 """Create a GBB for the image.
389
Simon Glass56577572011-07-19 11:08:06 +1200390 Args:
391 hardware_id: Hardware ID to use for this board. If None, then the
392 default from the Fdt will be used
393
Simon Glass89b86b82011-07-17 23:49:49 -0700394 Returns:
395 Path of the created GBB file.
Simon Glass89b86b82011-07-17 23:49:49 -0700396 """
Simon Glass56577572011-07-19 11:08:06 +1200397 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800398 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700399 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700400 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700401
Simon Glass4a887b12012-10-23 16:29:03 -0700402 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800403
Simon Glass157c0662012-10-23 13:52:42 -0700404 # Allow command line to override flags
405 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
406
Simon Glass4a887b12012-10-23 16:29:03 -0700407 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700408 self._out.Progress('Creating GBB')
409 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
410 sizes = ['%#x' % size for size in sizes]
411 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700412 keydir = self._tools.Filename(self._keydir)
413 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700414 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200415 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700416 '--rootkey=%s/root_key.vbpubk' % keydir,
417 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700418 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800419 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700420 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700421 cwd=odir)
422 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700423
Simon Glasse13ee2c2011-07-28 08:12:28 +1200424 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700425 """Sign an image so that the Tegra SOC will boot it.
426
427 Args:
428 bct: BCT file to use.
429 bootstub: Boot stub (U-Boot + fdt) file to sign.
430 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700431
432 Returns:
433 filename of signed image.
Simon Glass89b86b82011-07-17 23:49:49 -0700434 """
435 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200436 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700437 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200438 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700439 fd = open(config, 'w')
440 fd.write('Version = 1;\n')
441 fd.write('Redundancy = 1;\n')
442 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700443
444 # TODO(dianders): Right now, we don't have enough space in our flash map
445 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
446 # sure what this does for reliability, but at least things will fit...
447 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
448 if is_nand:
449 fd.write('Bctcopy = 1;\n')
450
Simon Glass89b86b82011-07-17 23:49:49 -0700451 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
452 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700453
Simon Glass89b86b82011-07-17 23:49:49 -0700454 fd.close()
455
456 self._tools.Run('cbootimage', [config, signed])
457 self._tools.OutputSize('BCT', bct)
458 self._tools.OutputSize('Signed image', signed)
459 return signed
460
Doug Anderson86ce5f42011-07-27 10:40:18 -0700461 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700462 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700463
464 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700465 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700466 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700467 """
Simon Glass468d8752012-09-19 16:36:19 -0700468 if bootcmd is not None:
469 if bootcmd == 'none':
470 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800471 self.fdt.PutString('/config', 'bootcmd', bootcmd)
472 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700473 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700474
Simon Glassa4934b72012-05-09 13:35:02 -0700475 def SetNodeEnabled(self, node_name, enabled):
476 """Set whether an node is enabled or disabled.
477
478 This simply sets the 'status' property of a node to "ok", or "disabled".
479
480 The node should either be a full path to the node (like '/uart@10200000')
481 or an alias property.
482
483 Aliases are supported like this:
484
485 aliases {
486 console = "/uart@10200000";
487 };
488
489 pointing to a node:
490
491 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700492 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700493 };
494
495 In this case, this function takes the name of the alias ('console' in
496 this case) and updates the status of the node that is pointed to, to
497 either ok or disabled. If the alias does not exist, a warning is
498 displayed.
499
500 Args:
501 node_name: Name of node (e.g. '/uart@10200000') or alias alias
502 (e.g. 'console') to adjust
503 enabled: True to enable, False to disable
504 """
505 # Look up the alias if this is an alias reference
506 if not node_name.startswith('/'):
507 lookup = self.fdt.GetString('/aliases', node_name, '')
508 if not lookup:
509 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
510 return
511 node_name = lookup
512 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700513 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700514 else:
515 status = 'disabled'
516 self.fdt.PutString(node_name, 'status', status)
517
518 def AddEnableList(self, enable_list):
519 """Process a list of nodes to enable/disable.
520
521 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700522 enable_list: List of (node, value) tuples to add to the fdt. For each
Simon Glassa4934b72012-05-09 13:35:02 -0700523 tuple:
524 node: The fdt node to write to will be <node> or pointed to by
525 /aliases/<node>. We can tell which
526 value: 0 to disable the node, 1 to enable it
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700527
Vadim Bendebury507c0012013-06-09 12:49:25 -0700528 Raises:
529 CmdError if a command fails.
Simon Glassa4934b72012-05-09 13:35:02 -0700530 """
531 if enable_list:
532 for node_name, enabled in enable_list:
533 try:
534 enabled = int(enabled)
535 if enabled not in (0, 1):
536 raise ValueError
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700537 except ValueError:
Simon Glassa4934b72012-05-09 13:35:02 -0700538 raise CmdError("Invalid enable option value '%s' "
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700539 "(should be 0 or 1)" % str(enabled))
Simon Glassa4934b72012-05-09 13:35:02 -0700540 self.SetNodeEnabled(node_name, enabled)
541
Simon Glass290a1802011-07-17 13:54:32 -0700542 def AddConfigList(self, config_list, use_int=False):
543 """Add a list of config items to the fdt.
544
545 Normally these values are written to the fdt as strings, but integers
546 are also supported, in which case the values will be converted to integers
547 (if necessary) before being stored.
548
549 Args:
550 config_list: List of (config, value) tuples to add to the fdt. For each
551 tuple:
552 config: The fdt node to write to will be /config/<config>.
553 value: An integer or string value to write.
554 use_int: True to only write integer values.
555
556 Raises:
557 CmdError: if a value is required to be converted to integer but can't be.
558 """
559 if config_list:
560 for config in config_list:
561 value = config[1]
562 if use_int:
563 try:
564 value = int(value)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700565 except ValueError:
Simon Glass290a1802011-07-17 13:54:32 -0700566 raise CmdError("Cannot convert config option '%s' to integer" %
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700567 str(value))
Simon Glass290a1802011-07-17 13:54:32 -0700568 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800569 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700570 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800571 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700572
Simon Glass7c2d5572011-11-15 14:47:08 -0800573 def DecodeTextBase(self, data):
574 """Look at a U-Boot image and try to decode its TEXT_BASE.
575
576 This works because U-Boot has a header with the value 0x12345678
577 immediately followed by the TEXT_BASE value. We can therefore read this
578 from the image with some certainty. We check only the first 40 words
579 since the header should be within that region.
580
Simon Glass96b50302012-07-20 06:55:28 +0100581 Since upstream Tegra has moved to having a 16KB SPL region at the start,
582 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
583 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
584
Simon Glass7c2d5572011-11-15 14:47:08 -0800585 Args:
586 data: U-Boot binary data
587
588 Returns:
589 Text base (integer) or None if none was found
590 """
591 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100592 for start in (0, 0x4000):
593 for i in range(start, start + 160, 4):
594 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800595
Simon Glass96b50302012-07-20 06:55:28 +0100596 # TODO(sjg): This does not cope with a big-endian target
597 value = struct.unpack('<I', word)[0]
598 if found:
599 return value - start
600 if value == 0x12345678:
601 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800602
603 return None
604
605 def CalcTextBase(self, name, fdt, fname):
606 """Calculate the TEXT_BASE to use for U-Boot.
607
608 Normally this value is in the fdt, so we just read it from there. But as
609 a second check we look at the image itself in case this is different, and
610 switch to that if it is.
611
612 This allows us to flash any U-Boot even if its TEXT_BASE is different.
613 This is particularly useful with upstream U-Boot which uses a different
614 value (which we will move to).
615 """
616 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800617 # The value that comes back from fdt.GetInt is signed, which makes no
618 # sense for an address base. Force it to unsigned.
619 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800620 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100621 text_base_str = '%#x' % text_base if text_base else 'None'
622 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
623 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800624
625 # If they are different, issue a warning and switch over.
626 if text_base and text_base != fdt_text_base:
627 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
628 "fdt value of %x. Using %x" % (text_base, name,
629 fdt_text_base, text_base))
630 fdt_text_base = text_base
631 return fdt_text_base
632
Simon Glass6dcc2f22011-07-28 15:26:49 +1200633 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700634 """Create a boot stub and a signed boot stub.
635
Simon Glass6dcc2f22011-07-28 15:26:49 +1200636 For postload:
637 We add a /config/postload-text-offset entry to the signed bootstub's
638 fdt so that U-Boot can find the postload code.
639
640 The raw (unsigned) bootstub will have a value of -1 for this since we will
641 simply append the postload code to the bootstub and it can find it there.
642 This will be used for RW A/B firmware.
643
644 For the signed case this value will specify where in the flash to find
645 the postload code. This will be used for RO firmware.
646
Simon Glass89b86b82011-07-17 23:49:49 -0700647 Args:
648 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800649 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200650 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700651
652 Returns:
653 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200654 Full path to bootstub (uboot + fdt(-1) + postload).
655 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700656
657 Raises:
658 CmdError if a command fails.
659 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200660 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800661 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700662 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200663
664 # Make a copy of the fdt for the bootstub
665 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700666 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff)
Simon Glass290a1802011-07-17 13:54:32 -0700667 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200668
Simon Glass89b86b82011-07-17 23:49:49 -0700669 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700670 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
671 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700672 self._tools.OutputSize('Combined binary', bootstub)
673
Simon Glasse13ee2c2011-07-28 08:12:28 +1200674 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700675 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700676 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200677 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200678
679 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
680 data = self._tools.ReadFile(signed)
681
682 if postload:
683 # We must add postload to the bootstub since A and B will need to
684 # be able to find it without the /config/postload-text-offset mechanism.
685 bs_data = self._tools.ReadFile(bootstub)
686 bs_data += self._tools.ReadFile(postload)
687 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
688 self._tools.WriteFile(bootstub, bs_data)
689 self._tools.OutputSize('Combined binary with postload', bootstub)
690
691 # Now that we know the file size, adjust the fdt and re-sign
692 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800693 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200694 fdt_data = self._tools.ReadFile(fdt.fname)
695 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
696 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
697 postload_bootstub, text_base)
698 if len(data) != os.path.getsize(signed):
699 raise CmdError('Signed file size changed from %d to %d after updating '
700 'fdt' % (len(data), os.path.getsize(signed)))
701
702 # Re-read the signed image, and add the post-load binary.
703 data = self._tools.ReadFile(signed)
704 data += self._tools.ReadFile(postload)
705 self._tools.OutputSize('Post-load binary', postload)
706
707 self._tools.WriteFile(signed_postload, data)
708 self._tools.OutputSize('Final bootstub with postload', signed_postload)
709
710 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700711
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700712 def _CreateCorebootStub(self, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700713 """Create a coreboot boot stub.
714
715 Args:
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700716 coreboot: Path to coreboot.rom
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700717
718 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100719 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700720 """
721 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700722 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100723
724 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700725 return bootstub
726
Simon Glass7e199222012-03-13 15:51:18 -0700727
Simon Glass89b86b82011-07-17 23:49:49 -0700728 def _PackOutput(self, msg):
729 """Helper function to write output from PackFirmware (verbose level 2).
730
731 This is passed to PackFirmware for it to use to write output.
732
733 Args:
734 msg: Message to display.
735 """
736 self._out.Notice(msg)
737
Simon Glass439fe7a2012-03-09 16:19:34 -0800738 def _BuildBlob(self, pack, fdt, blob_type):
739 """Build the blob data for a particular blob type.
740
741 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700742 pack: a PackFirmware object describing the firmware image to build.
743 fdt: an fdt object including image layout information
Simon Glass439fe7a2012-03-09 16:19:34 -0800744 blob_type: The type of blob to create data for. Supported types are:
745 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
746 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
Vadim Bendebury507c0012013-06-09 12:49:25 -0700747
748 Raises:
749 CmdError if a command fails.
Simon Glass439fe7a2012-03-09 16:19:34 -0800750 """
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700751 # stupid pylint insists that sha256 is not in hashlib.
752 # pylint: disable=E1101
Simon Glass439fe7a2012-03-09 16:19:34 -0800753 if blob_type == 'coreboot':
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700754 coreboot = self._CreateCorebootStub(self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800755 pack.AddProperty('coreboot', coreboot)
756 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700757 elif blob_type == 'legacy':
758 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800759 elif blob_type == 'signed':
760 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
761 self.postload_fname)
762 pack.AddProperty('bootstub', bootstub)
763 pack.AddProperty('signed', signed)
764 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700765 elif blob_type == 'exynos-bl1':
766 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700767
768 # TODO(sjg@chromium.org): Deprecate ecbin
769 elif blob_type in ['ecrw', 'ecbin']:
770 pack.AddProperty('ecrw', self.ecrw_fname)
771 pack.AddProperty('ecbin', self.ecrw_fname)
Randall Spangler7307da92014-07-18 12:47:34 -0700772 elif blob_type == 'pdrw':
773 pack.AddProperty('pdrw', self.pdrw_fname)
Gabe Blackcdbdfe12013-02-06 05:37:52 -0800774 elif blob_type == 'ecrwhash':
775 ec_hash_file = os.path.join(self._tools.outdir, 'ec_hash.bin')
776 ecrw = self._tools.ReadFile(self.ecrw_fname)
777 hasher = hashlib.sha256()
778 hasher.update(ecrw)
779 self._tools.WriteFile(ec_hash_file, hasher.digest())
780 pack.AddProperty(blob_type, ec_hash_file)
Randall Spangler7307da92014-07-18 12:47:34 -0700781 elif blob_type == 'pdrwhash':
782 pd_hash_file = os.path.join(self._tools.outdir, 'pd_hash.bin')
783 pdrw = self._tools.ReadFile(self.pdrw_fname)
784 hasher = hashlib.sha256()
785 hasher.update(pdrw)
786 self._tools.WriteFile(pd_hash_file, hasher.digest())
787 pack.AddProperty(blob_type, pd_hash_file)
Simon Glassbe0bc002012-08-16 12:50:48 -0700788 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700789 # crosbug.com/p/13143
790 # We cannot have an fmap in the EC image since there can be only one,
791 # which is the main fmap describing the whole image.
792 # Ultimately the EC will not have an fmap, since with software sync
793 # there is no flashrom involvement in updating the EC flash, and thus
794 # no need for the fmap.
795 # For now, mangle the fmap name to avoid problems.
796 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
797 data = self._tools.ReadFile(self.ecro_fname)
798 data = re.sub('__FMAP__', '__fMAP__', data)
799 self._tools.WriteFile(updated_ecro, data)
800 pack.AddProperty(blob_type, updated_ecro)
Simon Glass0a047bc2013-07-19 15:44:43 -0600801 elif blob_type.startswith('exynos-bl2'):
802 # We need to configure this per node, so do it later
803 pass
Simon Glass439fe7a2012-03-09 16:19:34 -0800804 elif pack.GetProperty(blob_type):
805 pass
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800806 elif blob_type in self.blobs:
807 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -0800808 else:
809 raise CmdError("Unknown blob type '%s' required in flash map" %
810 blob_type)
811
Simon Glass290a1802011-07-17 13:54:32 -0700812 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700813 """Create a full firmware image, along with various by-products.
814
815 This uses the provided u-boot.bin, fdt and bct to create a firmware
816 image containing all the required parts. If the GBB is not supplied
817 then this will just return a signed U-Boot as the image.
818
819 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700820 gbb: a string, full path to the GBB file, or empty if a GBB is not
821 required.
822 fdt: an fdt object containing required information.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200823
824 Returns:
825 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700826 """
Simon Glass02d124a2012-03-02 14:47:20 -0800827 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700828
Simon Glass439fe7a2012-03-09 16:19:34 -0800829 pack = PackFirmware(self._tools, self._out)
Simon Glassb8c6d952012-12-01 06:14:35 -0800830 if self._force_rw:
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700831 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
832 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
Simon Glass00d027e2013-07-20 14:51:12 -0600833 if self._force_efs:
834 fdt.PutInteger('/chromeos-config', 'early-firmware-selection', 1)
Simon Glassa7e66e22013-07-23 07:21:16 -0600835 pack.use_efs = fdt.GetInt('/chromeos-config', 'early-firmware-selection',
836 0)
Simon Glassb8c6d952012-12-01 06:14:35 -0800837
Simon Glass4f318912013-07-20 16:13:06 -0600838 pack.SelectFdt(fdt, self._board)
Simon Glass439fe7a2012-03-09 16:19:34 -0800839
840 # Get all our blobs ready
841 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -0800842 if self.skeleton_fname:
843 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700844 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700845
Simon Glassde9c8072012-07-02 22:29:02 -0700846 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
847 if self.kernel_fname:
848 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
849
Simon Glass439fe7a2012-03-09 16:19:34 -0800850 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100851 blob_list = pack.GetBlobList()
852 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700853 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800854 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700855
Simon Glass7306b902012-12-17 15:06:21 -0800856 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -0700857 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700858 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800859 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800860 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800861 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700862 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800863 pack.AddProperty('fwid', fwid)
864 pack.AddProperty('gbb', gbb)
865 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700866
Simon Glass0a047bc2013-07-19 15:44:43 -0600867 # Some blobs need to be configured according to the node they are in.
Simon Glass4c24f662013-07-19 15:53:02 -0600868 todo = pack.GetMissingBlobs()
869 for blob in todo:
Simon Glass0a047bc2013-07-19 15:44:43 -0600870 if blob.key.startswith('exynos-bl2'):
871 bl2 = ExynosBl2(self._tools, self._out)
872 pack.AddProperty(blob.key, bl2.MakeSpl(pack, fdt, blob,
873 self.exynos_bl2))
874
Simon Glassc90cf582012-03-13 15:40:47 -0700875 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700876
877 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -0800878 pack.UpdateBlobPositionsAndHashes(fdt)
Simon Glass8884b982012-06-21 12:41:41 -0700879
Simon Glass4c24f662013-07-19 15:53:02 -0600880 # Recalculate the Exynos BL2, since it may have a hash. The call to
881 # UpdateBlobPositionsAndHashes() may have updated the hash-target so we
882 # need to recalculate the hash.
883 for blob in todo:
884 if blob.key.startswith('exynos-bl2'):
885 bl2 = ExynosBl2(self._tools, self._out)
886 pack.AddProperty(blob.key, bl2.MakeSpl(pack, fdt, blob,
887 self.exynos_bl2))
888
Simon Glass6207efe2012-12-17 15:04:36 -0800889 # Make a copy of the fdt for the bootstub
890 fdt_data = self._tools.ReadFile(fdt.fname)
891 uboot_data = self._tools.ReadFile(self.uboot_fname)
892 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
893 self._tools.WriteFile(uboot_copy, uboot_data)
894
895 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
896 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
897
Simon Glassa10282a2013-01-08 17:06:41 -0800898 # Fix up the coreboot image here, since we can't do this until we have
899 # a final device tree binary.
Simon Glasscbc83552012-07-23 15:26:22 +0100900 if 'coreboot' in blob_list:
901 bootstub = pack.GetProperty('coreboot')
902 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -0800903 if self.coreboot_elf:
904 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
905 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
906 else:
Simon Glass0a7cf112013-05-21 23:08:21 -0700907 text_base = 0x1110000
908
909 # This is the the 'movw $GD_FLG_COLD_BOOT, %bx' instruction
910 # 1110015: 66 bb 00 01 mov $0x100,%bx
911 marker = struct.pack('<L', 0x0100bb66)
912 pos = uboot_data.find(marker)
913 if pos == -1 or pos > 0x100:
914 raise ValueError('Cannot find U-Boot cold boot entry point')
915 entry = text_base + pos
916 self._out.Notice('U-Boot entry point %#08x' % entry)
Simon Glassa10282a2013-01-08 17:06:41 -0800917 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
918 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
Simon Glass0a7cf112013-05-21 23:08:21 -0700919 '-l', '%#x' % text_base, '-e', '%#x' % entry])
Stefan Reinauer1502ea62012-11-01 10:15:38 -0700920 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
921 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -0800922 data = self._tools.ReadFile(bootstub)
923 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
924 self._tools.WriteFile(bootstub_copy, data)
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700925
Aaron Durbinab505932014-07-16 15:58:40 -0500926 if self._board in ('storm', 'rush', 'rush_ryu', ):
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700927 # This is a hack, as storm does not fall into any of the two
928 # categories of images covered by the [-0x100000:] range. Not applying
929 # this to all targets yet, as it is not clear that they all would fit
930 # this scheme where the /flash/ro-boot node has the 'reg' property
931 # showing the location of the ro coreboot part in the image.
932 #
933 # The upcoming refactor of this tool will have to take care of this in
934 # a more consistent way.
935 fdt_ro_boot = fdt.GetProp('/flash/ro-boot', 'reg')
936 rom_range = [int(x) for x in fdt_ro_boot.split()]
937 self._tools.WriteFile(bootstub, data[rom_range[0]:rom_range[1]])
938 else:
939 self._tools.WriteFile(bootstub, data[-0x100000:])
Simon Glasscbc83552012-07-23 15:26:22 +0100940
Simon Glass208ad952013-02-10 11:16:46 -0800941 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -0700942 image = os.path.join(self._tools.outdir, 'image.bin')
943 pack.PackImage(self._tools.outdir, image)
944 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700945
Simon Glass439fe7a2012-03-09 16:19:34 -0800946 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700947 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700948 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700949
Simon Glassdedda6f2013-02-09 13:44:14 -0800950 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -0700951 """Select an FDT to control the firmware bundling
952
Simon Glassdedda6f2013-02-09 13:44:14 -0800953 We make a copy of this which will include any on-the-fly changes we want
954 to make.
955
Simon Glass290a1802011-07-17 13:54:32 -0700956 Args:
957 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -0800958 use_defaults: True to use a default FDT name if available, and to add
959 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -0700960
Simon Glassc0f3dc62011-08-09 14:19:05 -0700961 Returns:
962 The Fdt object of the original fdt file, which we will not modify.
963
Simon Glassdedda6f2013-02-09 13:44:14 -0800964 Raises:
965 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
966 False).
Simon Glass290a1802011-07-17 13:54:32 -0700967 """
Simon Glassdedda6f2013-02-09 13:44:14 -0800968 if use_defaults:
969 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -0800970 if not fdt_fname:
971 raise ValueError('Please provide an FDT filename')
972 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -0700973 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -0800974
975 # For upstream, select the correct architecture .dtsi manually.
976 if self._board == 'link' or 'x86' in self._board:
977 arch_dts = 'coreboot.dtsi'
978 elif self._board == 'daisy':
979 arch_dts = 'exynos5250.dtsi'
980 else:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500981 arch_dts = 'tegra124.dtsi'
Simon Glassc3e42c32012-12-17 15:00:04 -0800982
983 fdt.Compile(arch_dts)
Simon Glasse53abbc2013-08-21 22:29:55 -0600984 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
985
986 # Get the flashmap so we know what to build. For board variants use the
987 # main board name as the key (drop the _<variant> suffix).
988 default_flashmap = default_flashmaps.get(self._board.split('_')[0], [])
989
990 if not fdt.GetProp('/flash', 'reg', ''):
991 fdt.InsertNodes(default_flashmap)
992
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500993 # Only check for /iram and /config nodes for boards that require it.
994 if self._board in ('daisy', 'peach'):
995 # Insert default values for any essential properties that are missing.
996 # This should only happen for upstream U-Boot, until our changes are
997 # upstreamed.
998 if not fdt.GetProp('/iram', 'reg', ''):
999 self._out.Warning('Cannot find /iram, using default')
1000 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/iram'])
Simon Glasse53abbc2013-08-21 22:29:55 -06001001
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -05001002 # Sadly the pit branch has an invalid /memory node. Work around it
1003 # for now. crosbug.com/p/22184
1004 if (not fdt.GetProp('/memory', 'reg', '') or
1005 fdt.GetIntList('/memory', 'reg')[0] == 0):
1006 self._out.Warning('Cannot find /memory, using default')
1007 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/memory'])
Simon Glasse53abbc2013-08-21 22:29:55 -06001008
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -05001009 if not fdt.GetProp('/config', 'samsung,bl1-offset', ''):
1010 self._out.Warning('Missing properties in /config, using defaults')
1011 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/config'])
Simon Glasse53abbc2013-08-21 22:29:55 -06001012
Simon Glass7df773b2013-08-25 18:02:29 -06001013 # Remember our board type.
1014 fdt.PutString('/chromeos-config', 'board', self._board)
1015
Simon Glasse53abbc2013-08-21 22:29:55 -06001016 self.fdt = fdt
1017 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001018
Simon Glassc90cf582012-03-13 15:40:47 -07001019 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001020 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001021
1022 - Checks options, tools, output directory, fdt.
1023 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001024
1025 Args:
Simon Glass56577572011-07-19 11:08:06 +12001026 hardware_id: Hardware ID to use for this board. If None, then the
1027 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001028 output_fname: Output filename for the image. If this is not None, then
1029 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001030 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001031
1032 Returns:
1033 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001034 """
Vadim Bendebury5baeec12013-04-02 13:01:22 -07001035 if self._small or self.fdt.GetProp('/config', 'nogbb', 'any') != 'any':
1036 gbb = '' # Building a small image or `nogbb' is requested in device tree.
1037 else:
Simon Glass56577572011-07-19 11:08:06 +12001038 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001039
1040 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001041 image, pack = self._CreateImage(gbb, self.fdt)
1042 if show_map:
1043 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001044 if output_fname:
1045 shutil.copyfile(image, output_fname)
1046 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001047 return image, pack.props