blob: b55a085c53dac52f41a3f1b98042a40d54a06173 [file] [log] [blame]
Simon Glass89b86b82011-07-17 23:49:49 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This module builds a firmware image for a tegra-based board.
6
7This modules uses a few rudimentary other libraries for its activity.
8
9Here are the names we give to the various files we deal with. It is important
10to keep these consistent!
11
12 uboot u-boot.bin (with no device tree)
13 fdt the fdt blob
14 bct the BCT file
15 bootstub uboot + fdt
16 signed (uboot + fdt + bct) signed blob
17"""
18
Simon Glassceff3ff2012-04-04 11:23:45 -070019import glob
Gabe Blackcdbdfe12013-02-06 05:37:52 -080020import hashlib
Simon Glass89b86b82011-07-17 23:49:49 -070021import os
22import re
23
24import cros_output
25from fdt import Fdt
26from pack_firmware import PackFirmware
27import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080028import struct
Simon Glass89b86b82011-07-17 23:49:49 -070029import tempfile
Simon Glass439fe7a2012-03-09 16:19:34 -080030from tools import CmdError
Simon Glass89b86b82011-07-17 23:49:49 -070031from tools import Tools
32from write_firmware import WriteFirmware
33
34# This data is required by bmpblk_utility. Does it ever change?
35# It was stored with the chromeos-bootimage ebuild, but we want
36# this utility to work outside the chroot.
37yaml_data = '''
38bmpblock: 1.0
39
40images:
41 devmode: DeveloperBmp/DeveloperBmp.bmp
42 recovery: RecoveryBmp/RecoveryBmp.bmp
43 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
44 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
45
46screens:
47 dev_en:
48 - [0, 0, devmode]
49 rec_en:
50 - [0, 0, recovery]
51 yuck_en:
52 - [0, 0, rec_yuck]
53 ins_en:
54 - [0, 0, rec_insert]
55
56localizations:
57 - [ dev_en, rec_en, yuck_en, ins_en ]
58'''
59
Simon Glass0c54ba52012-11-06 12:36:43 -080060# Default flash maps for various boards we support.
61# These are used when no fdt is provided (e.g. upstream U-Boot with no
62# fdt. Each is a list of nodes.
63default_flashmaps = {
Simon Glass76958702012-11-08 13:07:53 -080064 'tegra' : [
65 {
Simon Glass0c54ba52012-11-06 12:36:43 -080066 'node' : 'ro-boot',
67 'label' : 'boot-stub',
68 'size' : 512 << 10,
69 'read-only' : True,
70 'type' : 'blob signed',
71 'required' : True
72 }
73 ],
74 'daisy' : [
75 {
76 'node' : 'pre-boot',
77 'label' : "bl1 pre-boot",
78 'size' : 0x2000,
79 'read-only' : True,
80 'filename' : "e5250.nbl1.bin",
81 'type' : "blob exynos-bl1",
82 'required' : True,
83 }, {
84 'node' : 'spl',
85 'label' : "bl2 spl",
86 'size' : 0x4000,
87 'read-only' : True,
88 'filename' : "bl2.bin",
89 'type' : "blob exynos-bl2 boot,dtb",
90 'required' : True,
91 }, {
92 'node' : 'ro-boot',
93 'label' : "u-boot",
94 'size' : 0x9a000,
95 'read-only' : True,
96 'type' : "blob boot,dtb",
97 'required' : True,
98 }
Simon Glass76958702012-11-08 13:07:53 -080099 ],
100 'link' : [
101 {
102 'node' : 'si-all',
103 'label' : 'si-all',
104 'reg' : '%d %d' % (0x00000000, 0x00200000),
105 'type' : 'ifd',
106 'required' : True,
107 }, {
108 'node' : 'ro-boot',
109 'label' : 'boot-stub',
110 'reg' : '%d %d' % (0x00700000, 0x00100000),
111 'read-only' : True,
112 'type' : 'blob coreboot',
113 'required' : True,
114 }
Simon Glass0c54ba52012-11-06 12:36:43 -0800115 ]
116}
117
118
Simon Glass4a887b12012-10-23 16:29:03 -0700119# Build GBB flags.
120# (src/platform/vboot_reference/firmware/include/gbb_header.h)
121gbb_flag_properties = {
122 'dev-screen-short-delay': 0x00000001,
123 'load-option-roms': 0x00000002,
124 'enable-alternate-os': 0x00000004,
125 'force-dev-switch-on': 0x00000008,
126 'force-dev-boot-usb': 0x00000010,
127 'disable-fw-rollback-check': 0x00000020,
128 'enter-triggers-tonorm': 0x00000040,
129 'force-dev-boot-legacy': 0x00000080,
130}
131
Simon Glass5076a7f2012-10-23 16:31:54 -0700132def ListGoogleBinaryBlockFlags():
133 """Print out a list of GBB flags."""
134 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
135 for name, value in gbb_flag_properties.iteritems():
136 print ' %-30s %02x' % (name, value)
137
Simon Glass89b86b82011-07-17 23:49:49 -0700138class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -0700139 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -0700140
Simon Glass290a1802011-07-17 13:54:32 -0700141 Sequence of events:
142 bundle = Bundle(tools.Tools(), cros_output.Output())
143 bundle.SetDirs(...)
144 bundle.SetFiles(...)
145 bundle.SetOptions(...)
146 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -0700147 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -0700148 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -0700149
Simon Glass290a1802011-07-17 13:54:32 -0700150 Public properties:
151 fdt: The fdt object that we use for building our image. This wil be the
152 one specified by the user, except that we might add config options
153 to it. This is set up by SelectFdt() which must be called before
154 bundling starts.
155 uboot_fname: Full filename of the U-Boot binary we use.
156 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -0700157 spl_source: Source device to load U-Boot from, in SPL:
158 straps: Select device according to CPU strap pins
159 spi: Boot from SPI
160 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -0700161
162 Private attributes:
163 _small: True to create a 'small' signed U-Boot, False to produce a
164 full image. The small U-Boot is enough to boot but will not have
165 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700166 """
Simon Glass89b86b82011-07-17 23:49:49 -0700167
Simon Glass290a1802011-07-17 13:54:32 -0700168 def __init__(self, tools, output):
169 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700170
Simon Glass290a1802011-07-17 13:54:32 -0700171 Args:
172 tools: A tools.Tools object to use for external tools.
173 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700174 """
Simon Glass290a1802011-07-17 13:54:32 -0700175 self._tools = tools
176 self._out = output
177
178 # Set up the things we need to know in order to operate.
179 self._board = None # Board name, e.g. tegra2_seaboard.
180 self._fdt_fname = None # Filename of our FDT.
181 self.uboot_fname = None # Filename of our U-Boot binary.
182 self.bct_fname = None # Filename of our BCT file.
183 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800184 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700185 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -0700186 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -0700187 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
188 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass559b6612012-05-23 13:28:45 -0700189 self.spl_source = 'straps' # SPL boot according to board settings
Simon Glass07267952012-06-08 12:45:13 -0700190 self.skeleton_fname = None # Filename of Coreboot skeleton file
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800191 self.ecrw_fname = None # Filename of EC file
Simon Glassbe0bc002012-08-16 12:50:48 -0700192 self.ecro_fname = None # Filename of EC read-only file
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800193 self.blobs = {} # Table of (type, filename) of arbitrary blobs
Simon Glass23988ae2012-03-23 16:55:22 -0700194 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700195
196 def SetDirs(self, keydir):
197 """Set up directories required for Bundle.
198
199 Args:
200 keydir: Directory containing keys to use for signing firmware.
201 """
202 self._keydir = keydir
203
Simon Glass6dcc2f22011-07-28 15:26:49 +1200204 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800205 coreboot_elf=None,
Simon Glass07267952012-06-08 12:45:13 -0700206 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800207 skeleton=None, ecrw=None, ecro=None, kernel=None, blobs=None):
Simon Glass290a1802011-07-17 13:54:32 -0700208 """Set up files required for Bundle.
209
210 Args:
211 board: The name of the board to target (e.g. tegra2_seaboard).
212 uboot: The filename of the u-boot.bin image to use.
213 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800214 bmpblk: The filename of bitmap block file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800215 coreboot: The filename of the coreboot image to use (on x86).
216 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200217 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700218 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700219 exynos_bl1: The filename of the exynos BL1 file
220 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
221 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700222 ecrw: The filename of the EC (Embedded Controller) read-write file.
223 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700224 kernel: The filename of the kernel file if any.
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800225 blobs: List of (type, filename) of arbitrary blobs.
Simon Glass290a1802011-07-17 13:54:32 -0700226 """
227 self._board = board
228 self.uboot_fname = uboot
229 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800230 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700231 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800232 self.coreboot_elf = coreboot_elf
Simon Glass6dcc2f22011-07-28 15:26:49 +1200233 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700234 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700235 self.exynos_bl1 = exynos_bl1
236 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700237 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700238 self.ecrw_fname = ecrw
239 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700240 self.kernel_fname = kernel
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -0800241 self.blobs = dict(blobs or ())
Simon Glass290a1802011-07-17 13:54:32 -0700242
Simon Glass6e486c22012-10-26 15:43:42 -0700243 def SetOptions(self, small, gbb_flags, force_rw=False):
Simon Glass290a1802011-07-17 13:54:32 -0700244 """Set up options supported by Bundle.
245
246 Args:
247 small: Only create a signed U-Boot - don't produce the full packed
248 firmware image. This is useful for devs who want to replace just the
249 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700250 gbb_flags: Specification for string containing adjustments to make.
251 force_rw: Force firmware into RW mode.
Simon Glass290a1802011-07-17 13:54:32 -0700252 """
253 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700254 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700255 self._force_rw = force_rw
Simon Glass290a1802011-07-17 13:54:32 -0700256
Simon Glass22f39fb2013-02-09 13:44:14 -0800257 def _GetBuildRoot(self):
258 """Get the path to this board's 'firmware' directory.
259
260 Returns:
261 Path to firmware directory, with ## representing the path to the
262 chroot.
263 """
Simon Glass290a1802011-07-17 13:54:32 -0700264 if not self._board:
265 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800266 return os.path.join('##', 'build', self._board, 'firmware')
267
268 def _CheckFdtFilename(self, fname):
269 """Check provided FDT filename and return the correct name if needed.
270
271 Where the filename lacks a path, add a default path for this board.
272 Where no FDT filename is provided, select a default one for this board.
273
274 Args:
275 fname: Proposed FDT filename.
276
277 Returns:
278 Selected FDT filename, after validation.
279 """
280 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700281 dir_name = os.path.join(build_root, 'dts')
Simon Glass22f39fb2013-02-09 13:44:14 -0800282 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700283 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700284 base_name = re.sub('_', '-', self._board)
285
286 # In case the name exists with a prefix or suffix, find it.
287 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
288 found_list = glob.glob(self._tools.Filename(wildcard))
289 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800290 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700291 else:
292 # We didn't find anything definite, so set up our expected name.
Simon Glass22f39fb2013-02-09 13:44:14 -0800293 fname = os.path.join(dir_name, '%s.dts' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700294
Simon Glass881964d2012-04-04 11:34:09 -0700295 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800296 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700297 if not ext and not os.path.dirname(root):
Simon Glass22f39fb2013-02-09 13:44:14 -0800298 fname = os.path.join(dir_name, '%s.dts' % root)
299 return fname
300
301 def CheckOptions(self):
302 """Check provided options and select defaults."""
303 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700304
Simon Glass290a1802011-07-17 13:54:32 -0700305 if not self.uboot_fname:
306 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
307 if not self.bct_fname:
308 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700309 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700310 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700311 if not self.exynos_bl1:
312 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
313 if not self.exynos_bl2:
314 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700315 if not self.coreboot_fname:
316 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
317 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700318 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700319 if not self.seabios_fname:
320 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700321 if not self.ecrw_fname:
322 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
323 if not self.ecro_fname:
324 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700325
Simon Glass75759302012-03-15 20:26:53 -0700326 def GetFiles(self):
327 """Get a list of files that we know about.
328
329 This is the opposite of SetFiles except that we may have put in some
330 default names. It returns a dictionary containing the filename for
331 each of a number of pre-defined files.
332
333 Returns:
334 Dictionary, with one entry for each file.
335 """
336 file_list = {
337 'bct' : self.bct_fname,
338 'exynos-bl1' : self.exynos_bl1,
339 'exynos-bl2' : self.exynos_bl2,
340 }
341 return file_list
342
Simon Glass4a887b12012-10-23 16:29:03 -0700343 def DecodeGBBFlagsFromFdt(self):
344 """Get Google Binary Block flags from the FDT.
345
346 These should be in the chromeos-config node, like this:
347
348 chromeos-config {
349 gbb-flag-dev-screen-short-delay;
350 gbb-flag-force-dev-switch-on;
351 gbb-flag-force-dev-boot-usb;
352 gbb-flag-disable-fw-rollback-check;
353 };
354
355 Returns:
356 GBB flags value from FDT.
357 """
358 chromeos_config = self.fdt.GetProps("/chromeos-config")
359 gbb_flags = 0
360 for name in chromeos_config:
361 if name.startswith('gbb-flag-'):
362 flag_value = gbb_flag_properties.get(name[9:])
363 if flag_value:
364 gbb_flags |= flag_value
365 self._out.Notice("FDT: Enabling %s." % name)
366 else:
367 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
368 return gbb_flags
369
Simon Glass157c0662012-10-23 13:52:42 -0700370 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
371 """Decode ajustments to the provided GBB flags.
372
373 We support three options:
374
375 hex value: c2
376 defined value: force-dev-boot-usb,load-option-roms
377 adjust default value: -load-option-roms,+force-dev-boot-usb
378
379 The last option starts from the passed-in GBB flags and adds or removes
380 flags.
381
382 Args:
383 gbb_flags: Base (default) FDT flags.
384 adjustments: String containing adjustments to make.
385
386 Returns:
387 Updated FDT flags.
388 """
389 use_base_value = True
390 if adjustments:
391 try:
392 return int(adjustments, base=16)
393 except:
394 pass
395 for flag in adjustments.split(','):
396 oper = None
397 if flag[0] in ['-', '+']:
398 oper = flag[0]
399 flag = flag[1:]
400 value = gbb_flag_properties.get(flag)
401 if not value:
402 raise ValueError("Invalid GBB flag '%s'" % flag)
403 if oper == '+':
404 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800405 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700406 elif oper == '-':
407 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800408 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700409 else:
410 if use_base_value:
411 gbb_flags = 0
412 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800413 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700414 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800415 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700416
417 return gbb_flags
418
Simon Glass56577572011-07-19 11:08:06 +1200419 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700420 """Create a GBB for the image.
421
Simon Glass56577572011-07-19 11:08:06 +1200422 Args:
423 hardware_id: Hardware ID to use for this board. If None, then the
424 default from the Fdt will be used
425
Simon Glass89b86b82011-07-17 23:49:49 -0700426 Returns:
427 Path of the created GBB file.
428
429 Raises:
430 CmdError if a command fails.
431 """
Simon Glass56577572011-07-19 11:08:06 +1200432 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800433 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700434 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700435 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700436
Simon Glass4a887b12012-10-23 16:29:03 -0700437 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800438
Simon Glass157c0662012-10-23 13:52:42 -0700439 # Allow command line to override flags
440 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
441
Simon Glass4a887b12012-10-23 16:29:03 -0700442 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700443 self._out.Progress('Creating GBB')
444 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
445 sizes = ['%#x' % size for size in sizes]
446 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700447 keydir = self._tools.Filename(self._keydir)
448 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700449 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200450 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700451 '--rootkey=%s/root_key.vbpubk' % keydir,
452 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700453 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800454 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700455 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700456 cwd=odir)
457 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700458
Simon Glasse13ee2c2011-07-28 08:12:28 +1200459 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700460 """Sign an image so that the Tegra SOC will boot it.
461
462 Args:
463 bct: BCT file to use.
464 bootstub: Boot stub (U-Boot + fdt) file to sign.
465 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700466
467 Returns:
468 filename of signed image.
469
470 Raises:
471 CmdError if a command fails.
472 """
473 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200474 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700475 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200476 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700477 fd = open(config, 'w')
478 fd.write('Version = 1;\n')
479 fd.write('Redundancy = 1;\n')
480 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700481
482 # TODO(dianders): Right now, we don't have enough space in our flash map
483 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
484 # sure what this does for reliability, but at least things will fit...
485 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
486 if is_nand:
487 fd.write('Bctcopy = 1;\n')
488
Simon Glass89b86b82011-07-17 23:49:49 -0700489 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
490 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700491
Simon Glass89b86b82011-07-17 23:49:49 -0700492 fd.close()
493
494 self._tools.Run('cbootimage', [config, signed])
495 self._tools.OutputSize('BCT', bct)
496 self._tools.OutputSize('Signed image', signed)
497 return signed
498
Doug Anderson86ce5f42011-07-27 10:40:18 -0700499 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700500 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700501
502 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700503 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700504 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700505 """
Simon Glass468d8752012-09-19 16:36:19 -0700506 if bootcmd is not None:
507 if bootcmd == 'none':
508 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800509 self.fdt.PutString('/config', 'bootcmd', bootcmd)
510 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700511 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700512
Simon Glassa4934b72012-05-09 13:35:02 -0700513 def SetNodeEnabled(self, node_name, enabled):
514 """Set whether an node is enabled or disabled.
515
516 This simply sets the 'status' property of a node to "ok", or "disabled".
517
518 The node should either be a full path to the node (like '/uart@10200000')
519 or an alias property.
520
521 Aliases are supported like this:
522
523 aliases {
524 console = "/uart@10200000";
525 };
526
527 pointing to a node:
528
529 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700530 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700531 };
532
533 In this case, this function takes the name of the alias ('console' in
534 this case) and updates the status of the node that is pointed to, to
535 either ok or disabled. If the alias does not exist, a warning is
536 displayed.
537
538 Args:
539 node_name: Name of node (e.g. '/uart@10200000') or alias alias
540 (e.g. 'console') to adjust
541 enabled: True to enable, False to disable
542 """
543 # Look up the alias if this is an alias reference
544 if not node_name.startswith('/'):
545 lookup = self.fdt.GetString('/aliases', node_name, '')
546 if not lookup:
547 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
548 return
549 node_name = lookup
550 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700551 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700552 else:
553 status = 'disabled'
554 self.fdt.PutString(node_name, 'status', status)
555
556 def AddEnableList(self, enable_list):
557 """Process a list of nodes to enable/disable.
558
559 Args:
560 config_list: List of (node, value) tuples to add to the fdt. For each
561 tuple:
562 node: The fdt node to write to will be <node> or pointed to by
563 /aliases/<node>. We can tell which
564 value: 0 to disable the node, 1 to enable it
565 """
566 if enable_list:
567 for node_name, enabled in enable_list:
568 try:
569 enabled = int(enabled)
570 if enabled not in (0, 1):
571 raise ValueError
572 except ValueError as str:
573 raise CmdError("Invalid enable option value '%s' "
574 "(should be 0 or 1)" % enabled)
575 self.SetNodeEnabled(node_name, enabled)
576
Simon Glass290a1802011-07-17 13:54:32 -0700577 def AddConfigList(self, config_list, use_int=False):
578 """Add a list of config items to the fdt.
579
580 Normally these values are written to the fdt as strings, but integers
581 are also supported, in which case the values will be converted to integers
582 (if necessary) before being stored.
583
584 Args:
585 config_list: List of (config, value) tuples to add to the fdt. For each
586 tuple:
587 config: The fdt node to write to will be /config/<config>.
588 value: An integer or string value to write.
589 use_int: True to only write integer values.
590
591 Raises:
592 CmdError: if a value is required to be converted to integer but can't be.
593 """
594 if config_list:
595 for config in config_list:
596 value = config[1]
597 if use_int:
598 try:
599 value = int(value)
600 except ValueError as str:
601 raise CmdError("Cannot convert config option '%s' to integer" %
602 value)
603 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800604 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700605 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800606 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700607
Simon Glass7c2d5572011-11-15 14:47:08 -0800608 def DecodeTextBase(self, data):
609 """Look at a U-Boot image and try to decode its TEXT_BASE.
610
611 This works because U-Boot has a header with the value 0x12345678
612 immediately followed by the TEXT_BASE value. We can therefore read this
613 from the image with some certainty. We check only the first 40 words
614 since the header should be within that region.
615
Simon Glass96b50302012-07-20 06:55:28 +0100616 Since upstream Tegra has moved to having a 16KB SPL region at the start,
617 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
618 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
619
Simon Glass7c2d5572011-11-15 14:47:08 -0800620 Args:
621 data: U-Boot binary data
622
623 Returns:
624 Text base (integer) or None if none was found
625 """
626 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100627 for start in (0, 0x4000):
628 for i in range(start, start + 160, 4):
629 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800630
Simon Glass96b50302012-07-20 06:55:28 +0100631 # TODO(sjg): This does not cope with a big-endian target
632 value = struct.unpack('<I', word)[0]
633 if found:
634 return value - start
635 if value == 0x12345678:
636 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800637
638 return None
639
640 def CalcTextBase(self, name, fdt, fname):
641 """Calculate the TEXT_BASE to use for U-Boot.
642
643 Normally this value is in the fdt, so we just read it from there. But as
644 a second check we look at the image itself in case this is different, and
645 switch to that if it is.
646
647 This allows us to flash any U-Boot even if its TEXT_BASE is different.
648 This is particularly useful with upstream U-Boot which uses a different
649 value (which we will move to).
650 """
651 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800652 # The value that comes back from fdt.GetInt is signed, which makes no
653 # sense for an address base. Force it to unsigned.
654 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800655 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100656 text_base_str = '%#x' % text_base if text_base else 'None'
657 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
658 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800659
660 # If they are different, issue a warning and switch over.
661 if text_base and text_base != fdt_text_base:
662 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
663 "fdt value of %x. Using %x" % (text_base, name,
664 fdt_text_base, text_base))
665 fdt_text_base = text_base
666 return fdt_text_base
667
Simon Glass6dcc2f22011-07-28 15:26:49 +1200668 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700669 """Create a boot stub and a signed boot stub.
670
Simon Glass6dcc2f22011-07-28 15:26:49 +1200671 For postload:
672 We add a /config/postload-text-offset entry to the signed bootstub's
673 fdt so that U-Boot can find the postload code.
674
675 The raw (unsigned) bootstub will have a value of -1 for this since we will
676 simply append the postload code to the bootstub and it can find it there.
677 This will be used for RW A/B firmware.
678
679 For the signed case this value will specify where in the flash to find
680 the postload code. This will be used for RO firmware.
681
Simon Glass89b86b82011-07-17 23:49:49 -0700682 Args:
683 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800684 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200685 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700686
687 Returns:
688 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200689 Full path to bootstub (uboot + fdt(-1) + postload).
690 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700691
692 Raises:
693 CmdError if a command fails.
694 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200695 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800696 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700697 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200698
699 # Make a copy of the fdt for the bootstub
700 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800701 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700702 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200703
Simon Glass89b86b82011-07-17 23:49:49 -0700704 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700705 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
706 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700707 self._tools.OutputSize('Combined binary', bootstub)
708
Simon Glasse13ee2c2011-07-28 08:12:28 +1200709 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700710 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700711 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200712 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200713
714 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
715 data = self._tools.ReadFile(signed)
716
717 if postload:
718 # We must add postload to the bootstub since A and B will need to
719 # be able to find it without the /config/postload-text-offset mechanism.
720 bs_data = self._tools.ReadFile(bootstub)
721 bs_data += self._tools.ReadFile(postload)
722 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
723 self._tools.WriteFile(bootstub, bs_data)
724 self._tools.OutputSize('Combined binary with postload', bootstub)
725
726 # Now that we know the file size, adjust the fdt and re-sign
727 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800728 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200729 fdt_data = self._tools.ReadFile(fdt.fname)
730 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
731 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
732 postload_bootstub, text_base)
733 if len(data) != os.path.getsize(signed):
734 raise CmdError('Signed file size changed from %d to %d after updating '
735 'fdt' % (len(data), os.path.getsize(signed)))
736
737 # Re-read the signed image, and add the post-load binary.
738 data = self._tools.ReadFile(signed)
739 data += self._tools.ReadFile(postload)
740 self._tools.OutputSize('Post-load binary', postload)
741
742 self._tools.WriteFile(signed_postload, data)
743 self._tools.OutputSize('Final bootstub with postload', signed_postload)
744
745 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700746
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700747 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700748 """Create a coreboot boot stub.
749
750 Args:
751 uboot: Path to u-boot.bin (may be chroot-relative)
752 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700753 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700754
755 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100756 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700757
758 Raises:
759 CmdError if a command fails.
760 """
761 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700762 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100763
764 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700765 return bootstub
766
Simon Glass3b404092012-05-23 13:10:36 -0700767 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700768 """Update the parameters in a BL2 blob.
769
770 We look at the list in the parameter block, extract the value of each
771 from the device tree, and write that value to the parameter block.
772
773 Args:
774 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700775 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700776 data: The BL2 data.
777 pos: The position of the start of the parameter block.
778
779 Returns:
780 The new contents of the parameter block, after updating.
781 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700782 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
783 if version != 1:
784 raise CmdError("Cannot update machine parameter block version '%d'" %
785 version)
786 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700787 raise CmdError("Machine parameter block size %d is invalid: "
788 "pos=%d, size=%d, space=%d, len=%d" %
789 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700790
791 # Move past the header and read the parameter list, which is terminated
792 # with \0.
793 pos += 12
794 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
795 param_len = param_list.find('\0')
796 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700797 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700798
799 # Work through the parameters one at a time, adding each value
800 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700801 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700802 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700803 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glass56583742012-11-06 12:34:47 -0800804
805 # Use this to detect a missing value from the fdt.
806 not_given = 'not-given-invalid-value'
Simon Glassdf95dd22012-03-13 15:46:16 -0700807 if param == 'm' :
Simon Glass56583742012-11-06 12:34:47 -0800808 mem_type = fdt.GetString('/dmc', 'mem-type', not_given)
809 if mem_type == not_given:
810 mem_type = 'ddr3'
811 self._out.Warning("No value for memory type: using '%s'" % mem_type)
Simon Glassdf95dd22012-03-13 15:46:16 -0700812 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
813 if not mem_type in mem_types:
814 raise CmdError("Unknown memory type '%s'" % mem_type)
815 value = mem_types.index(mem_type)
816 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700817 elif param == 'M' :
Simon Glass56583742012-11-06 12:34:47 -0800818 mem_manuf = fdt.GetString('/dmc', 'mem-manuf', not_given)
819 if mem_manuf == not_given:
820 mem_manuf = 'samsung'
821 self._out.Warning("No value for memory manufacturer: using '%s'" %
822 mem_manuf)
Doug Andersonee46cfe2012-05-18 09:53:08 -0700823 mem_manufs = ['autodetect', 'elpida', 'samsung']
824 if not mem_manuf in mem_manufs:
825 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
826 value = mem_manufs.index(mem_manuf)
827 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700828 elif param == 'f' :
Simon Glass56583742012-11-06 12:34:47 -0800829 mem_freq = fdt.GetInt('/dmc', 'clock-frequency', -1)
830 if mem_freq == -1:
831 mem_freq = 800000000
832 self._out.Warning("No value for memory frequency: using '%s'" %
833 mem_freq)
834 mem_freq /= 1000000
Simon Glass158289e2012-09-14 11:42:25 -0700835 if not mem_freq in [533, 667, 800]:
836 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
837 value = mem_freq
838 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700839 elif param == 'v':
840 value = 31
841 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700842 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700843 value = (spl_load_size + 0xfff) & ~0xfff
844 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
845 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700846 elif param == 'b':
847 # These values come from enum boot_mode in U-Boot's cpu.h
848 if self.spl_source == 'straps':
849 value = 32
850 elif self.spl_source == 'emmc':
851 value = 4
852 elif self.spl_source == 'spi':
853 value = 20
854 elif self.spl_source == 'usb':
855 value = 33
856 else:
857 raise CmdError("Invalid boot source '%s'" % self.spl_source)
858 self._out.Info(' Boot source: %#0x' % value)
Tom Wai-Hong Tam99b7f112013-02-06 09:10:10 +0800859 elif param == 'z':
860 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
861 compress_types = ['none', 'lzo']
862 if not compress in compress_types:
863 raise CmdError("Unknown compression type '%s'" % compress)
864 value = compress_types.index(compress)
865 self._out.Info(' Compression type: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700866 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700867 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700868 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700869 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700870 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700871
872 # Put the data into our block.
873 data = data[:pos] + new_data + data[pos + len(new_data):]
874 self._out.Info('BL2 configuration complete')
875 return data
876
Simon Glasse5e8afb2012-05-23 11:19:23 -0700877 def _UpdateChecksum(self, data):
878 """Update the BL2 checksum.
879
880 The checksum is a 4 byte sum of all the bytes in the image before the
881 last 4 bytes (which hold the checksum).
882
883 Args:
884 data: The BL2 data to update.
885
886 Returns:
887 The new contents of the BL2 data, after updating the checksum.
888 """
889 checksum = 0
890 for ch in data[:-4]:
891 checksum += ord(ch)
892 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
893
Simon Glass559b6612012-05-23 13:28:45 -0700894 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700895 """Configure an Exynos BL2 binary for our needs.
896
897 We create a new modified BL2 and return its filename.
898
899 Args:
900 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700901 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700902 orig_bl2: Filename of original BL2 file to modify.
903 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700904 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700905 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700906 data = self._tools.ReadFile(orig_bl2)
907 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700908
909 # Locate the parameter block
910 data = self._tools.ReadFile(bl2)
911 marker = struct.pack('<L', 0xdeadbeef)
912 pos = data.rfind(marker)
913 if not pos:
914 raise CmdError("Could not find machine parameter block in '%s'" %
915 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700916 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700917 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700918 self._tools.WriteFile(bl2, data)
919 return bl2
920
Simon Glass89b86b82011-07-17 23:49:49 -0700921 def _PackOutput(self, msg):
922 """Helper function to write output from PackFirmware (verbose level 2).
923
924 This is passed to PackFirmware for it to use to write output.
925
926 Args:
927 msg: Message to display.
928 """
929 self._out.Notice(msg)
930
Simon Glass439fe7a2012-03-09 16:19:34 -0800931 def _BuildBlob(self, pack, fdt, blob_type):
932 """Build the blob data for a particular blob type.
933
934 Args:
935 blob_type: The type of blob to create data for. Supported types are:
936 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
937 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
938 """
939 if blob_type == 'coreboot':
940 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700941 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800942 pack.AddProperty('coreboot', coreboot)
943 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700944 elif blob_type == 'legacy':
945 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800946 elif blob_type == 'signed':
947 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
948 self.postload_fname)
949 pack.AddProperty('bootstub', bootstub)
950 pack.AddProperty('signed', signed)
951 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700952 elif blob_type == 'exynos-bl1':
953 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700954
955 # TODO(sjg@chromium.org): Deprecate ecbin
956 elif blob_type in ['ecrw', 'ecbin']:
957 pack.AddProperty('ecrw', self.ecrw_fname)
958 pack.AddProperty('ecbin', self.ecrw_fname)
Gabe Blackcdbdfe12013-02-06 05:37:52 -0800959 elif blob_type == 'ecrwhash':
960 ec_hash_file = os.path.join(self._tools.outdir, 'ec_hash.bin')
961 ecrw = self._tools.ReadFile(self.ecrw_fname)
962 hasher = hashlib.sha256()
963 hasher.update(ecrw)
964 self._tools.WriteFile(ec_hash_file, hasher.digest())
965 pack.AddProperty(blob_type, ec_hash_file)
Simon Glassbe0bc002012-08-16 12:50:48 -0700966 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700967 # crosbug.com/p/13143
968 # We cannot have an fmap in the EC image since there can be only one,
969 # which is the main fmap describing the whole image.
970 # Ultimately the EC will not have an fmap, since with software sync
971 # there is no flashrom involvement in updating the EC flash, and thus
972 # no need for the fmap.
973 # For now, mangle the fmap name to avoid problems.
974 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
975 data = self._tools.ReadFile(self.ecro_fname)
976 data = re.sub('__FMAP__', '__fMAP__', data)
977 self._tools.WriteFile(updated_ecro, data)
978 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700979 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700980 spl_payload = pack.GetBlobParams(blob_type)
981
982 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
983 # from all flash map files.
984 if not spl_payload:
985 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
986 prop_list = 'boot+dtb'
987
988 # Do this later, when we remove boot+dtb.
989 # raise CmdError("No parameters provided for blob type '%s'" %
990 # blob_type)
991 else:
992 prop_list = spl_payload[0].split(',')
Tom Wai-Hong Tam26e3a4c2013-02-06 09:36:47 +0800993 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
994 if compress == 'none':
995 compress = None
996 spl_load_size = len(pack.ConcatPropContents(prop_list, compress,
997 False)[0])
Simon Glass7d2542f2012-06-21 07:10:59 -0700998 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
999 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -07001000 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -07001001 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -08001002 elif pack.GetProperty(blob_type):
1003 pass
Che-Liang Chiou3bc344c2013-02-21 15:18:03 -08001004 elif blob_type in self.blobs:
1005 pack.AddProperty(blob_type, self.blobs[blob_type])
Simon Glass439fe7a2012-03-09 16:19:34 -08001006 else:
1007 raise CmdError("Unknown blob type '%s' required in flash map" %
1008 blob_type)
1009
Simon Glass290a1802011-07-17 13:54:32 -07001010 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -07001011 """Create a full firmware image, along with various by-products.
1012
1013 This uses the provided u-boot.bin, fdt and bct to create a firmware
1014 image containing all the required parts. If the GBB is not supplied
1015 then this will just return a signed U-Boot as the image.
1016
1017 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +12001018 gbb: Full path to the GBB file, or empty if a GBB is not required.
1019 fdt: Fdt object containing required information.
1020
1021 Returns:
1022 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -07001023
1024 Raises:
1025 CmdError if a command fails.
1026 """
Simon Glass02d124a2012-03-02 14:47:20 -08001027 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -07001028
Simon Glass439fe7a2012-03-09 16:19:34 -08001029 # Get the flashmap so we know what to build
1030 pack = PackFirmware(self._tools, self._out)
Simon Glass0c54ba52012-11-06 12:36:43 -08001031 default_flashmap = default_flashmaps.get(self._board)
Simon Glassb8c6d952012-12-01 06:14:35 -08001032 if self._force_rw:
1033 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
1034 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
1035
Simon Glass0c54ba52012-11-06 12:36:43 -08001036 pack.SelectFdt(fdt, self._board, default_flashmap)
Simon Glass439fe7a2012-03-09 16:19:34 -08001037
1038 # Get all our blobs ready
1039 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -08001040 if self.skeleton_fname:
1041 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -07001042 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -07001043
Simon Glass47817052012-10-20 13:30:07 -07001044 # Let's create some copies of the fdt for vboot. These can be used to
1045 # pass a different fdt to each firmware type. For now it is just used to
1046 # check that the right fdt comes through.
1047 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
1048 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
1049 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
1050 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
1051 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
1052 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
1053 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
1054
Simon Glassde9c8072012-07-02 22:29:02 -07001055 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
1056 if self.kernel_fname:
1057 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
1058
Simon Glass439fe7a2012-03-09 16:19:34 -08001059 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +01001060 blob_list = pack.GetBlobList()
1061 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -07001062 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -08001063 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -07001064
Simon Glass7306b902012-12-17 15:06:21 -08001065 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -07001066 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -07001067 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +08001068 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -08001069 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +08001070 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -07001071 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -08001072 pack.AddProperty('fwid', fwid)
1073 pack.AddProperty('gbb', gbb)
1074 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -07001075
1076 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -07001077
1078 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -08001079 pack.UpdateBlobPositionsAndHashes(fdt)
1080 pack.UpdateBlobPositionsAndHashes(fdt_rwa)
1081 pack.UpdateBlobPositionsAndHashes(fdt_rwb)
Simon Glass8884b982012-06-21 12:41:41 -07001082
Simon Glass6207efe2012-12-17 15:04:36 -08001083 # Make a copy of the fdt for the bootstub
1084 fdt_data = self._tools.ReadFile(fdt.fname)
1085 uboot_data = self._tools.ReadFile(self.uboot_fname)
1086 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
1087 self._tools.WriteFile(uboot_copy, uboot_data)
1088
1089 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
1090 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
1091
Simon Glassa10282a2013-01-08 17:06:41 -08001092 # Fix up the coreboot image here, since we can't do this until we have
1093 # a final device tree binary.
Simon Glasscbc83552012-07-23 15:26:22 +01001094 if 'coreboot' in blob_list:
1095 bootstub = pack.GetProperty('coreboot')
1096 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -08001097 if self.coreboot_elf:
1098 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
1099 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
1100 else:
1101 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
1102 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
1103 '-l', '0x1110000', '-e', '0x1110008'])
Stefan Reinauer1502ea62012-11-01 10:15:38 -07001104 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
1105 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -08001106 data = self._tools.ReadFile(bootstub)
1107 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
1108 self._tools.WriteFile(bootstub_copy, data)
Gabe Black3df75252013-02-14 21:32:10 -08001109 self._tools.WriteFile(bootstub, data[-0x100000:])
Simon Glasscbc83552012-07-23 15:26:22 +01001110
Simon Glass208ad952013-02-10 11:16:46 -08001111 pack.AddProperty('fdtmap', fdt.fname)
Simon Glassc90cf582012-03-13 15:40:47 -07001112 image = os.path.join(self._tools.outdir, 'image.bin')
1113 pack.PackImage(self._tools.outdir, image)
1114 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -07001115
Simon Glass439fe7a2012-03-09 16:19:34 -08001116 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -07001117 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001118 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001119
Simon Glassdedda6f2013-02-09 13:44:14 -08001120 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -07001121 """Select an FDT to control the firmware bundling
1122
Simon Glassdedda6f2013-02-09 13:44:14 -08001123 We make a copy of this which will include any on-the-fly changes we want
1124 to make.
1125
Simon Glass290a1802011-07-17 13:54:32 -07001126 Args:
1127 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -08001128 use_defaults: True to use a default FDT name if available, and to add
1129 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -07001130
Simon Glassc0f3dc62011-08-09 14:19:05 -07001131 Returns:
1132 The Fdt object of the original fdt file, which we will not modify.
1133
Simon Glassdedda6f2013-02-09 13:44:14 -08001134 Raises:
1135 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
1136 False).
Simon Glass290a1802011-07-17 13:54:32 -07001137 """
Simon Glassdedda6f2013-02-09 13:44:14 -08001138 if use_defaults:
1139 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -08001140 if not fdt_fname:
1141 raise ValueError('Please provide an FDT filename')
1142 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -07001143 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -08001144
1145 # For upstream, select the correct architecture .dtsi manually.
1146 if self._board == 'link' or 'x86' in self._board:
1147 arch_dts = 'coreboot.dtsi'
1148 elif self._board == 'daisy':
1149 arch_dts = 'exynos5250.dtsi'
1150 else:
1151 arch_dts = 'tegra20.dtsi'
1152
1153 fdt.Compile(arch_dts)
Simon Glass290a1802011-07-17 13:54:32 -07001154 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -07001155 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001156
Simon Glassc90cf582012-03-13 15:40:47 -07001157 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001158 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001159
1160 - Checks options, tools, output directory, fdt.
1161 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001162
1163 Args:
Simon Glass56577572011-07-19 11:08:06 +12001164 hardware_id: Hardware ID to use for this board. If None, then the
1165 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001166 output_fname: Output filename for the image. If this is not None, then
1167 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001168 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001169
1170 Returns:
1171 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001172 """
Simon Glass89b86b82011-07-17 23:49:49 -07001173 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -07001174 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +12001175 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001176
1177 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001178 image, pack = self._CreateImage(gbb, self.fdt)
1179 if show_map:
1180 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001181 if output_fname:
1182 shutil.copyfile(image, output_fname)
1183 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001184 return image, pack.props