blob: 6265d73fd6b2cfdfa73a12f26295da77a781d0d7 [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
5"""This module builds a firmware image for a tegra-based board.
6
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
24import cros_output
25from fdt import Fdt
26from pack_firmware import PackFirmware
27import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080028import struct
Simon Glass89b86b82011-07-17 23:49:49 -070029import tempfile
Simon Glass439fe7a2012-03-09 16:19:34 -080030from tools import CmdError
Simon Glass89b86b82011-07-17 23:49:49 -070031from tools import Tools
32from write_firmware import WriteFirmware
33
34# This data is required by bmpblk_utility. Does it ever change?
35# It was stored with the chromeos-bootimage ebuild, but we want
36# this utility to work outside the chroot.
37yaml_data = '''
38bmpblock: 1.0
39
40images:
41 devmode: DeveloperBmp/DeveloperBmp.bmp
42 recovery: RecoveryBmp/RecoveryBmp.bmp
43 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
44 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
45
46screens:
47 dev_en:
48 - [0, 0, devmode]
49 rec_en:
50 - [0, 0, recovery]
51 yuck_en:
52 - [0, 0, rec_yuck]
53 ins_en:
54 - [0, 0, rec_insert]
55
56localizations:
57 - [ dev_en, rec_en, yuck_en, ins_en ]
58'''
59
Simon Glass0c54ba52012-11-06 12:36:43 -080060# Default flash maps for various boards we support.
61# These are used when no fdt is provided (e.g. upstream U-Boot with no
62# fdt. Each is a list of nodes.
63default_flashmaps = {
Simon Glass76958702012-11-08 13:07:53 -080064 'tegra' : [
65 {
Simon Glass0c54ba52012-11-06 12:36:43 -080066 'node' : 'ro-boot',
67 'label' : 'boot-stub',
68 'size' : 512 << 10,
69 'read-only' : True,
70 'type' : 'blob signed',
71 'required' : True
72 }
73 ],
74 'daisy' : [
75 {
76 'node' : 'pre-boot',
77 'label' : "bl1 pre-boot",
78 'size' : 0x2000,
79 'read-only' : True,
80 'filename' : "e5250.nbl1.bin",
81 'type' : "blob exynos-bl1",
82 'required' : True,
83 }, {
84 'node' : 'spl',
85 'label' : "bl2 spl",
86 'size' : 0x4000,
87 'read-only' : True,
88 'filename' : "bl2.bin",
89 'type' : "blob exynos-bl2 boot,dtb",
90 'required' : True,
91 }, {
92 'node' : 'ro-boot',
93 'label' : "u-boot",
94 'size' : 0x9a000,
95 'read-only' : True,
96 'type' : "blob boot,dtb",
97 'required' : True,
98 }
Simon Glass76958702012-11-08 13:07:53 -080099 ],
100 'link' : [
101 {
102 'node' : 'si-all',
103 'label' : 'si-all',
104 'reg' : '%d %d' % (0x00000000, 0x00200000),
105 'type' : 'ifd',
106 'required' : True,
107 }, {
108 'node' : 'ro-boot',
109 'label' : 'boot-stub',
110 'reg' : '%d %d' % (0x00700000, 0x00100000),
111 'read-only' : True,
112 'type' : 'blob coreboot',
113 'required' : True,
114 }
Simon Glassf2534222013-03-20 15:42:02 -0700115 ],
116 'peach' : [
117 {
118 'node' : 'pre-boot',
119 'label' : "bl1 pre-boot",
120 'size' : 0x2000,
121 'read-only' : True,
122 'filename' : "e5420.nbl1.bin",
123 'type' : "blob exynos-bl1",
124 'required' : True,
125 }, {
126 'node' : 'spl',
127 'label' : "bl2 spl",
128 'size' : 0x4000,
129 'read-only' : True,
130 'filename' : "bl2.bin",
131 'type' : "blob exynos-bl2 boot,dtb",
132 'required' : True,
133 }, {
134 'node' : 'ro-boot',
135 'label' : "u-boot",
136 'size' : 0x9a000,
137 'read-only' : True,
138 'type' : "blob boot,dtb",
139 'required' : True,
140 }
141 ],
Simon Glass0c54ba52012-11-06 12:36:43 -0800142}
143
144
Simon Glass4a887b12012-10-23 16:29:03 -0700145# Build GBB flags.
146# (src/platform/vboot_reference/firmware/include/gbb_header.h)
147gbb_flag_properties = {
148 'dev-screen-short-delay': 0x00000001,
149 'load-option-roms': 0x00000002,
150 'enable-alternate-os': 0x00000004,
151 'force-dev-switch-on': 0x00000008,
152 'force-dev-boot-usb': 0x00000010,
153 'disable-fw-rollback-check': 0x00000020,
154 'enter-triggers-tonorm': 0x00000040,
155 'force-dev-boot-legacy': 0x00000080,
156}
157
Simon Glass5076a7f2012-10-23 16:31:54 -0700158def ListGoogleBinaryBlockFlags():
159 """Print out a list of GBB flags."""
160 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
161 for name, value in gbb_flag_properties.iteritems():
162 print ' %-30s %02x' % (name, value)
163
Simon Glass89b86b82011-07-17 23:49:49 -0700164class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -0700165 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -0700166
Simon Glass290a1802011-07-17 13:54:32 -0700167 Sequence of events:
168 bundle = Bundle(tools.Tools(), cros_output.Output())
169 bundle.SetDirs(...)
170 bundle.SetFiles(...)
171 bundle.SetOptions(...)
172 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -0700173 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -0700174 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -0700175
Simon Glass290a1802011-07-17 13:54:32 -0700176 Public properties:
177 fdt: The fdt object that we use for building our image. This wil be the
178 one specified by the user, except that we might add config options
179 to it. This is set up by SelectFdt() which must be called before
180 bundling starts.
181 uboot_fname: Full filename of the U-Boot binary we use.
182 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -0700183 spl_source: Source device to load U-Boot from, in SPL:
184 straps: Select device according to CPU strap pins
185 spi: Boot from SPI
186 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -0700187
188 Private attributes:
189 _small: True to create a 'small' signed U-Boot, False to produce a
190 full image. The small U-Boot is enough to boot but will not have
191 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700192 """
Simon Glass89b86b82011-07-17 23:49:49 -0700193
Simon Glass290a1802011-07-17 13:54:32 -0700194 def __init__(self, tools, output):
195 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700196
Simon Glass290a1802011-07-17 13:54:32 -0700197 Args:
198 tools: A tools.Tools object to use for external tools.
199 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700200 """
Simon Glass290a1802011-07-17 13:54:32 -0700201 self._tools = tools
202 self._out = output
203
204 # Set up the things we need to know in order to operate.
205 self._board = None # Board name, e.g. tegra2_seaboard.
206 self._fdt_fname = None # Filename of our FDT.
207 self.uboot_fname = None # Filename of our U-Boot binary.
208 self.bct_fname = None # Filename of our BCT file.
209 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800210 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700211 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -0700212 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -0700213 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
214 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass559b6612012-05-23 13:28:45 -0700215 self.spl_source = 'straps' # SPL boot according to board settings
Simon Glass07267952012-06-08 12:45:13 -0700216 self.skeleton_fname = None # Filename of Coreboot skeleton file
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800217 self.ecrw_fname = None # Filename of EC file
Simon Glassbe0bc002012-08-16 12:50:48 -0700218 self.ecro_fname = None # Filename of EC read-only file
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800219 self.blobs = {} # Table of (type, filename) of arbitrary blobs
Simon Glass23988ae2012-03-23 16:55:22 -0700220 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700221
222 def SetDirs(self, keydir):
223 """Set up directories required for Bundle.
224
225 Args:
226 keydir: Directory containing keys to use for signing firmware.
227 """
228 self._keydir = keydir
229
Simon Glass6dcc2f22011-07-28 15:26:49 +1200230 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800231 coreboot_elf=None,
Simon Glass07267952012-06-08 12:45:13 -0700232 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800233 skeleton=None, ecrw=None, ecro=None, kernel=None, blobs=None):
Simon Glass290a1802011-07-17 13:54:32 -0700234 """Set up files required for Bundle.
235
236 Args:
237 board: The name of the board to target (e.g. tegra2_seaboard).
238 uboot: The filename of the u-boot.bin image to use.
239 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800240 bmpblk: The filename of bitmap block file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800241 coreboot: The filename of the coreboot image to use (on x86).
242 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200243 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700244 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700245 exynos_bl1: The filename of the exynos BL1 file
246 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
247 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700248 ecrw: The filename of the EC (Embedded Controller) read-write file.
249 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700250 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800251 blobs: List of (type, filename) of arbitrary blobs.
Simon Glass290a1802011-07-17 13:54:32 -0700252 """
253 self._board = board
254 self.uboot_fname = uboot
255 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800256 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700257 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800258 self.coreboot_elf = coreboot_elf
Simon Glass6dcc2f22011-07-28 15:26:49 +1200259 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700260 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700261 self.exynos_bl1 = exynos_bl1
262 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700263 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700264 self.ecrw_fname = ecrw
265 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700266 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800267 self.blobs = dict(blobs or ())
Simon Glass290a1802011-07-17 13:54:32 -0700268
Simon Glass6e486c22012-10-26 15:43:42 -0700269 def SetOptions(self, small, gbb_flags, force_rw=False):
Simon Glass290a1802011-07-17 13:54:32 -0700270 """Set up options supported by Bundle.
271
272 Args:
273 small: Only create a signed U-Boot - don't produce the full packed
274 firmware image. This is useful for devs who want to replace just the
275 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700276 gbb_flags: Specification for string containing adjustments to make.
277 force_rw: Force firmware into RW mode.
Simon Glass290a1802011-07-17 13:54:32 -0700278 """
279 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700280 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700281 self._force_rw = force_rw
Simon Glass290a1802011-07-17 13:54:32 -0700282
Simon Glass22f39fb2013-02-09 13:44:14 -0800283 def _GetBuildRoot(self):
284 """Get the path to this board's 'firmware' directory.
285
286 Returns:
287 Path to firmware directory, with ## representing the path to the
288 chroot.
289 """
Simon Glass290a1802011-07-17 13:54:32 -0700290 if not self._board:
291 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800292 return os.path.join('##', 'build', self._board, 'firmware')
293
294 def _CheckFdtFilename(self, fname):
295 """Check provided FDT filename and return the correct name if needed.
296
297 Where the filename lacks a path, add a default path for this board.
298 Where no FDT filename is provided, select a default one for this board.
299
300 Args:
301 fname: Proposed FDT filename.
302
303 Returns:
304 Selected FDT filename, after validation.
305 """
306 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700307 dir_name = os.path.join(build_root, 'dts')
Simon Glass22f39fb2013-02-09 13:44:14 -0800308 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700309 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700310 base_name = re.sub('_', '-', self._board)
311
312 # In case the name exists with a prefix or suffix, find it.
313 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
314 found_list = glob.glob(self._tools.Filename(wildcard))
315 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800316 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700317 else:
318 # We didn't find anything definite, so set up our expected name.
Simon Glass22f39fb2013-02-09 13:44:14 -0800319 fname = os.path.join(dir_name, '%s.dts' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700320
Simon Glass881964d2012-04-04 11:34:09 -0700321 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800322 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700323 if not ext and not os.path.dirname(root):
Simon Glass22f39fb2013-02-09 13:44:14 -0800324 fname = os.path.join(dir_name, '%s.dts' % root)
325 return fname
326
327 def CheckOptions(self):
328 """Check provided options and select defaults."""
329 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700330
Simon Glass290a1802011-07-17 13:54:32 -0700331 if not self.uboot_fname:
332 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
333 if not self.bct_fname:
334 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700335 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700336 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700337 if not self.exynos_bl1:
338 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
339 if not self.exynos_bl2:
340 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700341 if not self.coreboot_fname:
342 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
343 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700344 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700345 if not self.seabios_fname:
346 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700347 if not self.ecrw_fname:
348 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
349 if not self.ecro_fname:
350 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700351
Simon Glass75759302012-03-15 20:26:53 -0700352 def GetFiles(self):
353 """Get a list of files that we know about.
354
355 This is the opposite of SetFiles except that we may have put in some
356 default names. It returns a dictionary containing the filename for
357 each of a number of pre-defined files.
358
359 Returns:
360 Dictionary, with one entry for each file.
361 """
362 file_list = {
363 'bct' : self.bct_fname,
364 'exynos-bl1' : self.exynos_bl1,
365 'exynos-bl2' : self.exynos_bl2,
366 }
367 return file_list
368
Simon Glass4a887b12012-10-23 16:29:03 -0700369 def DecodeGBBFlagsFromFdt(self):
370 """Get Google Binary Block flags from the FDT.
371
372 These should be in the chromeos-config node, like this:
373
374 chromeos-config {
375 gbb-flag-dev-screen-short-delay;
376 gbb-flag-force-dev-switch-on;
377 gbb-flag-force-dev-boot-usb;
378 gbb-flag-disable-fw-rollback-check;
379 };
380
381 Returns:
382 GBB flags value from FDT.
383 """
384 chromeos_config = self.fdt.GetProps("/chromeos-config")
385 gbb_flags = 0
386 for name in chromeos_config:
387 if name.startswith('gbb-flag-'):
388 flag_value = gbb_flag_properties.get(name[9:])
389 if flag_value:
390 gbb_flags |= flag_value
391 self._out.Notice("FDT: Enabling %s." % name)
392 else:
393 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
394 return gbb_flags
395
Simon Glass157c0662012-10-23 13:52:42 -0700396 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
397 """Decode ajustments to the provided GBB flags.
398
399 We support three options:
400
401 hex value: c2
402 defined value: force-dev-boot-usb,load-option-roms
403 adjust default value: -load-option-roms,+force-dev-boot-usb
404
405 The last option starts from the passed-in GBB flags and adds or removes
406 flags.
407
408 Args:
409 gbb_flags: Base (default) FDT flags.
410 adjustments: String containing adjustments to make.
411
412 Returns:
413 Updated FDT flags.
414 """
415 use_base_value = True
416 if adjustments:
417 try:
418 return int(adjustments, base=16)
419 except:
420 pass
421 for flag in adjustments.split(','):
422 oper = None
423 if flag[0] in ['-', '+']:
424 oper = flag[0]
425 flag = flag[1:]
426 value = gbb_flag_properties.get(flag)
427 if not value:
428 raise ValueError("Invalid GBB flag '%s'" % flag)
429 if oper == '+':
430 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800431 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700432 elif oper == '-':
433 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800434 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700435 else:
436 if use_base_value:
437 gbb_flags = 0
438 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800439 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700440 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800441 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700442
443 return gbb_flags
444
Simon Glass56577572011-07-19 11:08:06 +1200445 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700446 """Create a GBB for the image.
447
Simon Glass56577572011-07-19 11:08:06 +1200448 Args:
449 hardware_id: Hardware ID to use for this board. If None, then the
450 default from the Fdt will be used
451
Simon Glass89b86b82011-07-17 23:49:49 -0700452 Returns:
453 Path of the created GBB file.
454
455 Raises:
456 CmdError if a command fails.
457 """
Simon Glass56577572011-07-19 11:08:06 +1200458 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800459 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700460 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700461 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700462
Simon Glass4a887b12012-10-23 16:29:03 -0700463 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800464
Simon Glass157c0662012-10-23 13:52:42 -0700465 # Allow command line to override flags
466 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
467
Simon Glass4a887b12012-10-23 16:29:03 -0700468 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700469 self._out.Progress('Creating GBB')
470 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
471 sizes = ['%#x' % size for size in sizes]
472 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700473 keydir = self._tools.Filename(self._keydir)
474 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700475 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200476 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700477 '--rootkey=%s/root_key.vbpubk' % keydir,
478 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700479 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800480 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700481 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700482 cwd=odir)
483 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700484
Simon Glasse13ee2c2011-07-28 08:12:28 +1200485 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700486 """Sign an image so that the Tegra SOC will boot it.
487
488 Args:
489 bct: BCT file to use.
490 bootstub: Boot stub (U-Boot + fdt) file to sign.
491 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700492
493 Returns:
494 filename of signed image.
495
496 Raises:
497 CmdError if a command fails.
498 """
499 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200500 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700501 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200502 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700503 fd = open(config, 'w')
504 fd.write('Version = 1;\n')
505 fd.write('Redundancy = 1;\n')
506 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700507
508 # TODO(dianders): Right now, we don't have enough space in our flash map
509 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
510 # sure what this does for reliability, but at least things will fit...
511 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
512 if is_nand:
513 fd.write('Bctcopy = 1;\n')
514
Simon Glass89b86b82011-07-17 23:49:49 -0700515 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
516 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700517
Simon Glass89b86b82011-07-17 23:49:49 -0700518 fd.close()
519
520 self._tools.Run('cbootimage', [config, signed])
521 self._tools.OutputSize('BCT', bct)
522 self._tools.OutputSize('Signed image', signed)
523 return signed
524
Doug Anderson86ce5f42011-07-27 10:40:18 -0700525 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700526 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700527
528 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700529 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700530 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700531 """
Simon Glass468d8752012-09-19 16:36:19 -0700532 if bootcmd is not None:
533 if bootcmd == 'none':
534 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800535 self.fdt.PutString('/config', 'bootcmd', bootcmd)
536 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700537 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700538
Simon Glassa4934b72012-05-09 13:35:02 -0700539 def SetNodeEnabled(self, node_name, enabled):
540 """Set whether an node is enabled or disabled.
541
542 This simply sets the 'status' property of a node to "ok", or "disabled".
543
544 The node should either be a full path to the node (like '/uart@10200000')
545 or an alias property.
546
547 Aliases are supported like this:
548
549 aliases {
550 console = "/uart@10200000";
551 };
552
553 pointing to a node:
554
555 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700556 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700557 };
558
559 In this case, this function takes the name of the alias ('console' in
560 this case) and updates the status of the node that is pointed to, to
561 either ok or disabled. If the alias does not exist, a warning is
562 displayed.
563
564 Args:
565 node_name: Name of node (e.g. '/uart@10200000') or alias alias
566 (e.g. 'console') to adjust
567 enabled: True to enable, False to disable
568 """
569 # Look up the alias if this is an alias reference
570 if not node_name.startswith('/'):
571 lookup = self.fdt.GetString('/aliases', node_name, '')
572 if not lookup:
573 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
574 return
575 node_name = lookup
576 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700577 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700578 else:
579 status = 'disabled'
580 self.fdt.PutString(node_name, 'status', status)
581
582 def AddEnableList(self, enable_list):
583 """Process a list of nodes to enable/disable.
584
585 Args:
586 config_list: List of (node, value) tuples to add to the fdt. For each
587 tuple:
588 node: The fdt node to write to will be <node> or pointed to by
589 /aliases/<node>. We can tell which
590 value: 0 to disable the node, 1 to enable it
591 """
592 if enable_list:
593 for node_name, enabled in enable_list:
594 try:
595 enabled = int(enabled)
596 if enabled not in (0, 1):
597 raise ValueError
598 except ValueError as str:
599 raise CmdError("Invalid enable option value '%s' "
600 "(should be 0 or 1)" % enabled)
601 self.SetNodeEnabled(node_name, enabled)
602
Simon Glass290a1802011-07-17 13:54:32 -0700603 def AddConfigList(self, config_list, use_int=False):
604 """Add a list of config items to the fdt.
605
606 Normally these values are written to the fdt as strings, but integers
607 are also supported, in which case the values will be converted to integers
608 (if necessary) before being stored.
609
610 Args:
611 config_list: List of (config, value) tuples to add to the fdt. For each
612 tuple:
613 config: The fdt node to write to will be /config/<config>.
614 value: An integer or string value to write.
615 use_int: True to only write integer values.
616
617 Raises:
618 CmdError: if a value is required to be converted to integer but can't be.
619 """
620 if config_list:
621 for config in config_list:
622 value = config[1]
623 if use_int:
624 try:
625 value = int(value)
626 except ValueError as str:
627 raise CmdError("Cannot convert config option '%s' to integer" %
628 value)
629 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800630 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700631 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800632 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700633
Simon Glass7c2d5572011-11-15 14:47:08 -0800634 def DecodeTextBase(self, data):
635 """Look at a U-Boot image and try to decode its TEXT_BASE.
636
637 This works because U-Boot has a header with the value 0x12345678
638 immediately followed by the TEXT_BASE value. We can therefore read this
639 from the image with some certainty. We check only the first 40 words
640 since the header should be within that region.
641
Simon Glass96b50302012-07-20 06:55:28 +0100642 Since upstream Tegra has moved to having a 16KB SPL region at the start,
643 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
644 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
645
Simon Glass7c2d5572011-11-15 14:47:08 -0800646 Args:
647 data: U-Boot binary data
648
649 Returns:
650 Text base (integer) or None if none was found
651 """
652 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100653 for start in (0, 0x4000):
654 for i in range(start, start + 160, 4):
655 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800656
Simon Glass96b50302012-07-20 06:55:28 +0100657 # TODO(sjg): This does not cope with a big-endian target
658 value = struct.unpack('<I', word)[0]
659 if found:
660 return value - start
661 if value == 0x12345678:
662 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800663
664 return None
665
666 def CalcTextBase(self, name, fdt, fname):
667 """Calculate the TEXT_BASE to use for U-Boot.
668
669 Normally this value is in the fdt, so we just read it from there. But as
670 a second check we look at the image itself in case this is different, and
671 switch to that if it is.
672
673 This allows us to flash any U-Boot even if its TEXT_BASE is different.
674 This is particularly useful with upstream U-Boot which uses a different
675 value (which we will move to).
676 """
677 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800678 # The value that comes back from fdt.GetInt is signed, which makes no
679 # sense for an address base. Force it to unsigned.
680 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800681 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100682 text_base_str = '%#x' % text_base if text_base else 'None'
683 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
684 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800685
686 # If they are different, issue a warning and switch over.
687 if text_base and text_base != fdt_text_base:
688 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
689 "fdt value of %x. Using %x" % (text_base, name,
690 fdt_text_base, text_base))
691 fdt_text_base = text_base
692 return fdt_text_base
693
Simon Glass6dcc2f22011-07-28 15:26:49 +1200694 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700695 """Create a boot stub and a signed boot stub.
696
Simon Glass6dcc2f22011-07-28 15:26:49 +1200697 For postload:
698 We add a /config/postload-text-offset entry to the signed bootstub's
699 fdt so that U-Boot can find the postload code.
700
701 The raw (unsigned) bootstub will have a value of -1 for this since we will
702 simply append the postload code to the bootstub and it can find it there.
703 This will be used for RW A/B firmware.
704
705 For the signed case this value will specify where in the flash to find
706 the postload code. This will be used for RO firmware.
707
Simon Glass89b86b82011-07-17 23:49:49 -0700708 Args:
709 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800710 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200711 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700712
713 Returns:
714 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200715 Full path to bootstub (uboot + fdt(-1) + postload).
716 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700717
718 Raises:
719 CmdError if a command fails.
720 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200721 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800722 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700723 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200724
725 # Make a copy of the fdt for the bootstub
726 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800727 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700728 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200729
Simon Glass89b86b82011-07-17 23:49:49 -0700730 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700731 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
732 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700733 self._tools.OutputSize('Combined binary', bootstub)
734
Simon Glasse13ee2c2011-07-28 08:12:28 +1200735 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700736 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700737 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200738 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200739
740 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
741 data = self._tools.ReadFile(signed)
742
743 if postload:
744 # We must add postload to the bootstub since A and B will need to
745 # be able to find it without the /config/postload-text-offset mechanism.
746 bs_data = self._tools.ReadFile(bootstub)
747 bs_data += self._tools.ReadFile(postload)
748 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
749 self._tools.WriteFile(bootstub, bs_data)
750 self._tools.OutputSize('Combined binary with postload', bootstub)
751
752 # Now that we know the file size, adjust the fdt and re-sign
753 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800754 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200755 fdt_data = self._tools.ReadFile(fdt.fname)
756 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
757 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
758 postload_bootstub, text_base)
759 if len(data) != os.path.getsize(signed):
760 raise CmdError('Signed file size changed from %d to %d after updating '
761 'fdt' % (len(data), os.path.getsize(signed)))
762
763 # Re-read the signed image, and add the post-load binary.
764 data = self._tools.ReadFile(signed)
765 data += self._tools.ReadFile(postload)
766 self._tools.OutputSize('Post-load binary', postload)
767
768 self._tools.WriteFile(signed_postload, data)
769 self._tools.OutputSize('Final bootstub with postload', signed_postload)
770
771 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700772
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700773 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700774 """Create a coreboot boot stub.
775
776 Args:
777 uboot: Path to u-boot.bin (may be chroot-relative)
778 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700779 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700780
781 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100782 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700783
784 Raises:
785 CmdError if a command fails.
786 """
787 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700788 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100789
790 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700791 return bootstub
792
Simon Glass3b404092012-05-23 13:10:36 -0700793 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700794 """Update the parameters in a BL2 blob.
795
796 We look at the list in the parameter block, extract the value of each
797 from the device tree, and write that value to the parameter block.
798
799 Args:
800 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700801 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700802 data: The BL2 data.
803 pos: The position of the start of the parameter block.
804
805 Returns:
806 The new contents of the parameter block, after updating.
807 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700808 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
809 if version != 1:
810 raise CmdError("Cannot update machine parameter block version '%d'" %
811 version)
812 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700813 raise CmdError("Machine parameter block size %d is invalid: "
814 "pos=%d, size=%d, space=%d, len=%d" %
815 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700816
817 # Move past the header and read the parameter list, which is terminated
818 # with \0.
819 pos += 12
820 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
821 param_len = param_list.find('\0')
822 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700823 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700824
825 # Work through the parameters one at a time, adding each value
826 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700827 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700828 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700829 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glass56583742012-11-06 12:34:47 -0800830
831 # Use this to detect a missing value from the fdt.
832 not_given = 'not-given-invalid-value'
Simon Glassdf95dd22012-03-13 15:46:16 -0700833 if param == 'm' :
Simon Glass56583742012-11-06 12:34:47 -0800834 mem_type = fdt.GetString('/dmc', 'mem-type', not_given)
835 if mem_type == not_given:
836 mem_type = 'ddr3'
837 self._out.Warning("No value for memory type: using '%s'" % mem_type)
Simon Glassdf95dd22012-03-13 15:46:16 -0700838 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
839 if not mem_type in mem_types:
840 raise CmdError("Unknown memory type '%s'" % mem_type)
841 value = mem_types.index(mem_type)
842 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700843 elif param == 'M' :
Simon Glass56583742012-11-06 12:34:47 -0800844 mem_manuf = fdt.GetString('/dmc', 'mem-manuf', not_given)
845 if mem_manuf == not_given:
846 mem_manuf = 'samsung'
847 self._out.Warning("No value for memory manufacturer: using '%s'" %
848 mem_manuf)
Doug Andersonee46cfe2012-05-18 09:53:08 -0700849 mem_manufs = ['autodetect', 'elpida', 'samsung']
850 if not mem_manuf in mem_manufs:
851 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
852 value = mem_manufs.index(mem_manuf)
853 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700854 elif param == 'f' :
Simon Glass56583742012-11-06 12:34:47 -0800855 mem_freq = fdt.GetInt('/dmc', 'clock-frequency', -1)
856 if mem_freq == -1:
857 mem_freq = 800000000
858 self._out.Warning("No value for memory frequency: using '%s'" %
859 mem_freq)
860 mem_freq /= 1000000
Simon Glass158289e2012-09-14 11:42:25 -0700861 if not mem_freq in [533, 667, 800]:
862 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
863 value = mem_freq
864 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700865 elif param == 'v':
866 value = 31
867 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700868 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700869 value = (spl_load_size + 0xfff) & ~0xfff
870 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
871 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700872 elif param == 'b':
873 # These values come from enum boot_mode in U-Boot's cpu.h
874 if self.spl_source == 'straps':
875 value = 32
876 elif self.spl_source == 'emmc':
877 value = 4
878 elif self.spl_source == 'spi':
879 value = 20
880 elif self.spl_source == 'usb':
881 value = 33
882 else:
883 raise CmdError("Invalid boot source '%s'" % self.spl_source)
884 self._out.Info(' Boot source: %#0x' % value)
Tom Wai-Hong Tam99b7f112013-02-06 09:10:10 +0800885 elif param == 'z':
886 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
887 compress_types = ['none', 'lzo']
888 if not compress in compress_types:
889 raise CmdError("Unknown compression type '%s'" % compress)
890 value = compress_types.index(compress)
891 self._out.Info(' Compression type: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700892 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700893 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700894 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700895 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700896 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700897
898 # Put the data into our block.
899 data = data[:pos] + new_data + data[pos + len(new_data):]
900 self._out.Info('BL2 configuration complete')
901 return data
902
Simon Glasse5e8afb2012-05-23 11:19:23 -0700903 def _UpdateChecksum(self, data):
904 """Update the BL2 checksum.
905
906 The checksum is a 4 byte sum of all the bytes in the image before the
907 last 4 bytes (which hold the checksum).
908
909 Args:
910 data: The BL2 data to update.
911
912 Returns:
913 The new contents of the BL2 data, after updating the checksum.
914 """
915 checksum = 0
916 for ch in data[:-4]:
917 checksum += ord(ch)
918 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
919
Simon Glass559b6612012-05-23 13:28:45 -0700920 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700921 """Configure an Exynos BL2 binary for our needs.
922
923 We create a new modified BL2 and return its filename.
924
925 Args:
926 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700927 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700928 orig_bl2: Filename of original BL2 file to modify.
929 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700930 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700931 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700932 data = self._tools.ReadFile(orig_bl2)
933 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700934
935 # Locate the parameter block
936 data = self._tools.ReadFile(bl2)
937 marker = struct.pack('<L', 0xdeadbeef)
938 pos = data.rfind(marker)
939 if not pos:
940 raise CmdError("Could not find machine parameter block in '%s'" %
941 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700942 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700943 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700944 self._tools.WriteFile(bl2, data)
945 return bl2
946
Simon Glass89b86b82011-07-17 23:49:49 -0700947 def _PackOutput(self, msg):
948 """Helper function to write output from PackFirmware (verbose level 2).
949
950 This is passed to PackFirmware for it to use to write output.
951
952 Args:
953 msg: Message to display.
954 """
955 self._out.Notice(msg)
956
Simon Glass439fe7a2012-03-09 16:19:34 -0800957 def _BuildBlob(self, pack, fdt, blob_type):
958 """Build the blob data for a particular blob type.
959
960 Args:
961 blob_type: The type of blob to create data for. Supported types are:
962 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
963 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
964 """
965 if blob_type == 'coreboot':
966 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700967 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800968 pack.AddProperty('coreboot', coreboot)
969 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700970 elif blob_type == 'legacy':
971 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800972 elif blob_type == 'signed':
973 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
974 self.postload_fname)
975 pack.AddProperty('bootstub', bootstub)
976 pack.AddProperty('signed', signed)
977 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700978 elif blob_type == 'exynos-bl1':
979 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700980
981 # TODO(sjg@chromium.org): Deprecate ecbin
982 elif blob_type in ['ecrw', 'ecbin']:
983 pack.AddProperty('ecrw', self.ecrw_fname)
984 pack.AddProperty('ecbin', self.ecrw_fname)
Gabe Blackcdbdfe12013-02-06 05:37:52 -0800985 elif blob_type == 'ecrwhash':
986 ec_hash_file = os.path.join(self._tools.outdir, 'ec_hash.bin')
987 ecrw = self._tools.ReadFile(self.ecrw_fname)
988 hasher = hashlib.sha256()
989 hasher.update(ecrw)
990 self._tools.WriteFile(ec_hash_file, hasher.digest())
991 pack.AddProperty(blob_type, ec_hash_file)
Simon Glassbe0bc002012-08-16 12:50:48 -0700992 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700993 # crosbug.com/p/13143
994 # We cannot have an fmap in the EC image since there can be only one,
995 # which is the main fmap describing the whole image.
996 # Ultimately the EC will not have an fmap, since with software sync
997 # there is no flashrom involvement in updating the EC flash, and thus
998 # no need for the fmap.
999 # For now, mangle the fmap name to avoid problems.
1000 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
1001 data = self._tools.ReadFile(self.ecro_fname)
1002 data = re.sub('__FMAP__', '__fMAP__', data)
1003 self._tools.WriteFile(updated_ecro, data)
1004 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -07001005 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -07001006 spl_payload = pack.GetBlobParams(blob_type)
1007
1008 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
1009 # from all flash map files.
1010 if not spl_payload:
1011 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
1012 prop_list = 'boot+dtb'
1013
1014 # Do this later, when we remove boot+dtb.
1015 # raise CmdError("No parameters provided for blob type '%s'" %
1016 # blob_type)
1017 else:
1018 prop_list = spl_payload[0].split(',')
Tom Wai-Hong Tam26e3a4c2013-02-06 09:36:47 +08001019 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
1020 if compress == 'none':
1021 compress = None
1022 spl_load_size = len(pack.ConcatPropContents(prop_list, compress,
1023 False)[0])
Simon Glass7d2542f2012-06-21 07:10:59 -07001024 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
1025 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -07001026 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -07001027 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -08001028 elif pack.GetProperty(blob_type):
1029 pass
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -08001030 elif blob_type in self.blobs:
1031 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -08001032 else:
1033 raise CmdError("Unknown blob type '%s' required in flash map" %
1034 blob_type)
1035
Simon Glass290a1802011-07-17 13:54:32 -07001036 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -07001037 """Create a full firmware image, along with various by-products.
1038
1039 This uses the provided u-boot.bin, fdt and bct to create a firmware
1040 image containing all the required parts. If the GBB is not supplied
1041 then this will just return a signed U-Boot as the image.
1042
1043 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +12001044 gbb: Full path to the GBB file, or empty if a GBB is not required.
1045 fdt: Fdt object containing required information.
1046
1047 Returns:
1048 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -07001049
1050 Raises:
1051 CmdError if a command fails.
1052 """
Simon Glass02d124a2012-03-02 14:47:20 -08001053 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -07001054
Simon Glass439fe7a2012-03-09 16:19:34 -08001055 # Get the flashmap so we know what to build
1056 pack = PackFirmware(self._tools, self._out)
Simon Glass0c54ba52012-11-06 12:36:43 -08001057 default_flashmap = default_flashmaps.get(self._board)
Simon Glassb8c6d952012-12-01 06:14:35 -08001058 if self._force_rw:
1059 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
1060 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
1061
Simon Glass0c54ba52012-11-06 12:36:43 -08001062 pack.SelectFdt(fdt, self._board, default_flashmap)
Simon Glass439fe7a2012-03-09 16:19:34 -08001063
1064 # Get all our blobs ready
1065 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -08001066 if self.skeleton_fname:
1067 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -07001068 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -07001069
Simon Glass47817052012-10-20 13:30:07 -07001070 # Let's create some copies of the fdt for vboot. These can be used to
1071 # pass a different fdt to each firmware type. For now it is just used to
1072 # check that the right fdt comes through.
1073 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
1074 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
1075 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
1076 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
1077 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
1078 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
1079 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
1080
Simon Glassde9c8072012-07-02 22:29:02 -07001081 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
1082 if self.kernel_fname:
1083 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
1084
Simon Glass439fe7a2012-03-09 16:19:34 -08001085 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +01001086 blob_list = pack.GetBlobList()
1087 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -07001088 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -08001089 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -07001090
Simon Glass7306b902012-12-17 15:06:21 -08001091 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -07001092 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -07001093 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +08001094 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -08001095 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +08001096 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -07001097 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -08001098 pack.AddProperty('fwid', fwid)
1099 pack.AddProperty('gbb', gbb)
1100 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -07001101
1102 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -07001103
1104 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -08001105 pack.UpdateBlobPositionsAndHashes(fdt)
1106 pack.UpdateBlobPositionsAndHashes(fdt_rwa)
1107 pack.UpdateBlobPositionsAndHashes(fdt_rwb)
Simon Glass8884b982012-06-21 12:41:41 -07001108
Simon Glass6207efe2012-12-17 15:04:36 -08001109 # Make a copy of the fdt for the bootstub
1110 fdt_data = self._tools.ReadFile(fdt.fname)
1111 uboot_data = self._tools.ReadFile(self.uboot_fname)
1112 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
1113 self._tools.WriteFile(uboot_copy, uboot_data)
1114
1115 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
1116 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
1117
Simon Glassa10282a2013-01-08 17:06:41 -08001118 # Fix up the coreboot image here, since we can't do this until we have
1119 # a final device tree binary.
Simon Glasscbc83552012-07-23 15:26:22 +01001120 if 'coreboot' in blob_list:
1121 bootstub = pack.GetProperty('coreboot')
1122 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -08001123 if self.coreboot_elf:
1124 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
1125 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
1126 else:
1127 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
1128 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
1129 '-l', '0x1110000', '-e', '0x1110008'])
Stefan Reinauer1502ea62012-11-01 10:15:38 -07001130 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
1131 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -08001132 data = self._tools.ReadFile(bootstub)
1133 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
1134 self._tools.WriteFile(bootstub_copy, data)
Gabe Black3df75252013-02-14 21:32:10 -08001135 self._tools.WriteFile(bootstub, data[-0x100000:])
Simon Glasscbc83552012-07-23 15:26:22 +01001136
Simon Glass208ad952013-02-10 11:16:46 -08001137 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -07001138 image = os.path.join(self._tools.outdir, 'image.bin')
1139 pack.PackImage(self._tools.outdir, image)
1140 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -07001141
Simon Glass439fe7a2012-03-09 16:19:34 -08001142 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -07001143 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001144 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001145
Simon Glassdedda6f2013-02-09 13:44:14 -08001146 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -07001147 """Select an FDT to control the firmware bundling
1148
Simon Glassdedda6f2013-02-09 13:44:14 -08001149 We make a copy of this which will include any on-the-fly changes we want
1150 to make.
1151
Simon Glass290a1802011-07-17 13:54:32 -07001152 Args:
1153 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -08001154 use_defaults: True to use a default FDT name if available, and to add
1155 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -07001156
Simon Glassc0f3dc62011-08-09 14:19:05 -07001157 Returns:
1158 The Fdt object of the original fdt file, which we will not modify.
1159
Simon Glassdedda6f2013-02-09 13:44:14 -08001160 Raises:
1161 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
1162 False).
Simon Glass290a1802011-07-17 13:54:32 -07001163 """
Simon Glassdedda6f2013-02-09 13:44:14 -08001164 if use_defaults:
1165 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -08001166 if not fdt_fname:
1167 raise ValueError('Please provide an FDT filename')
1168 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -07001169 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -08001170
1171 # For upstream, select the correct architecture .dtsi manually.
1172 if self._board == 'link' or 'x86' in self._board:
1173 arch_dts = 'coreboot.dtsi'
1174 elif self._board == 'daisy':
1175 arch_dts = 'exynos5250.dtsi'
1176 else:
1177 arch_dts = 'tegra20.dtsi'
1178
1179 fdt.Compile(arch_dts)
Simon Glass290a1802011-07-17 13:54:32 -07001180 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -07001181 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001182
Simon Glassc90cf582012-03-13 15:40:47 -07001183 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001184 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001185
1186 - Checks options, tools, output directory, fdt.
1187 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001188
1189 Args:
Simon Glass56577572011-07-19 11:08:06 +12001190 hardware_id: Hardware ID to use for this board. If None, then the
1191 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001192 output_fname: Output filename for the image. If this is not None, then
1193 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001194 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001195
1196 Returns:
1197 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001198 """
Simon Glass89b86b82011-07-17 23:49:49 -07001199 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -07001200 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +12001201 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001202
1203 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001204 image, pack = self._CreateImage(gbb, self.fdt)
1205 if show_map:
1206 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001207 if output_fname:
1208 shutil.copyfile(image, output_fname)
1209 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001210 return image, pack.props