blob: 310535ca83b68fbd989284b650b8b910f1d136c8 [file] [log] [blame]
Simon Glass89b86b82011-07-17 23:49:49 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This module builds a firmware image for a tegra-based board.
6
7This modules uses a few rudimentary other libraries for its activity.
8
9Here are the names we give to the various files we deal with. It is important
10to keep these consistent!
11
12 uboot u-boot.bin (with no device tree)
13 fdt the fdt blob
14 bct the BCT file
15 bootstub uboot + fdt
16 signed (uboot + fdt + bct) signed blob
17"""
18
Simon Glassceff3ff2012-04-04 11:23:45 -070019import glob
Simon Glass89b86b82011-07-17 23:49:49 -070020import os
21import re
22
23import cros_output
24from fdt import Fdt
25from pack_firmware import PackFirmware
26import shutil
Simon Glass7c2d5572011-11-15 14:47:08 -080027import struct
Simon Glass89b86b82011-07-17 23:49:49 -070028import tempfile
Simon Glass439fe7a2012-03-09 16:19:34 -080029from tools import CmdError
Simon Glass89b86b82011-07-17 23:49:49 -070030from tools import Tools
31from write_firmware import WriteFirmware
32
33# This data is required by bmpblk_utility. Does it ever change?
34# It was stored with the chromeos-bootimage ebuild, but we want
35# this utility to work outside the chroot.
36yaml_data = '''
37bmpblock: 1.0
38
39images:
40 devmode: DeveloperBmp/DeveloperBmp.bmp
41 recovery: RecoveryBmp/RecoveryBmp.bmp
42 rec_yuck: RecoveryNoOSBmp/RecoveryNoOSBmp.bmp
43 rec_insert: RecoveryMissingOSBmp/RecoveryMissingOSBmp.bmp
44
45screens:
46 dev_en:
47 - [0, 0, devmode]
48 rec_en:
49 - [0, 0, recovery]
50 yuck_en:
51 - [0, 0, rec_yuck]
52 ins_en:
53 - [0, 0, rec_insert]
54
55localizations:
56 - [ dev_en, rec_en, yuck_en, ins_en ]
57'''
58
Simon Glass0c54ba52012-11-06 12:36:43 -080059# Default flash maps for various boards we support.
60# These are used when no fdt is provided (e.g. upstream U-Boot with no
61# fdt. Each is a list of nodes.
62default_flashmaps = {
63 'tegra' : [{
64 'node' : 'ro-boot',
65 'label' : 'boot-stub',
66 'size' : 512 << 10,
67 'read-only' : True,
68 'type' : 'blob signed',
69 'required' : True
70 }
71 ],
72 'daisy' : [
73 {
74 'node' : 'pre-boot',
75 'label' : "bl1 pre-boot",
76 'size' : 0x2000,
77 'read-only' : True,
78 'filename' : "e5250.nbl1.bin",
79 'type' : "blob exynos-bl1",
80 'required' : True,
81 }, {
82 'node' : 'spl',
83 'label' : "bl2 spl",
84 'size' : 0x4000,
85 'read-only' : True,
86 'filename' : "bl2.bin",
87 'type' : "blob exynos-bl2 boot,dtb",
88 'required' : True,
89 }, {
90 'node' : 'ro-boot',
91 'label' : "u-boot",
92 'size' : 0x9a000,
93 'read-only' : True,
94 'type' : "blob boot,dtb",
95 'required' : True,
96 }
97 ]
98}
99
100
Simon Glass4a887b12012-10-23 16:29:03 -0700101# Build GBB flags.
102# (src/platform/vboot_reference/firmware/include/gbb_header.h)
103gbb_flag_properties = {
104 'dev-screen-short-delay': 0x00000001,
105 'load-option-roms': 0x00000002,
106 'enable-alternate-os': 0x00000004,
107 'force-dev-switch-on': 0x00000008,
108 'force-dev-boot-usb': 0x00000010,
109 'disable-fw-rollback-check': 0x00000020,
110 'enter-triggers-tonorm': 0x00000040,
111 'force-dev-boot-legacy': 0x00000080,
112}
113
Simon Glass5076a7f2012-10-23 16:31:54 -0700114def ListGoogleBinaryBlockFlags():
115 """Print out a list of GBB flags."""
116 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
117 for name, value in gbb_flag_properties.iteritems():
118 print ' %-30s %02x' % (name, value)
119
Simon Glass89b86b82011-07-17 23:49:49 -0700120class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -0700121 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -0700122
Simon Glass290a1802011-07-17 13:54:32 -0700123 Sequence of events:
124 bundle = Bundle(tools.Tools(), cros_output.Output())
125 bundle.SetDirs(...)
126 bundle.SetFiles(...)
127 bundle.SetOptions(...)
128 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -0700129 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -0700130 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -0700131
Simon Glass290a1802011-07-17 13:54:32 -0700132 Public properties:
133 fdt: The fdt object that we use for building our image. This wil be the
134 one specified by the user, except that we might add config options
135 to it. This is set up by SelectFdt() which must be called before
136 bundling starts.
137 uboot_fname: Full filename of the U-Boot binary we use.
138 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -0700139 spl_source: Source device to load U-Boot from, in SPL:
140 straps: Select device according to CPU strap pins
141 spi: Boot from SPI
142 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -0700143
144 Private attributes:
145 _small: True to create a 'small' signed U-Boot, False to produce a
146 full image. The small U-Boot is enough to boot but will not have
147 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700148 """
Simon Glass89b86b82011-07-17 23:49:49 -0700149
Simon Glass290a1802011-07-17 13:54:32 -0700150 def __init__(self, tools, output):
151 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700152
Simon Glass290a1802011-07-17 13:54:32 -0700153 Args:
154 tools: A tools.Tools object to use for external tools.
155 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700156 """
Simon Glass290a1802011-07-17 13:54:32 -0700157 self._tools = tools
158 self._out = output
159
160 # Set up the things we need to know in order to operate.
161 self._board = None # Board name, e.g. tegra2_seaboard.
162 self._fdt_fname = None # Filename of our FDT.
163 self.uboot_fname = None # Filename of our U-Boot binary.
164 self.bct_fname = None # Filename of our BCT file.
165 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800166 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700167 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -0700168 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -0700169 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
170 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass559b6612012-05-23 13:28:45 -0700171 self.spl_source = 'straps' # SPL boot according to board settings
Simon Glass07267952012-06-08 12:45:13 -0700172 self.skeleton_fname = None # Filename of Coreboot skeleton file
Simon Glassbe0bc002012-08-16 12:50:48 -0700173 self.ecrw_fname = None # Filename of EC file
174 self.ecro_fname = None # Filename of EC read-only file
Simon Glass23988ae2012-03-23 16:55:22 -0700175 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700176
177 def SetDirs(self, keydir):
178 """Set up directories required for Bundle.
179
180 Args:
181 keydir: Directory containing keys to use for signing firmware.
182 """
183 self._keydir = keydir
184
Simon Glass6dcc2f22011-07-28 15:26:49 +1200185 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glass07267952012-06-08 12:45:13 -0700186 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassbe0bc002012-08-16 12:50:48 -0700187 skeleton=None, ecrw=None, ecro=None, kernel=None):
Simon Glass290a1802011-07-17 13:54:32 -0700188 """Set up files required for Bundle.
189
190 Args:
191 board: The name of the board to target (e.g. tegra2_seaboard).
192 uboot: The filename of the u-boot.bin image to use.
193 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800194 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700195 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200196 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700197 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700198 exynos_bl1: The filename of the exynos BL1 file
199 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
200 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700201 ecrw: The filename of the EC (Embedded Controller) read-write file.
202 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700203 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700204 """
205 self._board = board
206 self.uboot_fname = uboot
207 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800208 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700209 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200210 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700211 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700212 self.exynos_bl1 = exynos_bl1
213 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700214 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700215 self.ecrw_fname = ecrw
216 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700217 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700218
Simon Glass6e486c22012-10-26 15:43:42 -0700219 def SetOptions(self, small, gbb_flags, force_rw=False):
Simon Glass290a1802011-07-17 13:54:32 -0700220 """Set up options supported by Bundle.
221
222 Args:
223 small: Only create a signed U-Boot - don't produce the full packed
224 firmware image. This is useful for devs who want to replace just the
225 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700226 gbb_flags: Specification for string containing adjustments to make.
227 force_rw: Force firmware into RW mode.
Simon Glass290a1802011-07-17 13:54:32 -0700228 """
229 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700230 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700231 self._force_rw = force_rw
Simon Glass290a1802011-07-17 13:54:32 -0700232
233 def CheckOptions(self):
234 """Check provided options and select defaults."""
235 if not self._board:
236 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700237 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700238 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700239 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700240 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700241 base_name = re.sub('_', '-', self._board)
242
243 # In case the name exists with a prefix or suffix, find it.
244 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
245 found_list = glob.glob(self._tools.Filename(wildcard))
246 if len(found_list) == 1:
247 self._fdt_fname = found_list[0]
248 else:
249 # We didn't find anything definite, so set up our expected name.
250 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
251
Simon Glass881964d2012-04-04 11:34:09 -0700252 # Convert things like 'exynos5250-daisy' into a full path.
253 root, ext = os.path.splitext(self._fdt_fname)
254 if not ext and not os.path.dirname(root):
255 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
256
Simon Glass290a1802011-07-17 13:54:32 -0700257 if not self.uboot_fname:
258 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
259 if not self.bct_fname:
260 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700261 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700262 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700263 if not self.exynos_bl1:
264 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
265 if not self.exynos_bl2:
266 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700267 if not self.coreboot_fname:
268 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
269 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700270 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700271 if not self.seabios_fname:
272 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700273 if not self.ecrw_fname:
274 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
275 if not self.ecro_fname:
276 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700277
Simon Glass75759302012-03-15 20:26:53 -0700278 def GetFiles(self):
279 """Get a list of files that we know about.
280
281 This is the opposite of SetFiles except that we may have put in some
282 default names. It returns a dictionary containing the filename for
283 each of a number of pre-defined files.
284
285 Returns:
286 Dictionary, with one entry for each file.
287 """
288 file_list = {
289 'bct' : self.bct_fname,
290 'exynos-bl1' : self.exynos_bl1,
291 'exynos-bl2' : self.exynos_bl2,
292 }
293 return file_list
294
Simon Glass4a887b12012-10-23 16:29:03 -0700295 def DecodeGBBFlagsFromFdt(self):
296 """Get Google Binary Block flags from the FDT.
297
298 These should be in the chromeos-config node, like this:
299
300 chromeos-config {
301 gbb-flag-dev-screen-short-delay;
302 gbb-flag-force-dev-switch-on;
303 gbb-flag-force-dev-boot-usb;
304 gbb-flag-disable-fw-rollback-check;
305 };
306
307 Returns:
308 GBB flags value from FDT.
309 """
310 chromeos_config = self.fdt.GetProps("/chromeos-config")
311 gbb_flags = 0
312 for name in chromeos_config:
313 if name.startswith('gbb-flag-'):
314 flag_value = gbb_flag_properties.get(name[9:])
315 if flag_value:
316 gbb_flags |= flag_value
317 self._out.Notice("FDT: Enabling %s." % name)
318 else:
319 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
320 return gbb_flags
321
Simon Glass157c0662012-10-23 13:52:42 -0700322 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
323 """Decode ajustments to the provided GBB flags.
324
325 We support three options:
326
327 hex value: c2
328 defined value: force-dev-boot-usb,load-option-roms
329 adjust default value: -load-option-roms,+force-dev-boot-usb
330
331 The last option starts from the passed-in GBB flags and adds or removes
332 flags.
333
334 Args:
335 gbb_flags: Base (default) FDT flags.
336 adjustments: String containing adjustments to make.
337
338 Returns:
339 Updated FDT flags.
340 """
341 use_base_value = True
342 if adjustments:
343 try:
344 return int(adjustments, base=16)
345 except:
346 pass
347 for flag in adjustments.split(','):
348 oper = None
349 if flag[0] in ['-', '+']:
350 oper = flag[0]
351 flag = flag[1:]
352 value = gbb_flag_properties.get(flag)
353 if not value:
354 raise ValueError("Invalid GBB flag '%s'" % flag)
355 if oper == '+':
356 gbb_flags |= value
357 elif oper == '-':
358 gbb_flags &= ~value
359 else:
360 if use_base_value:
361 gbb_flags = 0
362 use_base_value = False
363 gbb_flags |= value
364
365 return gbb_flags
366
Simon Glass56577572011-07-19 11:08:06 +1200367 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700368 """Create a GBB for the image.
369
Simon Glass56577572011-07-19 11:08:06 +1200370 Args:
371 hardware_id: Hardware ID to use for this board. If None, then the
372 default from the Fdt will be used
373
Simon Glass89b86b82011-07-17 23:49:49 -0700374 Returns:
375 Path of the created GBB file.
376
377 Raises:
378 CmdError if a command fails.
379 """
Simon Glass56577572011-07-19 11:08:06 +1200380 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800381 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700382 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700383 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700384
Simon Glass4a887b12012-10-23 16:29:03 -0700385 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800386
Simon Glass157c0662012-10-23 13:52:42 -0700387 # Allow command line to override flags
388 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
389
Simon Glass4a887b12012-10-23 16:29:03 -0700390 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700391 self._out.Progress('Creating GBB')
392 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
393 sizes = ['%#x' % size for size in sizes]
394 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700395 keydir = self._tools.Filename(self._keydir)
396 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700397 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200398 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700399 '--rootkey=%s/root_key.vbpubk' % keydir,
400 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700401 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800402 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700403 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700404 cwd=odir)
405 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700406
Simon Glasse13ee2c2011-07-28 08:12:28 +1200407 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700408 """Sign an image so that the Tegra SOC will boot it.
409
410 Args:
411 bct: BCT file to use.
412 bootstub: Boot stub (U-Boot + fdt) file to sign.
413 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700414
415 Returns:
416 filename of signed image.
417
418 Raises:
419 CmdError if a command fails.
420 """
421 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200422 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700423 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200424 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700425 fd = open(config, 'w')
426 fd.write('Version = 1;\n')
427 fd.write('Redundancy = 1;\n')
428 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700429
430 # TODO(dianders): Right now, we don't have enough space in our flash map
431 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
432 # sure what this does for reliability, but at least things will fit...
433 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
434 if is_nand:
435 fd.write('Bctcopy = 1;\n')
436
Simon Glass89b86b82011-07-17 23:49:49 -0700437 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
438 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700439
Simon Glass89b86b82011-07-17 23:49:49 -0700440 fd.close()
441
442 self._tools.Run('cbootimage', [config, signed])
443 self._tools.OutputSize('BCT', bct)
444 self._tools.OutputSize('Signed image', signed)
445 return signed
446
Doug Anderson86ce5f42011-07-27 10:40:18 -0700447 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700448 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700449
450 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700451 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700452 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700453 """
Simon Glass468d8752012-09-19 16:36:19 -0700454 if bootcmd is not None:
455 if bootcmd == 'none':
456 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800457 self.fdt.PutString('/config', 'bootcmd', bootcmd)
458 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700459 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700460
Simon Glassa4934b72012-05-09 13:35:02 -0700461 def SetNodeEnabled(self, node_name, enabled):
462 """Set whether an node is enabled or disabled.
463
464 This simply sets the 'status' property of a node to "ok", or "disabled".
465
466 The node should either be a full path to the node (like '/uart@10200000')
467 or an alias property.
468
469 Aliases are supported like this:
470
471 aliases {
472 console = "/uart@10200000";
473 };
474
475 pointing to a node:
476
477 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700478 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700479 };
480
481 In this case, this function takes the name of the alias ('console' in
482 this case) and updates the status of the node that is pointed to, to
483 either ok or disabled. If the alias does not exist, a warning is
484 displayed.
485
486 Args:
487 node_name: Name of node (e.g. '/uart@10200000') or alias alias
488 (e.g. 'console') to adjust
489 enabled: True to enable, False to disable
490 """
491 # Look up the alias if this is an alias reference
492 if not node_name.startswith('/'):
493 lookup = self.fdt.GetString('/aliases', node_name, '')
494 if not lookup:
495 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
496 return
497 node_name = lookup
498 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700499 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700500 else:
501 status = 'disabled'
502 self.fdt.PutString(node_name, 'status', status)
503
504 def AddEnableList(self, enable_list):
505 """Process a list of nodes to enable/disable.
506
507 Args:
508 config_list: List of (node, value) tuples to add to the fdt. For each
509 tuple:
510 node: The fdt node to write to will be <node> or pointed to by
511 /aliases/<node>. We can tell which
512 value: 0 to disable the node, 1 to enable it
513 """
514 if enable_list:
515 for node_name, enabled in enable_list:
516 try:
517 enabled = int(enabled)
518 if enabled not in (0, 1):
519 raise ValueError
520 except ValueError as str:
521 raise CmdError("Invalid enable option value '%s' "
522 "(should be 0 or 1)" % enabled)
523 self.SetNodeEnabled(node_name, enabled)
524
Simon Glass290a1802011-07-17 13:54:32 -0700525 def AddConfigList(self, config_list, use_int=False):
526 """Add a list of config items to the fdt.
527
528 Normally these values are written to the fdt as strings, but integers
529 are also supported, in which case the values will be converted to integers
530 (if necessary) before being stored.
531
532 Args:
533 config_list: List of (config, value) tuples to add to the fdt. For each
534 tuple:
535 config: The fdt node to write to will be /config/<config>.
536 value: An integer or string value to write.
537 use_int: True to only write integer values.
538
539 Raises:
540 CmdError: if a value is required to be converted to integer but can't be.
541 """
542 if config_list:
543 for config in config_list:
544 value = config[1]
545 if use_int:
546 try:
547 value = int(value)
548 except ValueError as str:
549 raise CmdError("Cannot convert config option '%s' to integer" %
550 value)
551 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800552 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700553 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800554 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700555
Simon Glass7c2d5572011-11-15 14:47:08 -0800556 def DecodeTextBase(self, data):
557 """Look at a U-Boot image and try to decode its TEXT_BASE.
558
559 This works because U-Boot has a header with the value 0x12345678
560 immediately followed by the TEXT_BASE value. We can therefore read this
561 from the image with some certainty. We check only the first 40 words
562 since the header should be within that region.
563
Simon Glass96b50302012-07-20 06:55:28 +0100564 Since upstream Tegra has moved to having a 16KB SPL region at the start,
565 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
566 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
567
Simon Glass7c2d5572011-11-15 14:47:08 -0800568 Args:
569 data: U-Boot binary data
570
571 Returns:
572 Text base (integer) or None if none was found
573 """
574 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100575 for start in (0, 0x4000):
576 for i in range(start, start + 160, 4):
577 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800578
Simon Glass96b50302012-07-20 06:55:28 +0100579 # TODO(sjg): This does not cope with a big-endian target
580 value = struct.unpack('<I', word)[0]
581 if found:
582 return value - start
583 if value == 0x12345678:
584 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800585
586 return None
587
588 def CalcTextBase(self, name, fdt, fname):
589 """Calculate the TEXT_BASE to use for U-Boot.
590
591 Normally this value is in the fdt, so we just read it from there. But as
592 a second check we look at the image itself in case this is different, and
593 switch to that if it is.
594
595 This allows us to flash any U-Boot even if its TEXT_BASE is different.
596 This is particularly useful with upstream U-Boot which uses a different
597 value (which we will move to).
598 """
599 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200600 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800601 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100602 text_base_str = '%#x' % text_base if text_base else 'None'
603 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
604 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800605
606 # If they are different, issue a warning and switch over.
607 if text_base and text_base != fdt_text_base:
608 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
609 "fdt value of %x. Using %x" % (text_base, name,
610 fdt_text_base, text_base))
611 fdt_text_base = text_base
612 return fdt_text_base
613
Simon Glass6dcc2f22011-07-28 15:26:49 +1200614 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700615 """Create a boot stub and a signed boot stub.
616
Simon Glass6dcc2f22011-07-28 15:26:49 +1200617 For postload:
618 We add a /config/postload-text-offset entry to the signed bootstub's
619 fdt so that U-Boot can find the postload code.
620
621 The raw (unsigned) bootstub will have a value of -1 for this since we will
622 simply append the postload code to the bootstub and it can find it there.
623 This will be used for RW A/B firmware.
624
625 For the signed case this value will specify where in the flash to find
626 the postload code. This will be used for RO firmware.
627
Simon Glass89b86b82011-07-17 23:49:49 -0700628 Args:
629 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800630 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200631 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700632
633 Returns:
634 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200635 Full path to bootstub (uboot + fdt(-1) + postload).
636 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700637
638 Raises:
639 CmdError if a command fails.
640 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200641 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800642 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700643 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200644
645 # Make a copy of the fdt for the bootstub
646 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800647 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700648 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200649
Simon Glass89b86b82011-07-17 23:49:49 -0700650 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700651 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
652 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700653 self._tools.OutputSize('Combined binary', bootstub)
654
Simon Glasse13ee2c2011-07-28 08:12:28 +1200655 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700656 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700657 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200658 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200659
660 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
661 data = self._tools.ReadFile(signed)
662
663 if postload:
664 # We must add postload to the bootstub since A and B will need to
665 # be able to find it without the /config/postload-text-offset mechanism.
666 bs_data = self._tools.ReadFile(bootstub)
667 bs_data += self._tools.ReadFile(postload)
668 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
669 self._tools.WriteFile(bootstub, bs_data)
670 self._tools.OutputSize('Combined binary with postload', bootstub)
671
672 # Now that we know the file size, adjust the fdt and re-sign
673 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800674 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200675 fdt_data = self._tools.ReadFile(fdt.fname)
676 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
677 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
678 postload_bootstub, text_base)
679 if len(data) != os.path.getsize(signed):
680 raise CmdError('Signed file size changed from %d to %d after updating '
681 'fdt' % (len(data), os.path.getsize(signed)))
682
683 # Re-read the signed image, and add the post-load binary.
684 data = self._tools.ReadFile(signed)
685 data += self._tools.ReadFile(postload)
686 self._tools.OutputSize('Post-load binary', postload)
687
688 self._tools.WriteFile(signed_postload, data)
689 self._tools.OutputSize('Final bootstub with postload', signed_postload)
690
691 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700692
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700693 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700694 """Create a coreboot boot stub.
695
696 Args:
697 uboot: Path to u-boot.bin (may be chroot-relative)
698 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700699 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700700
701 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100702 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700703
704 Raises:
705 CmdError if a command fails.
706 """
707 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700708
709 # U-Boot itself does not put a .elf extension on the elf file.
710 # The U-Boot ebuild does, but we shouldn't actually require it since
711 # devs may want to just use what U-Boot creates.
712 uboot_elf = uboot.replace('.bin', '')
713 if not os.path.exists(self._tools.Filename(uboot_elf)):
714 uboot_elf = uboot.replace('.bin', '.elf')
715 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Stefan Reinauer1502ea62012-11-01 10:15:38 -0700716 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f', uboot_elf,
717 '-n', 'fallback/payload', '-c', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100718
719 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700720 return bootstub
721
Simon Glass3b404092012-05-23 13:10:36 -0700722 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700723 """Update the parameters in a BL2 blob.
724
725 We look at the list in the parameter block, extract the value of each
726 from the device tree, and write that value to the parameter block.
727
728 Args:
729 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700730 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700731 data: The BL2 data.
732 pos: The position of the start of the parameter block.
733
734 Returns:
735 The new contents of the parameter block, after updating.
736 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700737 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
738 if version != 1:
739 raise CmdError("Cannot update machine parameter block version '%d'" %
740 version)
741 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700742 raise CmdError("Machine parameter block size %d is invalid: "
743 "pos=%d, size=%d, space=%d, len=%d" %
744 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700745
746 # Move past the header and read the parameter list, which is terminated
747 # with \0.
748 pos += 12
749 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
750 param_len = param_list.find('\0')
751 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700752 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700753
754 # Work through the parameters one at a time, adding each value
755 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700756 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700757 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700758 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glass56583742012-11-06 12:34:47 -0800759
760 # Use this to detect a missing value from the fdt.
761 not_given = 'not-given-invalid-value'
Simon Glassdf95dd22012-03-13 15:46:16 -0700762 if param == 'm' :
Simon Glass56583742012-11-06 12:34:47 -0800763 mem_type = fdt.GetString('/dmc', 'mem-type', not_given)
764 if mem_type == not_given:
765 mem_type = 'ddr3'
766 self._out.Warning("No value for memory type: using '%s'" % mem_type)
Simon Glassdf95dd22012-03-13 15:46:16 -0700767 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
768 if not mem_type in mem_types:
769 raise CmdError("Unknown memory type '%s'" % mem_type)
770 value = mem_types.index(mem_type)
771 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700772 elif param == 'M' :
Simon Glass56583742012-11-06 12:34:47 -0800773 mem_manuf = fdt.GetString('/dmc', 'mem-manuf', not_given)
774 if mem_manuf == not_given:
775 mem_manuf = 'samsung'
776 self._out.Warning("No value for memory manufacturer: using '%s'" %
777 mem_manuf)
Doug Andersonee46cfe2012-05-18 09:53:08 -0700778 mem_manufs = ['autodetect', 'elpida', 'samsung']
779 if not mem_manuf in mem_manufs:
780 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
781 value = mem_manufs.index(mem_manuf)
782 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700783 elif param == 'f' :
Simon Glass56583742012-11-06 12:34:47 -0800784 mem_freq = fdt.GetInt('/dmc', 'clock-frequency', -1)
785 if mem_freq == -1:
786 mem_freq = 800000000
787 self._out.Warning("No value for memory frequency: using '%s'" %
788 mem_freq)
789 mem_freq /= 1000000
Simon Glass158289e2012-09-14 11:42:25 -0700790 if not mem_freq in [533, 667, 800]:
791 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
792 value = mem_freq
793 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700794 elif param == 'v':
795 value = 31
796 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700797 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700798 value = (spl_load_size + 0xfff) & ~0xfff
799 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
800 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700801 elif param == 'b':
802 # These values come from enum boot_mode in U-Boot's cpu.h
803 if self.spl_source == 'straps':
804 value = 32
805 elif self.spl_source == 'emmc':
806 value = 4
807 elif self.spl_source == 'spi':
808 value = 20
809 elif self.spl_source == 'usb':
810 value = 33
811 else:
812 raise CmdError("Invalid boot source '%s'" % self.spl_source)
813 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700814 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700815 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700816 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700817 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700818 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700819
820 # Put the data into our block.
821 data = data[:pos] + new_data + data[pos + len(new_data):]
822 self._out.Info('BL2 configuration complete')
823 return data
824
Simon Glasse5e8afb2012-05-23 11:19:23 -0700825 def _UpdateChecksum(self, data):
826 """Update the BL2 checksum.
827
828 The checksum is a 4 byte sum of all the bytes in the image before the
829 last 4 bytes (which hold the checksum).
830
831 Args:
832 data: The BL2 data to update.
833
834 Returns:
835 The new contents of the BL2 data, after updating the checksum.
836 """
837 checksum = 0
838 for ch in data[:-4]:
839 checksum += ord(ch)
840 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
841
Simon Glass559b6612012-05-23 13:28:45 -0700842 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700843 """Configure an Exynos BL2 binary for our needs.
844
845 We create a new modified BL2 and return its filename.
846
847 Args:
848 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700849 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700850 orig_bl2: Filename of original BL2 file to modify.
851 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700852 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700853 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700854 data = self._tools.ReadFile(orig_bl2)
855 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700856
857 # Locate the parameter block
858 data = self._tools.ReadFile(bl2)
859 marker = struct.pack('<L', 0xdeadbeef)
860 pos = data.rfind(marker)
861 if not pos:
862 raise CmdError("Could not find machine parameter block in '%s'" %
863 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700864 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700865 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700866 self._tools.WriteFile(bl2, data)
867 return bl2
868
Simon Glass89b86b82011-07-17 23:49:49 -0700869 def _PackOutput(self, msg):
870 """Helper function to write output from PackFirmware (verbose level 2).
871
872 This is passed to PackFirmware for it to use to write output.
873
874 Args:
875 msg: Message to display.
876 """
877 self._out.Notice(msg)
878
Simon Glass439fe7a2012-03-09 16:19:34 -0800879 def _BuildBlob(self, pack, fdt, blob_type):
880 """Build the blob data for a particular blob type.
881
882 Args:
883 blob_type: The type of blob to create data for. Supported types are:
884 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
885 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
886 """
887 if blob_type == 'coreboot':
888 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700889 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800890 pack.AddProperty('coreboot', coreboot)
891 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700892 elif blob_type == 'legacy':
893 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800894 elif blob_type == 'signed':
895 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
896 self.postload_fname)
897 pack.AddProperty('bootstub', bootstub)
898 pack.AddProperty('signed', signed)
899 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700900 elif blob_type == 'exynos-bl1':
901 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700902
903 # TODO(sjg@chromium.org): Deprecate ecbin
904 elif blob_type in ['ecrw', 'ecbin']:
905 pack.AddProperty('ecrw', self.ecrw_fname)
906 pack.AddProperty('ecbin', self.ecrw_fname)
907 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700908 # crosbug.com/p/13143
909 # We cannot have an fmap in the EC image since there can be only one,
910 # which is the main fmap describing the whole image.
911 # Ultimately the EC will not have an fmap, since with software sync
912 # there is no flashrom involvement in updating the EC flash, and thus
913 # no need for the fmap.
914 # For now, mangle the fmap name to avoid problems.
915 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
916 data = self._tools.ReadFile(self.ecro_fname)
917 data = re.sub('__FMAP__', '__fMAP__', data)
918 self._tools.WriteFile(updated_ecro, data)
919 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700920 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700921 spl_payload = pack.GetBlobParams(blob_type)
922
923 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
924 # from all flash map files.
925 if not spl_payload:
926 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
927 prop_list = 'boot+dtb'
928
929 # Do this later, when we remove boot+dtb.
930 # raise CmdError("No parameters provided for blob type '%s'" %
931 # blob_type)
932 else:
933 prop_list = spl_payload[0].split(',')
934 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
935 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
936 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700937 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700938 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800939 elif pack.GetProperty(blob_type):
940 pass
941 else:
942 raise CmdError("Unknown blob type '%s' required in flash map" %
943 blob_type)
944
Simon Glass290a1802011-07-17 13:54:32 -0700945 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700946 """Create a full firmware image, along with various by-products.
947
948 This uses the provided u-boot.bin, fdt and bct to create a firmware
949 image containing all the required parts. If the GBB is not supplied
950 then this will just return a signed U-Boot as the image.
951
952 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200953 gbb: Full path to the GBB file, or empty if a GBB is not required.
954 fdt: Fdt object containing required information.
955
956 Returns:
957 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700958
959 Raises:
960 CmdError if a command fails.
961 """
Simon Glass02d124a2012-03-02 14:47:20 -0800962 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700963
Simon Glass439fe7a2012-03-09 16:19:34 -0800964 # Get the flashmap so we know what to build
965 pack = PackFirmware(self._tools, self._out)
Simon Glass0c54ba52012-11-06 12:36:43 -0800966 default_flashmap = default_flashmaps.get(self._board)
967 pack.SelectFdt(fdt, self._board, default_flashmap)
Simon Glass439fe7a2012-03-09 16:19:34 -0800968
969 # Get all our blobs ready
970 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700971 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700972 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700973
Simon Glass6e486c22012-10-26 15:43:42 -0700974 if self._force_rw:
975 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
976 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
977
Simon Glass47817052012-10-20 13:30:07 -0700978 # Let's create some copies of the fdt for vboot. These can be used to
979 # pass a different fdt to each firmware type. For now it is just used to
980 # check that the right fdt comes through.
981 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
982 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
983 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
984 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
985 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
986 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
987 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
988
Simon Glassde9c8072012-07-02 22:29:02 -0700989 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
990 if self.kernel_fname:
991 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
992
Simon Glass50f74602012-03-15 21:04:25 -0700993 # Make a copy of the fdt for the bootstub
994 fdt_data = self._tools.ReadFile(fdt.fname)
995 uboot_data = self._tools.ReadFile(self.uboot_fname)
996 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
997 self._tools.WriteFile(uboot_copy, uboot_data)
998
999 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
1000 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -07001001
1002 # TODO(sjg@chromium.org): Deprecate this property when all boards
1003 # use a comma-separated list for section contents. We will then
1004 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -07001005 pack.AddProperty('boot+dtb', bootstub)
1006
Simon Glass439fe7a2012-03-09 16:19:34 -08001007 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +01001008 blob_list = pack.GetBlobList()
1009 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -07001010 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -08001011 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -07001012
1013 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -07001014 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +08001015 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -08001016 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +08001017 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -07001018 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -08001019 pack.AddProperty('fwid', fwid)
1020 pack.AddProperty('gbb', gbb)
1021 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -07001022
1023 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -07001024
1025 # Record position and size of all blob members in the FDT
1026 pack.UpdateBlobPositions(fdt)
1027
Simon Glasscbc83552012-07-23 15:26:22 +01001028 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
1029 # has created a rom file without the dtb, because until now it is not
1030 # complete. Add the dtb here.
1031 # A better anwer might be to put the dtb in memory immediately after
1032 # U-Boot as is done for ARM and have coreboot load it as a binary file
1033 # instead of an elf. However, I need to check whether coreboot supports
1034 # this, and whether this is desirable for other reasons.
1035 if 'coreboot' in blob_list:
1036 bootstub = pack.GetProperty('coreboot')
1037 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Stefan Reinauer1502ea62012-11-01 10:15:38 -07001038 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
1039 '-n', 'u-boot.dtb', '-t', '0xac'])
Stefan Reinauer728be822012-10-02 16:54:09 -07001040 bootstub_tmp = bootstub + '.tmp'
1041 self._tools.Run('dd', ['if=' + bootstub, 'of=' + bootstub_tmp,
1042 'bs=1M', 'skip=7'])
1043 shutil.move(bootstub_tmp, bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +01001044
Simon Glassc90cf582012-03-13 15:40:47 -07001045 image = os.path.join(self._tools.outdir, 'image.bin')
1046 pack.PackImage(self._tools.outdir, image)
1047 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -07001048
Simon Glass439fe7a2012-03-09 16:19:34 -08001049 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -07001050 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001051 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001052
Simon Glass290a1802011-07-17 13:54:32 -07001053 def SelectFdt(self, fdt_fname):
1054 """Select an FDT to control the firmware bundling
1055
1056 Args:
1057 fdt_fname: The filename of the fdt to use.
1058
Simon Glassc0f3dc62011-08-09 14:19:05 -07001059 Returns:
1060 The Fdt object of the original fdt file, which we will not modify.
1061
Simon Glass290a1802011-07-17 13:54:32 -07001062 We make a copy of this which will include any on-the-fly changes we want
1063 to make.
1064 """
1065 self._fdt_fname = fdt_fname
1066 self.CheckOptions()
1067 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -08001068 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -07001069 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -07001070 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001071
Simon Glassc90cf582012-03-13 15:40:47 -07001072 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001073 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001074
1075 - Checks options, tools, output directory, fdt.
1076 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001077
1078 Args:
Simon Glass56577572011-07-19 11:08:06 +12001079 hardware_id: Hardware ID to use for this board. If None, then the
1080 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001081 output_fname: Output filename for the image. If this is not None, then
1082 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001083 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001084
1085 Returns:
1086 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001087 """
Simon Glass89b86b82011-07-17 23:49:49 -07001088 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -07001089 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +12001090 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001091
1092 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001093 image, pack = self._CreateImage(gbb, self.fdt)
1094 if show_map:
1095 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001096 if output_fname:
1097 shutil.copyfile(image, output_fname)
1098 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001099 return image, pack.props