blob: fd0a73a906964b01f6656a57428082d0fd220a6b [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 Glassa10282a2013-01-08 17:06:41 -0800203 coreboot_elf=None,
Simon Glass07267952012-06-08 12:45:13 -0700204 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassbe0bc002012-08-16 12:50:48 -0700205 skeleton=None, ecrw=None, ecro=None, kernel=None):
Simon Glass290a1802011-07-17 13:54:32 -0700206 """Set up files required for Bundle.
207
208 Args:
209 board: The name of the board to target (e.g. tegra2_seaboard).
210 uboot: The filename of the u-boot.bin image to use.
211 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800212 bmpblk: The filename of bitmap block file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800213 coreboot: The filename of the coreboot image to use (on x86).
214 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200215 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700216 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700217 exynos_bl1: The filename of the exynos BL1 file
218 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
219 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700220 ecrw: The filename of the EC (Embedded Controller) read-write file.
221 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700222 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700223 """
224 self._board = board
225 self.uboot_fname = uboot
226 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800227 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700228 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800229 self.coreboot_elf = coreboot_elf
Simon Glass6dcc2f22011-07-28 15:26:49 +1200230 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700231 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700232 self.exynos_bl1 = exynos_bl1
233 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700234 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700235 self.ecrw_fname = ecrw
236 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700237 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700238
Simon Glass6e486c22012-10-26 15:43:42 -0700239 def SetOptions(self, small, gbb_flags, force_rw=False):
Simon Glass290a1802011-07-17 13:54:32 -0700240 """Set up options supported by Bundle.
241
242 Args:
243 small: Only create a signed U-Boot - don't produce the full packed
244 firmware image. This is useful for devs who want to replace just the
245 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700246 gbb_flags: Specification for string containing adjustments to make.
247 force_rw: Force firmware into RW mode.
Simon Glass290a1802011-07-17 13:54:32 -0700248 """
249 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700250 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700251 self._force_rw = force_rw
Simon Glass290a1802011-07-17 13:54:32 -0700252
253 def CheckOptions(self):
254 """Check provided options and select defaults."""
255 if not self._board:
256 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700257 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700258 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700259 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700260 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700261 base_name = re.sub('_', '-', self._board)
262
263 # In case the name exists with a prefix or suffix, find it.
264 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
265 found_list = glob.glob(self._tools.Filename(wildcard))
266 if len(found_list) == 1:
267 self._fdt_fname = found_list[0]
268 else:
269 # We didn't find anything definite, so set up our expected name.
270 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
271
Simon Glass881964d2012-04-04 11:34:09 -0700272 # Convert things like 'exynos5250-daisy' into a full path.
273 root, ext = os.path.splitext(self._fdt_fname)
274 if not ext and not os.path.dirname(root):
275 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
276
Simon Glass290a1802011-07-17 13:54:32 -0700277 if not self.uboot_fname:
278 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
279 if not self.bct_fname:
280 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700281 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700282 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700283 if not self.exynos_bl1:
284 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
285 if not self.exynos_bl2:
286 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700287 if not self.coreboot_fname:
288 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
289 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700290 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700291 if not self.seabios_fname:
292 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700293 if not self.ecrw_fname:
294 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
295 if not self.ecro_fname:
296 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700297
Simon Glass75759302012-03-15 20:26:53 -0700298 def GetFiles(self):
299 """Get a list of files that we know about.
300
301 This is the opposite of SetFiles except that we may have put in some
302 default names. It returns a dictionary containing the filename for
303 each of a number of pre-defined files.
304
305 Returns:
306 Dictionary, with one entry for each file.
307 """
308 file_list = {
309 'bct' : self.bct_fname,
310 'exynos-bl1' : self.exynos_bl1,
311 'exynos-bl2' : self.exynos_bl2,
312 }
313 return file_list
314
Simon Glass4a887b12012-10-23 16:29:03 -0700315 def DecodeGBBFlagsFromFdt(self):
316 """Get Google Binary Block flags from the FDT.
317
318 These should be in the chromeos-config node, like this:
319
320 chromeos-config {
321 gbb-flag-dev-screen-short-delay;
322 gbb-flag-force-dev-switch-on;
323 gbb-flag-force-dev-boot-usb;
324 gbb-flag-disable-fw-rollback-check;
325 };
326
327 Returns:
328 GBB flags value from FDT.
329 """
330 chromeos_config = self.fdt.GetProps("/chromeos-config")
331 gbb_flags = 0
332 for name in chromeos_config:
333 if name.startswith('gbb-flag-'):
334 flag_value = gbb_flag_properties.get(name[9:])
335 if flag_value:
336 gbb_flags |= flag_value
337 self._out.Notice("FDT: Enabling %s." % name)
338 else:
339 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
340 return gbb_flags
341
Simon Glass157c0662012-10-23 13:52:42 -0700342 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
343 """Decode ajustments to the provided GBB flags.
344
345 We support three options:
346
347 hex value: c2
348 defined value: force-dev-boot-usb,load-option-roms
349 adjust default value: -load-option-roms,+force-dev-boot-usb
350
351 The last option starts from the passed-in GBB flags and adds or removes
352 flags.
353
354 Args:
355 gbb_flags: Base (default) FDT flags.
356 adjustments: String containing adjustments to make.
357
358 Returns:
359 Updated FDT flags.
360 """
361 use_base_value = True
362 if adjustments:
363 try:
364 return int(adjustments, base=16)
365 except:
366 pass
367 for flag in adjustments.split(','):
368 oper = None
369 if flag[0] in ['-', '+']:
370 oper = flag[0]
371 flag = flag[1:]
372 value = gbb_flag_properties.get(flag)
373 if not value:
374 raise ValueError("Invalid GBB flag '%s'" % flag)
375 if oper == '+':
376 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800377 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700378 elif oper == '-':
379 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800380 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700381 else:
382 if use_base_value:
383 gbb_flags = 0
384 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800385 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700386 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800387 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700388
389 return gbb_flags
390
Simon Glass56577572011-07-19 11:08:06 +1200391 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700392 """Create a GBB for the image.
393
Simon Glass56577572011-07-19 11:08:06 +1200394 Args:
395 hardware_id: Hardware ID to use for this board. If None, then the
396 default from the Fdt will be used
397
Simon Glass89b86b82011-07-17 23:49:49 -0700398 Returns:
399 Path of the created GBB file.
400
401 Raises:
402 CmdError if a command fails.
403 """
Simon Glass56577572011-07-19 11:08:06 +1200404 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800405 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700406 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700407 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700408
Simon Glass4a887b12012-10-23 16:29:03 -0700409 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800410
Simon Glass157c0662012-10-23 13:52:42 -0700411 # Allow command line to override flags
412 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
413
Simon Glass4a887b12012-10-23 16:29:03 -0700414 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700415 self._out.Progress('Creating GBB')
416 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
417 sizes = ['%#x' % size for size in sizes]
418 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700419 keydir = self._tools.Filename(self._keydir)
420 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700421 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200422 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700423 '--rootkey=%s/root_key.vbpubk' % keydir,
424 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700425 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800426 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700427 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700428 cwd=odir)
429 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700430
Simon Glasse13ee2c2011-07-28 08:12:28 +1200431 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700432 """Sign an image so that the Tegra SOC will boot it.
433
434 Args:
435 bct: BCT file to use.
436 bootstub: Boot stub (U-Boot + fdt) file to sign.
437 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700438
439 Returns:
440 filename of signed image.
441
442 Raises:
443 CmdError if a command fails.
444 """
445 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200446 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700447 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200448 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700449 fd = open(config, 'w')
450 fd.write('Version = 1;\n')
451 fd.write('Redundancy = 1;\n')
452 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700453
454 # TODO(dianders): Right now, we don't have enough space in our flash map
455 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
456 # sure what this does for reliability, but at least things will fit...
457 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
458 if is_nand:
459 fd.write('Bctcopy = 1;\n')
460
Simon Glass89b86b82011-07-17 23:49:49 -0700461 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
462 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700463
Simon Glass89b86b82011-07-17 23:49:49 -0700464 fd.close()
465
466 self._tools.Run('cbootimage', [config, signed])
467 self._tools.OutputSize('BCT', bct)
468 self._tools.OutputSize('Signed image', signed)
469 return signed
470
Doug Anderson86ce5f42011-07-27 10:40:18 -0700471 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700472 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700473
474 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700475 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700476 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700477 """
Simon Glass468d8752012-09-19 16:36:19 -0700478 if bootcmd is not None:
479 if bootcmd == 'none':
480 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800481 self.fdt.PutString('/config', 'bootcmd', bootcmd)
482 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700483 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700484
Simon Glassa4934b72012-05-09 13:35:02 -0700485 def SetNodeEnabled(self, node_name, enabled):
486 """Set whether an node is enabled or disabled.
487
488 This simply sets the 'status' property of a node to "ok", or "disabled".
489
490 The node should either be a full path to the node (like '/uart@10200000')
491 or an alias property.
492
493 Aliases are supported like this:
494
495 aliases {
496 console = "/uart@10200000";
497 };
498
499 pointing to a node:
500
501 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700502 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700503 };
504
505 In this case, this function takes the name of the alias ('console' in
506 this case) and updates the status of the node that is pointed to, to
507 either ok or disabled. If the alias does not exist, a warning is
508 displayed.
509
510 Args:
511 node_name: Name of node (e.g. '/uart@10200000') or alias alias
512 (e.g. 'console') to adjust
513 enabled: True to enable, False to disable
514 """
515 # Look up the alias if this is an alias reference
516 if not node_name.startswith('/'):
517 lookup = self.fdt.GetString('/aliases', node_name, '')
518 if not lookup:
519 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
520 return
521 node_name = lookup
522 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700523 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700524 else:
525 status = 'disabled'
526 self.fdt.PutString(node_name, 'status', status)
527
528 def AddEnableList(self, enable_list):
529 """Process a list of nodes to enable/disable.
530
531 Args:
532 config_list: List of (node, value) tuples to add to the fdt. For each
533 tuple:
534 node: The fdt node to write to will be <node> or pointed to by
535 /aliases/<node>. We can tell which
536 value: 0 to disable the node, 1 to enable it
537 """
538 if enable_list:
539 for node_name, enabled in enable_list:
540 try:
541 enabled = int(enabled)
542 if enabled not in (0, 1):
543 raise ValueError
544 except ValueError as str:
545 raise CmdError("Invalid enable option value '%s' "
546 "(should be 0 or 1)" % enabled)
547 self.SetNodeEnabled(node_name, enabled)
548
Simon Glass290a1802011-07-17 13:54:32 -0700549 def AddConfigList(self, config_list, use_int=False):
550 """Add a list of config items to the fdt.
551
552 Normally these values are written to the fdt as strings, but integers
553 are also supported, in which case the values will be converted to integers
554 (if necessary) before being stored.
555
556 Args:
557 config_list: List of (config, value) tuples to add to the fdt. For each
558 tuple:
559 config: The fdt node to write to will be /config/<config>.
560 value: An integer or string value to write.
561 use_int: True to only write integer values.
562
563 Raises:
564 CmdError: if a value is required to be converted to integer but can't be.
565 """
566 if config_list:
567 for config in config_list:
568 value = config[1]
569 if use_int:
570 try:
571 value = int(value)
572 except ValueError as str:
573 raise CmdError("Cannot convert config option '%s' to integer" %
574 value)
575 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800576 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700577 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800578 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700579
Simon Glass7c2d5572011-11-15 14:47:08 -0800580 def DecodeTextBase(self, data):
581 """Look at a U-Boot image and try to decode its TEXT_BASE.
582
583 This works because U-Boot has a header with the value 0x12345678
584 immediately followed by the TEXT_BASE value. We can therefore read this
585 from the image with some certainty. We check only the first 40 words
586 since the header should be within that region.
587
Simon Glass96b50302012-07-20 06:55:28 +0100588 Since upstream Tegra has moved to having a 16KB SPL region at the start,
589 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
590 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
591
Simon Glass7c2d5572011-11-15 14:47:08 -0800592 Args:
593 data: U-Boot binary data
594
595 Returns:
596 Text base (integer) or None if none was found
597 """
598 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100599 for start in (0, 0x4000):
600 for i in range(start, start + 160, 4):
601 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800602
Simon Glass96b50302012-07-20 06:55:28 +0100603 # TODO(sjg): This does not cope with a big-endian target
604 value = struct.unpack('<I', word)[0]
605 if found:
606 return value - start
607 if value == 0x12345678:
608 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800609
610 return None
611
612 def CalcTextBase(self, name, fdt, fname):
613 """Calculate the TEXT_BASE to use for U-Boot.
614
615 Normally this value is in the fdt, so we just read it from there. But as
616 a second check we look at the image itself in case this is different, and
617 switch to that if it is.
618
619 This allows us to flash any U-Boot even if its TEXT_BASE is different.
620 This is particularly useful with upstream U-Boot which uses a different
621 value (which we will move to).
622 """
623 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800624 # The value that comes back from fdt.GetInt is signed, which makes no
625 # sense for an address base. Force it to unsigned.
626 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800627 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100628 text_base_str = '%#x' % text_base if text_base else 'None'
629 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
630 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800631
632 # If they are different, issue a warning and switch over.
633 if text_base and text_base != fdt_text_base:
634 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
635 "fdt value of %x. Using %x" % (text_base, name,
636 fdt_text_base, text_base))
637 fdt_text_base = text_base
638 return fdt_text_base
639
Simon Glass6dcc2f22011-07-28 15:26:49 +1200640 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700641 """Create a boot stub and a signed boot stub.
642
Simon Glass6dcc2f22011-07-28 15:26:49 +1200643 For postload:
644 We add a /config/postload-text-offset entry to the signed bootstub's
645 fdt so that U-Boot can find the postload code.
646
647 The raw (unsigned) bootstub will have a value of -1 for this since we will
648 simply append the postload code to the bootstub and it can find it there.
649 This will be used for RW A/B firmware.
650
651 For the signed case this value will specify where in the flash to find
652 the postload code. This will be used for RO firmware.
653
Simon Glass89b86b82011-07-17 23:49:49 -0700654 Args:
655 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800656 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200657 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700658
659 Returns:
660 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200661 Full path to bootstub (uboot + fdt(-1) + postload).
662 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700663
664 Raises:
665 CmdError if a command fails.
666 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200667 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800668 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700669 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200670
671 # Make a copy of the fdt for the bootstub
672 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800673 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700674 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200675
Simon Glass89b86b82011-07-17 23:49:49 -0700676 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700677 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
678 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700679 self._tools.OutputSize('Combined binary', bootstub)
680
Simon Glasse13ee2c2011-07-28 08:12:28 +1200681 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700682 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700683 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200684 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200685
686 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
687 data = self._tools.ReadFile(signed)
688
689 if postload:
690 # We must add postload to the bootstub since A and B will need to
691 # be able to find it without the /config/postload-text-offset mechanism.
692 bs_data = self._tools.ReadFile(bootstub)
693 bs_data += self._tools.ReadFile(postload)
694 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
695 self._tools.WriteFile(bootstub, bs_data)
696 self._tools.OutputSize('Combined binary with postload', bootstub)
697
698 # Now that we know the file size, adjust the fdt and re-sign
699 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800700 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200701 fdt_data = self._tools.ReadFile(fdt.fname)
702 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
703 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
704 postload_bootstub, text_base)
705 if len(data) != os.path.getsize(signed):
706 raise CmdError('Signed file size changed from %d to %d after updating '
707 'fdt' % (len(data), os.path.getsize(signed)))
708
709 # Re-read the signed image, and add the post-load binary.
710 data = self._tools.ReadFile(signed)
711 data += self._tools.ReadFile(postload)
712 self._tools.OutputSize('Post-load binary', postload)
713
714 self._tools.WriteFile(signed_postload, data)
715 self._tools.OutputSize('Final bootstub with postload', signed_postload)
716
717 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700718
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700719 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700720 """Create a coreboot boot stub.
721
722 Args:
723 uboot: Path to u-boot.bin (may be chroot-relative)
724 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700725 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700726
727 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100728 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700729
730 Raises:
731 CmdError if a command fails.
732 """
733 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700734 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100735
736 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700737 return bootstub
738
Simon Glass3b404092012-05-23 13:10:36 -0700739 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700740 """Update the parameters in a BL2 blob.
741
742 We look at the list in the parameter block, extract the value of each
743 from the device tree, and write that value to the parameter block.
744
745 Args:
746 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700747 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700748 data: The BL2 data.
749 pos: The position of the start of the parameter block.
750
751 Returns:
752 The new contents of the parameter block, after updating.
753 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700754 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
755 if version != 1:
756 raise CmdError("Cannot update machine parameter block version '%d'" %
757 version)
758 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700759 raise CmdError("Machine parameter block size %d is invalid: "
760 "pos=%d, size=%d, space=%d, len=%d" %
761 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700762
763 # Move past the header and read the parameter list, which is terminated
764 # with \0.
765 pos += 12
766 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
767 param_len = param_list.find('\0')
768 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700769 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700770
771 # Work through the parameters one at a time, adding each value
772 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700773 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700774 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700775 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glass56583742012-11-06 12:34:47 -0800776
777 # Use this to detect a missing value from the fdt.
778 not_given = 'not-given-invalid-value'
Simon Glassdf95dd22012-03-13 15:46:16 -0700779 if param == 'm' :
Simon Glass56583742012-11-06 12:34:47 -0800780 mem_type = fdt.GetString('/dmc', 'mem-type', not_given)
781 if mem_type == not_given:
782 mem_type = 'ddr3'
783 self._out.Warning("No value for memory type: using '%s'" % mem_type)
Simon Glassdf95dd22012-03-13 15:46:16 -0700784 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
785 if not mem_type in mem_types:
786 raise CmdError("Unknown memory type '%s'" % mem_type)
787 value = mem_types.index(mem_type)
788 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700789 elif param == 'M' :
Simon Glass56583742012-11-06 12:34:47 -0800790 mem_manuf = fdt.GetString('/dmc', 'mem-manuf', not_given)
791 if mem_manuf == not_given:
792 mem_manuf = 'samsung'
793 self._out.Warning("No value for memory manufacturer: using '%s'" %
794 mem_manuf)
Doug Andersonee46cfe2012-05-18 09:53:08 -0700795 mem_manufs = ['autodetect', 'elpida', 'samsung']
796 if not mem_manuf in mem_manufs:
797 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
798 value = mem_manufs.index(mem_manuf)
799 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700800 elif param == 'f' :
Simon Glass56583742012-11-06 12:34:47 -0800801 mem_freq = fdt.GetInt('/dmc', 'clock-frequency', -1)
802 if mem_freq == -1:
803 mem_freq = 800000000
804 self._out.Warning("No value for memory frequency: using '%s'" %
805 mem_freq)
806 mem_freq /= 1000000
Simon Glass158289e2012-09-14 11:42:25 -0700807 if not mem_freq in [533, 667, 800]:
808 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
809 value = mem_freq
810 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700811 elif param == 'v':
812 value = 31
813 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700814 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700815 value = (spl_load_size + 0xfff) & ~0xfff
816 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
817 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700818 elif param == 'b':
819 # These values come from enum boot_mode in U-Boot's cpu.h
820 if self.spl_source == 'straps':
821 value = 32
822 elif self.spl_source == 'emmc':
823 value = 4
824 elif self.spl_source == 'spi':
825 value = 20
826 elif self.spl_source == 'usb':
827 value = 33
828 else:
829 raise CmdError("Invalid boot source '%s'" % self.spl_source)
830 self._out.Info(' Boot source: %#0x' % value)
Tom Wai-Hong Tam99b7f112013-02-06 09:10:10 +0800831 elif param == 'z':
832 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
833 compress_types = ['none', 'lzo']
834 if not compress in compress_types:
835 raise CmdError("Unknown compression type '%s'" % compress)
836 value = compress_types.index(compress)
837 self._out.Info(' Compression type: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700838 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700839 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700840 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700841 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700842 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700843
844 # Put the data into our block.
845 data = data[:pos] + new_data + data[pos + len(new_data):]
846 self._out.Info('BL2 configuration complete')
847 return data
848
Simon Glasse5e8afb2012-05-23 11:19:23 -0700849 def _UpdateChecksum(self, data):
850 """Update the BL2 checksum.
851
852 The checksum is a 4 byte sum of all the bytes in the image before the
853 last 4 bytes (which hold the checksum).
854
855 Args:
856 data: The BL2 data to update.
857
858 Returns:
859 The new contents of the BL2 data, after updating the checksum.
860 """
861 checksum = 0
862 for ch in data[:-4]:
863 checksum += ord(ch)
864 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
865
Simon Glass559b6612012-05-23 13:28:45 -0700866 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700867 """Configure an Exynos BL2 binary for our needs.
868
869 We create a new modified BL2 and return its filename.
870
871 Args:
872 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700873 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700874 orig_bl2: Filename of original BL2 file to modify.
875 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700876 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700877 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700878 data = self._tools.ReadFile(orig_bl2)
879 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700880
881 # Locate the parameter block
882 data = self._tools.ReadFile(bl2)
883 marker = struct.pack('<L', 0xdeadbeef)
884 pos = data.rfind(marker)
885 if not pos:
886 raise CmdError("Could not find machine parameter block in '%s'" %
887 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700888 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700889 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700890 self._tools.WriteFile(bl2, data)
891 return bl2
892
Simon Glass89b86b82011-07-17 23:49:49 -0700893 def _PackOutput(self, msg):
894 """Helper function to write output from PackFirmware (verbose level 2).
895
896 This is passed to PackFirmware for it to use to write output.
897
898 Args:
899 msg: Message to display.
900 """
901 self._out.Notice(msg)
902
Simon Glass439fe7a2012-03-09 16:19:34 -0800903 def _BuildBlob(self, pack, fdt, blob_type):
904 """Build the blob data for a particular blob type.
905
906 Args:
907 blob_type: The type of blob to create data for. Supported types are:
908 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
909 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
910 """
911 if blob_type == 'coreboot':
912 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700913 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800914 pack.AddProperty('coreboot', coreboot)
915 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700916 elif blob_type == 'legacy':
917 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800918 elif blob_type == 'signed':
919 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
920 self.postload_fname)
921 pack.AddProperty('bootstub', bootstub)
922 pack.AddProperty('signed', signed)
923 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700924 elif blob_type == 'exynos-bl1':
925 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700926
927 # TODO(sjg@chromium.org): Deprecate ecbin
928 elif blob_type in ['ecrw', 'ecbin']:
929 pack.AddProperty('ecrw', self.ecrw_fname)
930 pack.AddProperty('ecbin', self.ecrw_fname)
931 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700932 # crosbug.com/p/13143
933 # We cannot have an fmap in the EC image since there can be only one,
934 # which is the main fmap describing the whole image.
935 # Ultimately the EC will not have an fmap, since with software sync
936 # there is no flashrom involvement in updating the EC flash, and thus
937 # no need for the fmap.
938 # For now, mangle the fmap name to avoid problems.
939 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
940 data = self._tools.ReadFile(self.ecro_fname)
941 data = re.sub('__FMAP__', '__fMAP__', data)
942 self._tools.WriteFile(updated_ecro, data)
943 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700944 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700945 spl_payload = pack.GetBlobParams(blob_type)
946
947 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
948 # from all flash map files.
949 if not spl_payload:
950 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
951 prop_list = 'boot+dtb'
952
953 # Do this later, when we remove boot+dtb.
954 # raise CmdError("No parameters provided for blob type '%s'" %
955 # blob_type)
956 else:
957 prop_list = spl_payload[0].split(',')
Tom Wai-Hong Tam26e3a4c2013-02-06 09:36:47 +0800958 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
959 if compress == 'none':
960 compress = None
961 spl_load_size = len(pack.ConcatPropContents(prop_list, compress,
962 False)[0])
Simon Glass7d2542f2012-06-21 07:10:59 -0700963 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
964 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700965 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700966 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800967 elif pack.GetProperty(blob_type):
968 pass
969 else:
970 raise CmdError("Unknown blob type '%s' required in flash map" %
971 blob_type)
972
Simon Glass290a1802011-07-17 13:54:32 -0700973 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700974 """Create a full firmware image, along with various by-products.
975
976 This uses the provided u-boot.bin, fdt and bct to create a firmware
977 image containing all the required parts. If the GBB is not supplied
978 then this will just return a signed U-Boot as the image.
979
980 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200981 gbb: Full path to the GBB file, or empty if a GBB is not required.
982 fdt: Fdt object containing required information.
983
984 Returns:
985 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700986
987 Raises:
988 CmdError if a command fails.
989 """
Simon Glass02d124a2012-03-02 14:47:20 -0800990 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700991
Simon Glass439fe7a2012-03-09 16:19:34 -0800992 # Get the flashmap so we know what to build
993 pack = PackFirmware(self._tools, self._out)
Simon Glass0c54ba52012-11-06 12:36:43 -0800994 default_flashmap = default_flashmaps.get(self._board)
Simon Glassb8c6d952012-12-01 06:14:35 -0800995 if self._force_rw:
996 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
997 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
998
Simon Glass0c54ba52012-11-06 12:36:43 -0800999 pack.SelectFdt(fdt, self._board, default_flashmap)
Simon Glass439fe7a2012-03-09 16:19:34 -08001000
1001 # Get all our blobs ready
1002 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -07001003 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -07001004 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -07001005
Simon Glass47817052012-10-20 13:30:07 -07001006 # Let's create some copies of the fdt for vboot. These can be used to
1007 # pass a different fdt to each firmware type. For now it is just used to
1008 # check that the right fdt comes through.
1009 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
1010 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
1011 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
1012 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
1013 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
1014 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
1015 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
1016
Simon Glassde9c8072012-07-02 22:29:02 -07001017 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
1018 if self.kernel_fname:
1019 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
1020
Simon Glass439fe7a2012-03-09 16:19:34 -08001021 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +01001022 blob_list = pack.GetBlobList()
1023 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -07001024 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -08001025 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -07001026
Simon Glass7306b902012-12-17 15:06:21 -08001027 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -07001028 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -07001029 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +08001030 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -08001031 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +08001032 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -07001033 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -08001034 pack.AddProperty('fwid', fwid)
1035 pack.AddProperty('gbb', gbb)
1036 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -07001037
1038 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -07001039
1040 # Record position and size of all blob members in the FDT
1041 pack.UpdateBlobPositions(fdt)
Gabe Black4c871d52012-12-05 00:00:23 -08001042 pack.UpdateBlobPositions(fdt_rwa)
1043 pack.UpdateBlobPositions(fdt_rwb)
Simon Glass8884b982012-06-21 12:41:41 -07001044
Simon Glass6207efe2012-12-17 15:04:36 -08001045 # Make a copy of the fdt for the bootstub
1046 fdt_data = self._tools.ReadFile(fdt.fname)
1047 uboot_data = self._tools.ReadFile(self.uboot_fname)
1048 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
1049 self._tools.WriteFile(uboot_copy, uboot_data)
1050
1051 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
1052 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
1053
Simon Glassa10282a2013-01-08 17:06:41 -08001054 # Fix up the coreboot image here, since we can't do this until we have
1055 # a final device tree binary.
Simon Glasscbc83552012-07-23 15:26:22 +01001056 if 'coreboot' in blob_list:
1057 bootstub = pack.GetProperty('coreboot')
1058 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -08001059 if self.coreboot_elf:
1060 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
1061 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
1062 else:
1063 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
1064 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
1065 '-l', '0x1110000', '-e', '0x1110008'])
Stefan Reinauer1502ea62012-11-01 10:15:38 -07001066 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
1067 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -08001068 data = self._tools.ReadFile(bootstub)
1069 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
1070 self._tools.WriteFile(bootstub_copy, data)
1071 self._tools.WriteFile(bootstub, data[0x700000:])
Simon Glasscbc83552012-07-23 15:26:22 +01001072
Simon Glassc90cf582012-03-13 15:40:47 -07001073 image = os.path.join(self._tools.outdir, 'image.bin')
1074 pack.PackImage(self._tools.outdir, image)
1075 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -07001076
Simon Glass439fe7a2012-03-09 16:19:34 -08001077 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -07001078 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001079 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001080
Simon Glass290a1802011-07-17 13:54:32 -07001081 def SelectFdt(self, fdt_fname):
1082 """Select an FDT to control the firmware bundling
1083
1084 Args:
1085 fdt_fname: The filename of the fdt to use.
1086
Simon Glassc0f3dc62011-08-09 14:19:05 -07001087 Returns:
1088 The Fdt object of the original fdt file, which we will not modify.
1089
Simon Glass290a1802011-07-17 13:54:32 -07001090 We make a copy of this which will include any on-the-fly changes we want
1091 to make.
1092 """
1093 self._fdt_fname = fdt_fname
1094 self.CheckOptions()
1095 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glassc3e42c32012-12-17 15:00:04 -08001096
1097 # For upstream, select the correct architecture .dtsi manually.
1098 if self._board == 'link' or 'x86' in self._board:
1099 arch_dts = 'coreboot.dtsi'
1100 elif self._board == 'daisy':
1101 arch_dts = 'exynos5250.dtsi'
1102 else:
1103 arch_dts = 'tegra20.dtsi'
1104
1105 fdt.Compile(arch_dts)
Simon Glass290a1802011-07-17 13:54:32 -07001106 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -07001107 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001108
Simon Glassc90cf582012-03-13 15:40:47 -07001109 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001110 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001111
1112 - Checks options, tools, output directory, fdt.
1113 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001114
1115 Args:
Simon Glass56577572011-07-19 11:08:06 +12001116 hardware_id: Hardware ID to use for this board. If None, then the
1117 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001118 output_fname: Output filename for the image. If this is not None, then
1119 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001120 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001121
1122 Returns:
1123 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001124 """
Simon Glass89b86b82011-07-17 23:49:49 -07001125 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -07001126 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +12001127 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001128
1129 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001130 image, pack = self._CreateImage(gbb, self.fdt)
1131 if show_map:
1132 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001133 if output_fname:
1134 shutil.copyfile(image, output_fname)
1135 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001136 return image, pack.props