blob: 61df9efb0c1be742837d3b058733e1dd6e8860ed [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
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
Simon Glass439fe7a2012-03-09 16:19:34 -080028from tools import CmdError
Simon Glass89b86b82011-07-17 23:49:49 -070029
30# This data is required by bmpblk_utility. Does it ever change?
31# It was stored with the chromeos-bootimage ebuild, but we want
32# this utility to work outside the chroot.
33yaml_data = '''
34bmpblock: 1.0
35
36images:
37 devmode: DeveloperBmp/DeveloperBmp.bmp
38 recovery: RecoveryBmp/RecoveryBmp.bmp
39 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
40 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
41
42screens:
43 dev_en:
44 - [0, 0, devmode]
45 rec_en:
46 - [0, 0, recovery]
47 yuck_en:
48 - [0, 0, rec_yuck]
49 ins_en:
50 - [0, 0, rec_insert]
51
52localizations:
53 - [ dev_en, rec_en, yuck_en, ins_en ]
54'''
55
Simon Glass0c54ba52012-11-06 12:36:43 -080056# Default flash maps for various boards we support.
57# These are used when no fdt is provided (e.g. upstream U-Boot with no
58# fdt. Each is a list of nodes.
59default_flashmaps = {
Simon Glass76958702012-11-08 13:07:53 -080060 'tegra' : [
61 {
Simon Glass0c54ba52012-11-06 12:36:43 -080062 'node' : 'ro-boot',
63 'label' : 'boot-stub',
64 'size' : 512 << 10,
65 'read-only' : True,
66 'type' : 'blob signed',
67 'required' : True
68 }
69 ],
70 'daisy' : [
71 {
72 'node' : 'pre-boot',
73 'label' : "bl1 pre-boot",
74 'size' : 0x2000,
75 'read-only' : True,
76 'filename' : "e5250.nbl1.bin",
77 'type' : "blob exynos-bl1",
78 'required' : True,
79 }, {
80 'node' : 'spl',
81 'label' : "bl2 spl",
82 'size' : 0x4000,
83 'read-only' : True,
84 'filename' : "bl2.bin",
85 'type' : "blob exynos-bl2 boot,dtb",
86 'required' : True,
87 }, {
88 'node' : 'ro-boot',
89 'label' : "u-boot",
90 'size' : 0x9a000,
91 'read-only' : True,
92 'type' : "blob boot,dtb",
93 'required' : True,
94 }
Simon Glass76958702012-11-08 13:07:53 -080095 ],
96 'link' : [
97 {
98 'node' : 'si-all',
99 'label' : 'si-all',
100 'reg' : '%d %d' % (0x00000000, 0x00200000),
101 'type' : 'ifd',
102 'required' : True,
103 }, {
104 'node' : 'ro-boot',
105 'label' : 'boot-stub',
106 'reg' : '%d %d' % (0x00700000, 0x00100000),
107 'read-only' : True,
108 'type' : 'blob coreboot',
109 'required' : True,
110 }
Simon Glassf2534222013-03-20 15:42:02 -0700111 ],
112 'peach' : [
113 {
114 'node' : 'pre-boot',
115 'label' : "bl1 pre-boot",
116 'size' : 0x2000,
117 'read-only' : True,
118 'filename' : "e5420.nbl1.bin",
119 'type' : "blob exynos-bl1",
120 'required' : True,
121 }, {
122 'node' : 'spl',
123 'label' : "bl2 spl",
124 'size' : 0x4000,
125 'read-only' : True,
126 'filename' : "bl2.bin",
127 'type' : "blob exynos-bl2 boot,dtb",
128 'required' : True,
129 }, {
130 'node' : 'ro-boot',
131 'label' : "u-boot",
132 'size' : 0x9a000,
133 'read-only' : True,
134 'type' : "blob boot,dtb",
135 'required' : True,
136 }
137 ],
Simon Glass0c54ba52012-11-06 12:36:43 -0800138}
139
140
Simon Glass4a887b12012-10-23 16:29:03 -0700141# Build GBB flags.
142# (src/platform/vboot_reference/firmware/include/gbb_header.h)
143gbb_flag_properties = {
144 'dev-screen-short-delay': 0x00000001,
145 'load-option-roms': 0x00000002,
146 'enable-alternate-os': 0x00000004,
147 'force-dev-switch-on': 0x00000008,
148 'force-dev-boot-usb': 0x00000010,
149 'disable-fw-rollback-check': 0x00000020,
150 'enter-triggers-tonorm': 0x00000040,
151 'force-dev-boot-legacy': 0x00000080,
152}
153
Simon Glass5076a7f2012-10-23 16:31:54 -0700154def ListGoogleBinaryBlockFlags():
155 """Print out a list of GBB flags."""
156 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
157 for name, value in gbb_flag_properties.iteritems():
158 print ' %-30s %02x' % (name, value)
159
Simon Glass89b86b82011-07-17 23:49:49 -0700160class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -0700161 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -0700162
Simon Glass290a1802011-07-17 13:54:32 -0700163 Sequence of events:
164 bundle = Bundle(tools.Tools(), cros_output.Output())
165 bundle.SetDirs(...)
166 bundle.SetFiles(...)
167 bundle.SetOptions(...)
168 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -0700169 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -0700170 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -0700171
Simon Glass290a1802011-07-17 13:54:32 -0700172 Public properties:
173 fdt: The fdt object that we use for building our image. This wil be the
174 one specified by the user, except that we might add config options
175 to it. This is set up by SelectFdt() which must be called before
176 bundling starts.
177 uboot_fname: Full filename of the U-Boot binary we use.
178 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -0700179 spl_source: Source device to load U-Boot from, in SPL:
180 straps: Select device according to CPU strap pins
181 spi: Boot from SPI
182 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -0700183
184 Private attributes:
185 _small: True to create a 'small' signed U-Boot, False to produce a
186 full image. The small U-Boot is enough to boot but will not have
187 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700188 """
Simon Glass89b86b82011-07-17 23:49:49 -0700189
Simon Glass290a1802011-07-17 13:54:32 -0700190 def __init__(self, tools, output):
191 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700192
Simon Glass290a1802011-07-17 13:54:32 -0700193 Args:
194 tools: A tools.Tools object to use for external tools.
195 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700196 """
Simon Glass290a1802011-07-17 13:54:32 -0700197 self._tools = tools
198 self._out = output
199
200 # Set up the things we need to know in order to operate.
201 self._board = None # Board name, e.g. tegra2_seaboard.
202 self._fdt_fname = None # Filename of our FDT.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700203 self._force_rw = None
204 self._gbb_flags = None
205 self._keydir = None
206 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700207 self.bct_fname = None # Filename of our BCT file.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700208 self.blobs = {} # Table of (type, filename) of arbitrary blobs
Hung-Te Lin5b649382011-08-03 15:01:16 +0800209 self.bmpblk_fname = None # Filename of our Bitmap Block
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700210 self.coreboot_elf = None
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700211 self.coreboot_fname = None # Filename of our coreboot binary.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700212 self.ecro_fname = None # Filename of EC read-only file
213 self.ecrw_fname = None # Filename of EC file
Simon Glass7e199222012-03-13 15:51:18 -0700214 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
215 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700216 self.fdt = None # Our Fdt object.
217 self.kernel_fname = None
218 self.postload_fname = None
219 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass07267952012-06-08 12:45:13 -0700220 self.skeleton_fname = None # Filename of Coreboot skeleton file
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700221 self.spl_source = 'straps' # SPL boot according to board settings
222 self.uboot_fname = None # Filename of our U-Boot binary.
Simon Glass290a1802011-07-17 13:54:32 -0700223
224 def SetDirs(self, keydir):
225 """Set up directories required for Bundle.
226
227 Args:
228 keydir: Directory containing keys to use for signing firmware.
229 """
230 self._keydir = keydir
231
Simon Glass6dcc2f22011-07-28 15:26:49 +1200232 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800233 coreboot_elf=None,
Simon Glass07267952012-06-08 12:45:13 -0700234 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800235 skeleton=None, ecrw=None, ecro=None, kernel=None, blobs=None):
Simon Glass290a1802011-07-17 13:54:32 -0700236 """Set up files required for Bundle.
237
238 Args:
239 board: The name of the board to target (e.g. tegra2_seaboard).
240 uboot: The filename of the u-boot.bin image to use.
241 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800242 bmpblk: The filename of bitmap block file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800243 coreboot: The filename of the coreboot image to use (on x86).
244 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200245 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700246 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700247 exynos_bl1: The filename of the exynos BL1 file
248 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
249 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700250 ecrw: The filename of the EC (Embedded Controller) read-write file.
251 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700252 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800253 blobs: List of (type, filename) of arbitrary blobs.
Simon Glass290a1802011-07-17 13:54:32 -0700254 """
255 self._board = board
256 self.uboot_fname = uboot
257 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800258 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700259 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800260 self.coreboot_elf = coreboot_elf
Simon Glass6dcc2f22011-07-28 15:26:49 +1200261 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700262 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700263 self.exynos_bl1 = exynos_bl1
264 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700265 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700266 self.ecrw_fname = ecrw
267 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700268 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800269 self.blobs = dict(blobs or ())
Simon Glass290a1802011-07-17 13:54:32 -0700270
Simon Glass6e486c22012-10-26 15:43:42 -0700271 def SetOptions(self, small, gbb_flags, force_rw=False):
Simon Glass290a1802011-07-17 13:54:32 -0700272 """Set up options supported by Bundle.
273
274 Args:
275 small: Only create a signed U-Boot - don't produce the full packed
276 firmware image. This is useful for devs who want to replace just the
277 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700278 gbb_flags: Specification for string containing adjustments to make.
279 force_rw: Force firmware into RW mode.
Simon Glass290a1802011-07-17 13:54:32 -0700280 """
281 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700282 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700283 self._force_rw = force_rw
Simon Glass290a1802011-07-17 13:54:32 -0700284
Simon Glass22f39fb2013-02-09 13:44:14 -0800285 def _GetBuildRoot(self):
286 """Get the path to this board's 'firmware' directory.
287
288 Returns:
289 Path to firmware directory, with ## representing the path to the
290 chroot.
291 """
Simon Glass290a1802011-07-17 13:54:32 -0700292 if not self._board:
293 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800294 return os.path.join('##', 'build', self._board, 'firmware')
295
296 def _CheckFdtFilename(self, fname):
297 """Check provided FDT filename and return the correct name if needed.
298
299 Where the filename lacks a path, add a default path for this board.
300 Where no FDT filename is provided, select a default one for this board.
301
302 Args:
303 fname: Proposed FDT filename.
304
305 Returns:
306 Selected FDT filename, after validation.
307 """
308 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700309 dir_name = os.path.join(build_root, 'dts')
Simon Glass22f39fb2013-02-09 13:44:14 -0800310 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700311 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700312 base_name = re.sub('_', '-', self._board)
313
314 # In case the name exists with a prefix or suffix, find it.
315 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
316 found_list = glob.glob(self._tools.Filename(wildcard))
317 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800318 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700319 else:
320 # We didn't find anything definite, so set up our expected name.
Simon Glass22f39fb2013-02-09 13:44:14 -0800321 fname = os.path.join(dir_name, '%s.dts' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700322
Simon Glass881964d2012-04-04 11:34:09 -0700323 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800324 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700325 if not ext and not os.path.dirname(root):
Simon Glass22f39fb2013-02-09 13:44:14 -0800326 fname = os.path.join(dir_name, '%s.dts' % root)
327 return fname
328
329 def CheckOptions(self):
330 """Check provided options and select defaults."""
331 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700332
Simon Glass290a1802011-07-17 13:54:32 -0700333 if not self.uboot_fname:
334 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
335 if not self.bct_fname:
336 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700337 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700338 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700339 if not self.exynos_bl1:
340 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
341 if not self.exynos_bl2:
342 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700343 if not self.coreboot_fname:
344 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
345 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700346 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700347 if not self.seabios_fname:
348 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700349 if not self.ecrw_fname:
350 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
351 if not self.ecro_fname:
352 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700353
Simon Glass75759302012-03-15 20:26:53 -0700354 def GetFiles(self):
355 """Get a list of files that we know about.
356
357 This is the opposite of SetFiles except that we may have put in some
358 default names. It returns a dictionary containing the filename for
359 each of a number of pre-defined files.
360
361 Returns:
362 Dictionary, with one entry for each file.
363 """
364 file_list = {
365 'bct' : self.bct_fname,
366 'exynos-bl1' : self.exynos_bl1,
367 'exynos-bl2' : self.exynos_bl2,
368 }
369 return file_list
370
Simon Glass4a887b12012-10-23 16:29:03 -0700371 def DecodeGBBFlagsFromFdt(self):
372 """Get Google Binary Block flags from the FDT.
373
374 These should be in the chromeos-config node, like this:
375
376 chromeos-config {
377 gbb-flag-dev-screen-short-delay;
378 gbb-flag-force-dev-switch-on;
379 gbb-flag-force-dev-boot-usb;
380 gbb-flag-disable-fw-rollback-check;
381 };
382
383 Returns:
384 GBB flags value from FDT.
385 """
386 chromeos_config = self.fdt.GetProps("/chromeos-config")
387 gbb_flags = 0
388 for name in chromeos_config:
389 if name.startswith('gbb-flag-'):
390 flag_value = gbb_flag_properties.get(name[9:])
391 if flag_value:
392 gbb_flags |= flag_value
393 self._out.Notice("FDT: Enabling %s." % name)
394 else:
395 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
396 return gbb_flags
397
Simon Glass157c0662012-10-23 13:52:42 -0700398 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
399 """Decode ajustments to the provided GBB flags.
400
401 We support three options:
402
403 hex value: c2
404 defined value: force-dev-boot-usb,load-option-roms
405 adjust default value: -load-option-roms,+force-dev-boot-usb
406
407 The last option starts from the passed-in GBB flags and adds or removes
408 flags.
409
410 Args:
411 gbb_flags: Base (default) FDT flags.
412 adjustments: String containing adjustments to make.
413
414 Returns:
415 Updated FDT flags.
416 """
417 use_base_value = True
418 if adjustments:
419 try:
420 return int(adjustments, base=16)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700421 except (ValueError, TypeError):
Simon Glass157c0662012-10-23 13:52:42 -0700422 pass
423 for flag in adjustments.split(','):
424 oper = None
425 if flag[0] in ['-', '+']:
426 oper = flag[0]
427 flag = flag[1:]
428 value = gbb_flag_properties.get(flag)
429 if not value:
430 raise ValueError("Invalid GBB flag '%s'" % flag)
431 if oper == '+':
432 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800433 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700434 elif oper == '-':
435 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800436 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700437 else:
438 if use_base_value:
439 gbb_flags = 0
440 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800441 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700442 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800443 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700444
445 return gbb_flags
446
Simon Glass56577572011-07-19 11:08:06 +1200447 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700448 """Create a GBB for the image.
449
Simon Glass56577572011-07-19 11:08:06 +1200450 Args:
451 hardware_id: Hardware ID to use for this board. If None, then the
452 default from the Fdt will be used
453
Simon Glass89b86b82011-07-17 23:49:49 -0700454 Returns:
455 Path of the created GBB file.
456
457 Raises:
458 CmdError if a command fails.
459 """
Simon Glass56577572011-07-19 11:08:06 +1200460 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800461 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700462 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700463 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700464
Simon Glass4a887b12012-10-23 16:29:03 -0700465 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800466
Simon Glass157c0662012-10-23 13:52:42 -0700467 # Allow command line to override flags
468 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
469
Simon Glass4a887b12012-10-23 16:29:03 -0700470 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700471 self._out.Progress('Creating GBB')
472 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
473 sizes = ['%#x' % size for size in sizes]
474 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700475 keydir = self._tools.Filename(self._keydir)
476 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700477 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200478 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700479 '--rootkey=%s/root_key.vbpubk' % keydir,
480 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700481 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800482 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700483 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700484 cwd=odir)
485 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700486
Simon Glasse13ee2c2011-07-28 08:12:28 +1200487 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700488 """Sign an image so that the Tegra SOC will boot it.
489
490 Args:
491 bct: BCT file to use.
492 bootstub: Boot stub (U-Boot + fdt) file to sign.
493 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700494
495 Returns:
496 filename of signed image.
497
498 Raises:
499 CmdError if a command fails.
500 """
501 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200502 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700503 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200504 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700505 fd = open(config, 'w')
506 fd.write('Version = 1;\n')
507 fd.write('Redundancy = 1;\n')
508 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700509
510 # TODO(dianders): Right now, we don't have enough space in our flash map
511 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
512 # sure what this does for reliability, but at least things will fit...
513 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
514 if is_nand:
515 fd.write('Bctcopy = 1;\n')
516
Simon Glass89b86b82011-07-17 23:49:49 -0700517 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
518 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700519
Simon Glass89b86b82011-07-17 23:49:49 -0700520 fd.close()
521
522 self._tools.Run('cbootimage', [config, signed])
523 self._tools.OutputSize('BCT', bct)
524 self._tools.OutputSize('Signed image', signed)
525 return signed
526
Doug Anderson86ce5f42011-07-27 10:40:18 -0700527 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700528 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700529
530 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700531 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700532 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700533 """
Simon Glass468d8752012-09-19 16:36:19 -0700534 if bootcmd is not None:
535 if bootcmd == 'none':
536 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800537 self.fdt.PutString('/config', 'bootcmd', bootcmd)
538 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700539 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700540
Simon Glassa4934b72012-05-09 13:35:02 -0700541 def SetNodeEnabled(self, node_name, enabled):
542 """Set whether an node is enabled or disabled.
543
544 This simply sets the 'status' property of a node to "ok", or "disabled".
545
546 The node should either be a full path to the node (like '/uart@10200000')
547 or an alias property.
548
549 Aliases are supported like this:
550
551 aliases {
552 console = "/uart@10200000";
553 };
554
555 pointing to a node:
556
557 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700558 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700559 };
560
561 In this case, this function takes the name of the alias ('console' in
562 this case) and updates the status of the node that is pointed to, to
563 either ok or disabled. If the alias does not exist, a warning is
564 displayed.
565
566 Args:
567 node_name: Name of node (e.g. '/uart@10200000') or alias alias
568 (e.g. 'console') to adjust
569 enabled: True to enable, False to disable
570 """
571 # Look up the alias if this is an alias reference
572 if not node_name.startswith('/'):
573 lookup = self.fdt.GetString('/aliases', node_name, '')
574 if not lookup:
575 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
576 return
577 node_name = lookup
578 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700579 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700580 else:
581 status = 'disabled'
582 self.fdt.PutString(node_name, 'status', status)
583
584 def AddEnableList(self, enable_list):
585 """Process a list of nodes to enable/disable.
586
587 Args:
588 config_list: List of (node, value) tuples to add to the fdt. For each
589 tuple:
590 node: The fdt node to write to will be <node> or pointed to by
591 /aliases/<node>. We can tell which
592 value: 0 to disable the node, 1 to enable it
593 """
594 if enable_list:
595 for node_name, enabled in enable_list:
596 try:
597 enabled = int(enabled)
598 if enabled not in (0, 1):
599 raise ValueError
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700600 except ValueError:
Simon Glassa4934b72012-05-09 13:35:02 -0700601 raise CmdError("Invalid enable option value '%s' "
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700602 "(should be 0 or 1)" % str(enabled))
Simon Glassa4934b72012-05-09 13:35:02 -0700603 self.SetNodeEnabled(node_name, enabled)
604
Simon Glass290a1802011-07-17 13:54:32 -0700605 def AddConfigList(self, config_list, use_int=False):
606 """Add a list of config items to the fdt.
607
608 Normally these values are written to the fdt as strings, but integers
609 are also supported, in which case the values will be converted to integers
610 (if necessary) before being stored.
611
612 Args:
613 config_list: List of (config, value) tuples to add to the fdt. For each
614 tuple:
615 config: The fdt node to write to will be /config/<config>.
616 value: An integer or string value to write.
617 use_int: True to only write integer values.
618
619 Raises:
620 CmdError: if a value is required to be converted to integer but can't be.
621 """
622 if config_list:
623 for config in config_list:
624 value = config[1]
625 if use_int:
626 try:
627 value = int(value)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700628 except ValueError:
Simon Glass290a1802011-07-17 13:54:32 -0700629 raise CmdError("Cannot convert config option '%s' to integer" %
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700630 str(value))
Simon Glass290a1802011-07-17 13:54:32 -0700631 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800632 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700633 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800634 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700635
Simon Glass7c2d5572011-11-15 14:47:08 -0800636 def DecodeTextBase(self, data):
637 """Look at a U-Boot image and try to decode its TEXT_BASE.
638
639 This works because U-Boot has a header with the value 0x12345678
640 immediately followed by the TEXT_BASE value. We can therefore read this
641 from the image with some certainty. We check only the first 40 words
642 since the header should be within that region.
643
Simon Glass96b50302012-07-20 06:55:28 +0100644 Since upstream Tegra has moved to having a 16KB SPL region at the start,
645 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
646 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
647
Simon Glass7c2d5572011-11-15 14:47:08 -0800648 Args:
649 data: U-Boot binary data
650
651 Returns:
652 Text base (integer) or None if none was found
653 """
654 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100655 for start in (0, 0x4000):
656 for i in range(start, start + 160, 4):
657 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800658
Simon Glass96b50302012-07-20 06:55:28 +0100659 # TODO(sjg): This does not cope with a big-endian target
660 value = struct.unpack('<I', word)[0]
661 if found:
662 return value - start
663 if value == 0x12345678:
664 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800665
666 return None
667
668 def CalcTextBase(self, name, fdt, fname):
669 """Calculate the TEXT_BASE to use for U-Boot.
670
671 Normally this value is in the fdt, so we just read it from there. But as
672 a second check we look at the image itself in case this is different, and
673 switch to that if it is.
674
675 This allows us to flash any U-Boot even if its TEXT_BASE is different.
676 This is particularly useful with upstream U-Boot which uses a different
677 value (which we will move to).
678 """
679 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800680 # The value that comes back from fdt.GetInt is signed, which makes no
681 # sense for an address base. Force it to unsigned.
682 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800683 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100684 text_base_str = '%#x' % text_base if text_base else 'None'
685 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
686 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800687
688 # If they are different, issue a warning and switch over.
689 if text_base and text_base != fdt_text_base:
690 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
691 "fdt value of %x. Using %x" % (text_base, name,
692 fdt_text_base, text_base))
693 fdt_text_base = text_base
694 return fdt_text_base
695
Simon Glass6dcc2f22011-07-28 15:26:49 +1200696 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700697 """Create a boot stub and a signed boot stub.
698
Simon Glass6dcc2f22011-07-28 15:26:49 +1200699 For postload:
700 We add a /config/postload-text-offset entry to the signed bootstub's
701 fdt so that U-Boot can find the postload code.
702
703 The raw (unsigned) bootstub will have a value of -1 for this since we will
704 simply append the postload code to the bootstub and it can find it there.
705 This will be used for RW A/B firmware.
706
707 For the signed case this value will specify where in the flash to find
708 the postload code. This will be used for RO firmware.
709
Simon Glass89b86b82011-07-17 23:49:49 -0700710 Args:
711 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800712 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200713 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700714
715 Returns:
716 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200717 Full path to bootstub (uboot + fdt(-1) + postload).
718 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700719
720 Raises:
721 CmdError if a command fails.
722 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200723 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800724 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700725 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200726
727 # Make a copy of the fdt for the bootstub
728 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700729 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff)
Simon Glass290a1802011-07-17 13:54:32 -0700730 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200731
Simon Glass89b86b82011-07-17 23:49:49 -0700732 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700733 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
734 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700735 self._tools.OutputSize('Combined binary', bootstub)
736
Simon Glasse13ee2c2011-07-28 08:12:28 +1200737 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700738 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700739 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200740 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200741
742 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
743 data = self._tools.ReadFile(signed)
744
745 if postload:
746 # We must add postload to the bootstub since A and B will need to
747 # be able to find it without the /config/postload-text-offset mechanism.
748 bs_data = self._tools.ReadFile(bootstub)
749 bs_data += self._tools.ReadFile(postload)
750 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
751 self._tools.WriteFile(bootstub, bs_data)
752 self._tools.OutputSize('Combined binary with postload', bootstub)
753
754 # Now that we know the file size, adjust the fdt and re-sign
755 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800756 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200757 fdt_data = self._tools.ReadFile(fdt.fname)
758 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
759 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
760 postload_bootstub, text_base)
761 if len(data) != os.path.getsize(signed):
762 raise CmdError('Signed file size changed from %d to %d after updating '
763 'fdt' % (len(data), os.path.getsize(signed)))
764
765 # Re-read the signed image, and add the post-load binary.
766 data = self._tools.ReadFile(signed)
767 data += self._tools.ReadFile(postload)
768 self._tools.OutputSize('Post-load binary', postload)
769
770 self._tools.WriteFile(signed_postload, data)
771 self._tools.OutputSize('Final bootstub with postload', signed_postload)
772
773 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700774
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700775 def _CreateCorebootStub(self, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700776 """Create a coreboot boot stub.
777
778 Args:
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700779 coreboot: Path to coreboot.rom
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 """
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700965 # stupid pylint insists that sha256 is not in hashlib.
966 # pylint: disable=E1101
Simon Glass439fe7a2012-03-09 16:19:34 -0800967 if blob_type == 'coreboot':
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700968 coreboot = self._CreateCorebootStub(self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800969 pack.AddProperty('coreboot', coreboot)
970 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700971 elif blob_type == 'legacy':
972 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800973 elif blob_type == 'signed':
974 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
975 self.postload_fname)
976 pack.AddProperty('bootstub', bootstub)
977 pack.AddProperty('signed', signed)
978 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700979 elif blob_type == 'exynos-bl1':
980 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700981
982 # TODO(sjg@chromium.org): Deprecate ecbin
983 elif blob_type in ['ecrw', 'ecbin']:
984 pack.AddProperty('ecrw', self.ecrw_fname)
985 pack.AddProperty('ecbin', self.ecrw_fname)
Gabe Blackcdbdfe12013-02-06 05:37:52 -0800986 elif blob_type == 'ecrwhash':
987 ec_hash_file = os.path.join(self._tools.outdir, 'ec_hash.bin')
988 ecrw = self._tools.ReadFile(self.ecrw_fname)
989 hasher = hashlib.sha256()
990 hasher.update(ecrw)
991 self._tools.WriteFile(ec_hash_file, hasher.digest())
992 pack.AddProperty(blob_type, ec_hash_file)
Simon Glassbe0bc002012-08-16 12:50:48 -0700993 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700994 # crosbug.com/p/13143
995 # We cannot have an fmap in the EC image since there can be only one,
996 # which is the main fmap describing the whole image.
997 # Ultimately the EC will not have an fmap, since with software sync
998 # there is no flashrom involvement in updating the EC flash, and thus
999 # no need for the fmap.
1000 # For now, mangle the fmap name to avoid problems.
1001 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
1002 data = self._tools.ReadFile(self.ecro_fname)
1003 data = re.sub('__FMAP__', '__fMAP__', data)
1004 self._tools.WriteFile(updated_ecro, data)
1005 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -07001006 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -07001007 spl_payload = pack.GetBlobParams(blob_type)
1008
1009 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
1010 # from all flash map files.
1011 if not spl_payload:
1012 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
1013 prop_list = 'boot+dtb'
1014
1015 # Do this later, when we remove boot+dtb.
1016 # raise CmdError("No parameters provided for blob type '%s'" %
1017 # blob_type)
1018 else:
1019 prop_list = spl_payload[0].split(',')
Tom Wai-Hong Tam26e3a4c2013-02-06 09:36:47 +08001020 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
1021 if compress == 'none':
1022 compress = None
1023 spl_load_size = len(pack.ConcatPropContents(prop_list, compress,
1024 False)[0])
Simon Glass7d2542f2012-06-21 07:10:59 -07001025 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
1026 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -07001027 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -07001028 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -08001029 elif pack.GetProperty(blob_type):
1030 pass
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -08001031 elif blob_type in self.blobs:
1032 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -08001033 else:
1034 raise CmdError("Unknown blob type '%s' required in flash map" %
1035 blob_type)
1036
Simon Glass290a1802011-07-17 13:54:32 -07001037 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -07001038 """Create a full firmware image, along with various by-products.
1039
1040 This uses the provided u-boot.bin, fdt and bct to create a firmware
1041 image containing all the required parts. If the GBB is not supplied
1042 then this will just return a signed U-Boot as the image.
1043
1044 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +12001045 gbb: Full path to the GBB file, or empty if a GBB is not required.
1046 fdt: Fdt object containing required information.
1047
1048 Returns:
1049 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -07001050
1051 Raises:
1052 CmdError if a command fails.
1053 """
Simon Glass02d124a2012-03-02 14:47:20 -08001054 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -07001055
Simon Glass439fe7a2012-03-09 16:19:34 -08001056 pack = PackFirmware(self._tools, self._out)
Vadim Bendebury238f6442013-03-27 11:23:25 -07001057 # Get the flashmap so we know what to build. For board variants use the
1058 # main board name as the key (drop the _<variant> suffix).
1059 default_flashmap = default_flashmaps.get(self._board.split('_')[0])
Simon Glassb8c6d952012-12-01 06:14:35 -08001060 if self._force_rw:
Vadim Bendebury7bfdb372013-03-27 11:52:58 -07001061 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
1062 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
Simon Glassb8c6d952012-12-01 06:14:35 -08001063
Simon Glass0c54ba52012-11-06 12:36:43 -08001064 pack.SelectFdt(fdt, self._board, default_flashmap)
Simon Glass439fe7a2012-03-09 16:19:34 -08001065
1066 # Get all our blobs ready
1067 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -08001068 if self.skeleton_fname:
1069 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -07001070 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -07001071
Simon Glass47817052012-10-20 13:30:07 -07001072 # Let's create some copies of the fdt for vboot. These can be used to
1073 # pass a different fdt to each firmware type. For now it is just used to
1074 # check that the right fdt comes through.
1075 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
1076 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
1077 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
1078 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
1079 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
1080 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
1081 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
1082
Simon Glassde9c8072012-07-02 22:29:02 -07001083 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
1084 if self.kernel_fname:
1085 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
1086
Simon Glass439fe7a2012-03-09 16:19:34 -08001087 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +01001088 blob_list = pack.GetBlobList()
1089 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -07001090 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -08001091 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -07001092
Simon Glass7306b902012-12-17 15:06:21 -08001093 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -07001094 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -07001095 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +08001096 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -08001097 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +08001098 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -07001099 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -08001100 pack.AddProperty('fwid', fwid)
1101 pack.AddProperty('gbb', gbb)
1102 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -07001103
1104 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -07001105
1106 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -08001107 pack.UpdateBlobPositionsAndHashes(fdt)
1108 pack.UpdateBlobPositionsAndHashes(fdt_rwa)
1109 pack.UpdateBlobPositionsAndHashes(fdt_rwb)
Simon Glass8884b982012-06-21 12:41:41 -07001110
Simon Glass6207efe2012-12-17 15:04:36 -08001111 # Make a copy of the fdt for the bootstub
1112 fdt_data = self._tools.ReadFile(fdt.fname)
1113 uboot_data = self._tools.ReadFile(self.uboot_fname)
1114 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
1115 self._tools.WriteFile(uboot_copy, uboot_data)
1116
1117 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
1118 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
1119
Simon Glassa10282a2013-01-08 17:06:41 -08001120 # Fix up the coreboot image here, since we can't do this until we have
1121 # a final device tree binary.
Simon Glasscbc83552012-07-23 15:26:22 +01001122 if 'coreboot' in blob_list:
1123 bootstub = pack.GetProperty('coreboot')
1124 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -08001125 if self.coreboot_elf:
1126 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
1127 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
1128 else:
1129 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
1130 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
1131 '-l', '0x1110000', '-e', '0x1110008'])
Stefan Reinauer1502ea62012-11-01 10:15:38 -07001132 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
1133 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -08001134 data = self._tools.ReadFile(bootstub)
1135 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
1136 self._tools.WriteFile(bootstub_copy, data)
Gabe Black3df75252013-02-14 21:32:10 -08001137 self._tools.WriteFile(bootstub, data[-0x100000:])
Simon Glasscbc83552012-07-23 15:26:22 +01001138
Simon Glass208ad952013-02-10 11:16:46 -08001139 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -07001140 image = os.path.join(self._tools.outdir, 'image.bin')
1141 pack.PackImage(self._tools.outdir, image)
1142 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -07001143
Simon Glass439fe7a2012-03-09 16:19:34 -08001144 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -07001145 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001146 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001147
Simon Glassdedda6f2013-02-09 13:44:14 -08001148 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -07001149 """Select an FDT to control the firmware bundling
1150
Simon Glassdedda6f2013-02-09 13:44:14 -08001151 We make a copy of this which will include any on-the-fly changes we want
1152 to make.
1153
Simon Glass290a1802011-07-17 13:54:32 -07001154 Args:
1155 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -08001156 use_defaults: True to use a default FDT name if available, and to add
1157 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -07001158
Simon Glassc0f3dc62011-08-09 14:19:05 -07001159 Returns:
1160 The Fdt object of the original fdt file, which we will not modify.
1161
Simon Glassdedda6f2013-02-09 13:44:14 -08001162 Raises:
1163 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
1164 False).
Simon Glass290a1802011-07-17 13:54:32 -07001165 """
Simon Glassdedda6f2013-02-09 13:44:14 -08001166 if use_defaults:
1167 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -08001168 if not fdt_fname:
1169 raise ValueError('Please provide an FDT filename')
1170 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -07001171 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -08001172
1173 # For upstream, select the correct architecture .dtsi manually.
1174 if self._board == 'link' or 'x86' in self._board:
1175 arch_dts = 'coreboot.dtsi'
1176 elif self._board == 'daisy':
1177 arch_dts = 'exynos5250.dtsi'
1178 else:
1179 arch_dts = 'tegra20.dtsi'
1180
1181 fdt.Compile(arch_dts)
Simon Glass290a1802011-07-17 13:54:32 -07001182 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -07001183 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001184
Simon Glassc90cf582012-03-13 15:40:47 -07001185 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001186 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001187
1188 - Checks options, tools, output directory, fdt.
1189 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001190
1191 Args:
Simon Glass56577572011-07-19 11:08:06 +12001192 hardware_id: Hardware ID to use for this board. If None, then the
1193 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001194 output_fname: Output filename for the image. If this is not None, then
1195 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001196 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001197
1198 Returns:
1199 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001200 """
Simon Glass89b86b82011-07-17 23:49:49 -07001201 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -07001202 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +12001203 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001204
1205 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001206 image, pack = self._CreateImage(gbb, self.fdt)
1207 if show_map:
1208 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001209 if output_fname:
1210 shutil.copyfile(image, output_fname)
1211 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001212 return image, pack.props