blob: 8b5ff708b881cc1cccc3309af574630bdd37bbed [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,
69}
70
Simon Glass49b026b2013-04-26 16:38:42 -070071# Maps board name to Exynos product number
72type_to_model = {
73 'peach' : '5420',
74 'daisy' : '5250'
75}
76
Simon Glass5076a7f2012-10-23 16:31:54 -070077def ListGoogleBinaryBlockFlags():
78 """Print out a list of GBB flags."""
79 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
80 for name, value in gbb_flag_properties.iteritems():
81 print ' %-30s %02x' % (name, value)
82
Simon Glass89b86b82011-07-17 23:49:49 -070083class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070084 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070085
Simon Glass290a1802011-07-17 13:54:32 -070086 Sequence of events:
87 bundle = Bundle(tools.Tools(), cros_output.Output())
88 bundle.SetDirs(...)
89 bundle.SetFiles(...)
90 bundle.SetOptions(...)
91 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070092 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070093 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070094
Simon Glass290a1802011-07-17 13:54:32 -070095 Public properties:
96 fdt: The fdt object that we use for building our image. This wil be the
97 one specified by the user, except that we might add config options
98 to it. This is set up by SelectFdt() which must be called before
99 bundling starts.
100 uboot_fname: Full filename of the U-Boot binary we use.
101 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -0700102 spl_source: Source device to load U-Boot from, in SPL:
103 straps: Select device according to CPU strap pins
104 spi: Boot from SPI
105 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -0700106
107 Private attributes:
108 _small: True to create a 'small' signed U-Boot, False to produce a
109 full image. The small U-Boot is enough to boot but will not have
110 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700111 """
Simon Glass89b86b82011-07-17 23:49:49 -0700112
Simon Glass290a1802011-07-17 13:54:32 -0700113 def __init__(self, tools, output):
114 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700115
Simon Glass290a1802011-07-17 13:54:32 -0700116 Args:
117 tools: A tools.Tools object to use for external tools.
118 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700119 """
Simon Glass290a1802011-07-17 13:54:32 -0700120 self._tools = tools
121 self._out = output
122
123 # Set up the things we need to know in order to operate.
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500124 self._board = None # Board name, e.g. nyan.
Simon Glass290a1802011-07-17 13:54:32 -0700125 self._fdt_fname = None # Filename of our FDT.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700126 self._force_rw = None
Simon Glass00d027e2013-07-20 14:51:12 -0600127 self._force_efs = None
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700128 self._gbb_flags = None
129 self._keydir = None
130 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700131 self.bct_fname = None # Filename of our BCT file.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700132 self.blobs = {} # Table of (type, filename) of arbitrary blobs
Hung-Te Lin5b649382011-08-03 15:01:16 +0800133 self.bmpblk_fname = None # Filename of our Bitmap Block
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700134 self.coreboot_elf = None
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700135 self.coreboot_fname = None # Filename of our coreboot binary.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700136 self.ecro_fname = None # Filename of EC read-only file
137 self.ecrw_fname = None # Filename of EC file
Simon Glass7e199222012-03-13 15:51:18 -0700138 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
139 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700140 self.fdt = None # Our Fdt object.
141 self.kernel_fname = None
142 self.postload_fname = None
143 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass07267952012-06-08 12:45:13 -0700144 self.skeleton_fname = None # Filename of Coreboot skeleton file
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700145 self.uboot_fname = None # Filename of our U-Boot binary.
Simon Glass290a1802011-07-17 13:54:32 -0700146
147 def SetDirs(self, keydir):
148 """Set up directories required for Bundle.
149
150 Args:
151 keydir: Directory containing keys to use for signing firmware.
152 """
153 self._keydir = keydir
154
Simon Glass6dcc2f22011-07-28 15:26:49 +1200155 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800156 coreboot_elf=None,
Simon Glass07267952012-06-08 12:45:13 -0700157 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800158 skeleton=None, ecrw=None, ecro=None, kernel=None, blobs=None):
Simon Glass290a1802011-07-17 13:54:32 -0700159 """Set up files required for Bundle.
160
161 Args:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500162 board: The name of the board to target (e.g. nyan).
Simon Glass290a1802011-07-17 13:54:32 -0700163 uboot: The filename of the u-boot.bin image to use.
164 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800165 bmpblk: The filename of bitmap block file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800166 coreboot: The filename of the coreboot image to use (on x86).
167 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200168 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700169 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700170 exynos_bl1: The filename of the exynos BL1 file
171 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
172 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700173 ecrw: The filename of the EC (Embedded Controller) read-write file.
174 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700175 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800176 blobs: List of (type, filename) of arbitrary blobs.
Simon Glass290a1802011-07-17 13:54:32 -0700177 """
178 self._board = board
179 self.uboot_fname = uboot
180 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800181 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700182 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800183 self.coreboot_elf = coreboot_elf
Simon Glass6dcc2f22011-07-28 15:26:49 +1200184 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700185 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700186 self.exynos_bl1 = exynos_bl1
187 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700188 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700189 self.ecrw_fname = ecrw
190 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700191 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800192 self.blobs = dict(blobs or ())
Simon Glass290a1802011-07-17 13:54:32 -0700193
Simon Glass00d027e2013-07-20 14:51:12 -0600194 def SetOptions(self, small, gbb_flags, force_rw=False, force_efs=False):
Simon Glass290a1802011-07-17 13:54:32 -0700195 """Set up options supported by Bundle.
196
197 Args:
198 small: Only create a signed U-Boot - don't produce the full packed
199 firmware image. This is useful for devs who want to replace just the
200 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700201 gbb_flags: Specification for string containing adjustments to make.
202 force_rw: Force firmware into RW mode.
Simon Glass00d027e2013-07-20 14:51:12 -0600203 force_efs: Force firmware to use 'early firmware selection' feature,
204 where RW firmware is selected before SDRAM is initialized.
Simon Glass290a1802011-07-17 13:54:32 -0700205 """
206 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700207 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700208 self._force_rw = force_rw
Simon Glass00d027e2013-07-20 14:51:12 -0600209 self._force_efs = force_efs
Simon Glass290a1802011-07-17 13:54:32 -0700210
Simon Glass22f39fb2013-02-09 13:44:14 -0800211 def _GetBuildRoot(self):
212 """Get the path to this board's 'firmware' directory.
213
214 Returns:
215 Path to firmware directory, with ## representing the path to the
216 chroot.
217 """
Simon Glass290a1802011-07-17 13:54:32 -0700218 if not self._board:
219 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800220 return os.path.join('##', 'build', self._board, 'firmware')
221
222 def _CheckFdtFilename(self, fname):
223 """Check provided FDT filename and return the correct name if needed.
224
225 Where the filename lacks a path, add a default path for this board.
226 Where no FDT filename is provided, select a default one for this board.
227
228 Args:
229 fname: Proposed FDT filename.
230
231 Returns:
232 Selected FDT filename, after validation.
233 """
234 build_root = self._GetBuildRoot()
Julius Wernerb4b14392013-08-09 14:41:40 -0700235 dir_name = os.path.join(build_root, 'dtb')
Simon Glass22f39fb2013-02-09 13:44:14 -0800236 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700237 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700238 base_name = re.sub('_', '-', self._board)
239
240 # In case the name exists with a prefix or suffix, find it.
Julius Wernerb4b14392013-08-09 14:41:40 -0700241 wildcard = os.path.join(dir_name, '*%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700242 found_list = glob.glob(self._tools.Filename(wildcard))
243 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800244 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700245 else:
246 # We didn't find anything definite, so set up our expected name.
Julius Wernerb4b14392013-08-09 14:41:40 -0700247 fname = os.path.join(dir_name, '%s.dtb' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700248
Simon Glass881964d2012-04-04 11:34:09 -0700249 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800250 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700251 if not ext and not os.path.dirname(root):
Julius Wernerb4b14392013-08-09 14:41:40 -0700252 fname = os.path.join(dir_name, '%s.dtb' % root)
Simon Glass22f39fb2013-02-09 13:44:14 -0800253 return fname
254
255 def CheckOptions(self):
256 """Check provided options and select defaults."""
257 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700258
Simon Glass49b026b2013-04-26 16:38:42 -0700259 board_type = self._board.split('_')[0]
260 model = type_to_model.get(board_type)
261
Simon Glass290a1802011-07-17 13:54:32 -0700262 if not self.uboot_fname:
263 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
264 if not self.bct_fname:
265 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700266 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700267 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700268 if model:
269 if not self.exynos_bl1:
Simon Glassd05696e2013-06-13 20:14:00 -0700270 self.exynos_bl1 = os.path.join(build_root, 'u-boot.bl1.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700271 if not self.exynos_bl2:
Julius Wernerb12c0052013-08-14 13:57:04 -0700272 self.exynos_bl2 = os.path.join(build_root, 'u-boot-spl.wrapped.bin')
Simon Glass07267952012-06-08 12:45:13 -0700273 if not self.coreboot_fname:
274 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
275 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700276 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700277 if not self.seabios_fname:
278 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700279 if not self.ecrw_fname:
280 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
281 if not self.ecro_fname:
282 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700283
Simon Glass75759302012-03-15 20:26:53 -0700284 def GetFiles(self):
285 """Get a list of files that we know about.
286
287 This is the opposite of SetFiles except that we may have put in some
288 default names. It returns a dictionary containing the filename for
289 each of a number of pre-defined files.
290
291 Returns:
292 Dictionary, with one entry for each file.
293 """
294 file_list = {
295 'bct' : self.bct_fname,
296 'exynos-bl1' : self.exynos_bl1,
297 'exynos-bl2' : self.exynos_bl2,
298 }
299 return file_list
300
Simon Glass4a887b12012-10-23 16:29:03 -0700301 def DecodeGBBFlagsFromFdt(self):
302 """Get Google Binary Block flags from the FDT.
303
304 These should be in the chromeos-config node, like this:
305
306 chromeos-config {
307 gbb-flag-dev-screen-short-delay;
308 gbb-flag-force-dev-switch-on;
309 gbb-flag-force-dev-boot-usb;
310 gbb-flag-disable-fw-rollback-check;
311 };
312
313 Returns:
314 GBB flags value from FDT.
315 """
316 chromeos_config = self.fdt.GetProps("/chromeos-config")
317 gbb_flags = 0
318 for name in chromeos_config:
319 if name.startswith('gbb-flag-'):
320 flag_value = gbb_flag_properties.get(name[9:])
321 if flag_value:
322 gbb_flags |= flag_value
323 self._out.Notice("FDT: Enabling %s." % name)
324 else:
325 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
326 return gbb_flags
327
Simon Glass157c0662012-10-23 13:52:42 -0700328 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
329 """Decode ajustments to the provided GBB flags.
330
331 We support three options:
332
333 hex value: c2
334 defined value: force-dev-boot-usb,load-option-roms
335 adjust default value: -load-option-roms,+force-dev-boot-usb
336
337 The last option starts from the passed-in GBB flags and adds or removes
338 flags.
339
340 Args:
341 gbb_flags: Base (default) FDT flags.
342 adjustments: String containing adjustments to make.
343
344 Returns:
345 Updated FDT flags.
346 """
347 use_base_value = True
348 if adjustments:
349 try:
350 return int(adjustments, base=16)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700351 except (ValueError, TypeError):
Simon Glass157c0662012-10-23 13:52:42 -0700352 pass
353 for flag in adjustments.split(','):
354 oper = None
355 if flag[0] in ['-', '+']:
356 oper = flag[0]
357 flag = flag[1:]
358 value = gbb_flag_properties.get(flag)
359 if not value:
360 raise ValueError("Invalid GBB flag '%s'" % flag)
361 if oper == '+':
362 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800363 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700364 elif oper == '-':
365 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800366 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700367 else:
368 if use_base_value:
369 gbb_flags = 0
370 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800371 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700372 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
375 return gbb_flags
376
Simon Glass56577572011-07-19 11:08:06 +1200377 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700378 """Create a GBB for the image.
379
Simon Glass56577572011-07-19 11:08:06 +1200380 Args:
381 hardware_id: Hardware ID to use for this board. If None, then the
382 default from the Fdt will be used
383
Simon Glass89b86b82011-07-17 23:49:49 -0700384 Returns:
385 Path of the created GBB file.
Simon Glass89b86b82011-07-17 23:49:49 -0700386 """
Simon Glass56577572011-07-19 11:08:06 +1200387 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800388 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700389 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700390 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700391
Simon Glass4a887b12012-10-23 16:29:03 -0700392 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800393
Simon Glass157c0662012-10-23 13:52:42 -0700394 # Allow command line to override flags
395 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
396
Simon Glass4a887b12012-10-23 16:29:03 -0700397 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700398 self._out.Progress('Creating GBB')
399 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
400 sizes = ['%#x' % size for size in sizes]
401 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700402 keydir = self._tools.Filename(self._keydir)
403 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700404 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200405 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700406 '--rootkey=%s/root_key.vbpubk' % keydir,
407 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700408 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800409 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700410 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700411 cwd=odir)
412 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700413
Simon Glasse13ee2c2011-07-28 08:12:28 +1200414 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700415 """Sign an image so that the Tegra SOC will boot it.
416
417 Args:
418 bct: BCT file to use.
419 bootstub: Boot stub (U-Boot + fdt) file to sign.
420 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700421
422 Returns:
423 filename of signed image.
Simon Glass89b86b82011-07-17 23:49:49 -0700424 """
425 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200426 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700427 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200428 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700429 fd = open(config, 'w')
430 fd.write('Version = 1;\n')
431 fd.write('Redundancy = 1;\n')
432 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700433
434 # TODO(dianders): Right now, we don't have enough space in our flash map
435 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
436 # sure what this does for reliability, but at least things will fit...
437 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
438 if is_nand:
439 fd.write('Bctcopy = 1;\n')
440
Simon Glass89b86b82011-07-17 23:49:49 -0700441 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
442 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700443
Simon Glass89b86b82011-07-17 23:49:49 -0700444 fd.close()
445
446 self._tools.Run('cbootimage', [config, signed])
447 self._tools.OutputSize('BCT', bct)
448 self._tools.OutputSize('Signed image', signed)
449 return signed
450
Doug Anderson86ce5f42011-07-27 10:40:18 -0700451 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700452 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700453
454 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700455 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700456 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700457 """
Simon Glass468d8752012-09-19 16:36:19 -0700458 if bootcmd is not None:
459 if bootcmd == 'none':
460 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800461 self.fdt.PutString('/config', 'bootcmd', bootcmd)
462 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700463 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700464
Simon Glassa4934b72012-05-09 13:35:02 -0700465 def SetNodeEnabled(self, node_name, enabled):
466 """Set whether an node is enabled or disabled.
467
468 This simply sets the 'status' property of a node to "ok", or "disabled".
469
470 The node should either be a full path to the node (like '/uart@10200000')
471 or an alias property.
472
473 Aliases are supported like this:
474
475 aliases {
476 console = "/uart@10200000";
477 };
478
479 pointing to a node:
480
481 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700482 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700483 };
484
485 In this case, this function takes the name of the alias ('console' in
486 this case) and updates the status of the node that is pointed to, to
487 either ok or disabled. If the alias does not exist, a warning is
488 displayed.
489
490 Args:
491 node_name: Name of node (e.g. '/uart@10200000') or alias alias
492 (e.g. 'console') to adjust
493 enabled: True to enable, False to disable
494 """
495 # Look up the alias if this is an alias reference
496 if not node_name.startswith('/'):
497 lookup = self.fdt.GetString('/aliases', node_name, '')
498 if not lookup:
499 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
500 return
501 node_name = lookup
502 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700503 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700504 else:
505 status = 'disabled'
506 self.fdt.PutString(node_name, 'status', status)
507
508 def AddEnableList(self, enable_list):
509 """Process a list of nodes to enable/disable.
510
511 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700512 enable_list: List of (node, value) tuples to add to the fdt. For each
Simon Glassa4934b72012-05-09 13:35:02 -0700513 tuple:
514 node: The fdt node to write to will be <node> or pointed to by
515 /aliases/<node>. We can tell which
516 value: 0 to disable the node, 1 to enable it
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700517
Vadim Bendebury507c0012013-06-09 12:49:25 -0700518 Raises:
519 CmdError if a command fails.
Simon Glassa4934b72012-05-09 13:35:02 -0700520 """
521 if enable_list:
522 for node_name, enabled in enable_list:
523 try:
524 enabled = int(enabled)
525 if enabled not in (0, 1):
526 raise ValueError
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700527 except ValueError:
Simon Glassa4934b72012-05-09 13:35:02 -0700528 raise CmdError("Invalid enable option value '%s' "
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700529 "(should be 0 or 1)" % str(enabled))
Simon Glassa4934b72012-05-09 13:35:02 -0700530 self.SetNodeEnabled(node_name, enabled)
531
Simon Glass290a1802011-07-17 13:54:32 -0700532 def AddConfigList(self, config_list, use_int=False):
533 """Add a list of config items to the fdt.
534
535 Normally these values are written to the fdt as strings, but integers
536 are also supported, in which case the values will be converted to integers
537 (if necessary) before being stored.
538
539 Args:
540 config_list: List of (config, value) tuples to add to the fdt. For each
541 tuple:
542 config: The fdt node to write to will be /config/<config>.
543 value: An integer or string value to write.
544 use_int: True to only write integer values.
545
546 Raises:
547 CmdError: if a value is required to be converted to integer but can't be.
548 """
549 if config_list:
550 for config in config_list:
551 value = config[1]
552 if use_int:
553 try:
554 value = int(value)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700555 except ValueError:
Simon Glass290a1802011-07-17 13:54:32 -0700556 raise CmdError("Cannot convert config option '%s' to integer" %
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700557 str(value))
Simon Glass290a1802011-07-17 13:54:32 -0700558 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800559 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700560 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800561 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700562
Simon Glass7c2d5572011-11-15 14:47:08 -0800563 def DecodeTextBase(self, data):
564 """Look at a U-Boot image and try to decode its TEXT_BASE.
565
566 This works because U-Boot has a header with the value 0x12345678
567 immediately followed by the TEXT_BASE value. We can therefore read this
568 from the image with some certainty. We check only the first 40 words
569 since the header should be within that region.
570
Simon Glass96b50302012-07-20 06:55:28 +0100571 Since upstream Tegra has moved to having a 16KB SPL region at the start,
572 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
573 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
574
Simon Glass7c2d5572011-11-15 14:47:08 -0800575 Args:
576 data: U-Boot binary data
577
578 Returns:
579 Text base (integer) or None if none was found
580 """
581 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100582 for start in (0, 0x4000):
583 for i in range(start, start + 160, 4):
584 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800585
Simon Glass96b50302012-07-20 06:55:28 +0100586 # TODO(sjg): This does not cope with a big-endian target
587 value = struct.unpack('<I', word)[0]
588 if found:
589 return value - start
590 if value == 0x12345678:
591 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800592
593 return None
594
595 def CalcTextBase(self, name, fdt, fname):
596 """Calculate the TEXT_BASE to use for U-Boot.
597
598 Normally this value is in the fdt, so we just read it from there. But as
599 a second check we look at the image itself in case this is different, and
600 switch to that if it is.
601
602 This allows us to flash any U-Boot even if its TEXT_BASE is different.
603 This is particularly useful with upstream U-Boot which uses a different
604 value (which we will move to).
605 """
606 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800607 # The value that comes back from fdt.GetInt is signed, which makes no
608 # sense for an address base. Force it to unsigned.
609 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800610 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100611 text_base_str = '%#x' % text_base if text_base else 'None'
612 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
613 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800614
615 # If they are different, issue a warning and switch over.
616 if text_base and text_base != fdt_text_base:
617 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
618 "fdt value of %x. Using %x" % (text_base, name,
619 fdt_text_base, text_base))
620 fdt_text_base = text_base
621 return fdt_text_base
622
Simon Glass6dcc2f22011-07-28 15:26:49 +1200623 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700624 """Create a boot stub and a signed boot stub.
625
Simon Glass6dcc2f22011-07-28 15:26:49 +1200626 For postload:
627 We add a /config/postload-text-offset entry to the signed bootstub's
628 fdt so that U-Boot can find the postload code.
629
630 The raw (unsigned) bootstub will have a value of -1 for this since we will
631 simply append the postload code to the bootstub and it can find it there.
632 This will be used for RW A/B firmware.
633
634 For the signed case this value will specify where in the flash to find
635 the postload code. This will be used for RO firmware.
636
Simon Glass89b86b82011-07-17 23:49:49 -0700637 Args:
638 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800639 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200640 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700641
642 Returns:
643 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200644 Full path to bootstub (uboot + fdt(-1) + postload).
645 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700646
647 Raises:
648 CmdError if a command fails.
649 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200650 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800651 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700652 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200653
654 # Make a copy of the fdt for the bootstub
655 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700656 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff)
Simon Glass290a1802011-07-17 13:54:32 -0700657 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200658
Simon Glass89b86b82011-07-17 23:49:49 -0700659 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700660 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
661 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700662 self._tools.OutputSize('Combined binary', bootstub)
663
Simon Glasse13ee2c2011-07-28 08:12:28 +1200664 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700665 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700666 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200667 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200668
669 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
670 data = self._tools.ReadFile(signed)
671
672 if postload:
673 # We must add postload to the bootstub since A and B will need to
674 # be able to find it without the /config/postload-text-offset mechanism.
675 bs_data = self._tools.ReadFile(bootstub)
676 bs_data += self._tools.ReadFile(postload)
677 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
678 self._tools.WriteFile(bootstub, bs_data)
679 self._tools.OutputSize('Combined binary with postload', bootstub)
680
681 # Now that we know the file size, adjust the fdt and re-sign
682 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800683 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200684 fdt_data = self._tools.ReadFile(fdt.fname)
685 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
686 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
687 postload_bootstub, text_base)
688 if len(data) != os.path.getsize(signed):
689 raise CmdError('Signed file size changed from %d to %d after updating '
690 'fdt' % (len(data), os.path.getsize(signed)))
691
692 # Re-read the signed image, and add the post-load binary.
693 data = self._tools.ReadFile(signed)
694 data += self._tools.ReadFile(postload)
695 self._tools.OutputSize('Post-load binary', postload)
696
697 self._tools.WriteFile(signed_postload, data)
698 self._tools.OutputSize('Final bootstub with postload', signed_postload)
699
700 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700701
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700702 def _CreateCorebootStub(self, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700703 """Create a coreboot boot stub.
704
705 Args:
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700706 coreboot: Path to coreboot.rom
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700707
708 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100709 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700710 """
711 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700712 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100713
714 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700715 return bootstub
716
Simon Glass7e199222012-03-13 15:51:18 -0700717
Simon Glass89b86b82011-07-17 23:49:49 -0700718 def _PackOutput(self, msg):
719 """Helper function to write output from PackFirmware (verbose level 2).
720
721 This is passed to PackFirmware for it to use to write output.
722
723 Args:
724 msg: Message to display.
725 """
726 self._out.Notice(msg)
727
Simon Glass439fe7a2012-03-09 16:19:34 -0800728 def _BuildBlob(self, pack, fdt, blob_type):
729 """Build the blob data for a particular blob type.
730
731 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700732 pack: a PackFirmware object describing the firmware image to build.
733 fdt: an fdt object including image layout information
Simon Glass439fe7a2012-03-09 16:19:34 -0800734 blob_type: The type of blob to create data for. Supported types are:
735 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
736 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
Vadim Bendebury507c0012013-06-09 12:49:25 -0700737
738 Raises:
739 CmdError if a command fails.
Simon Glass439fe7a2012-03-09 16:19:34 -0800740 """
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700741 # stupid pylint insists that sha256 is not in hashlib.
742 # pylint: disable=E1101
Simon Glass439fe7a2012-03-09 16:19:34 -0800743 if blob_type == 'coreboot':
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700744 coreboot = self._CreateCorebootStub(self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800745 pack.AddProperty('coreboot', coreboot)
746 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700747 elif blob_type == 'legacy':
748 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800749 elif blob_type == 'signed':
750 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
751 self.postload_fname)
752 pack.AddProperty('bootstub', bootstub)
753 pack.AddProperty('signed', signed)
754 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700755 elif blob_type == 'exynos-bl1':
756 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700757
758 # TODO(sjg@chromium.org): Deprecate ecbin
759 elif blob_type in ['ecrw', 'ecbin']:
760 pack.AddProperty('ecrw', self.ecrw_fname)
761 pack.AddProperty('ecbin', self.ecrw_fname)
Gabe Blackcdbdfe12013-02-06 05:37:52 -0800762 elif blob_type == 'ecrwhash':
763 ec_hash_file = os.path.join(self._tools.outdir, 'ec_hash.bin')
764 ecrw = self._tools.ReadFile(self.ecrw_fname)
765 hasher = hashlib.sha256()
766 hasher.update(ecrw)
767 self._tools.WriteFile(ec_hash_file, hasher.digest())
768 pack.AddProperty(blob_type, ec_hash_file)
Simon Glassbe0bc002012-08-16 12:50:48 -0700769 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700770 # crosbug.com/p/13143
771 # We cannot have an fmap in the EC image since there can be only one,
772 # which is the main fmap describing the whole image.
773 # Ultimately the EC will not have an fmap, since with software sync
774 # there is no flashrom involvement in updating the EC flash, and thus
775 # no need for the fmap.
776 # For now, mangle the fmap name to avoid problems.
777 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
778 data = self._tools.ReadFile(self.ecro_fname)
779 data = re.sub('__FMAP__', '__fMAP__', data)
780 self._tools.WriteFile(updated_ecro, data)
781 pack.AddProperty(blob_type, updated_ecro)
Simon Glass0a047bc2013-07-19 15:44:43 -0600782 elif blob_type.startswith('exynos-bl2'):
783 # We need to configure this per node, so do it later
784 pass
Simon Glass439fe7a2012-03-09 16:19:34 -0800785 elif pack.GetProperty(blob_type):
786 pass
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800787 elif blob_type in self.blobs:
788 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -0800789 else:
790 raise CmdError("Unknown blob type '%s' required in flash map" %
791 blob_type)
792
Simon Glass290a1802011-07-17 13:54:32 -0700793 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700794 """Create a full firmware image, along with various by-products.
795
796 This uses the provided u-boot.bin, fdt and bct to create a firmware
797 image containing all the required parts. If the GBB is not supplied
798 then this will just return a signed U-Boot as the image.
799
800 Args:
Vadim Bendebury7dac18c2014-05-06 14:13:35 -0700801 gbb: a string, full path to the GBB file, or empty if a GBB is not
802 required.
803 fdt: an fdt object containing required information.
Simon Glasse13ee2c2011-07-28 08:12:28 +1200804
805 Returns:
806 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700807 """
Simon Glass02d124a2012-03-02 14:47:20 -0800808 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700809
Simon Glass439fe7a2012-03-09 16:19:34 -0800810 pack = PackFirmware(self._tools, self._out)
Simon Glassb8c6d952012-12-01 06:14:35 -0800811 if self._force_rw:
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700812 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
813 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
Simon Glass00d027e2013-07-20 14:51:12 -0600814 if self._force_efs:
815 fdt.PutInteger('/chromeos-config', 'early-firmware-selection', 1)
Simon Glassa7e66e22013-07-23 07:21:16 -0600816 pack.use_efs = fdt.GetInt('/chromeos-config', 'early-firmware-selection',
817 0)
Simon Glassb8c6d952012-12-01 06:14:35 -0800818
Simon Glass4f318912013-07-20 16:13:06 -0600819 pack.SelectFdt(fdt, self._board)
Simon Glass439fe7a2012-03-09 16:19:34 -0800820
821 # Get all our blobs ready
822 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -0800823 if self.skeleton_fname:
824 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700825 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700826
Simon Glassde9c8072012-07-02 22:29:02 -0700827 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
828 if self.kernel_fname:
829 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
830
Simon Glass439fe7a2012-03-09 16:19:34 -0800831 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100832 blob_list = pack.GetBlobList()
833 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700834 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800835 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700836
Simon Glass7306b902012-12-17 15:06:21 -0800837 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -0700838 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700839 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800840 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800841 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800842 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700843 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800844 pack.AddProperty('fwid', fwid)
845 pack.AddProperty('gbb', gbb)
846 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700847
Simon Glass0a047bc2013-07-19 15:44:43 -0600848 # Some blobs need to be configured according to the node they are in.
Simon Glass4c24f662013-07-19 15:53:02 -0600849 todo = pack.GetMissingBlobs()
850 for blob in todo:
Simon Glass0a047bc2013-07-19 15:44:43 -0600851 if blob.key.startswith('exynos-bl2'):
852 bl2 = ExynosBl2(self._tools, self._out)
853 pack.AddProperty(blob.key, bl2.MakeSpl(pack, fdt, blob,
854 self.exynos_bl2))
855
Simon Glassc90cf582012-03-13 15:40:47 -0700856 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700857
858 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -0800859 pack.UpdateBlobPositionsAndHashes(fdt)
Simon Glass8884b982012-06-21 12:41:41 -0700860
Simon Glass4c24f662013-07-19 15:53:02 -0600861 # Recalculate the Exynos BL2, since it may have a hash. The call to
862 # UpdateBlobPositionsAndHashes() may have updated the hash-target so we
863 # need to recalculate the hash.
864 for blob in todo:
865 if blob.key.startswith('exynos-bl2'):
866 bl2 = ExynosBl2(self._tools, self._out)
867 pack.AddProperty(blob.key, bl2.MakeSpl(pack, fdt, blob,
868 self.exynos_bl2))
869
Simon Glass6207efe2012-12-17 15:04:36 -0800870 # Make a copy of the fdt for the bootstub
871 fdt_data = self._tools.ReadFile(fdt.fname)
872 uboot_data = self._tools.ReadFile(self.uboot_fname)
873 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
874 self._tools.WriteFile(uboot_copy, uboot_data)
875
876 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
877 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
878
Simon Glassa10282a2013-01-08 17:06:41 -0800879 # Fix up the coreboot image here, since we can't do this until we have
880 # a final device tree binary.
Simon Glasscbc83552012-07-23 15:26:22 +0100881 if 'coreboot' in blob_list:
882 bootstub = pack.GetProperty('coreboot')
883 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -0800884 if self.coreboot_elf:
885 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
886 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
887 else:
Simon Glass0a7cf112013-05-21 23:08:21 -0700888 text_base = 0x1110000
889
890 # This is the the 'movw $GD_FLG_COLD_BOOT, %bx' instruction
891 # 1110015: 66 bb 00 01 mov $0x100,%bx
892 marker = struct.pack('<L', 0x0100bb66)
893 pos = uboot_data.find(marker)
894 if pos == -1 or pos > 0x100:
895 raise ValueError('Cannot find U-Boot cold boot entry point')
896 entry = text_base + pos
897 self._out.Notice('U-Boot entry point %#08x' % entry)
Simon Glassa10282a2013-01-08 17:06:41 -0800898 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
899 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
Simon Glass0a7cf112013-05-21 23:08:21 -0700900 '-l', '%#x' % text_base, '-e', '%#x' % entry])
Stefan Reinauer1502ea62012-11-01 10:15:38 -0700901 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
902 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -0800903 data = self._tools.ReadFile(bootstub)
904 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
905 self._tools.WriteFile(bootstub_copy, data)
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700906
Aaron Durbinab505932014-07-16 15:58:40 -0500907 if self._board in ('storm', 'rush', 'rush_ryu', ):
Vadim Bendebury9f36e712014-06-12 13:37:59 -0700908 # This is a hack, as storm does not fall into any of the two
909 # categories of images covered by the [-0x100000:] range. Not applying
910 # this to all targets yet, as it is not clear that they all would fit
911 # this scheme where the /flash/ro-boot node has the 'reg' property
912 # showing the location of the ro coreboot part in the image.
913 #
914 # The upcoming refactor of this tool will have to take care of this in
915 # a more consistent way.
916 fdt_ro_boot = fdt.GetProp('/flash/ro-boot', 'reg')
917 rom_range = [int(x) for x in fdt_ro_boot.split()]
918 self._tools.WriteFile(bootstub, data[rom_range[0]:rom_range[1]])
919 else:
920 self._tools.WriteFile(bootstub, data[-0x100000:])
Simon Glasscbc83552012-07-23 15:26:22 +0100921
Simon Glass208ad952013-02-10 11:16:46 -0800922 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -0700923 image = os.path.join(self._tools.outdir, 'image.bin')
924 pack.PackImage(self._tools.outdir, image)
925 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700926
Simon Glass439fe7a2012-03-09 16:19:34 -0800927 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700928 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700929 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700930
Simon Glassdedda6f2013-02-09 13:44:14 -0800931 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -0700932 """Select an FDT to control the firmware bundling
933
Simon Glassdedda6f2013-02-09 13:44:14 -0800934 We make a copy of this which will include any on-the-fly changes we want
935 to make.
936
Simon Glass290a1802011-07-17 13:54:32 -0700937 Args:
938 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -0800939 use_defaults: True to use a default FDT name if available, and to add
940 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -0700941
Simon Glassc0f3dc62011-08-09 14:19:05 -0700942 Returns:
943 The Fdt object of the original fdt file, which we will not modify.
944
Simon Glassdedda6f2013-02-09 13:44:14 -0800945 Raises:
946 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
947 False).
Simon Glass290a1802011-07-17 13:54:32 -0700948 """
Simon Glassdedda6f2013-02-09 13:44:14 -0800949 if use_defaults:
950 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -0800951 if not fdt_fname:
952 raise ValueError('Please provide an FDT filename')
953 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -0700954 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -0800955
956 # For upstream, select the correct architecture .dtsi manually.
957 if self._board == 'link' or 'x86' in self._board:
958 arch_dts = 'coreboot.dtsi'
959 elif self._board == 'daisy':
960 arch_dts = 'exynos5250.dtsi'
961 else:
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500962 arch_dts = 'tegra124.dtsi'
Simon Glassc3e42c32012-12-17 15:00:04 -0800963
964 fdt.Compile(arch_dts)
Simon Glasse53abbc2013-08-21 22:29:55 -0600965 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
966
967 # Get the flashmap so we know what to build. For board variants use the
968 # main board name as the key (drop the _<variant> suffix).
969 default_flashmap = default_flashmaps.get(self._board.split('_')[0], [])
970
971 if not fdt.GetProp('/flash', 'reg', ''):
972 fdt.InsertNodes(default_flashmap)
973
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500974 # Only check for /iram and /config nodes for boards that require it.
975 if self._board in ('daisy', 'peach'):
976 # Insert default values for any essential properties that are missing.
977 # This should only happen for upstream U-Boot, until our changes are
978 # upstreamed.
979 if not fdt.GetProp('/iram', 'reg', ''):
980 self._out.Warning('Cannot find /iram, using default')
981 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/iram'])
Simon Glasse53abbc2013-08-21 22:29:55 -0600982
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500983 # Sadly the pit branch has an invalid /memory node. Work around it
984 # for now. crosbug.com/p/22184
985 if (not fdt.GetProp('/memory', 'reg', '') or
986 fdt.GetIntList('/memory', 'reg')[0] == 0):
987 self._out.Warning('Cannot find /memory, using default')
988 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/memory'])
Simon Glasse53abbc2013-08-21 22:29:55 -0600989
Rhyland Kleinc2df3ca2014-01-06 15:15:34 -0500990 if not fdt.GetProp('/config', 'samsung,bl1-offset', ''):
991 self._out.Warning('Missing properties in /config, using defaults')
992 fdt.InsertNodes([i for i in default_flashmap if i['path'] == '/config'])
Simon Glasse53abbc2013-08-21 22:29:55 -0600993
Simon Glass7df773b2013-08-25 18:02:29 -0600994 # Remember our board type.
995 fdt.PutString('/chromeos-config', 'board', self._board)
996
Simon Glasse53abbc2013-08-21 22:29:55 -0600997 self.fdt = fdt
998 return fdt
Simon Glass290a1802011-07-17 13:54:32 -0700999
Simon Glassc90cf582012-03-13 15:40:47 -07001000 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001001 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001002
1003 - Checks options, tools, output directory, fdt.
1004 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001005
1006 Args:
Simon Glass56577572011-07-19 11:08:06 +12001007 hardware_id: Hardware ID to use for this board. If None, then the
1008 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001009 output_fname: Output filename for the image. If this is not None, then
1010 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001011 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001012
1013 Returns:
1014 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001015 """
Vadim Bendebury5baeec12013-04-02 13:01:22 -07001016 if self._small or self.fdt.GetProp('/config', 'nogbb', 'any') != 'any':
1017 gbb = '' # Building a small image or `nogbb' is requested in device tree.
1018 else:
Simon Glass56577572011-07-19 11:08:06 +12001019 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001020
1021 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001022 image, pack = self._CreateImage(gbb, self.fdt)
1023 if show_map:
1024 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001025 if output_fname:
1026 shutil.copyfile(image, output_fname)
1027 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001028 return image, pack.props