blob: b4420becd8f5f32f919070b7ab66f0371ec59f4b [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
254 def CheckOptions(self):
255 """Check provided options and select defaults."""
256 if not self._board:
257 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700258 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700259 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700260 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700261 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700262 base_name = re.sub('_', '-', self._board)
263
264 # In case the name exists with a prefix or suffix, find it.
265 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
266 found_list = glob.glob(self._tools.Filename(wildcard))
267 if len(found_list) == 1:
268 self._fdt_fname = found_list[0]
269 else:
270 # We didn't find anything definite, so set up our expected name.
271 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
272
Simon Glass881964d2012-04-04 11:34:09 -0700273 # Convert things like 'exynos5250-daisy' into a full path.
274 root, ext = os.path.splitext(self._fdt_fname)
275 if not ext and not os.path.dirname(root):
276 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
277
Simon Glass290a1802011-07-17 13:54:32 -0700278 if not self.uboot_fname:
279 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
280 if not self.bct_fname:
281 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700282 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700283 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700284 if not self.exynos_bl1:
285 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
286 if not self.exynos_bl2:
287 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700288 if not self.coreboot_fname:
289 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
290 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700291 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700292 if not self.seabios_fname:
293 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700294 if not self.ecrw_fname:
295 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
296 if not self.ecro_fname:
297 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700298
Simon Glass75759302012-03-15 20:26:53 -0700299 def GetFiles(self):
300 """Get a list of files that we know about.
301
302 This is the opposite of SetFiles except that we may have put in some
303 default names. It returns a dictionary containing the filename for
304 each of a number of pre-defined files.
305
306 Returns:
307 Dictionary, with one entry for each file.
308 """
309 file_list = {
310 'bct' : self.bct_fname,
311 'exynos-bl1' : self.exynos_bl1,
312 'exynos-bl2' : self.exynos_bl2,
313 }
314 return file_list
315
Simon Glass4a887b12012-10-23 16:29:03 -0700316 def DecodeGBBFlagsFromFdt(self):
317 """Get Google Binary Block flags from the FDT.
318
319 These should be in the chromeos-config node, like this:
320
321 chromeos-config {
322 gbb-flag-dev-screen-short-delay;
323 gbb-flag-force-dev-switch-on;
324 gbb-flag-force-dev-boot-usb;
325 gbb-flag-disable-fw-rollback-check;
326 };
327
328 Returns:
329 GBB flags value from FDT.
330 """
331 chromeos_config = self.fdt.GetProps("/chromeos-config")
332 gbb_flags = 0
333 for name in chromeos_config:
334 if name.startswith('gbb-flag-'):
335 flag_value = gbb_flag_properties.get(name[9:])
336 if flag_value:
337 gbb_flags |= flag_value
338 self._out.Notice("FDT: Enabling %s." % name)
339 else:
340 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
341 return gbb_flags
342
Simon Glass157c0662012-10-23 13:52:42 -0700343 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
344 """Decode ajustments to the provided GBB flags.
345
346 We support three options:
347
348 hex value: c2
349 defined value: force-dev-boot-usb,load-option-roms
350 adjust default value: -load-option-roms,+force-dev-boot-usb
351
352 The last option starts from the passed-in GBB flags and adds or removes
353 flags.
354
355 Args:
356 gbb_flags: Base (default) FDT flags.
357 adjustments: String containing adjustments to make.
358
359 Returns:
360 Updated FDT flags.
361 """
362 use_base_value = True
363 if adjustments:
364 try:
365 return int(adjustments, base=16)
366 except:
367 pass
368 for flag in adjustments.split(','):
369 oper = None
370 if flag[0] in ['-', '+']:
371 oper = flag[0]
372 flag = flag[1:]
373 value = gbb_flag_properties.get(flag)
374 if not value:
375 raise ValueError("Invalid GBB flag '%s'" % flag)
376 if oper == '+':
377 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800378 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700379 elif oper == '-':
380 gbb_flags &= ~value
Simon Glass84816582012-11-20 10:53:10 -0800381 self._out.Notice("Cmdline: Disabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700382 else:
383 if use_base_value:
384 gbb_flags = 0
385 use_base_value = False
Simon Glass84816582012-11-20 10:53:10 -0800386 self._out.Notice('Cmdline: Resetting flags to 0')
Simon Glass157c0662012-10-23 13:52:42 -0700387 gbb_flags |= value
Simon Glass84816582012-11-20 10:53:10 -0800388 self._out.Notice("Cmdline: Enabling %s." % flag)
Simon Glass157c0662012-10-23 13:52:42 -0700389
390 return gbb_flags
391
Simon Glass56577572011-07-19 11:08:06 +1200392 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700393 """Create a GBB for the image.
394
Simon Glass56577572011-07-19 11:08:06 +1200395 Args:
396 hardware_id: Hardware ID to use for this board. If None, then the
397 default from the Fdt will be used
398
Simon Glass89b86b82011-07-17 23:49:49 -0700399 Returns:
400 Path of the created GBB file.
401
402 Raises:
403 CmdError if a command fails.
404 """
Simon Glass56577572011-07-19 11:08:06 +1200405 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800406 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700407 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700408 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700409
Simon Glass4a887b12012-10-23 16:29:03 -0700410 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800411
Simon Glass157c0662012-10-23 13:52:42 -0700412 # Allow command line to override flags
413 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
414
Simon Glass4a887b12012-10-23 16:29:03 -0700415 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700416 self._out.Progress('Creating GBB')
417 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
418 sizes = ['%#x' % size for size in sizes]
419 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700420 keydir = self._tools.Filename(self._keydir)
421 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700422 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200423 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700424 '--rootkey=%s/root_key.vbpubk' % keydir,
425 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700426 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800427 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700428 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700429 cwd=odir)
430 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700431
Simon Glasse13ee2c2011-07-28 08:12:28 +1200432 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700433 """Sign an image so that the Tegra SOC will boot it.
434
435 Args:
436 bct: BCT file to use.
437 bootstub: Boot stub (U-Boot + fdt) file to sign.
438 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700439
440 Returns:
441 filename of signed image.
442
443 Raises:
444 CmdError if a command fails.
445 """
446 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200447 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700448 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200449 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700450 fd = open(config, 'w')
451 fd.write('Version = 1;\n')
452 fd.write('Redundancy = 1;\n')
453 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700454
455 # TODO(dianders): Right now, we don't have enough space in our flash map
456 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
457 # sure what this does for reliability, but at least things will fit...
458 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
459 if is_nand:
460 fd.write('Bctcopy = 1;\n')
461
Simon Glass89b86b82011-07-17 23:49:49 -0700462 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
463 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700464
Simon Glass89b86b82011-07-17 23:49:49 -0700465 fd.close()
466
467 self._tools.Run('cbootimage', [config, signed])
468 self._tools.OutputSize('BCT', bct)
469 self._tools.OutputSize('Signed image', signed)
470 return signed
471
Doug Anderson86ce5f42011-07-27 10:40:18 -0700472 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700473 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700474
475 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700476 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700477 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700478 """
Simon Glass468d8752012-09-19 16:36:19 -0700479 if bootcmd is not None:
480 if bootcmd == 'none':
481 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800482 self.fdt.PutString('/config', 'bootcmd', bootcmd)
483 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700484 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700485
Simon Glassa4934b72012-05-09 13:35:02 -0700486 def SetNodeEnabled(self, node_name, enabled):
487 """Set whether an node is enabled or disabled.
488
489 This simply sets the 'status' property of a node to "ok", or "disabled".
490
491 The node should either be a full path to the node (like '/uart@10200000')
492 or an alias property.
493
494 Aliases are supported like this:
495
496 aliases {
497 console = "/uart@10200000";
498 };
499
500 pointing to a node:
501
502 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700503 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700504 };
505
506 In this case, this function takes the name of the alias ('console' in
507 this case) and updates the status of the node that is pointed to, to
508 either ok or disabled. If the alias does not exist, a warning is
509 displayed.
510
511 Args:
512 node_name: Name of node (e.g. '/uart@10200000') or alias alias
513 (e.g. 'console') to adjust
514 enabled: True to enable, False to disable
515 """
516 # Look up the alias if this is an alias reference
517 if not node_name.startswith('/'):
518 lookup = self.fdt.GetString('/aliases', node_name, '')
519 if not lookup:
520 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
521 return
522 node_name = lookup
523 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700524 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700525 else:
526 status = 'disabled'
527 self.fdt.PutString(node_name, 'status', status)
528
529 def AddEnableList(self, enable_list):
530 """Process a list of nodes to enable/disable.
531
532 Args:
533 config_list: List of (node, value) tuples to add to the fdt. For each
534 tuple:
535 node: The fdt node to write to will be <node> or pointed to by
536 /aliases/<node>. We can tell which
537 value: 0 to disable the node, 1 to enable it
538 """
539 if enable_list:
540 for node_name, enabled in enable_list:
541 try:
542 enabled = int(enabled)
543 if enabled not in (0, 1):
544 raise ValueError
545 except ValueError as str:
546 raise CmdError("Invalid enable option value '%s' "
547 "(should be 0 or 1)" % enabled)
548 self.SetNodeEnabled(node_name, enabled)
549
Simon Glass290a1802011-07-17 13:54:32 -0700550 def AddConfigList(self, config_list, use_int=False):
551 """Add a list of config items to the fdt.
552
553 Normally these values are written to the fdt as strings, but integers
554 are also supported, in which case the values will be converted to integers
555 (if necessary) before being stored.
556
557 Args:
558 config_list: List of (config, value) tuples to add to the fdt. For each
559 tuple:
560 config: The fdt node to write to will be /config/<config>.
561 value: An integer or string value to write.
562 use_int: True to only write integer values.
563
564 Raises:
565 CmdError: if a value is required to be converted to integer but can't be.
566 """
567 if config_list:
568 for config in config_list:
569 value = config[1]
570 if use_int:
571 try:
572 value = int(value)
573 except ValueError as str:
574 raise CmdError("Cannot convert config option '%s' to integer" %
575 value)
576 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800577 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700578 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800579 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700580
Simon Glass7c2d5572011-11-15 14:47:08 -0800581 def DecodeTextBase(self, data):
582 """Look at a U-Boot image and try to decode its TEXT_BASE.
583
584 This works because U-Boot has a header with the value 0x12345678
585 immediately followed by the TEXT_BASE value. We can therefore read this
586 from the image with some certainty. We check only the first 40 words
587 since the header should be within that region.
588
Simon Glass96b50302012-07-20 06:55:28 +0100589 Since upstream Tegra has moved to having a 16KB SPL region at the start,
590 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
591 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
592
Simon Glass7c2d5572011-11-15 14:47:08 -0800593 Args:
594 data: U-Boot binary data
595
596 Returns:
597 Text base (integer) or None if none was found
598 """
599 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100600 for start in (0, 0x4000):
601 for i in range(start, start + 160, 4):
602 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800603
Simon Glass96b50302012-07-20 06:55:28 +0100604 # TODO(sjg): This does not cope with a big-endian target
605 value = struct.unpack('<I', word)[0]
606 if found:
607 return value - start
608 if value == 0x12345678:
609 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800610
611 return None
612
613 def CalcTextBase(self, name, fdt, fname):
614 """Calculate the TEXT_BASE to use for U-Boot.
615
616 Normally this value is in the fdt, so we just read it from there. But as
617 a second check we look at the image itself in case this is different, and
618 switch to that if it is.
619
620 This allows us to flash any U-Boot even if its TEXT_BASE is different.
621 This is particularly useful with upstream U-Boot which uses a different
622 value (which we will move to).
623 """
624 data = self._tools.ReadFile(fname)
Andrew Chewaa092542013-01-09 16:30:52 -0800625 # The value that comes back from fdt.GetInt is signed, which makes no
626 # sense for an address base. Force it to unsigned.
627 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0) & 0xffffffff
Simon Glass7c2d5572011-11-15 14:47:08 -0800628 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100629 text_base_str = '%#x' % text_base if text_base else 'None'
630 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
631 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800632
633 # If they are different, issue a warning and switch over.
634 if text_base and text_base != fdt_text_base:
635 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
636 "fdt value of %x. Using %x" % (text_base, name,
637 fdt_text_base, text_base))
638 fdt_text_base = text_base
639 return fdt_text_base
640
Simon Glass6dcc2f22011-07-28 15:26:49 +1200641 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700642 """Create a boot stub and a signed boot stub.
643
Simon Glass6dcc2f22011-07-28 15:26:49 +1200644 For postload:
645 We add a /config/postload-text-offset entry to the signed bootstub's
646 fdt so that U-Boot can find the postload code.
647
648 The raw (unsigned) bootstub will have a value of -1 for this since we will
649 simply append the postload code to the bootstub and it can find it there.
650 This will be used for RW A/B firmware.
651
652 For the signed case this value will specify where in the flash to find
653 the postload code. This will be used for RO firmware.
654
Simon Glass89b86b82011-07-17 23:49:49 -0700655 Args:
656 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800657 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200658 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700659
660 Returns:
661 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200662 Full path to bootstub (uboot + fdt(-1) + postload).
663 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700664
665 Raises:
666 CmdError if a command fails.
667 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200668 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800669 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700670 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200671
672 # Make a copy of the fdt for the bootstub
673 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800674 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700675 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200676
Simon Glass89b86b82011-07-17 23:49:49 -0700677 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700678 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
679 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700680 self._tools.OutputSize('Combined binary', bootstub)
681
Simon Glasse13ee2c2011-07-28 08:12:28 +1200682 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700683 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700684 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200685 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200686
687 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
688 data = self._tools.ReadFile(signed)
689
690 if postload:
691 # We must add postload to the bootstub since A and B will need to
692 # be able to find it without the /config/postload-text-offset mechanism.
693 bs_data = self._tools.ReadFile(bootstub)
694 bs_data += self._tools.ReadFile(postload)
695 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
696 self._tools.WriteFile(bootstub, bs_data)
697 self._tools.OutputSize('Combined binary with postload', bootstub)
698
699 # Now that we know the file size, adjust the fdt and re-sign
700 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800701 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200702 fdt_data = self._tools.ReadFile(fdt.fname)
703 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
704 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
705 postload_bootstub, text_base)
706 if len(data) != os.path.getsize(signed):
707 raise CmdError('Signed file size changed from %d to %d after updating '
708 'fdt' % (len(data), os.path.getsize(signed)))
709
710 # Re-read the signed image, and add the post-load binary.
711 data = self._tools.ReadFile(signed)
712 data += self._tools.ReadFile(postload)
713 self._tools.OutputSize('Post-load binary', postload)
714
715 self._tools.WriteFile(signed_postload, data)
716 self._tools.OutputSize('Final bootstub with postload', signed_postload)
717
718 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700719
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700720 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700721 """Create a coreboot boot stub.
722
723 Args:
724 uboot: Path to u-boot.bin (may be chroot-relative)
725 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700726 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700727
728 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100729 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700730
731 Raises:
732 CmdError if a command fails.
733 """
734 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700735 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100736
737 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700738 return bootstub
739
Simon Glass3b404092012-05-23 13:10:36 -0700740 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700741 """Update the parameters in a BL2 blob.
742
743 We look at the list in the parameter block, extract the value of each
744 from the device tree, and write that value to the parameter block.
745
746 Args:
747 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700748 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700749 data: The BL2 data.
750 pos: The position of the start of the parameter block.
751
752 Returns:
753 The new contents of the parameter block, after updating.
754 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700755 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
756 if version != 1:
757 raise CmdError("Cannot update machine parameter block version '%d'" %
758 version)
759 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700760 raise CmdError("Machine parameter block size %d is invalid: "
761 "pos=%d, size=%d, space=%d, len=%d" %
762 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700763
764 # Move past the header and read the parameter list, which is terminated
765 # with \0.
766 pos += 12
767 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
768 param_len = param_list.find('\0')
769 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700770 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700771
772 # Work through the parameters one at a time, adding each value
773 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700774 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700775 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700776 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glass56583742012-11-06 12:34:47 -0800777
778 # Use this to detect a missing value from the fdt.
779 not_given = 'not-given-invalid-value'
Simon Glassdf95dd22012-03-13 15:46:16 -0700780 if param == 'm' :
Simon Glass56583742012-11-06 12:34:47 -0800781 mem_type = fdt.GetString('/dmc', 'mem-type', not_given)
782 if mem_type == not_given:
783 mem_type = 'ddr3'
784 self._out.Warning("No value for memory type: using '%s'" % mem_type)
Simon Glassdf95dd22012-03-13 15:46:16 -0700785 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
786 if not mem_type in mem_types:
787 raise CmdError("Unknown memory type '%s'" % mem_type)
788 value = mem_types.index(mem_type)
789 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700790 elif param == 'M' :
Simon Glass56583742012-11-06 12:34:47 -0800791 mem_manuf = fdt.GetString('/dmc', 'mem-manuf', not_given)
792 if mem_manuf == not_given:
793 mem_manuf = 'samsung'
794 self._out.Warning("No value for memory manufacturer: using '%s'" %
795 mem_manuf)
Doug Andersonee46cfe2012-05-18 09:53:08 -0700796 mem_manufs = ['autodetect', 'elpida', 'samsung']
797 if not mem_manuf in mem_manufs:
798 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
799 value = mem_manufs.index(mem_manuf)
800 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700801 elif param == 'f' :
Simon Glass56583742012-11-06 12:34:47 -0800802 mem_freq = fdt.GetInt('/dmc', 'clock-frequency', -1)
803 if mem_freq == -1:
804 mem_freq = 800000000
805 self._out.Warning("No value for memory frequency: using '%s'" %
806 mem_freq)
807 mem_freq /= 1000000
Simon Glass158289e2012-09-14 11:42:25 -0700808 if not mem_freq in [533, 667, 800]:
809 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
810 value = mem_freq
811 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700812 elif param == 'v':
813 value = 31
814 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700815 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700816 value = (spl_load_size + 0xfff) & ~0xfff
817 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
818 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700819 elif param == 'b':
820 # These values come from enum boot_mode in U-Boot's cpu.h
821 if self.spl_source == 'straps':
822 value = 32
823 elif self.spl_source == 'emmc':
824 value = 4
825 elif self.spl_source == 'spi':
826 value = 20
827 elif self.spl_source == 'usb':
828 value = 33
829 else:
830 raise CmdError("Invalid boot source '%s'" % self.spl_source)
831 self._out.Info(' Boot source: %#0x' % value)
Tom Wai-Hong Tam99b7f112013-02-06 09:10:10 +0800832 elif param == 'z':
833 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
834 compress_types = ['none', 'lzo']
835 if not compress in compress_types:
836 raise CmdError("Unknown compression type '%s'" % compress)
837 value = compress_types.index(compress)
838 self._out.Info(' Compression type: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700839 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700840 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700841 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700842 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700843 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700844
845 # Put the data into our block.
846 data = data[:pos] + new_data + data[pos + len(new_data):]
847 self._out.Info('BL2 configuration complete')
848 return data
849
Simon Glasse5e8afb2012-05-23 11:19:23 -0700850 def _UpdateChecksum(self, data):
851 """Update the BL2 checksum.
852
853 The checksum is a 4 byte sum of all the bytes in the image before the
854 last 4 bytes (which hold the checksum).
855
856 Args:
857 data: The BL2 data to update.
858
859 Returns:
860 The new contents of the BL2 data, after updating the checksum.
861 """
862 checksum = 0
863 for ch in data[:-4]:
864 checksum += ord(ch)
865 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
866
Simon Glass559b6612012-05-23 13:28:45 -0700867 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700868 """Configure an Exynos BL2 binary for our needs.
869
870 We create a new modified BL2 and return its filename.
871
872 Args:
873 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700874 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700875 orig_bl2: Filename of original BL2 file to modify.
876 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700877 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700878 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700879 data = self._tools.ReadFile(orig_bl2)
880 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700881
882 # Locate the parameter block
883 data = self._tools.ReadFile(bl2)
884 marker = struct.pack('<L', 0xdeadbeef)
885 pos = data.rfind(marker)
886 if not pos:
887 raise CmdError("Could not find machine parameter block in '%s'" %
888 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700889 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700890 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700891 self._tools.WriteFile(bl2, data)
892 return bl2
893
Simon Glass89b86b82011-07-17 23:49:49 -0700894 def _PackOutput(self, msg):
895 """Helper function to write output from PackFirmware (verbose level 2).
896
897 This is passed to PackFirmware for it to use to write output.
898
899 Args:
900 msg: Message to display.
901 """
902 self._out.Notice(msg)
903
Simon Glass439fe7a2012-03-09 16:19:34 -0800904 def _BuildBlob(self, pack, fdt, blob_type):
905 """Build the blob data for a particular blob type.
906
907 Args:
908 blob_type: The type of blob to create data for. Supported types are:
909 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
910 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
911 """
912 if blob_type == 'coreboot':
913 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700914 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800915 pack.AddProperty('coreboot', coreboot)
916 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700917 elif blob_type == 'legacy':
918 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800919 elif blob_type == 'signed':
920 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
921 self.postload_fname)
922 pack.AddProperty('bootstub', bootstub)
923 pack.AddProperty('signed', signed)
924 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700925 elif blob_type == 'exynos-bl1':
926 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700927
928 # TODO(sjg@chromium.org): Deprecate ecbin
929 elif blob_type in ['ecrw', 'ecbin']:
930 pack.AddProperty('ecrw', self.ecrw_fname)
931 pack.AddProperty('ecbin', self.ecrw_fname)
Gabe Blackcdbdfe12013-02-06 05:37:52 -0800932 elif blob_type == 'ecrwhash':
933 ec_hash_file = os.path.join(self._tools.outdir, 'ec_hash.bin')
934 ecrw = self._tools.ReadFile(self.ecrw_fname)
935 hasher = hashlib.sha256()
936 hasher.update(ecrw)
937 self._tools.WriteFile(ec_hash_file, hasher.digest())
938 pack.AddProperty(blob_type, ec_hash_file)
Simon Glassbe0bc002012-08-16 12:50:48 -0700939 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700940 # crosbug.com/p/13143
941 # We cannot have an fmap in the EC image since there can be only one,
942 # which is the main fmap describing the whole image.
943 # Ultimately the EC will not have an fmap, since with software sync
944 # there is no flashrom involvement in updating the EC flash, and thus
945 # no need for the fmap.
946 # For now, mangle the fmap name to avoid problems.
947 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
948 data = self._tools.ReadFile(self.ecro_fname)
949 data = re.sub('__FMAP__', '__fMAP__', data)
950 self._tools.WriteFile(updated_ecro, data)
951 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700952 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700953 spl_payload = pack.GetBlobParams(blob_type)
954
955 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
956 # from all flash map files.
957 if not spl_payload:
958 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
959 prop_list = 'boot+dtb'
960
961 # Do this later, when we remove boot+dtb.
962 # raise CmdError("No parameters provided for blob type '%s'" %
963 # blob_type)
964 else:
965 prop_list = spl_payload[0].split(',')
Tom Wai-Hong Tam26e3a4c2013-02-06 09:36:47 +0800966 compress = fdt.GetString('/flash/ro-boot', 'compress', 'none')
967 if compress == 'none':
968 compress = None
969 spl_load_size = len(pack.ConcatPropContents(prop_list, compress,
970 False)[0])
Simon Glass7d2542f2012-06-21 07:10:59 -0700971 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
972 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700973 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700974 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800975 elif pack.GetProperty(blob_type):
976 pass
977 else:
978 raise CmdError("Unknown blob type '%s' required in flash map" %
979 blob_type)
980
Simon Glass290a1802011-07-17 13:54:32 -0700981 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700982 """Create a full firmware image, along with various by-products.
983
984 This uses the provided u-boot.bin, fdt and bct to create a firmware
985 image containing all the required parts. If the GBB is not supplied
986 then this will just return a signed U-Boot as the image.
987
988 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200989 gbb: Full path to the GBB file, or empty if a GBB is not required.
990 fdt: Fdt object containing required information.
991
992 Returns:
993 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700994
995 Raises:
996 CmdError if a command fails.
997 """
Simon Glass02d124a2012-03-02 14:47:20 -0800998 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700999
Simon Glass439fe7a2012-03-09 16:19:34 -08001000 # Get the flashmap so we know what to build
1001 pack = PackFirmware(self._tools, self._out)
Simon Glass0c54ba52012-11-06 12:36:43 -08001002 default_flashmap = default_flashmaps.get(self._board)
Simon Glassb8c6d952012-12-01 06:14:35 -08001003 if self._force_rw:
1004 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
1005 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
1006
Simon Glass0c54ba52012-11-06 12:36:43 -08001007 pack.SelectFdt(fdt, self._board, default_flashmap)
Simon Glass439fe7a2012-03-09 16:19:34 -08001008
1009 # Get all our blobs ready
1010 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -07001011 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -07001012 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -07001013
Simon Glass47817052012-10-20 13:30:07 -07001014 # Let's create some copies of the fdt for vboot. These can be used to
1015 # pass a different fdt to each firmware type. For now it is just used to
1016 # check that the right fdt comes through.
1017 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
1018 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
1019 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
1020 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
1021 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
1022 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
1023 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
1024
Simon Glassde9c8072012-07-02 22:29:02 -07001025 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
1026 if self.kernel_fname:
1027 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
1028
Simon Glass439fe7a2012-03-09 16:19:34 -08001029 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +01001030 blob_list = pack.GetBlobList()
1031 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -07001032 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -08001033 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -07001034
Simon Glass7306b902012-12-17 15:06:21 -08001035 self._out.Progress('Packing image')
Simon Glass89b86b82011-07-17 23:49:49 -07001036 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -07001037 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +08001038 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -08001039 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +08001040 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -07001041 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -08001042 pack.AddProperty('fwid', fwid)
1043 pack.AddProperty('gbb', gbb)
1044 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -07001045
1046 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -07001047
1048 # Record position and size of all blob members in the FDT
Gabe Blackcc22d772013-02-04 23:12:02 -08001049 pack.UpdateBlobPositionsAndHashes(fdt)
1050 pack.UpdateBlobPositionsAndHashes(fdt_rwa)
1051 pack.UpdateBlobPositionsAndHashes(fdt_rwb)
Simon Glass8884b982012-06-21 12:41:41 -07001052
Simon Glass6207efe2012-12-17 15:04:36 -08001053 # Make a copy of the fdt for the bootstub
1054 fdt_data = self._tools.ReadFile(fdt.fname)
1055 uboot_data = self._tools.ReadFile(self.uboot_fname)
1056 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
1057 self._tools.WriteFile(uboot_copy, uboot_data)
1058
1059 uboot_dtb = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
1060 self._tools.WriteFile(uboot_dtb, uboot_data + fdt_data)
1061
Simon Glassa10282a2013-01-08 17:06:41 -08001062 # Fix up the coreboot image here, since we can't do this until we have
1063 # a final device tree binary.
Simon Glasscbc83552012-07-23 15:26:22 +01001064 if 'coreboot' in blob_list:
1065 bootstub = pack.GetProperty('coreboot')
1066 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glassa10282a2013-01-08 17:06:41 -08001067 if self.coreboot_elf:
1068 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f',
1069 self.coreboot_elf, '-n', 'fallback/payload', '-c', 'lzma'])
1070 else:
1071 self._tools.Run('cbfstool', [bootstub, 'add-flat-binary', '-f',
1072 uboot_dtb, '-n', 'fallback/payload', '-c', 'lzma',
1073 '-l', '0x1110000', '-e', '0x1110008'])
Stefan Reinauer1502ea62012-11-01 10:15:38 -07001074 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
1075 '-n', 'u-boot.dtb', '-t', '0xac'])
Simon Glassb8ea1802012-12-17 15:08:00 -08001076 data = self._tools.ReadFile(bootstub)
1077 bootstub_copy = os.path.join(self._tools.outdir, 'coreboot-8mb.rom')
1078 self._tools.WriteFile(bootstub_copy, data)
1079 self._tools.WriteFile(bootstub, data[0x700000:])
Simon Glasscbc83552012-07-23 15:26:22 +01001080
Simon Glassc90cf582012-03-13 15:40:47 -07001081 image = os.path.join(self._tools.outdir, 'image.bin')
1082 pack.PackImage(self._tools.outdir, image)
1083 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -07001084
Simon Glass439fe7a2012-03-09 16:19:34 -08001085 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -07001086 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001087 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001088
Simon Glass290a1802011-07-17 13:54:32 -07001089 def SelectFdt(self, fdt_fname):
1090 """Select an FDT to control the firmware bundling
1091
1092 Args:
1093 fdt_fname: The filename of the fdt to use.
1094
Simon Glassc0f3dc62011-08-09 14:19:05 -07001095 Returns:
1096 The Fdt object of the original fdt file, which we will not modify.
1097
Simon Glass290a1802011-07-17 13:54:32 -07001098 We make a copy of this which will include any on-the-fly changes we want
1099 to make.
1100 """
1101 self._fdt_fname = fdt_fname
1102 self.CheckOptions()
1103 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glassc3e42c32012-12-17 15:00:04 -08001104
1105 # For upstream, select the correct architecture .dtsi manually.
1106 if self._board == 'link' or 'x86' in self._board:
1107 arch_dts = 'coreboot.dtsi'
1108 elif self._board == 'daisy':
1109 arch_dts = 'exynos5250.dtsi'
1110 else:
1111 arch_dts = 'tegra20.dtsi'
1112
1113 fdt.Compile(arch_dts)
Simon Glass290a1802011-07-17 13:54:32 -07001114 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -07001115 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001116
Simon Glassc90cf582012-03-13 15:40:47 -07001117 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001118 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001119
1120 - Checks options, tools, output directory, fdt.
1121 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001122
1123 Args:
Simon Glass56577572011-07-19 11:08:06 +12001124 hardware_id: Hardware ID to use for this board. If None, then the
1125 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001126 output_fname: Output filename for the image. If this is not None, then
1127 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001128 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001129
1130 Returns:
1131 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001132 """
Simon Glass89b86b82011-07-17 23:49:49 -07001133 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -07001134 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +12001135 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001136
1137 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001138 image, pack = self._CreateImage(gbb, self.fdt)
1139 if show_map:
1140 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001141 if output_fname:
1142 shutil.copyfile(image, output_fname)
1143 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001144 return image, pack.props