blob: 6bdb40f53f11ea17e35cfd0d0ae3450d0ce4651f [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
Simon Glassbe0bc002012-08-16 12:50:48 -0700191 self.ecrw_fname = None # Filename of EC file
192 self.ecro_fname = None # Filename of EC read-only file
Simon Glass23988ae2012-03-23 16:55:22 -0700193 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700194
195 def SetDirs(self, keydir):
196 """Set up directories required for Bundle.
197
198 Args:
199 keydir: Directory containing keys to use for signing firmware.
200 """
201 self._keydir = keydir
202
Simon Glass6dcc2f22011-07-28 15:26:49 +1200203 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glassa10282a2013-01-08 17:06:41 -0800204 coreboot_elf=None,
Simon Glass07267952012-06-08 12:45:13 -0700205 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassbe0bc002012-08-16 12:50:48 -0700206 skeleton=None, ecrw=None, ecro=None, kernel=None):
Simon Glass290a1802011-07-17 13:54:32 -0700207 """Set up files required for Bundle.
208
209 Args:
210 board: The name of the board to target (e.g. tegra2_seaboard).
211 uboot: The filename of the u-boot.bin image to use.
212 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800213 bmpblk: The filename of bitmap block file to use.
Simon Glassa10282a2013-01-08 17:06:41 -0800214 coreboot: The filename of the coreboot image to use (on x86).
215 coreboot_elf: If not none, the ELF file to add as a Coreboot payload.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200216 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700217 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700218 exynos_bl1: The filename of the exynos BL1 file
219 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
220 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700221 ecrw: The filename of the EC (Embedded Controller) read-write file.
222 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700223 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700224 """
225 self._board = board
226 self.uboot_fname = uboot
227 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800228 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700229 self.coreboot_fname = coreboot
Simon Glassa10282a2013-01-08 17:06:41 -0800230 self.coreboot_elf = coreboot_elf
Simon Glass6dcc2f22011-07-28 15:26:49 +1200231 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700232 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700233 self.exynos_bl1 = exynos_bl1
234 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700235 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700236 self.ecrw_fname = ecrw
237 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700238 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700239
Simon Glass6e486c22012-10-26 15:43:42 -0700240 def SetOptions(self, small, gbb_flags, force_rw=False):
Simon Glass290a1802011-07-17 13:54:32 -0700241 """Set up options supported by Bundle.
242
243 Args:
244 small: Only create a signed U-Boot - don't produce the full packed
245 firmware image. This is useful for devs who want to replace just the
246 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700247 gbb_flags: Specification for string containing adjustments to make.
248 force_rw: Force firmware into RW mode.
Simon Glass290a1802011-07-17 13:54:32 -0700249 """
250 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700251 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700252 self._force_rw = force_rw
Simon Glass290a1802011-07-17 13:54:32 -0700253
Simon Glass22f39fb2013-02-09 13:44:14 -0800254 def _GetBuildRoot(self):
255 """Get the path to this board's 'firmware' directory.
256
257 Returns:
258 Path to firmware directory, with ## representing the path to the
259 chroot.
260 """
Simon Glass290a1802011-07-17 13:54:32 -0700261 if not self._board:
262 raise ValueError('No board defined - please define a board to use')
Simon Glass22f39fb2013-02-09 13:44:14 -0800263 return os.path.join('##', 'build', self._board, 'firmware')
264
265 def _CheckFdtFilename(self, fname):
266 """Check provided FDT filename and return the correct name if needed.
267
268 Where the filename lacks a path, add a default path for this board.
269 Where no FDT filename is provided, select a default one for this board.
270
271 Args:
272 fname: Proposed FDT filename.
273
274 Returns:
275 Selected FDT filename, after validation.
276 """
277 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700278 dir_name = os.path.join(build_root, 'dts')
Simon Glass22f39fb2013-02-09 13:44:14 -0800279 if not fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700280 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700281 base_name = re.sub('_', '-', self._board)
282
283 # In case the name exists with a prefix or suffix, find it.
284 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
285 found_list = glob.glob(self._tools.Filename(wildcard))
286 if len(found_list) == 1:
Simon Glass22f39fb2013-02-09 13:44:14 -0800287 fname = found_list[0]
Simon Glassceff3ff2012-04-04 11:23:45 -0700288 else:
289 # We didn't find anything definite, so set up our expected name.
Simon Glass22f39fb2013-02-09 13:44:14 -0800290 fname = os.path.join(dir_name, '%s.dts' % base_name)
Simon Glassceff3ff2012-04-04 11:23:45 -0700291
Simon Glass881964d2012-04-04 11:34:09 -0700292 # Convert things like 'exynos5250-daisy' into a full path.
Simon Glass22f39fb2013-02-09 13:44:14 -0800293 root, ext = os.path.splitext(fname)
Simon Glass881964d2012-04-04 11:34:09 -0700294 if not ext and not os.path.dirname(root):
Simon Glass22f39fb2013-02-09 13:44:14 -0800295 fname = os.path.join(dir_name, '%s.dts' % root)
296 return fname
297
298 def CheckOptions(self):
299 """Check provided options and select defaults."""
300 build_root = self._GetBuildRoot()
Simon Glass881964d2012-04-04 11:34:09 -0700301
Simon Glass290a1802011-07-17 13:54:32 -0700302 if not self.uboot_fname:
303 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
304 if not self.bct_fname:
305 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700306 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700307 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700308 if not self.exynos_bl1:
309 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
310 if not self.exynos_bl2:
311 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700312 if not self.coreboot_fname:
313 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
314 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700315 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700316 if not self.seabios_fname:
317 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700318 if not self.ecrw_fname:
319 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
320 if not self.ecro_fname:
321 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700322
Simon Glass75759302012-03-15 20:26:53 -0700323 def GetFiles(self):
324 """Get a list of files that we know about.
325
326 This is the opposite of SetFiles except that we may have put in some
327 default names. It returns a dictionary containing the filename for
328 each of a number of pre-defined files.
329
330 Returns:
331 Dictionary, with one entry for each file.
332 """
333 file_list = {
334 'bct' : self.bct_fname,
335 'exynos-bl1' : self.exynos_bl1,
336 'exynos-bl2' : self.exynos_bl2,
337 }
338 return file_list
339
Simon Glass4a887b12012-10-23 16:29:03 -0700340 def DecodeGBBFlagsFromFdt(self):
341 """Get Google Binary Block flags from the FDT.
342
343 These should be in the chromeos-config node, like this:
344
345 chromeos-config {
346 gbb-flag-dev-screen-short-delay;
347 gbb-flag-force-dev-switch-on;
348 gbb-flag-force-dev-boot-usb;
349 gbb-flag-disable-fw-rollback-check;
350 };
351
352 Returns:
353 GBB flags value from FDT.
354 """
355 chromeos_config = self.fdt.GetProps("/chromeos-config")
356 gbb_flags = 0
357 for name in chromeos_config:
358 if name.startswith('gbb-flag-'):
359 flag_value = gbb_flag_properties.get(name[9:])
360 if flag_value:
361 gbb_flags |= flag_value
362 self._out.Notice("FDT: Enabling %s." % name)
363 else:
364 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
365 return gbb_flags
366
Simon Glass157c0662012-10-23 13:52:42 -0700367 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
368 """Decode ajustments to the provided GBB flags.
369
370 We support three options:
371
372 hex value: c2
373 defined value: force-dev-boot-usb,load-option-roms
374 adjust default value: -load-option-roms,+force-dev-boot-usb
375
376 The last option starts from the passed-in GBB flags and adds or removes
377 flags.
378
379 Args:
380 gbb_flags: Base (default) FDT flags.
381 adjustments: String containing adjustments to make.
382
383 Returns:
384 Updated FDT flags.
385 """
386 use_base_value = True
387 if adjustments:
388 try:
389 return int(adjustments, base=16)
390 except:
391 pass
392 for flag in adjustments.split(','):
393 oper = None
394 if flag[0] in ['-', '+']:
395 oper = flag[0]
396 flag = flag[1:]
397 value = gbb_flag_properties.get(flag)
398 if not value:
399 raise ValueError("Invalid GBB flag '%s'" % flag)
400 if oper == '+':
401 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800402 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700403 elif oper == '-':
404 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800405 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700406 else:
407 if use_base_value:
408 gbb_flags = 0
409 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800410 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700411 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800412 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700413
414 return gbb_flags
415
Simon Glass56577572011-07-19 11:08:06 +1200416 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700417 """Create a GBB for the image.
418
Simon Glass56577572011-07-19 11:08:06 +1200419 Args:
420 hardware_id: Hardware ID to use for this board. If None, then the
421 default from the Fdt will be used
422
Simon Glass89b86b82011-07-17 23:49:49 -0700423 Returns:
424 Path of the created GBB file.
425
426 Raises:
427 CmdError if a command fails.
428 """
Simon Glass56577572011-07-19 11:08:06 +1200429 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800430 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700431 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700432 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700433
Simon Glass4a887b12012-10-23 16:29:03 -0700434 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800435
Simon Glass157c0662012-10-23 13:52:42 -0700436 # Allow command line to override flags
437 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
438
Simon Glass4a887b12012-10-23 16:29:03 -0700439 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700440 self._out.Progress('Creating GBB')
441 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
442 sizes = ['%#x' % size for size in sizes]
443 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700444 keydir = self._tools.Filename(self._keydir)
445 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700446 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200447 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700448 '--rootkey=%s/root_key.vbpubk' % keydir,
449 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700450 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800451 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700452 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700453 cwd=odir)
454 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700455
Simon Glasse13ee2c2011-07-28 08:12:28 +1200456 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700457 """Sign an image so that the Tegra SOC will boot it.
458
459 Args:
460 bct: BCT file to use.
461 bootstub: Boot stub (U-Boot + fdt) file to sign.
462 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700463
464 Returns:
465 filename of signed image.
466
467 Raises:
468 CmdError if a command fails.
469 """
470 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200471 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700472 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200473 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700474 fd = open(config, 'w')
475 fd.write('Version = 1;\n')
476 fd.write('Redundancy = 1;\n')
477 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700478
479 # TODO(dianders): Right now, we don't have enough space in our flash map
480 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
481 # sure what this does for reliability, but at least things will fit...
482 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
483 if is_nand:
484 fd.write('Bctcopy = 1;\n')
485
Simon Glass89b86b82011-07-17 23:49:49 -0700486 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
487 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700488
Simon Glass89b86b82011-07-17 23:49:49 -0700489 fd.close()
490
491 self._tools.Run('cbootimage', [config, signed])
492 self._tools.OutputSize('BCT', bct)
493 self._tools.OutputSize('Signed image', signed)
494 return signed
495
Doug Anderson86ce5f42011-07-27 10:40:18 -0700496 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700497 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700498
499 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700500 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700501 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700502 """
Simon Glass468d8752012-09-19 16:36:19 -0700503 if bootcmd is not None:
504 if bootcmd == 'none':
505 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800506 self.fdt.PutString('/config', 'bootcmd', bootcmd)
507 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700508 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700509
Simon Glassa4934b72012-05-09 13:35:02 -0700510 def SetNodeEnabled(self, node_name, enabled):
511 """Set whether an node is enabled or disabled.
512
513 This simply sets the 'status' property of a node to "ok", or "disabled".
514
515 The node should either be a full path to the node (like '/uart@10200000')
516 or an alias property.
517
518 Aliases are supported like this:
519
520 aliases {
521 console = "/uart@10200000";
522 };
523
524 pointing to a node:
525
526 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700527 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700528 };
529
530 In this case, this function takes the name of the alias ('console' in
531 this case) and updates the status of the node that is pointed to, to
532 either ok or disabled. If the alias does not exist, a warning is
533 displayed.
534
535 Args:
536 node_name: Name of node (e.g. '/uart@10200000') or alias alias
537 (e.g. 'console') to adjust
538 enabled: True to enable, False to disable
539 """
540 # Look up the alias if this is an alias reference
541 if not node_name.startswith('/'):
542 lookup = self.fdt.GetString('/aliases', node_name, '')
543 if not lookup:
544 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
545 return
546 node_name = lookup
547 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700548 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700549 else:
550 status = 'disabled'
551 self.fdt.PutString(node_name, 'status', status)
552
553 def AddEnableList(self, enable_list):
554 """Process a list of nodes to enable/disable.
555
556 Args:
557 config_list: List of (node, value) tuples to add to the fdt. For each
558 tuple:
559 node: The fdt node to write to will be <node> or pointed to by
560 /aliases/<node>. We can tell which
561 value: 0 to disable the node, 1 to enable it
562 """
563 if enable_list:
564 for node_name, enabled in enable_list:
565 try:
566 enabled = int(enabled)
567 if enabled not in (0, 1):
568 raise ValueError
569 except ValueError as str:
570 raise CmdError("Invalid enable option value '%s' "
571 "(should be 0 or 1)" % enabled)
572 self.SetNodeEnabled(node_name, enabled)
573
Simon Glass290a1802011-07-17 13:54:32 -0700574 def AddConfigList(self, config_list, use_int=False):
575 """Add a list of config items to the fdt.
576
577 Normally these values are written to the fdt as strings, but integers
578 are also supported, in which case the values will be converted to integers
579 (if necessary) before being stored.
580
581 Args:
582 config_list: List of (config, value) tuples to add to the fdt. For each
583 tuple:
584 config: The fdt node to write to will be /config/<config>.
585 value: An integer or string value to write.
586 use_int: True to only write integer values.
587
588 Raises:
589 CmdError: if a value is required to be converted to integer but can't be.
590 """
591 if config_list:
592 for config in config_list:
593 value = config[1]
594 if use_int:
595 try:
596 value = int(value)
597 except ValueError as str:
598 raise CmdError("Cannot convert config option '%s' to integer" %
599 value)
600 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800601 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700602 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800603 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700604
Simon Glass7c2d5572011-11-15 14:47:08 -0800605 def DecodeTextBase(self, data):
606 """Look at a U-Boot image and try to decode its TEXT_BASE.
607
608 This works because U-Boot has a header with the value 0x12345678
609 immediately followed by the TEXT_BASE value. We can therefore read this
610 from the image with some certainty. We check only the first 40 words
611 since the header should be within that region.
612
Simon Glass96b50302012-07-20 06:55:28 +0100613 Since upstream Tegra has moved to having a 16KB SPL region at the start,
614 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
615 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
616
Simon Glass7c2d5572011-11-15 14:47:08 -0800617 Args:
618 data: U-Boot binary data
619
620 Returns:
621 Text base (integer) or None if none was found
622 """
623 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100624 for start in (0, 0x4000):
625 for i in range(start, start + 160, 4):
626 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800627
Simon Glass96b50302012-07-20 06:55:28 +0100628 # TODO(sjg): This does not cope with a big-endian target
629 value = struct.unpack('<I', word)[0]
630 if found:
631 return value - start
632 if value == 0x12345678:
633 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800634
635 return None
636
637 def CalcTextBase(self, name, fdt, fname):
638 """Calculate the TEXT_BASE to use for U-Boot.
639
640 Normally this value is in the fdt, so we just read it from there. But as
641 a second check we look at the image itself in case this is different, and
642 switch to that if it is.
643
644 This allows us to flash any U-Boot even if its TEXT_BASE is different.
645 This is particularly useful with upstream U-Boot which uses a different
646 value (which we will move to).
647 """
648 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800649 # The value that comes back from fdt.GetInt is signed, which makes no
650 # sense for an address base. Force it to unsigned.
651 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800652 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100653 text_base_str = '%#x' % text_base if text_base else 'None'
654 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
655 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800656
657 # If they are different, issue a warning and switch over.
658 if text_base and text_base != fdt_text_base:
659 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
660 "fdt value of %x. Using %x" % (text_base, name,
661 fdt_text_base, text_base))
662 fdt_text_base = text_base
663 return fdt_text_base
664
Simon Glass6dcc2f22011-07-28 15:26:49 +1200665 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700666 """Create a boot stub and a signed boot stub.
667
Simon Glass6dcc2f22011-07-28 15:26:49 +1200668 For postload:
669 We add a /config/postload-text-offset entry to the signed bootstub's
670 fdt so that U-Boot can find the postload code.
671
672 The raw (unsigned) bootstub will have a value of -1 for this since we will
673 simply append the postload code to the bootstub and it can find it there.
674 This will be used for RW A/B firmware.
675
676 For the signed case this value will specify where in the flash to find
677 the postload code. This will be used for RO firmware.
678
Simon Glass89b86b82011-07-17 23:49:49 -0700679 Args:
680 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800681 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200682 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700683
684 Returns:
685 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200686 Full path to bootstub (uboot + fdt(-1) + postload).
687 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700688
689 Raises:
690 CmdError if a command fails.
691 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200692 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800693 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700694 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200695
696 # Make a copy of the fdt for the bootstub
697 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800698 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700699 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200700
Simon Glass89b86b82011-07-17 23:49:49 -0700701 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700702 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
703 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700704 self._tools.OutputSize('Combined binary', bootstub)
705
Simon Glasse13ee2c2011-07-28 08:12:28 +1200706 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700707 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700708 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200709 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200710
711 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
712 data = self._tools.ReadFile(signed)
713
714 if postload:
715 # We must add postload to the bootstub since A and B will need to
716 # be able to find it without the /config/postload-text-offset mechanism.
717 bs_data = self._tools.ReadFile(bootstub)
718 bs_data += self._tools.ReadFile(postload)
719 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
720 self._tools.WriteFile(bootstub, bs_data)
721 self._tools.OutputSize('Combined binary with postload', bootstub)
722
723 # Now that we know the file size, adjust the fdt and re-sign
724 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800725 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200726 fdt_data = self._tools.ReadFile(fdt.fname)
727 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
728 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
729 postload_bootstub, text_base)
730 if len(data) != os.path.getsize(signed):
731 raise CmdError('Signed file size changed from %d to %d after updating '
732 'fdt' % (len(data), os.path.getsize(signed)))
733
734 # Re-read the signed image, and add the post-load binary.
735 data = self._tools.ReadFile(signed)
736 data += self._tools.ReadFile(postload)
737 self._tools.OutputSize('Post-load binary', postload)
738
739 self._tools.WriteFile(signed_postload, data)
740 self._tools.OutputSize('Final bootstub with postload', signed_postload)
741
742 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700743
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700744 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700745 """Create a coreboot boot stub.
746
747 Args:
748 uboot: Path to u-boot.bin (may be chroot-relative)
749 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700750 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700751
752 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100753 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700754
755 Raises:
756 CmdError if a command fails.
757 """
758 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700759 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100760
761 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700762 return bootstub
763
Simon Glass3b404092012-05-23 13:10:36 -0700764 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700765 """Update the parameters in a BL2 blob.
766
767 We look at the list in the parameter block, extract the value of each
768 from the device tree, and write that value to the parameter block.
769
770 Args:
771 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700772 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700773 data: The BL2 data.
774 pos: The position of the start of the parameter block.
775
776 Returns:
777 The new contents of the parameter block, after updating.
778 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700779 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
780 if version != 1:
781 raise CmdError("Cannot update machine parameter block version '%d'" %
782 version)
783 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700784 raise CmdError("Machine parameter block size %d is invalid: "
785 "pos=%d, size=%d, space=%d, len=%d" %
786 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700787
788 # Move past the header and read the parameter list, which is terminated
789 # with \0.
790 pos += 12
791 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
792 param_len = param_list.find('\0')
793 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700794 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700795
796 # Work through the parameters one at a time, adding each value
797 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700798 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700799 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700800 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glass56583742012-11-06 12:34:47 -0800801
802 # Use this to detect a missing value from the fdt.
803 not_given = 'not-given-invalid-value'
Simon Glassdf95dd22012-03-13 15:46:16 -0700804 if param == 'm' :
Simon Glass56583742012-11-06 12:34:47 -0800805 mem_type = fdt.GetString('/dmc', 'mem-type', not_given)
806 if mem_type == not_given:
807 mem_type = 'ddr3'
808 self._out.Warning("No value for memory type: using '%s'" % mem_type)
Simon Glassdf95dd22012-03-13 15:46:16 -0700809 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
810 if not mem_type in mem_types:
811 raise CmdError("Unknown memory type '%s'" % mem_type)
812 value = mem_types.index(mem_type)
813 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700814 elif param == 'M' :
Simon Glass56583742012-11-06 12:34:47 -0800815 mem_manuf = fdt.GetString('/dmc', 'mem-manuf', not_given)
816 if mem_manuf == not_given:
817 mem_manuf = 'samsung'
818 self._out.Warning("No value for memory manufacturer: using '%s'" %
819 mem_manuf)
Doug Andersonee46cfe2012-05-18 09:53:08 -0700820 mem_manufs = ['autodetect', 'elpida', 'samsung']
821 if not mem_manuf in mem_manufs:
822 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
823 value = mem_manufs.index(mem_manuf)
824 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700825 elif param == 'f' :
Simon Glass56583742012-11-06 12:34:47 -0800826 mem_freq = fdt.GetInt('/dmc', 'clock-frequency', -1)
827 if mem_freq == -1:
828 mem_freq = 800000000
829 self._out.Warning("No value for memory frequency: using '%s'" %
830 mem_freq)
831 mem_freq /= 1000000
Simon Glass158289e2012-09-14 11:42:25 -0700832 if not mem_freq in [533, 667, 800]:
833 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
834 value = mem_freq
835 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700836 elif param == 'v':
837 value = 31
838 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700839 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700840 value = (spl_load_size + 0xfff) & ~0xfff
841 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
842 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700843 elif param == 'b':
844 # These values come from enum boot_mode in U-Boot's cpu.h
845 if self.spl_source == 'straps':
846 value = 32
847 elif self.spl_source == 'emmc':
848 value = 4
849 elif self.spl_source == 'spi':
850 value = 20
851 elif self.spl_source == 'usb':
852 value = 33
853 else:
854 raise CmdError("Invalid boot source '%s'" % self.spl_source)
855 self._out.Info(' Boot source: %#0x' % value)
Tom Wai-Hong Tam99b7f112013-02-06 09:10:10 +0800856 elif param == 'z':
857 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
858 compress_types = ['none', 'lzo']
859 if not compress in compress_types:
860 raise CmdError("Unknown compression type '%s'" % compress)
861 value = compress_types.index(compress)
862 self._out.Info(' Compression type: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700863 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700864 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700865 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700866 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700867 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700868
869 # Put the data into our block.
870 data = data[:pos] + new_data + data[pos + len(new_data):]
871 self._out.Info('BL2 configuration complete')
872 return data
873
Simon Glasse5e8afb2012-05-23 11:19:23 -0700874 def _UpdateChecksum(self, data):
875 """Update the BL2 checksum.
876
877 The checksum is a 4 byte sum of all the bytes in the image before the
878 last 4 bytes (which hold the checksum).
879
880 Args:
881 data: The BL2 data to update.
882
883 Returns:
884 The new contents of the BL2 data, after updating the checksum.
885 """
886 checksum = 0
887 for ch in data[:-4]:
888 checksum += ord(ch)
889 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
890
Simon Glass559b6612012-05-23 13:28:45 -0700891 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700892 """Configure an Exynos BL2 binary for our needs.
893
894 We create a new modified BL2 and return its filename.
895
896 Args:
897 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700898 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700899 orig_bl2: Filename of original BL2 file to modify.
900 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700901 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700902 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700903 data = self._tools.ReadFile(orig_bl2)
904 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700905
906 # Locate the parameter block
907 data = self._tools.ReadFile(bl2)
908 marker = struct.pack('<L', 0xdeadbeef)
909 pos = data.rfind(marker)
910 if not pos:
911 raise CmdError("Could not find machine parameter block in '%s'" %
912 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700913 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700914 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700915 self._tools.WriteFile(bl2, data)
916 return bl2
917
Simon Glass89b86b82011-07-17 23:49:49 -0700918 def _PackOutput(self, msg):
919 """Helper function to write output from PackFirmware (verbose level 2).
920
921 This is passed to PackFirmware for it to use to write output.
922
923 Args:
924 msg: Message to display.
925 """
926 self._out.Notice(msg)
927
Simon Glass439fe7a2012-03-09 16:19:34 -0800928 def _BuildBlob(self, pack, fdt, blob_type):
929 """Build the blob data for a particular blob type.
930
931 Args:
932 blob_type: The type of blob to create data for. Supported types are:
933 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
934 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
935 """
936 if blob_type == 'coreboot':
937 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700938 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800939 pack.AddProperty('coreboot', coreboot)
940 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700941 elif blob_type == 'legacy':
942 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800943 elif blob_type == 'signed':
944 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
945 self.postload_fname)
946 pack.AddProperty('bootstub', bootstub)
947 pack.AddProperty('signed', signed)
948 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700949 elif blob_type == 'exynos-bl1':
950 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700951
952 # TODO(sjg@chromium.org): Deprecate ecbin
953 elif blob_type in ['ecrw', 'ecbin']:
954 pack.AddProperty('ecrw', self.ecrw_fname)
955 pack.AddProperty('ecbin', self.ecrw_fname)
Gabe Blackcdbdfe12013-02-06 05:37:52 -0800956 elif blob_type == 'ecrwhash':
957 ec_hash_file = os.path.join(self._tools.outdir, 'ec_hash.bin')
958 ecrw = self._tools.ReadFile(self.ecrw_fname)
959 hasher = hashlib.sha256()
960 hasher.update(ecrw)
961 self._tools.WriteFile(ec_hash_file, hasher.digest())
962 pack.AddProperty(blob_type, ec_hash_file)
Simon Glassbe0bc002012-08-16 12:50:48 -0700963 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700964 # crosbug.com/p/13143
965 # We cannot have an fmap in the EC image since there can be only one,
966 # which is the main fmap describing the whole image.
967 # Ultimately the EC will not have an fmap, since with software sync
968 # there is no flashrom involvement in updating the EC flash, and thus
969 # no need for the fmap.
970 # For now, mangle the fmap name to avoid problems.
971 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
972 data = self._tools.ReadFile(self.ecro_fname)
973 data = re.sub('__FMAP__', '__fMAP__', data)
974 self._tools.WriteFile(updated_ecro, data)
975 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700976 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700977 spl_payload = pack.GetBlobParams(blob_type)
978
979 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
980 # from all flash map files.
981 if not spl_payload:
982 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
983 prop_list = 'boot+dtb'
984
985 # Do this later, when we remove boot+dtb.
986 # raise CmdError("No parameters provided for blob type '%s'" %
987 # blob_type)
988 else:
989 prop_list = spl_payload[0].split(',')
Tom Wai-Hong Tam26e3a4c2013-02-06 09:36:47 +0800990 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
991 if compress == 'none':
992 compress = None
993 spl_load_size = len(pack.ConcatPropContents(prop_list, compress,
994 False)[0])
Simon Glass7d2542f2012-06-21 07:10:59 -0700995 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
996 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700997 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700998 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800999 elif pack.GetProperty(blob_type):
1000 pass
1001 else:
1002 raise CmdError("Unknown blob type '%s' required in flash map" %
1003 blob_type)
1004
Simon Glass290a1802011-07-17 13:54:32 -07001005 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -07001006 """Create a full firmware image, along with various by-products.
1007
1008 This uses the provided u-boot.bin, fdt and bct to create a firmware
1009 image containing all the required parts. If the GBB is not supplied
1010 then this will just return a signed U-Boot as the image.
1011
1012 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +12001013 gbb: Full path to the GBB file, or empty if a GBB is not required.
1014 fdt: Fdt object containing required information.
1015
1016 Returns:
1017 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -07001018
1019 Raises:
1020 CmdError if a command fails.
1021 """
Simon Glass02d124a2012-03-02 14:47:20 -08001022 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -07001023
Simon Glass439fe7a2012-03-09 16:19:34 -08001024 # Get the flashmap so we know what to build
1025 pack = PackFirmware(self._tools, self._out)
Simon Glass0c54ba52012-11-06 12:36:43 -08001026 default_flashmap = default_flashmaps.get(self._board)
Simon Glassb8c6d952012-12-01 06:14:35 -08001027 if self._force_rw:
1028 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
1029 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
1030
Simon Glass0c54ba52012-11-06 12:36:43 -08001031 pack.SelectFdt(fdt, self._board, default_flashmap)
Simon Glass439fe7a2012-03-09 16:19:34 -08001032
1033 # Get all our blobs ready
1034 pack.AddProperty('boot', self.uboot_fname)
Simon Glass284cb892013-02-09 13:38:03 -08001035 if self.skeleton_fname:
1036 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -07001037 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -07001038
Simon Glass47817052012-10-20 13:30:07 -07001039 # Let's create some copies of the fdt for vboot. These can be used to
1040 # pass a different fdt to each firmware type. For now it is just used to
1041 # check that the right fdt comes through.
1042 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
1043 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
1044 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
1045 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
1046 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
1047 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
1048 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
1049
Simon Glassde9c8072012-07-02 22:29:02 -07001050 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
1051 if self.kernel_fname:
1052 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
1053
Simon Glass439fe7a2012-03-09 16:19:34 -08001054 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +01001055 blob_list = pack.GetBlobList()
1056 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -07001057 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -08001058 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -07001059
Simon Glass7306b902012-12-17 15:06:21 -08001060 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -07001061 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -07001062 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +08001063 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -08001064 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +08001065 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -07001066 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -08001067 pack.AddProperty('fwid', fwid)
1068 pack.AddProperty('gbb', gbb)
1069 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -07001070
1071 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -07001072
1073 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -08001074 pack.UpdateBlobPositionsAndHashes(fdt)
1075 pack.UpdateBlobPositionsAndHashes(fdt_rwa)
1076 pack.UpdateBlobPositionsAndHashes(fdt_rwb)
Simon Glass8884b982012-06-21 12:41:41 -07001077
Simon Glass6207efe2012-12-17 15:04:36 -08001078 # Make a copy of the fdt for the bootstub
1079 fdt_data = self._tools.ReadFile(fdt.fname)
1080 uboot_data = self._tools.ReadFile(self.uboot_fname)
1081 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
1082 self._tools.WriteFile(uboot_copy, uboot_data)
1083
1084 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
1085 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
1086
Simon Glassa10282a2013-01-08 17:06:41 -08001087 # Fix up the coreboot image here, since we can't do this until we have
1088 # a final device tree binary.
Simon Glasscbc83552012-07-23 15:26:22 +01001089 if 'coreboot' in blob_list:
1090 bootstub = pack.GetProperty('coreboot')
1091 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -08001092 if self.coreboot_elf:
1093 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
1094 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
1095 else:
1096 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
1097 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
1098 '-l', '0x1110000', '-e', '0x1110008'])
Stefan Reinauer1502ea62012-11-01 10:15:38 -07001099 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
1100 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -08001101 data = self._tools.ReadFile(bootstub)
1102 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
1103 self._tools.WriteFile(bootstub_copy, data)
Gabe Black3df75252013-02-14 21:32:10 -08001104 self._tools.WriteFile(bootstub, data[-0x100000:])
Simon Glasscbc83552012-07-23 15:26:22 +01001105
Simon Glassc90cf582012-03-13 15:40:47 -07001106 image = os.path.join(self._tools.outdir, 'image.bin')
1107 pack.PackImage(self._tools.outdir, image)
1108 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -07001109
Simon Glass439fe7a2012-03-09 16:19:34 -08001110 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -07001111 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001112 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001113
Simon Glassdedda6f2013-02-09 13:44:14 -08001114 def SelectFdt(self, fdt_fname, use_defaults):
Simon Glass290a1802011-07-17 13:54:32 -07001115 """Select an FDT to control the firmware bundling
1116
Simon Glassdedda6f2013-02-09 13:44:14 -08001117 We make a copy of this which will include any on-the-fly changes we want
1118 to make.
1119
Simon Glass290a1802011-07-17 13:54:32 -07001120 Args:
1121 fdt_fname: The filename of the fdt to use.
Simon Glassdedda6f2013-02-09 13:44:14 -08001122 use_defaults: True to use a default FDT name if available, and to add
1123 a full path to the provided filename if necessary.
Simon Glass290a1802011-07-17 13:54:32 -07001124
Simon Glassc0f3dc62011-08-09 14:19:05 -07001125 Returns:
1126 The Fdt object of the original fdt file, which we will not modify.
1127
Simon Glassdedda6f2013-02-09 13:44:14 -08001128 Raises:
1129 ValueError if no FDT is provided (fdt_fname is None and use_defaults is
1130 False).
Simon Glass290a1802011-07-17 13:54:32 -07001131 """
Simon Glassdedda6f2013-02-09 13:44:14 -08001132 if use_defaults:
1133 fdt_fname = self._CheckFdtFilename(fdt_fname)
Simon Glass22f39fb2013-02-09 13:44:14 -08001134 if not fdt_fname:
1135 raise ValueError('Please provide an FDT filename')
1136 fdt = Fdt(self._tools, fdt_fname)
Simon Glass290a1802011-07-17 13:54:32 -07001137 self._fdt_fname = fdt_fname
Simon Glassc3e42c32012-12-17 15:00:04 -08001138
1139 # For upstream, select the correct architecture .dtsi manually.
1140 if self._board == 'link' or 'x86' in self._board:
1141 arch_dts = 'coreboot.dtsi'
1142 elif self._board == 'daisy':
1143 arch_dts = 'exynos5250.dtsi'
1144 else:
1145 arch_dts = 'tegra20.dtsi'
1146
1147 fdt.Compile(arch_dts)
Simon Glass290a1802011-07-17 13:54:32 -07001148 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -07001149 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001150
Simon Glassc90cf582012-03-13 15:40:47 -07001151 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001152 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001153
1154 - Checks options, tools, output directory, fdt.
1155 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001156
1157 Args:
Simon Glass56577572011-07-19 11:08:06 +12001158 hardware_id: Hardware ID to use for this board. If None, then the
1159 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001160 output_fname: Output filename for the image. If this is not None, then
1161 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001162 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001163
1164 Returns:
1165 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001166 """
Simon Glass89b86b82011-07-17 23:49:49 -07001167 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -07001168 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +12001169 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001170
1171 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001172 image, pack = self._CreateImage(gbb, self.fdt)
1173 if show_map:
1174 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001175 if output_fname:
1176 shutil.copyfile(image, output_fname)
1177 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001178 return image, pack.props