blob: b7118a6171854f66033d6e5fa7710eb599d6bb77 [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
Simon Glass89b86b82011-07-17 23:49:49 -070020import os
21import re
22
23import cros_output
24from fdt import Fdt
25from pack_firmware import PackFirmware
26import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080027import struct
Simon Glass89b86b82011-07-17 23:49:49 -070028import tempfile
Simon Glass439fe7a2012-03-09 16:19:34 -080029from tools import CmdError
Simon Glass89b86b82011-07-17 23:49:49 -070030from tools import Tools
31from write_firmware import WriteFirmware
32
33# This data is required by bmpblk_utility. Does it ever change?
34# It was stored with the chromeos-bootimage ebuild, but we want
35# this utility to work outside the chroot.
36yaml_data = '''
37bmpblock: 1.0
38
39images:
40 devmode: DeveloperBmp/DeveloperBmp.bmp
41 recovery: RecoveryBmp/RecoveryBmp.bmp
42 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
43 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
44
45screens:
46 dev_en:
47 - [0, 0, devmode]
48 rec_en:
49 - [0, 0, recovery]
50 yuck_en:
51 - [0, 0, rec_yuck]
52 ins_en:
53 - [0, 0, rec_insert]
54
55localizations:
56 - [ dev_en, rec_en, yuck_en, ins_en ]
57'''
58
Simon Glass0c54ba52012-11-06 12:36:43 -080059# Default flash maps for various boards we support.
60# These are used when no fdt is provided (e.g. upstream U-Boot with no
61# fdt. Each is a list of nodes.
62default_flashmaps = {
Simon Glass76958702012-11-08 13:07:53 -080063 'tegra' : [
64 {
Simon Glass0c54ba52012-11-06 12:36:43 -080065 'node' : 'ro-boot',
66 'label' : 'boot-stub',
67 'size' : 512 << 10,
68 'read-only' : True,
69 'type' : 'blob signed',
70 'required' : True
71 }
72 ],
73 'daisy' : [
74 {
75 'node' : 'pre-boot',
76 'label' : "bl1 pre-boot",
77 'size' : 0x2000,
78 'read-only' : True,
79 'filename' : "e5250.nbl1.bin",
80 'type' : "blob exynos-bl1",
81 'required' : True,
82 }, {
83 'node' : 'spl',
84 'label' : "bl2 spl",
85 'size' : 0x4000,
86 'read-only' : True,
87 'filename' : "bl2.bin",
88 'type' : "blob exynos-bl2 boot,dtb",
89 'required' : True,
90 }, {
91 'node' : 'ro-boot',
92 'label' : "u-boot",
93 'size' : 0x9a000,
94 'read-only' : True,
95 'type' : "blob boot,dtb",
96 'required' : True,
97 }
Simon Glass76958702012-11-08 13:07:53 -080098 ],
99 'link' : [
100 {
101 'node' : 'si-all',
102 'label' : 'si-all',
103 'reg' : '%d %d' % (0x00000000, 0x00200000),
104 'type' : 'ifd',
105 'required' : True,
106 }, {
107 'node' : 'ro-boot',
108 'label' : 'boot-stub',
109 'reg' : '%d %d' % (0x00700000, 0x00100000),
110 'read-only' : True,
111 'type' : 'blob coreboot',
112 'required' : True,
113 }
Simon Glass0c54ba52012-11-06 12:36:43 -0800114 ]
115}
116
117
Simon Glass4a887b12012-10-23 16:29:03 -0700118# Build GBB flags.
119# (src/platform/vboot_reference/firmware/include/gbb_header.h)
120gbb_flag_properties = {
121 'dev-screen-short-delay': 0x00000001,
122 'load-option-roms': 0x00000002,
123 'enable-alternate-os': 0x00000004,
124 'force-dev-switch-on': 0x00000008,
125 'force-dev-boot-usb': 0x00000010,
126 'disable-fw-rollback-check': 0x00000020,
127 'enter-triggers-tonorm': 0x00000040,
128 'force-dev-boot-legacy': 0x00000080,
129}
130
Simon Glass5076a7f2012-10-23 16:31:54 -0700131def ListGoogleBinaryBlockFlags():
132 """Print out a list of GBB flags."""
133 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
134 for name, value in gbb_flag_properties.iteritems():
135 print ' %-30s %02x' % (name, value)
136
Simon Glass89b86b82011-07-17 23:49:49 -0700137class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -0700138 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -0700139
Simon Glass290a1802011-07-17 13:54:32 -0700140 Sequence of events:
141 bundle = Bundle(tools.Tools(), cros_output.Output())
142 bundle.SetDirs(...)
143 bundle.SetFiles(...)
144 bundle.SetOptions(...)
145 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -0700146 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -0700147 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -0700148
Simon Glass290a1802011-07-17 13:54:32 -0700149 Public properties:
150 fdt: The fdt object that we use for building our image. This wil be the
151 one specified by the user, except that we might add config options
152 to it. This is set up by SelectFdt() which must be called before
153 bundling starts.
154 uboot_fname: Full filename of the U-Boot binary we use.
155 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -0700156 spl_source: Source device to load U-Boot from, in SPL:
157 straps: Select device according to CPU strap pins
158 spi: Boot from SPI
159 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -0700160
161 Private attributes:
162 _small: True to create a 'small' signed U-Boot, False to produce a
163 full image. The small U-Boot is enough to boot but will not have
164 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700165 """
Simon Glass89b86b82011-07-17 23:49:49 -0700166
Simon Glass290a1802011-07-17 13:54:32 -0700167 def __init__(self, tools, output):
168 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700169
Simon Glass290a1802011-07-17 13:54:32 -0700170 Args:
171 tools: A tools.Tools object to use for external tools.
172 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700173 """
Simon Glass290a1802011-07-17 13:54:32 -0700174 self._tools = tools
175 self._out = output
176
177 # Set up the things we need to know in order to operate.
178 self._board = None # Board name, e.g. tegra2_seaboard.
179 self._fdt_fname = None # Filename of our FDT.
180 self.uboot_fname = None # Filename of our U-Boot binary.
181 self.bct_fname = None # Filename of our BCT file.
182 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800183 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700184 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -0700185 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -0700186 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
187 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass559b6612012-05-23 13:28:45 -0700188 self.spl_source = 'straps' # SPL boot according to board settings
Simon Glass07267952012-06-08 12:45:13 -0700189 self.skeleton_fname = None # Filename of Coreboot skeleton file
Simon Glassbe0bc002012-08-16 12:50:48 -0700190 self.ecrw_fname = None # Filename of EC file
191 self.ecro_fname = None # Filename of EC read-only file
Simon Glass23988ae2012-03-23 16:55:22 -0700192 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700193
194 def SetDirs(self, keydir):
195 """Set up directories required for Bundle.
196
197 Args:
198 keydir: Directory containing keys to use for signing firmware.
199 """
200 self._keydir = keydir
201
Simon Glass6dcc2f22011-07-28 15:26:49 +1200202 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glass07267952012-06-08 12:45:13 -0700203 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassbe0bc002012-08-16 12:50:48 -0700204 skeleton=None, ecrw=None, ecro=None, kernel=None):
Simon Glass290a1802011-07-17 13:54:32 -0700205 """Set up files required for Bundle.
206
207 Args:
208 board: The name of the board to target (e.g. tegra2_seaboard).
209 uboot: The filename of the u-boot.bin image to use.
210 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800211 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700212 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200213 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700214 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700215 exynos_bl1: The filename of the exynos BL1 file
216 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
217 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700218 ecrw: The filename of the EC (Embedded Controller) read-write file.
219 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700220 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700221 """
222 self._board = board
223 self.uboot_fname = uboot
224 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800225 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700226 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200227 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700228 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700229 self.exynos_bl1 = exynos_bl1
230 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700231 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700232 self.ecrw_fname = ecrw
233 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700234 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700235
Simon Glass6e486c22012-10-26 15:43:42 -0700236 def SetOptions(self, small, gbb_flags, force_rw=False):
Simon Glass290a1802011-07-17 13:54:32 -0700237 """Set up options supported by Bundle.
238
239 Args:
240 small: Only create a signed U-Boot - don't produce the full packed
241 firmware image. This is useful for devs who want to replace just the
242 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700243 gbb_flags: Specification for string containing adjustments to make.
244 force_rw: Force firmware into RW mode.
Simon Glass290a1802011-07-17 13:54:32 -0700245 """
246 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700247 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700248 self._force_rw = force_rw
Simon Glass290a1802011-07-17 13:54:32 -0700249
250 def CheckOptions(self):
251 """Check provided options and select defaults."""
252 if not self._board:
253 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700254 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700255 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700256 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700257 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700258 base_name = re.sub('_', '-', self._board)
259
260 # In case the name exists with a prefix or suffix, find it.
261 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
262 found_list = glob.glob(self._tools.Filename(wildcard))
263 if len(found_list) == 1:
264 self._fdt_fname = found_list[0]
265 else:
266 # We didn't find anything definite, so set up our expected name.
267 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
268
Simon Glass881964d2012-04-04 11:34:09 -0700269 # Convert things like 'exynos5250-daisy' into a full path.
270 root, ext = os.path.splitext(self._fdt_fname)
271 if not ext and not os.path.dirname(root):
272 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
273
Simon Glass290a1802011-07-17 13:54:32 -0700274 if not self.uboot_fname:
275 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
276 if not self.bct_fname:
277 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700278 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700279 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700280 if not self.exynos_bl1:
281 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
282 if not self.exynos_bl2:
283 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700284 if not self.coreboot_fname:
285 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
286 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700287 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700288 if not self.seabios_fname:
289 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700290 if not self.ecrw_fname:
291 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
292 if not self.ecro_fname:
293 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700294
Simon Glass75759302012-03-15 20:26:53 -0700295 def GetFiles(self):
296 """Get a list of files that we know about.
297
298 This is the opposite of SetFiles except that we may have put in some
299 default names. It returns a dictionary containing the filename for
300 each of a number of pre-defined files.
301
302 Returns:
303 Dictionary, with one entry for each file.
304 """
305 file_list = {
306 'bct' : self.bct_fname,
307 'exynos-bl1' : self.exynos_bl1,
308 'exynos-bl2' : self.exynos_bl2,
309 }
310 return file_list
311
Simon Glass4a887b12012-10-23 16:29:03 -0700312 def DecodeGBBFlagsFromFdt(self):
313 """Get Google Binary Block flags from the FDT.
314
315 These should be in the chromeos-config node, like this:
316
317 chromeos-config {
318 gbb-flag-dev-screen-short-delay;
319 gbb-flag-force-dev-switch-on;
320 gbb-flag-force-dev-boot-usb;
321 gbb-flag-disable-fw-rollback-check;
322 };
323
324 Returns:
325 GBB flags value from FDT.
326 """
327 chromeos_config = self.fdt.GetProps("/chromeos-config")
328 gbb_flags = 0
329 for name in chromeos_config:
330 if name.startswith('gbb-flag-'):
331 flag_value = gbb_flag_properties.get(name[9:])
332 if flag_value:
333 gbb_flags |= flag_value
334 self._out.Notice("FDT: Enabling %s." % name)
335 else:
336 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
337 return gbb_flags
338
Simon Glass157c0662012-10-23 13:52:42 -0700339 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
340 """Decode ajustments to the provided GBB flags.
341
342 We support three options:
343
344 hex value: c2
345 defined value: force-dev-boot-usb,load-option-roms
346 adjust default value: -load-option-roms,+force-dev-boot-usb
347
348 The last option starts from the passed-in GBB flags and adds or removes
349 flags.
350
351 Args:
352 gbb_flags: Base (default) FDT flags.
353 adjustments: String containing adjustments to make.
354
355 Returns:
356 Updated FDT flags.
357 """
358 use_base_value = True
359 if adjustments:
360 try:
361 return int(adjustments, base=16)
362 except:
363 pass
364 for flag in adjustments.split(','):
365 oper = None
366 if flag[0] in ['-', '+']:
367 oper = flag[0]
368 flag = flag[1:]
369 value = gbb_flag_properties.get(flag)
370 if not value:
371 raise ValueError("Invalid GBB flag '%s'" % flag)
372 if oper == '+':
373 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800374 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700375 elif oper == '-':
376 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800377 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700378 else:
379 if use_base_value:
380 gbb_flags = 0
381 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800382 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700383 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800384 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700385
386 return gbb_flags
387
Simon Glass56577572011-07-19 11:08:06 +1200388 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700389 """Create a GBB for the image.
390
Simon Glass56577572011-07-19 11:08:06 +1200391 Args:
392 hardware_id: Hardware ID to use for this board. If None, then the
393 default from the Fdt will be used
394
Simon Glass89b86b82011-07-17 23:49:49 -0700395 Returns:
396 Path of the created GBB file.
397
398 Raises:
399 CmdError if a command fails.
400 """
Simon Glass56577572011-07-19 11:08:06 +1200401 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800402 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700403 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700404 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700405
Simon Glass4a887b12012-10-23 16:29:03 -0700406 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800407
Simon Glass157c0662012-10-23 13:52:42 -0700408 # Allow command line to override flags
409 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
410
Simon Glass4a887b12012-10-23 16:29:03 -0700411 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700412 self._out.Progress('Creating GBB')
413 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
414 sizes = ['%#x' % size for size in sizes]
415 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700416 keydir = self._tools.Filename(self._keydir)
417 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700418 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200419 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700420 '--rootkey=%s/root_key.vbpubk' % keydir,
421 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700422 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800423 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700424 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700425 cwd=odir)
426 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700427
Simon Glasse13ee2c2011-07-28 08:12:28 +1200428 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700429 """Sign an image so that the Tegra SOC will boot it.
430
431 Args:
432 bct: BCT file to use.
433 bootstub: Boot stub (U-Boot + fdt) file to sign.
434 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700435
436 Returns:
437 filename of signed image.
438
439 Raises:
440 CmdError if a command fails.
441 """
442 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200443 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700444 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200445 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700446 fd = open(config, 'w')
447 fd.write('Version = 1;\n')
448 fd.write('Redundancy = 1;\n')
449 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700450
451 # TODO(dianders): Right now, we don't have enough space in our flash map
452 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
453 # sure what this does for reliability, but at least things will fit...
454 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
455 if is_nand:
456 fd.write('Bctcopy = 1;\n')
457
Simon Glass89b86b82011-07-17 23:49:49 -0700458 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
459 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700460
Simon Glass89b86b82011-07-17 23:49:49 -0700461 fd.close()
462
463 self._tools.Run('cbootimage', [config, signed])
464 self._tools.OutputSize('BCT', bct)
465 self._tools.OutputSize('Signed image', signed)
466 return signed
467
Doug Anderson86ce5f42011-07-27 10:40:18 -0700468 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700469 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700470
471 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700472 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700473 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700474 """
Simon Glass468d8752012-09-19 16:36:19 -0700475 if bootcmd is not None:
476 if bootcmd == 'none':
477 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800478 self.fdt.PutString('/config', 'bootcmd', bootcmd)
479 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700480 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700481
Simon Glassa4934b72012-05-09 13:35:02 -0700482 def SetNodeEnabled(self, node_name, enabled):
483 """Set whether an node is enabled or disabled.
484
485 This simply sets the 'status' property of a node to "ok", or "disabled".
486
487 The node should either be a full path to the node (like '/uart@10200000')
488 or an alias property.
489
490 Aliases are supported like this:
491
492 aliases {
493 console = "/uart@10200000";
494 };
495
496 pointing to a node:
497
498 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700499 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700500 };
501
502 In this case, this function takes the name of the alias ('console' in
503 this case) and updates the status of the node that is pointed to, to
504 either ok or disabled. If the alias does not exist, a warning is
505 displayed.
506
507 Args:
508 node_name: Name of node (e.g. '/uart@10200000') or alias alias
509 (e.g. 'console') to adjust
510 enabled: True to enable, False to disable
511 """
512 # Look up the alias if this is an alias reference
513 if not node_name.startswith('/'):
514 lookup = self.fdt.GetString('/aliases', node_name, '')
515 if not lookup:
516 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
517 return
518 node_name = lookup
519 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700520 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700521 else:
522 status = 'disabled'
523 self.fdt.PutString(node_name, 'status', status)
524
525 def AddEnableList(self, enable_list):
526 """Process a list of nodes to enable/disable.
527
528 Args:
529 config_list: List of (node, value) tuples to add to the fdt. For each
530 tuple:
531 node: The fdt node to write to will be <node> or pointed to by
532 /aliases/<node>. We can tell which
533 value: 0 to disable the node, 1 to enable it
534 """
535 if enable_list:
536 for node_name, enabled in enable_list:
537 try:
538 enabled = int(enabled)
539 if enabled not in (0, 1):
540 raise ValueError
541 except ValueError as str:
542 raise CmdError("Invalid enable option value '%s' "
543 "(should be 0 or 1)" % enabled)
544 self.SetNodeEnabled(node_name, enabled)
545
Simon Glass290a1802011-07-17 13:54:32 -0700546 def AddConfigList(self, config_list, use_int=False):
547 """Add a list of config items to the fdt.
548
549 Normally these values are written to the fdt as strings, but integers
550 are also supported, in which case the values will be converted to integers
551 (if necessary) before being stored.
552
553 Args:
554 config_list: List of (config, value) tuples to add to the fdt. For each
555 tuple:
556 config: The fdt node to write to will be /config/<config>.
557 value: An integer or string value to write.
558 use_int: True to only write integer values.
559
560 Raises:
561 CmdError: if a value is required to be converted to integer but can't be.
562 """
563 if config_list:
564 for config in config_list:
565 value = config[1]
566 if use_int:
567 try:
568 value = int(value)
569 except ValueError as str:
570 raise CmdError("Cannot convert config option '%s' to integer" %
571 value)
572 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800573 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700574 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800575 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700576
Simon Glass7c2d5572011-11-15 14:47:08 -0800577 def DecodeTextBase(self, data):
578 """Look at a U-Boot image and try to decode its TEXT_BASE.
579
580 This works because U-Boot has a header with the value 0x12345678
581 immediately followed by the TEXT_BASE value. We can therefore read this
582 from the image with some certainty. We check only the first 40 words
583 since the header should be within that region.
584
Simon Glass96b50302012-07-20 06:55:28 +0100585 Since upstream Tegra has moved to having a 16KB SPL region at the start,
586 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
587 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
588
Simon Glass7c2d5572011-11-15 14:47:08 -0800589 Args:
590 data: U-Boot binary data
591
592 Returns:
593 Text base (integer) or None if none was found
594 """
595 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100596 for start in (0, 0x4000):
597 for i in range(start, start + 160, 4):
598 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800599
Simon Glass96b50302012-07-20 06:55:28 +0100600 # TODO(sjg): This does not cope with a big-endian target
601 value = struct.unpack('<I', word)[0]
602 if found:
603 return value - start
604 if value == 0x12345678:
605 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800606
607 return None
608
609 def CalcTextBase(self, name, fdt, fname):
610 """Calculate the TEXT_BASE to use for U-Boot.
611
612 Normally this value is in the fdt, so we just read it from there. But as
613 a second check we look at the image itself in case this is different, and
614 switch to that if it is.
615
616 This allows us to flash any U-Boot even if its TEXT_BASE is different.
617 This is particularly useful with upstream U-Boot which uses a different
618 value (which we will move to).
619 """
620 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200621 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800622 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100623 text_base_str = '%#x' % text_base if text_base else 'None'
624 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
625 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800626
627 # If they are different, issue a warning and switch over.
628 if text_base and text_base != fdt_text_base:
629 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
630 "fdt value of %x. Using %x" % (text_base, name,
631 fdt_text_base, text_base))
632 fdt_text_base = text_base
633 return fdt_text_base
634
Simon Glass6dcc2f22011-07-28 15:26:49 +1200635 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700636 """Create a boot stub and a signed boot stub.
637
Simon Glass6dcc2f22011-07-28 15:26:49 +1200638 For postload:
639 We add a /config/postload-text-offset entry to the signed bootstub's
640 fdt so that U-Boot can find the postload code.
641
642 The raw (unsigned) bootstub will have a value of -1 for this since we will
643 simply append the postload code to the bootstub and it can find it there.
644 This will be used for RW A/B firmware.
645
646 For the signed case this value will specify where in the flash to find
647 the postload code. This will be used for RO firmware.
648
Simon Glass89b86b82011-07-17 23:49:49 -0700649 Args:
650 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800651 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200652 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700653
654 Returns:
655 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200656 Full path to bootstub (uboot + fdt(-1) + postload).
657 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700658
659 Raises:
660 CmdError if a command fails.
661 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200662 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800663 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700664 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200665
666 # Make a copy of the fdt for the bootstub
667 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800668 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700669 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200670
Simon Glass89b86b82011-07-17 23:49:49 -0700671 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700672 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
673 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700674 self._tools.OutputSize('Combined binary', bootstub)
675
Simon Glasse13ee2c2011-07-28 08:12:28 +1200676 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700677 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700678 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200679 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200680
681 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
682 data = self._tools.ReadFile(signed)
683
684 if postload:
685 # We must add postload to the bootstub since A and B will need to
686 # be able to find it without the /config/postload-text-offset mechanism.
687 bs_data = self._tools.ReadFile(bootstub)
688 bs_data += self._tools.ReadFile(postload)
689 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
690 self._tools.WriteFile(bootstub, bs_data)
691 self._tools.OutputSize('Combined binary with postload', bootstub)
692
693 # Now that we know the file size, adjust the fdt and re-sign
694 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800695 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200696 fdt_data = self._tools.ReadFile(fdt.fname)
697 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
698 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
699 postload_bootstub, text_base)
700 if len(data) != os.path.getsize(signed):
701 raise CmdError('Signed file size changed from %d to %d after updating '
702 'fdt' % (len(data), os.path.getsize(signed)))
703
704 # Re-read the signed image, and add the post-load binary.
705 data = self._tools.ReadFile(signed)
706 data += self._tools.ReadFile(postload)
707 self._tools.OutputSize('Post-load binary', postload)
708
709 self._tools.WriteFile(signed_postload, data)
710 self._tools.OutputSize('Final bootstub with postload', signed_postload)
711
712 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700713
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700714 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700715 """Create a coreboot boot stub.
716
717 Args:
718 uboot: Path to u-boot.bin (may be chroot-relative)
719 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700720 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700721
722 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100723 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700724
725 Raises:
726 CmdError if a command fails.
727 """
728 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700729
730 # U-Boot itself does not put a .elf extension on the elf file.
731 # The U-Boot ebuild does, but we shouldn't actually require it since
732 # devs may want to just use what U-Boot creates.
733 uboot_elf = uboot.replace('.bin', '')
734 if not os.path.exists(self._tools.Filename(uboot_elf)):
735 uboot_elf = uboot.replace('.bin', '.elf')
736 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Stefan Reinauer1502ea62012-11-01 10:15:38 -0700737 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f', uboot_elf,
738 '-n', 'fallback/payload', '-c', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100739
740 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700741 return bootstub
742
Simon Glass3b404092012-05-23 13:10:36 -0700743 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700744 """Update the parameters in a BL2 blob.
745
746 We look at the list in the parameter block, extract the value of each
747 from the device tree, and write that value to the parameter block.
748
749 Args:
750 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700751 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700752 data: The BL2 data.
753 pos: The position of the start of the parameter block.
754
755 Returns:
756 The new contents of the parameter block, after updating.
757 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700758 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
759 if version != 1:
760 raise CmdError("Cannot update machine parameter block version '%d'" %
761 version)
762 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700763 raise CmdError("Machine parameter block size %d is invalid: "
764 "pos=%d, size=%d, space=%d, len=%d" %
765 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700766
767 # Move past the header and read the parameter list, which is terminated
768 # with \0.
769 pos += 12
770 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
771 param_len = param_list.find('\0')
772 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700773 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700774
775 # Work through the parameters one at a time, adding each value
776 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700777 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700778 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700779 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glass56583742012-11-06 12:34:47 -0800780
781 # Use this to detect a missing value from the fdt.
782 not_given = 'not-given-invalid-value'
Simon Glassdf95dd22012-03-13 15:46:16 -0700783 if param == 'm' :
Simon Glass56583742012-11-06 12:34:47 -0800784 mem_type = fdt.GetString('/dmc', 'mem-type', not_given)
785 if mem_type == not_given:
786 mem_type = 'ddr3'
787 self._out.Warning("No value for memory type: using '%s'" % mem_type)
Simon Glassdf95dd22012-03-13 15:46:16 -0700788 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
789 if not mem_type in mem_types:
790 raise CmdError("Unknown memory type '%s'" % mem_type)
791 value = mem_types.index(mem_type)
792 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700793 elif param == 'M' :
Simon Glass56583742012-11-06 12:34:47 -0800794 mem_manuf = fdt.GetString('/dmc', 'mem-manuf', not_given)
795 if mem_manuf == not_given:
796 mem_manuf = 'samsung'
797 self._out.Warning("No value for memory manufacturer: using '%s'" %
798 mem_manuf)
Doug Andersonee46cfe2012-05-18 09:53:08 -0700799 mem_manufs = ['autodetect', 'elpida', 'samsung']
800 if not mem_manuf in mem_manufs:
801 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
802 value = mem_manufs.index(mem_manuf)
803 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700804 elif param == 'f' :
Simon Glass56583742012-11-06 12:34:47 -0800805 mem_freq = fdt.GetInt('/dmc', 'clock-frequency', -1)
806 if mem_freq == -1:
807 mem_freq = 800000000
808 self._out.Warning("No value for memory frequency: using '%s'" %
809 mem_freq)
810 mem_freq /= 1000000
Simon Glass158289e2012-09-14 11:42:25 -0700811 if not mem_freq in [533, 667, 800]:
812 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
813 value = mem_freq
814 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700815 elif param == 'v':
816 value = 31
817 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700818 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700819 value = (spl_load_size + 0xfff) & ~0xfff
820 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
821 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700822 elif param == 'b':
823 # These values come from enum boot_mode in U-Boot's cpu.h
824 if self.spl_source == 'straps':
825 value = 32
826 elif self.spl_source == 'emmc':
827 value = 4
828 elif self.spl_source == 'spi':
829 value = 20
830 elif self.spl_source == 'usb':
831 value = 33
832 else:
833 raise CmdError("Invalid boot source '%s'" % self.spl_source)
834 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700835 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700836 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700837 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700838 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700839 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700840
841 # Put the data into our block.
842 data = data[:pos] + new_data + data[pos + len(new_data):]
843 self._out.Info('BL2 configuration complete')
844 return data
845
Simon Glasse5e8afb2012-05-23 11:19:23 -0700846 def _UpdateChecksum(self, data):
847 """Update the BL2 checksum.
848
849 The checksum is a 4 byte sum of all the bytes in the image before the
850 last 4 bytes (which hold the checksum).
851
852 Args:
853 data: The BL2 data to update.
854
855 Returns:
856 The new contents of the BL2 data, after updating the checksum.
857 """
858 checksum = 0
859 for ch in data[:-4]:
860 checksum += ord(ch)
861 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
862
Simon Glass559b6612012-05-23 13:28:45 -0700863 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700864 """Configure an Exynos BL2 binary for our needs.
865
866 We create a new modified BL2 and return its filename.
867
868 Args:
869 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700870 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700871 orig_bl2: Filename of original BL2 file to modify.
872 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700873 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700874 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700875 data = self._tools.ReadFile(orig_bl2)
876 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700877
878 # Locate the parameter block
879 data = self._tools.ReadFile(bl2)
880 marker = struct.pack('<L', 0xdeadbeef)
881 pos = data.rfind(marker)
882 if not pos:
883 raise CmdError("Could not find machine parameter block in '%s'" %
884 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700885 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700886 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700887 self._tools.WriteFile(bl2, data)
888 return bl2
889
Simon Glass89b86b82011-07-17 23:49:49 -0700890 def _PackOutput(self, msg):
891 """Helper function to write output from PackFirmware (verbose level 2).
892
893 This is passed to PackFirmware for it to use to write output.
894
895 Args:
896 msg: Message to display.
897 """
898 self._out.Notice(msg)
899
Simon Glass439fe7a2012-03-09 16:19:34 -0800900 def _BuildBlob(self, pack, fdt, blob_type):
901 """Build the blob data for a particular blob type.
902
903 Args:
904 blob_type: The type of blob to create data for. Supported types are:
905 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
906 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
907 """
908 if blob_type == 'coreboot':
909 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700910 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800911 pack.AddProperty('coreboot', coreboot)
912 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700913 elif blob_type == 'legacy':
914 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800915 elif blob_type == 'signed':
916 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
917 self.postload_fname)
918 pack.AddProperty('bootstub', bootstub)
919 pack.AddProperty('signed', signed)
920 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700921 elif blob_type == 'exynos-bl1':
922 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700923
924 # TODO(sjg@chromium.org): Deprecate ecbin
925 elif blob_type in ['ecrw', 'ecbin']:
926 pack.AddProperty('ecrw', self.ecrw_fname)
927 pack.AddProperty('ecbin', self.ecrw_fname)
928 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700929 # crosbug.com/p/13143
930 # We cannot have an fmap in the EC image since there can be only one,
931 # which is the main fmap describing the whole image.
932 # Ultimately the EC will not have an fmap, since with software sync
933 # there is no flashrom involvement in updating the EC flash, and thus
934 # no need for the fmap.
935 # For now, mangle the fmap name to avoid problems.
936 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
937 data = self._tools.ReadFile(self.ecro_fname)
938 data = re.sub('__FMAP__', '__fMAP__', data)
939 self._tools.WriteFile(updated_ecro, data)
940 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700941 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700942 spl_payload = pack.GetBlobParams(blob_type)
943
944 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
945 # from all flash map files.
946 if not spl_payload:
947 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
948 prop_list = 'boot+dtb'
949
950 # Do this later, when we remove boot+dtb.
951 # raise CmdError("No parameters provided for blob type '%s'" %
952 # blob_type)
953 else:
954 prop_list = spl_payload[0].split(',')
955 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
956 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
957 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700958 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700959 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800960 elif pack.GetProperty(blob_type):
961 pass
962 else:
963 raise CmdError("Unknown blob type '%s' required in flash map" %
964 blob_type)
965
Simon Glass290a1802011-07-17 13:54:32 -0700966 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700967 """Create a full firmware image, along with various by-products.
968
969 This uses the provided u-boot.bin, fdt and bct to create a firmware
970 image containing all the required parts. If the GBB is not supplied
971 then this will just return a signed U-Boot as the image.
972
973 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200974 gbb: Full path to the GBB file, or empty if a GBB is not required.
975 fdt: Fdt object containing required information.
976
977 Returns:
978 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700979
980 Raises:
981 CmdError if a command fails.
982 """
Simon Glass02d124a2012-03-02 14:47:20 -0800983 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700984
Simon Glass439fe7a2012-03-09 16:19:34 -0800985 # Get the flashmap so we know what to build
986 pack = PackFirmware(self._tools, self._out)
Simon Glass0c54ba52012-11-06 12:36:43 -0800987 default_flashmap = default_flashmaps.get(self._board)
Simon Glassb8c6d952012-12-01 06:14:35 -0800988 if self._force_rw:
989 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
990 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
991
Simon Glass0c54ba52012-11-06 12:36:43 -0800992 pack.SelectFdt(fdt, self._board, default_flashmap)
Simon Glass439fe7a2012-03-09 16:19:34 -0800993
994 # Get all our blobs ready
995 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700996 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700997 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700998
Simon Glass47817052012-10-20 13:30:07 -0700999 # Let's create some copies of the fdt for vboot. These can be used to
1000 # pass a different fdt to each firmware type. For now it is just used to
1001 # check that the right fdt comes through.
1002 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
1003 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
1004 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
1005 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
1006 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
1007 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
1008 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
1009
Simon Glassde9c8072012-07-02 22:29:02 -07001010 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
1011 if self.kernel_fname:
1012 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
1013
Simon Glass50f74602012-03-15 21:04:25 -07001014 # Make a copy of the fdt for the bootstub
1015 fdt_data = self._tools.ReadFile(fdt.fname)
1016 uboot_data = self._tools.ReadFile(self.uboot_fname)
1017 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
1018 self._tools.WriteFile(uboot_copy, uboot_data)
1019
1020 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
1021 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -07001022
1023 # TODO(sjg@chromium.org): Deprecate this property when all boards
1024 # use a comma-separated list for section contents. We will then
1025 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -07001026 pack.AddProperty('boot+dtb', bootstub)
1027
Simon Glass439fe7a2012-03-09 16:19:34 -08001028 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +01001029 blob_list = pack.GetBlobList()
1030 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -07001031 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -08001032 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -07001033
1034 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -07001035 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +08001036 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -08001037 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +08001038 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -07001039 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -08001040 pack.AddProperty('fwid', fwid)
1041 pack.AddProperty('gbb', gbb)
1042 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -07001043
1044 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -07001045
1046 # Record position and size of all blob members in the FDT
1047 pack.UpdateBlobPositions(fdt)
1048
Simon Glasscbc83552012-07-23 15:26:22 +01001049 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
1050 # has created a rom file without the dtb, because until now it is not
1051 # complete. Add the dtb here.
1052 # A better anwer might be to put the dtb in memory immediately after
1053 # U-Boot as is done for ARM and have coreboot load it as a binary file
1054 # instead of an elf. However, I need to check whether coreboot supports
1055 # this, and whether this is desirable for other reasons.
1056 if 'coreboot' in blob_list:
1057 bootstub = pack.GetProperty('coreboot')
1058 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Stefan Reinauer1502ea62012-11-01 10:15:38 -07001059 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
1060 '-n', 'u-boot.dtb', '-t', '0xac'])
Stefan Reinauer728be822012-10-02 16:54:09 -07001061 bootstub_tmp = bootstub + '.tmp'
1062 self._tools.Run('dd', ['if=' + bootstub, 'of=' + bootstub_tmp,
1063 'bs=1M', 'skip=7'])
1064 shutil.move(bootstub_tmp, bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +01001065
Simon Glassc90cf582012-03-13 15:40:47 -07001066 image = os.path.join(self._tools.outdir, 'image.bin')
1067 pack.PackImage(self._tools.outdir, image)
1068 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -07001069
Simon Glass439fe7a2012-03-09 16:19:34 -08001070 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -07001071 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001072 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001073
Simon Glass290a1802011-07-17 13:54:32 -07001074 def SelectFdt(self, fdt_fname):
1075 """Select an FDT to control the firmware bundling
1076
1077 Args:
1078 fdt_fname: The filename of the fdt to use.
1079
Simon Glassc0f3dc62011-08-09 14:19:05 -07001080 Returns:
1081 The Fdt object of the original fdt file, which we will not modify.
1082
Simon Glass290a1802011-07-17 13:54:32 -07001083 We make a copy of this which will include any on-the-fly changes we want
1084 to make.
1085 """
1086 self._fdt_fname = fdt_fname
1087 self.CheckOptions()
1088 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -08001089 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -07001090 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -07001091 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001092
Simon Glassc90cf582012-03-13 15:40:47 -07001093 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001094 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001095
1096 - Checks options, tools, output directory, fdt.
1097 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001098
1099 Args:
Simon Glass56577572011-07-19 11:08:06 +12001100 hardware_id: Hardware ID to use for this board. If None, then the
1101 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001102 output_fname: Output filename for the image. If this is not None, then
1103 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001104 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001105
1106 Returns:
1107 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001108 """
Simon Glass89b86b82011-07-17 23:49:49 -07001109 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -07001110 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +12001111 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001112
1113 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001114 image, pack = self._CreateImage(gbb, self.fdt)
1115 if show_map:
1116 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001117 if output_fname:
1118 shutil.copyfile(image, output_fname)
1119 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001120 return image, pack.props