blob: ffec8d1265988d20579c28a68095a076e7ece6c7 [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 Glass49b026b2013-04-26 16:38:42 -0700154# Maps board name to Exynos product number
155type_to_model = {
156 'peach' : '5420',
157 'daisy' : '5250'
158}
159
Simon Glass5076a7f2012-10-23 16:31:54 -0700160def ListGoogleBinaryBlockFlags():
161 """Print out a list of GBB flags."""
162 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
163 for name, value in gbb_flag_properties.iteritems():
164 print ' %-30s %02x' % (name, value)
165
Simon Glass89b86b82011-07-17 23:49:49 -0700166class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -0700167 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -0700168
Simon Glass290a1802011-07-17 13:54:32 -0700169 Sequence of events:
170 bundle = Bundle(tools.Tools(), cros_output.Output())
171 bundle.SetDirs(...)
172 bundle.SetFiles(...)
173 bundle.SetOptions(...)
174 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -0700175 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -0700176 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -0700177
Simon Glass290a1802011-07-17 13:54:32 -0700178 Public properties:
179 fdt: The fdt object that we use for building our image. This wil be the
180 one specified by the user, except that we might add config options
181 to it. This is set up by SelectFdt() which must be called before
182 bundling starts.
183 uboot_fname: Full filename of the U-Boot binary we use.
184 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -0700185 spl_source: Source device to load U-Boot from, in SPL:
186 straps: Select device according to CPU strap pins
187 spi: Boot from SPI
188 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -0700189
190 Private attributes:
191 _small: True to create a 'small' signed U-Boot, False to produce a
192 full image. The small U-Boot is enough to boot but will not have
193 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700194 """
Simon Glass89b86b82011-07-17 23:49:49 -0700195
Simon Glass290a1802011-07-17 13:54:32 -0700196 def __init__(self, tools, output):
197 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700198
Simon Glass290a1802011-07-17 13:54:32 -0700199 Args:
200 tools: A tools.Tools object to use for external tools.
201 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700202 """
Simon Glass290a1802011-07-17 13:54:32 -0700203 self._tools = tools
204 self._out = output
205
206 # Set up the things we need to know in order to operate.
207 self._board = None # Board name, e.g. tegra2_seaboard.
208 self._fdt_fname = None # Filename of our FDT.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700209 self._force_rw = None
210 self._gbb_flags = None
211 self._keydir = None
212 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700213 self.bct_fname = None # Filename of our BCT file.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700214 self.blobs = {} # Table of (type, filename) of arbitrary blobs
Hung-Te Lin5b649382011-08-03 15:01:16 +0800215 self.bmpblk_fname = None # Filename of our Bitmap Block
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700216 self.coreboot_elf = None
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700217 self.coreboot_fname = None # Filename of our coreboot binary.
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700218 self.ecro_fname = None # Filename of EC read-only file
219 self.ecrw_fname = None # Filename of EC file
Simon Glass7e199222012-03-13 15:51:18 -0700220 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
221 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700222 self.fdt = None # Our Fdt object.
223 self.kernel_fname = None
224 self.postload_fname = None
225 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass07267952012-06-08 12:45:13 -0700226 self.skeleton_fname = None # Filename of Coreboot skeleton file
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700227 self.spl_source = 'straps' # SPL boot according to board settings
228 self.uboot_fname = None # Filename of our U-Boot binary.
Simon Glass290a1802011-07-17 13:54:32 -0700229
230 def SetDirs(self, keydir):
231 """Set up directories required for Bundle.
232
233 Args:
234 keydir: Directory containing keys to use for signing firmware.
235 """
236 self._keydir = keydir
237
Simon Glass6dcc2f22011-07-28 15:26:49 +1200238 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800239 coreboot_elf=None,
Simon Glass07267952012-06-08 12:45:13 -0700240 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800241 skeleton=None, ecrw=None, ecro=None, kernel=None, blobs=None):
Simon Glass290a1802011-07-17 13:54:32 -0700242 """Set up files required for Bundle.
243
244 Args:
245 board: The name of the board to target (e.g. tegra2_seaboard).
246 uboot: The filename of the u-boot.bin image to use.
247 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800248 bmpblk: The filename of bitmap block file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800249 coreboot: The filename of the coreboot image to use (on x86).
250 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200251 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700252 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700253 exynos_bl1: The filename of the exynos BL1 file
254 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
255 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700256 ecrw: The filename of the EC (Embedded Controller) read-write file.
257 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700258 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800259 blobs: List of (type, filename) of arbitrary blobs.
Simon Glass290a1802011-07-17 13:54:32 -0700260 """
261 self._board = board
262 self.uboot_fname = uboot
263 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800264 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700265 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800266 self.coreboot_elf = coreboot_elf
Simon Glass6dcc2f22011-07-28 15:26:49 +1200267 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700268 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700269 self.exynos_bl1 = exynos_bl1
270 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700271 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700272 self.ecrw_fname = ecrw
273 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700274 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800275 self.blobs = dict(blobs or ())
Simon Glass290a1802011-07-17 13:54:32 -0700276
Simon Glass6e486c22012-10-26 15:43:42 -0700277 def SetOptions(self, small, gbb_flags, force_rw=False):
Simon Glass290a1802011-07-17 13:54:32 -0700278 """Set up options supported by Bundle.
279
280 Args:
281 small: Only create a signed U-Boot - don't produce the full packed
282 firmware image. This is useful for devs who want to replace just the
283 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700284 gbb_flags: Specification for string containing adjustments to make.
285 force_rw: Force firmware into RW mode.
Simon Glass290a1802011-07-17 13:54:32 -0700286 """
287 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700288 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700289 self._force_rw = force_rw
Simon Glass290a1802011-07-17 13:54:32 -0700290
Simon Glass22f39fb2013-02-09 13:44:14 -0800291 def _GetBuildRoot(self):
292 """Get the path to this board's 'firmware' directory.
293
294 Returns:
295 Path to firmware directory, with ## representing the path to the
296 chroot.
297 """
Simon Glass290a1802011-07-17 13:54:32 -0700298 if not self._board:
299 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800300 return os.path.join('##', 'build', self._board, 'firmware')
301
302 def _CheckFdtFilename(self, fname):
303 """Check provided FDT filename and return the correct name if needed.
304
305 Where the filename lacks a path, add a default path for this board.
306 Where no FDT filename is provided, select a default one for this board.
307
308 Args:
309 fname: Proposed FDT filename.
310
311 Returns:
312 Selected FDT filename, after validation.
313 """
314 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700315 dir_name = os.path.join(build_root, 'dts')
Simon Glass22f39fb2013-02-09 13:44:14 -0800316 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700317 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700318 base_name = re.sub('_', '-', self._board)
319
320 # In case the name exists with a prefix or suffix, find it.
321 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
322 found_list = glob.glob(self._tools.Filename(wildcard))
323 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800324 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700325 else:
326 # We didn't find anything definite, so set up our expected name.
Simon Glass22f39fb2013-02-09 13:44:14 -0800327 fname = os.path.join(dir_name, '%s.dts' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700328
Simon Glass881964d2012-04-04 11:34:09 -0700329 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800330 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700331 if not ext and not os.path.dirname(root):
Simon Glass22f39fb2013-02-09 13:44:14 -0800332 fname = os.path.join(dir_name, '%s.dts' % root)
333 return fname
334
335 def CheckOptions(self):
336 """Check provided options and select defaults."""
337 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700338
Simon Glass49b026b2013-04-26 16:38:42 -0700339 board_type = self._board.split('_')[0]
340 model = type_to_model.get(board_type)
341
Simon Glass290a1802011-07-17 13:54:32 -0700342 if not self.uboot_fname:
343 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
344 if not self.bct_fname:
345 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700346 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700347 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass49b026b2013-04-26 16:38:42 -0700348 if model:
349 if not self.exynos_bl1:
350 self.exynos_bl1 = os.path.join(build_root, 'E%s.nbl1.bin' % model)
351 if not self.exynos_bl2:
352 self.exynos_bl2 = os.path.join(build_root, 'smdk%s-spl.bin' % model)
Simon Glass07267952012-06-08 12:45:13 -0700353 if not self.coreboot_fname:
354 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
355 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700356 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700357 if not self.seabios_fname:
358 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700359 if not self.ecrw_fname:
360 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
361 if not self.ecro_fname:
362 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700363
Simon Glass75759302012-03-15 20:26:53 -0700364 def GetFiles(self):
365 """Get a list of files that we know about.
366
367 This is the opposite of SetFiles except that we may have put in some
368 default names. It returns a dictionary containing the filename for
369 each of a number of pre-defined files.
370
371 Returns:
372 Dictionary, with one entry for each file.
373 """
374 file_list = {
375 'bct' : self.bct_fname,
376 'exynos-bl1' : self.exynos_bl1,
377 'exynos-bl2' : self.exynos_bl2,
378 }
379 return file_list
380
Simon Glass4a887b12012-10-23 16:29:03 -0700381 def DecodeGBBFlagsFromFdt(self):
382 """Get Google Binary Block flags from the FDT.
383
384 These should be in the chromeos-config node, like this:
385
386 chromeos-config {
387 gbb-flag-dev-screen-short-delay;
388 gbb-flag-force-dev-switch-on;
389 gbb-flag-force-dev-boot-usb;
390 gbb-flag-disable-fw-rollback-check;
391 };
392
393 Returns:
394 GBB flags value from FDT.
395 """
396 chromeos_config = self.fdt.GetProps("/chromeos-config")
397 gbb_flags = 0
398 for name in chromeos_config:
399 if name.startswith('gbb-flag-'):
400 flag_value = gbb_flag_properties.get(name[9:])
401 if flag_value:
402 gbb_flags |= flag_value
403 self._out.Notice("FDT: Enabling %s." % name)
404 else:
405 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
406 return gbb_flags
407
Simon Glass157c0662012-10-23 13:52:42 -0700408 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
409 """Decode ajustments to the provided GBB flags.
410
411 We support three options:
412
413 hex value: c2
414 defined value: force-dev-boot-usb,load-option-roms
415 adjust default value: -load-option-roms,+force-dev-boot-usb
416
417 The last option starts from the passed-in GBB flags and adds or removes
418 flags.
419
420 Args:
421 gbb_flags: Base (default) FDT flags.
422 adjustments: String containing adjustments to make.
423
424 Returns:
425 Updated FDT flags.
426 """
427 use_base_value = True
428 if adjustments:
429 try:
430 return int(adjustments, base=16)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700431 except (ValueError, TypeError):
Simon Glass157c0662012-10-23 13:52:42 -0700432 pass
433 for flag in adjustments.split(','):
434 oper = None
435 if flag[0] in ['-', '+']:
436 oper = flag[0]
437 flag = flag[1:]
438 value = gbb_flag_properties.get(flag)
439 if not value:
440 raise ValueError("Invalid GBB flag '%s'" % flag)
441 if oper == '+':
442 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 elif oper == '-':
445 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800446 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700447 else:
448 if use_base_value:
449 gbb_flags = 0
450 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800451 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700452 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800453 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700454
455 return gbb_flags
456
Simon Glass56577572011-07-19 11:08:06 +1200457 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700458 """Create a GBB for the image.
459
Simon Glass56577572011-07-19 11:08:06 +1200460 Args:
461 hardware_id: Hardware ID to use for this board. If None, then the
462 default from the Fdt will be used
463
Simon Glass89b86b82011-07-17 23:49:49 -0700464 Returns:
465 Path of the created GBB file.
466
467 Raises:
468 CmdError if a command fails.
469 """
Simon Glass56577572011-07-19 11:08:06 +1200470 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800471 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700472 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700473 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700474
Simon Glass4a887b12012-10-23 16:29:03 -0700475 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800476
Simon Glass157c0662012-10-23 13:52:42 -0700477 # Allow command line to override flags
478 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
479
Simon Glass4a887b12012-10-23 16:29:03 -0700480 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700481 self._out.Progress('Creating GBB')
482 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
483 sizes = ['%#x' % size for size in sizes]
484 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700485 keydir = self._tools.Filename(self._keydir)
486 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700487 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200488 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700489 '--rootkey=%s/root_key.vbpubk' % keydir,
490 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700491 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800492 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700493 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700494 cwd=odir)
495 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700496
Simon Glasse13ee2c2011-07-28 08:12:28 +1200497 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700498 """Sign an image so that the Tegra SOC will boot it.
499
500 Args:
501 bct: BCT file to use.
502 bootstub: Boot stub (U-Boot + fdt) file to sign.
503 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700504
505 Returns:
506 filename of signed image.
507
508 Raises:
509 CmdError if a command fails.
510 """
511 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200512 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700513 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200514 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700515 fd = open(config, 'w')
516 fd.write('Version = 1;\n')
517 fd.write('Redundancy = 1;\n')
518 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700519
520 # TODO(dianders): Right now, we don't have enough space in our flash map
521 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
522 # sure what this does for reliability, but at least things will fit...
523 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
524 if is_nand:
525 fd.write('Bctcopy = 1;\n')
526
Simon Glass89b86b82011-07-17 23:49:49 -0700527 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
528 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700529
Simon Glass89b86b82011-07-17 23:49:49 -0700530 fd.close()
531
532 self._tools.Run('cbootimage', [config, signed])
533 self._tools.OutputSize('BCT', bct)
534 self._tools.OutputSize('Signed image', signed)
535 return signed
536
Doug Anderson86ce5f42011-07-27 10:40:18 -0700537 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700538 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700539
540 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700541 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700542 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700543 """
Simon Glass468d8752012-09-19 16:36:19 -0700544 if bootcmd is not None:
545 if bootcmd == 'none':
546 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800547 self.fdt.PutString('/config', 'bootcmd', bootcmd)
548 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700549 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700550
Simon Glassa4934b72012-05-09 13:35:02 -0700551 def SetNodeEnabled(self, node_name, enabled):
552 """Set whether an node is enabled or disabled.
553
554 This simply sets the 'status' property of a node to "ok", or "disabled".
555
556 The node should either be a full path to the node (like '/uart@10200000')
557 or an alias property.
558
559 Aliases are supported like this:
560
561 aliases {
562 console = "/uart@10200000";
563 };
564
565 pointing to a node:
566
567 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700568 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700569 };
570
571 In this case, this function takes the name of the alias ('console' in
572 this case) and updates the status of the node that is pointed to, to
573 either ok or disabled. If the alias does not exist, a warning is
574 displayed.
575
576 Args:
577 node_name: Name of node (e.g. '/uart@10200000') or alias alias
578 (e.g. 'console') to adjust
579 enabled: True to enable, False to disable
580 """
581 # Look up the alias if this is an alias reference
582 if not node_name.startswith('/'):
583 lookup = self.fdt.GetString('/aliases', node_name, '')
584 if not lookup:
585 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
586 return
587 node_name = lookup
588 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700589 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700590 else:
591 status = 'disabled'
592 self.fdt.PutString(node_name, 'status', status)
593
594 def AddEnableList(self, enable_list):
595 """Process a list of nodes to enable/disable.
596
597 Args:
598 config_list: List of (node, value) tuples to add to the fdt. For each
599 tuple:
600 node: The fdt node to write to will be <node> or pointed to by
601 /aliases/<node>. We can tell which
602 value: 0 to disable the node, 1 to enable it
603 """
604 if enable_list:
605 for node_name, enabled in enable_list:
606 try:
607 enabled = int(enabled)
608 if enabled not in (0, 1):
609 raise ValueError
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700610 except ValueError:
Simon Glassa4934b72012-05-09 13:35:02 -0700611 raise CmdError("Invalid enable option value '%s' "
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700612 "(should be 0 or 1)" % str(enabled))
Simon Glassa4934b72012-05-09 13:35:02 -0700613 self.SetNodeEnabled(node_name, enabled)
614
Simon Glass290a1802011-07-17 13:54:32 -0700615 def AddConfigList(self, config_list, use_int=False):
616 """Add a list of config items to the fdt.
617
618 Normally these values are written to the fdt as strings, but integers
619 are also supported, in which case the values will be converted to integers
620 (if necessary) before being stored.
621
622 Args:
623 config_list: List of (config, value) tuples to add to the fdt. For each
624 tuple:
625 config: The fdt node to write to will be /config/<config>.
626 value: An integer or string value to write.
627 use_int: True to only write integer values.
628
629 Raises:
630 CmdError: if a value is required to be converted to integer but can't be.
631 """
632 if config_list:
633 for config in config_list:
634 value = config[1]
635 if use_int:
636 try:
637 value = int(value)
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700638 except ValueError:
Simon Glass290a1802011-07-17 13:54:32 -0700639 raise CmdError("Cannot convert config option '%s' to integer" %
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700640 str(value))
Simon Glass290a1802011-07-17 13:54:32 -0700641 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800642 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700643 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800644 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700645
Simon Glass7c2d5572011-11-15 14:47:08 -0800646 def DecodeTextBase(self, data):
647 """Look at a U-Boot image and try to decode its TEXT_BASE.
648
649 This works because U-Boot has a header with the value 0x12345678
650 immediately followed by the TEXT_BASE value. We can therefore read this
651 from the image with some certainty. We check only the first 40 words
652 since the header should be within that region.
653
Simon Glass96b50302012-07-20 06:55:28 +0100654 Since upstream Tegra has moved to having a 16KB SPL region at the start,
655 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
656 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
657
Simon Glass7c2d5572011-11-15 14:47:08 -0800658 Args:
659 data: U-Boot binary data
660
661 Returns:
662 Text base (integer) or None if none was found
663 """
664 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100665 for start in (0, 0x4000):
666 for i in range(start, start + 160, 4):
667 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800668
Simon Glass96b50302012-07-20 06:55:28 +0100669 # TODO(sjg): This does not cope with a big-endian target
670 value = struct.unpack('<I', word)[0]
671 if found:
672 return value - start
673 if value == 0x12345678:
674 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800675
676 return None
677
678 def CalcTextBase(self, name, fdt, fname):
679 """Calculate the TEXT_BASE to use for U-Boot.
680
681 Normally this value is in the fdt, so we just read it from there. But as
682 a second check we look at the image itself in case this is different, and
683 switch to that if it is.
684
685 This allows us to flash any U-Boot even if its TEXT_BASE is different.
686 This is particularly useful with upstream U-Boot which uses a different
687 value (which we will move to).
688 """
689 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800690 # The value that comes back from fdt.GetInt is signed, which makes no
691 # sense for an address base. Force it to unsigned.
692 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800693 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100694 text_base_str = '%#x' % text_base if text_base else 'None'
695 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
696 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800697
698 # If they are different, issue a warning and switch over.
699 if text_base and text_base != fdt_text_base:
700 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
701 "fdt value of %x. Using %x" % (text_base, name,
702 fdt_text_base, text_base))
703 fdt_text_base = text_base
704 return fdt_text_base
705
Simon Glass6dcc2f22011-07-28 15:26:49 +1200706 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700707 """Create a boot stub and a signed boot stub.
708
Simon Glass6dcc2f22011-07-28 15:26:49 +1200709 For postload:
710 We add a /config/postload-text-offset entry to the signed bootstub's
711 fdt so that U-Boot can find the postload code.
712
713 The raw (unsigned) bootstub will have a value of -1 for this since we will
714 simply append the postload code to the bootstub and it can find it there.
715 This will be used for RW A/B firmware.
716
717 For the signed case this value will specify where in the flash to find
718 the postload code. This will be used for RO firmware.
719
Simon Glass89b86b82011-07-17 23:49:49 -0700720 Args:
721 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800722 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200723 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700724
725 Returns:
726 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200727 Full path to bootstub (uboot + fdt(-1) + postload).
728 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700729
730 Raises:
731 CmdError if a command fails.
732 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200733 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800734 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700735 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200736
737 # Make a copy of the fdt for the bootstub
738 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700739 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff)
Simon Glass290a1802011-07-17 13:54:32 -0700740 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200741
Simon Glass89b86b82011-07-17 23:49:49 -0700742 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700743 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
744 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700745 self._tools.OutputSize('Combined binary', bootstub)
746
Simon Glasse13ee2c2011-07-28 08:12:28 +1200747 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700748 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700749 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200750 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200751
752 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
753 data = self._tools.ReadFile(signed)
754
755 if postload:
756 # We must add postload to the bootstub since A and B will need to
757 # be able to find it without the /config/postload-text-offset mechanism.
758 bs_data = self._tools.ReadFile(bootstub)
759 bs_data += self._tools.ReadFile(postload)
760 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
761 self._tools.WriteFile(bootstub, bs_data)
762 self._tools.OutputSize('Combined binary with postload', bootstub)
763
764 # Now that we know the file size, adjust the fdt and re-sign
765 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800766 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200767 fdt_data = self._tools.ReadFile(fdt.fname)
768 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
769 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
770 postload_bootstub, text_base)
771 if len(data) != os.path.getsize(signed):
772 raise CmdError('Signed file size changed from %d to %d after updating '
773 'fdt' % (len(data), os.path.getsize(signed)))
774
775 # Re-read the signed image, and add the post-load binary.
776 data = self._tools.ReadFile(signed)
777 data += self._tools.ReadFile(postload)
778 self._tools.OutputSize('Post-load binary', postload)
779
780 self._tools.WriteFile(signed_postload, data)
781 self._tools.OutputSize('Final bootstub with postload', signed_postload)
782
783 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700784
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700785 def _CreateCorebootStub(self, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700786 """Create a coreboot boot stub.
787
788 Args:
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700789 coreboot: Path to coreboot.rom
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700790
791 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100792 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700793
794 Raises:
795 CmdError if a command fails.
796 """
797 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700798 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100799
800 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700801 return bootstub
802
Simon Glass3b404092012-05-23 13:10:36 -0700803 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700804 """Update the parameters in a BL2 blob.
805
806 We look at the list in the parameter block, extract the value of each
807 from the device tree, and write that value to the parameter block.
808
809 Args:
810 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700811 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700812 data: The BL2 data.
813 pos: The position of the start of the parameter block.
814
815 Returns:
816 The new contents of the parameter block, after updating.
817 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700818 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
819 if version != 1:
820 raise CmdError("Cannot update machine parameter block version '%d'" %
821 version)
822 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700823 raise CmdError("Machine parameter block size %d is invalid: "
824 "pos=%d, size=%d, space=%d, len=%d" %
825 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700826
827 # Move past the header and read the parameter list, which is terminated
828 # with \0.
829 pos += 12
830 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
831 param_len = param_list.find('\0')
832 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700833 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700834
835 # Work through the parameters one at a time, adding each value
836 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700837 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700838 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700839 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glass56583742012-11-06 12:34:47 -0800840
841 # Use this to detect a missing value from the fdt.
842 not_given = 'not-given-invalid-value'
Simon Glassdf95dd22012-03-13 15:46:16 -0700843 if param == 'm' :
Simon Glass56583742012-11-06 12:34:47 -0800844 mem_type = fdt.GetString('/dmc', 'mem-type', not_given)
845 if mem_type == not_given:
846 mem_type = 'ddr3'
847 self._out.Warning("No value for memory type: using '%s'" % mem_type)
Simon Glassdf95dd22012-03-13 15:46:16 -0700848 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
849 if not mem_type in mem_types:
850 raise CmdError("Unknown memory type '%s'" % mem_type)
851 value = mem_types.index(mem_type)
852 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700853 elif param == 'M' :
Simon Glass56583742012-11-06 12:34:47 -0800854 mem_manuf = fdt.GetString('/dmc', 'mem-manuf', not_given)
855 if mem_manuf == not_given:
856 mem_manuf = 'samsung'
857 self._out.Warning("No value for memory manufacturer: using '%s'" %
858 mem_manuf)
Doug Andersonee46cfe2012-05-18 09:53:08 -0700859 mem_manufs = ['autodetect', 'elpida', 'samsung']
860 if not mem_manuf in mem_manufs:
861 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
862 value = mem_manufs.index(mem_manuf)
863 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700864 elif param == 'f' :
Simon Glass56583742012-11-06 12:34:47 -0800865 mem_freq = fdt.GetInt('/dmc', 'clock-frequency', -1)
866 if mem_freq == -1:
867 mem_freq = 800000000
868 self._out.Warning("No value for memory frequency: using '%s'" %
869 mem_freq)
870 mem_freq /= 1000000
Simon Glass158289e2012-09-14 11:42:25 -0700871 if not mem_freq in [533, 667, 800]:
872 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
873 value = mem_freq
874 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700875 elif param == 'v':
876 value = 31
877 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700878 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700879 value = (spl_load_size + 0xfff) & ~0xfff
880 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
881 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700882 elif param == 'b':
883 # These values come from enum boot_mode in U-Boot's cpu.h
884 if self.spl_source == 'straps':
885 value = 32
886 elif self.spl_source == 'emmc':
887 value = 4
888 elif self.spl_source == 'spi':
889 value = 20
890 elif self.spl_source == 'usb':
891 value = 33
892 else:
893 raise CmdError("Invalid boot source '%s'" % self.spl_source)
894 self._out.Info(' Boot source: %#0x' % value)
Tom Wai-Hong Tam99b7f112013-02-06 09:10:10 +0800895 elif param == 'z':
896 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
897 compress_types = ['none', 'lzo']
898 if not compress in compress_types:
899 raise CmdError("Unknown compression type '%s'" % compress)
900 value = compress_types.index(compress)
901 self._out.Info(' Compression type: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700902 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700903 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700904 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700905 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700906 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700907
908 # Put the data into our block.
909 data = data[:pos] + new_data + data[pos + len(new_data):]
910 self._out.Info('BL2 configuration complete')
911 return data
912
Simon Glasse5e8afb2012-05-23 11:19:23 -0700913 def _UpdateChecksum(self, data):
914 """Update the BL2 checksum.
915
916 The checksum is a 4 byte sum of all the bytes in the image before the
917 last 4 bytes (which hold the checksum).
918
919 Args:
920 data: The BL2 data to update.
921
922 Returns:
923 The new contents of the BL2 data, after updating the checksum.
924 """
925 checksum = 0
926 for ch in data[:-4]:
927 checksum += ord(ch)
928 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
929
Simon Glass559b6612012-05-23 13:28:45 -0700930 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700931 """Configure an Exynos BL2 binary for our needs.
932
933 We create a new modified BL2 and return its filename.
934
935 Args:
936 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700937 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700938 orig_bl2: Filename of original BL2 file to modify.
939 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700940 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700941 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700942 data = self._tools.ReadFile(orig_bl2)
943 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700944
945 # Locate the parameter block
946 data = self._tools.ReadFile(bl2)
947 marker = struct.pack('<L', 0xdeadbeef)
948 pos = data.rfind(marker)
949 if not pos:
950 raise CmdError("Could not find machine parameter block in '%s'" %
951 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700952 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700953 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700954 self._tools.WriteFile(bl2, data)
955 return bl2
956
Simon Glass89b86b82011-07-17 23:49:49 -0700957 def _PackOutput(self, msg):
958 """Helper function to write output from PackFirmware (verbose level 2).
959
960 This is passed to PackFirmware for it to use to write output.
961
962 Args:
963 msg: Message to display.
964 """
965 self._out.Notice(msg)
966
Simon Glass439fe7a2012-03-09 16:19:34 -0800967 def _BuildBlob(self, pack, fdt, blob_type):
968 """Build the blob data for a particular blob type.
969
970 Args:
971 blob_type: The type of blob to create data for. Supported types are:
972 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
973 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
974 """
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700975 # stupid pylint insists that sha256 is not in hashlib.
976 # pylint: disable=E1101
Simon Glass439fe7a2012-03-09 16:19:34 -0800977 if blob_type == 'coreboot':
Vadim Bendebury7bfdb372013-03-27 11:52:58 -0700978 coreboot = self._CreateCorebootStub(self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800979 pack.AddProperty('coreboot', coreboot)
980 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700981 elif blob_type == 'legacy':
982 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800983 elif blob_type == 'signed':
984 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
985 self.postload_fname)
986 pack.AddProperty('bootstub', bootstub)
987 pack.AddProperty('signed', signed)
988 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700989 elif blob_type == 'exynos-bl1':
990 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700991
992 # TODO(sjg@chromium.org): Deprecate ecbin
993 elif blob_type in ['ecrw', 'ecbin']:
994 pack.AddProperty('ecrw', self.ecrw_fname)
995 pack.AddProperty('ecbin', self.ecrw_fname)
Gabe Blackcdbdfe12013-02-06 05:37:52 -0800996 elif blob_type == 'ecrwhash':
997 ec_hash_file = os.path.join(self._tools.outdir, 'ec_hash.bin')
998 ecrw = self._tools.ReadFile(self.ecrw_fname)
999 hasher = hashlib.sha256()
1000 hasher.update(ecrw)
1001 self._tools.WriteFile(ec_hash_file, hasher.digest())
1002 pack.AddProperty(blob_type, ec_hash_file)
Simon Glassbe0bc002012-08-16 12:50:48 -07001003 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -07001004 # crosbug.com/p/13143
1005 # We cannot have an fmap in the EC image since there can be only one,
1006 # which is the main fmap describing the whole image.
1007 # Ultimately the EC will not have an fmap, since with software sync
1008 # there is no flashrom involvement in updating the EC flash, and thus
1009 # no need for the fmap.
1010 # For now, mangle the fmap name to avoid problems.
1011 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
1012 data = self._tools.ReadFile(self.ecro_fname)
1013 data = re.sub('__FMAP__', '__fMAP__', data)
1014 self._tools.WriteFile(updated_ecro, data)
1015 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -07001016 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -07001017 spl_payload = pack.GetBlobParams(blob_type)
1018
1019 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
1020 # from all flash map files.
1021 if not spl_payload:
1022 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
1023 prop_list = 'boot+dtb'
1024
1025 # Do this later, when we remove boot+dtb.
1026 # raise CmdError("No parameters provided for blob type '%s'" %
1027 # blob_type)
1028 else:
1029 prop_list = spl_payload[0].split(',')
Tom Wai-Hong Tam26e3a4c2013-02-06 09:36:47 +08001030 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
1031 if compress == 'none':
1032 compress = None
1033 spl_load_size = len(pack.ConcatPropContents(prop_list, compress,
1034 False)[0])
Simon Glass7d2542f2012-06-21 07:10:59 -07001035 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
1036 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -07001037 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -07001038 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -08001039 elif pack.GetProperty(blob_type):
1040 pass
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -08001041 elif blob_type in self.blobs:
1042 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -08001043 else:
1044 raise CmdError("Unknown blob type '%s' required in flash map" %
1045 blob_type)
1046
Simon Glass290a1802011-07-17 13:54:32 -07001047 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -07001048 """Create a full firmware image, along with various by-products.
1049
1050 This uses the provided u-boot.bin, fdt and bct to create a firmware
1051 image containing all the required parts. If the GBB is not supplied
1052 then this will just return a signed U-Boot as the image.
1053
1054 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +12001055 gbb: Full path to the GBB file, or empty if a GBB is not required.
1056 fdt: Fdt object containing required information.
1057
1058 Returns:
1059 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -07001060
1061 Raises:
1062 CmdError if a command fails.
1063 """
Simon Glass02d124a2012-03-02 14:47:20 -08001064 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -07001065
Simon Glass439fe7a2012-03-09 16:19:34 -08001066 pack = PackFirmware(self._tools, self._out)
Vadim Bendebury238f6442013-03-27 11:23:25 -07001067 # Get the flashmap so we know what to build. For board variants use the
1068 # main board name as the key (drop the _<variant> suffix).
1069 default_flashmap = default_flashmaps.get(self._board.split('_')[0])
Simon Glassb8c6d952012-12-01 06:14:35 -08001070 if self._force_rw:
Vadim Bendebury7bfdb372013-03-27 11:52:58 -07001071 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
1072 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
Simon Glassb8c6d952012-12-01 06:14:35 -08001073
Simon Glass0c54ba52012-11-06 12:36:43 -08001074 pack.SelectFdt(fdt, self._board, default_flashmap)
Simon Glass439fe7a2012-03-09 16:19:34 -08001075
1076 # Get all our blobs ready
1077 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -08001078 if self.skeleton_fname:
1079 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -07001080 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -07001081
Simon Glass47817052012-10-20 13:30:07 -07001082 # Let's create some copies of the fdt for vboot. These can be used to
1083 # pass a different fdt to each firmware type. For now it is just used to
1084 # check that the right fdt comes through.
1085 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
1086 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
1087 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
1088 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
1089 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
1090 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
1091 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
1092
Simon Glassde9c8072012-07-02 22:29:02 -07001093 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
1094 if self.kernel_fname:
1095 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
1096
Simon Glass439fe7a2012-03-09 16:19:34 -08001097 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +01001098 blob_list = pack.GetBlobList()
1099 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -07001100 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -08001101 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -07001102
Simon Glass7306b902012-12-17 15:06:21 -08001103 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -07001104 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -07001105 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +08001106 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -08001107 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +08001108 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -07001109 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -08001110 pack.AddProperty('fwid', fwid)
1111 pack.AddProperty('gbb', gbb)
1112 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -07001113
1114 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -07001115
1116 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -08001117 pack.UpdateBlobPositionsAndHashes(fdt)
1118 pack.UpdateBlobPositionsAndHashes(fdt_rwa)
1119 pack.UpdateBlobPositionsAndHashes(fdt_rwb)
Simon Glass8884b982012-06-21 12:41:41 -07001120
Simon Glass6207efe2012-12-17 15:04:36 -08001121 # Make a copy of the fdt for the bootstub
1122 fdt_data = self._tools.ReadFile(fdt.fname)
1123 uboot_data = self._tools.ReadFile(self.uboot_fname)
1124 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
1125 self._tools.WriteFile(uboot_copy, uboot_data)
1126
1127 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
1128 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
1129
Simon Glassa10282a2013-01-08 17:06:41 -08001130 # Fix up the coreboot image here, since we can't do this until we have
1131 # a final device tree binary.
Simon Glasscbc83552012-07-23 15:26:22 +01001132 if 'coreboot' in blob_list:
1133 bootstub = pack.GetProperty('coreboot')
1134 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -08001135 if self.coreboot_elf:
1136 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
1137 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
1138 else:
1139 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
1140 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
1141 '-l', '0x1110000', '-e', '0x1110008'])
Stefan Reinauer1502ea62012-11-01 10:15:38 -07001142 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
1143 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -08001144 data = self._tools.ReadFile(bootstub)
1145 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
1146 self._tools.WriteFile(bootstub_copy, data)
Gabe Black3df75252013-02-14 21:32:10 -08001147 self._tools.WriteFile(bootstub, data[-0x100000:])
Simon Glasscbc83552012-07-23 15:26:22 +01001148
Simon Glass208ad952013-02-10 11:16:46 -08001149 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -07001150 image = os.path.join(self._tools.outdir, 'image.bin')
1151 pack.PackImage(self._tools.outdir, image)
1152 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -07001153
Simon Glass439fe7a2012-03-09 16:19:34 -08001154 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -07001155 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001156 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001157
Simon Glassdedda6f2013-02-09 13:44:14 -08001158 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -07001159 """Select an FDT to control the firmware bundling
1160
Simon Glassdedda6f2013-02-09 13:44:14 -08001161 We make a copy of this which will include any on-the-fly changes we want
1162 to make.
1163
Simon Glass290a1802011-07-17 13:54:32 -07001164 Args:
1165 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -08001166 use_defaults: True to use a default FDT name if available, and to add
1167 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -07001168
Simon Glassc0f3dc62011-08-09 14:19:05 -07001169 Returns:
1170 The Fdt object of the original fdt file, which we will not modify.
1171
Simon Glassdedda6f2013-02-09 13:44:14 -08001172 Raises:
1173 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
1174 False).
Simon Glass290a1802011-07-17 13:54:32 -07001175 """
Simon Glassdedda6f2013-02-09 13:44:14 -08001176 if use_defaults:
1177 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -08001178 if not fdt_fname:
1179 raise ValueError('Please provide an FDT filename')
1180 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -07001181 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -08001182
1183 # For upstream, select the correct architecture .dtsi manually.
1184 if self._board == 'link' or 'x86' in self._board:
1185 arch_dts = 'coreboot.dtsi'
1186 elif self._board == 'daisy':
1187 arch_dts = 'exynos5250.dtsi'
1188 else:
1189 arch_dts = 'tegra20.dtsi'
1190
1191 fdt.Compile(arch_dts)
Simon Glass290a1802011-07-17 13:54:32 -07001192 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -07001193 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001194
Simon Glassc90cf582012-03-13 15:40:47 -07001195 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001196 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001197
1198 - Checks options, tools, output directory, fdt.
1199 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001200
1201 Args:
Simon Glass56577572011-07-19 11:08:06 +12001202 hardware_id: Hardware ID to use for this board. If None, then the
1203 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001204 output_fname: Output filename for the image. If this is not None, then
1205 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001206 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001207
1208 Returns:
1209 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001210 """
Vadim Bendebury5baeec12013-04-02 13:01:22 -07001211 if self._small or self.fdt.GetProp('/config', 'nogbb', 'any') != 'any':
1212 gbb = '' # Building a small image or `nogbb' is requested in device tree.
1213 else:
Simon Glass56577572011-07-19 11:08:06 +12001214 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001215
1216 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001217 image, pack = self._CreateImage(gbb, self.fdt)
1218 if show_map:
1219 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001220 if output_fname:
1221 shutil.copyfile(image, output_fname)
1222 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001223 return image, pack.props