blob: edbec066f281ebfc25d547634cd033846237cd97 [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 Glass4a887b12012-10-23 16:29:03 -070059# Build GBB flags.
60# (src/platform/vboot_reference/firmware/include/gbb_header.h)
61gbb_flag_properties = {
62 'dev-screen-short-delay': 0x00000001,
63 'load-option-roms': 0x00000002,
64 'enable-alternate-os': 0x00000004,
65 'force-dev-switch-on': 0x00000008,
66 'force-dev-boot-usb': 0x00000010,
67 'disable-fw-rollback-check': 0x00000020,
68 'enter-triggers-tonorm': 0x00000040,
69 'force-dev-boot-legacy': 0x00000080,
70}
71
Simon Glass5076a7f2012-10-23 16:31:54 -070072def ListGoogleBinaryBlockFlags():
73 """Print out a list of GBB flags."""
74 print ' %-30s %s' % ('Available GBB flags:', 'Hex')
75 for name, value in gbb_flag_properties.iteritems():
76 print ' %-30s %02x' % (name, value)
77
Simon Glass89b86b82011-07-17 23:49:49 -070078class Bundle:
Simon Glass290a1802011-07-17 13:54:32 -070079 """This class encapsulates the entire bundle firmware logic.
Simon Glass89b86b82011-07-17 23:49:49 -070080
Simon Glass290a1802011-07-17 13:54:32 -070081 Sequence of events:
82 bundle = Bundle(tools.Tools(), cros_output.Output())
83 bundle.SetDirs(...)
84 bundle.SetFiles(...)
85 bundle.SetOptions(...)
86 bundle.SelectFdt(fdt.Fdt('filename.dtb')
Simon Glassa4934b72012-05-09 13:35:02 -070087 .. can call bundle.AddConfigList(), AddEnableList() if required
Simon Glass290a1802011-07-17 13:54:32 -070088 bundle.Start(...)
Simon Glass89b86b82011-07-17 23:49:49 -070089
Simon Glass290a1802011-07-17 13:54:32 -070090 Public properties:
91 fdt: The fdt object that we use for building our image. This wil be the
92 one specified by the user, except that we might add config options
93 to it. This is set up by SelectFdt() which must be called before
94 bundling starts.
95 uboot_fname: Full filename of the U-Boot binary we use.
96 bct_fname: Full filename of the BCT file we use.
Simon Glass559b6612012-05-23 13:28:45 -070097 spl_source: Source device to load U-Boot from, in SPL:
98 straps: Select device according to CPU strap pins
99 spi: Boot from SPI
100 emmc: Boot from eMMC
Simon Glass23988ae2012-03-23 16:55:22 -0700101
102 Private attributes:
103 _small: True to create a 'small' signed U-Boot, False to produce a
104 full image. The small U-Boot is enough to boot but will not have
105 access to GBB, RW U-Boot, etc.
Simon Glass290a1802011-07-17 13:54:32 -0700106 """
Simon Glass89b86b82011-07-17 23:49:49 -0700107
Simon Glass290a1802011-07-17 13:54:32 -0700108 def __init__(self, tools, output):
109 """Set up a new Bundle object.
Simon Glass89b86b82011-07-17 23:49:49 -0700110
Simon Glass290a1802011-07-17 13:54:32 -0700111 Args:
112 tools: A tools.Tools object to use for external tools.
113 output: A cros_output.Output object to use for program output.
Simon Glass89b86b82011-07-17 23:49:49 -0700114 """
Simon Glass290a1802011-07-17 13:54:32 -0700115 self._tools = tools
116 self._out = output
117
118 # Set up the things we need to know in order to operate.
119 self._board = None # Board name, e.g. tegra2_seaboard.
120 self._fdt_fname = None # Filename of our FDT.
121 self.uboot_fname = None # Filename of our U-Boot binary.
122 self.bct_fname = None # Filename of our BCT file.
123 self.fdt = None # Our Fdt object.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800124 self.bmpblk_fname = None # Filename of our Bitmap Block
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700125 self.coreboot_fname = None # Filename of our coreboot binary.
Vincent Palatinf7286772011-10-12 14:31:53 -0700126 self.seabios_fname = None # Filename of our SeaBIOS payload.
Simon Glass7e199222012-03-13 15:51:18 -0700127 self.exynos_bl1 = None # Filename of Exynos BL1 (pre-boot)
128 self.exynos_bl2 = None # Filename of Exynos BL2 (SPL)
Simon Glass559b6612012-05-23 13:28:45 -0700129 self.spl_source = 'straps' # SPL boot according to board settings
Simon Glass07267952012-06-08 12:45:13 -0700130 self.skeleton_fname = None # Filename of Coreboot skeleton file
Simon Glassbe0bc002012-08-16 12:50:48 -0700131 self.ecrw_fname = None # Filename of EC file
132 self.ecro_fname = None # Filename of EC read-only file
Simon Glass23988ae2012-03-23 16:55:22 -0700133 self._small = False
Simon Glass290a1802011-07-17 13:54:32 -0700134
135 def SetDirs(self, keydir):
136 """Set up directories required for Bundle.
137
138 Args:
139 keydir: Directory containing keys to use for signing firmware.
140 """
141 self._keydir = keydir
142
Simon Glass6dcc2f22011-07-28 15:26:49 +1200143 def SetFiles(self, board, bct, uboot=None, bmpblk=None, coreboot=None,
Simon Glass07267952012-06-08 12:45:13 -0700144 postload=None, seabios=None, exynos_bl1=None, exynos_bl2=None,
Simon Glassbe0bc002012-08-16 12:50:48 -0700145 skeleton=None, ecrw=None, ecro=None, kernel=None):
Simon Glass290a1802011-07-17 13:54:32 -0700146 """Set up files required for Bundle.
147
148 Args:
149 board: The name of the board to target (e.g. tegra2_seaboard).
150 uboot: The filename of the u-boot.bin image to use.
151 bct: The filename of the binary BCT file to use.
Hung-Te Lin5b649382011-08-03 15:01:16 +0800152 bmpblk: The filename of bitmap block file to use.
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700153 coreboot: The filename of the coreboot image to use (on x86)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200154 postload: The filename of the u-boot-post.bin image to use.
Vincent Palatinf7286772011-10-12 14:31:53 -0700155 seabios: The filename of the SeaBIOS payload to use if any.
Simon Glass07267952012-06-08 12:45:13 -0700156 exynos_bl1: The filename of the exynos BL1 file
157 exynos_bl2: The filename of the exynos BL2 file (U-Boot spl)
158 skeleton: The filename of the coreboot skeleton file.
Simon Glassbe0bc002012-08-16 12:50:48 -0700159 ecrw: The filename of the EC (Embedded Controller) read-write file.
160 ecro: The filename of the EC (Embedded Controller) read-only file.
Simon Glassde9c8072012-07-02 22:29:02 -0700161 kernel: The filename of the kernel file if any.
Simon Glass290a1802011-07-17 13:54:32 -0700162 """
163 self._board = board
164 self.uboot_fname = uboot
165 self.bct_fname = bct
Hung-Te Lin5b649382011-08-03 15:01:16 +0800166 self.bmpblk_fname = bmpblk
Stefan Reinauer8d79d362011-08-16 14:20:43 -0700167 self.coreboot_fname = coreboot
Simon Glass6dcc2f22011-07-28 15:26:49 +1200168 self.postload_fname = postload
Vincent Palatinf7286772011-10-12 14:31:53 -0700169 self.seabios_fname = seabios
Simon Glass7e199222012-03-13 15:51:18 -0700170 self.exynos_bl1 = exynos_bl1
171 self.exynos_bl2 = exynos_bl2
Simon Glass07267952012-06-08 12:45:13 -0700172 self.skeleton_fname = skeleton
Simon Glassbe0bc002012-08-16 12:50:48 -0700173 self.ecrw_fname = ecrw
174 self.ecro_fname = ecro
Simon Glassde9c8072012-07-02 22:29:02 -0700175 self.kernel_fname = kernel
Simon Glass290a1802011-07-17 13:54:32 -0700176
Simon Glass6e486c22012-10-26 15:43:42 -0700177 def SetOptions(self, small, gbb_flags, force_rw=False):
Simon Glass290a1802011-07-17 13:54:32 -0700178 """Set up options supported by Bundle.
179
180 Args:
181 small: Only create a signed U-Boot - don't produce the full packed
182 firmware image. This is useful for devs who want to replace just the
183 U-Boot part while keeping the keys, gbb, etc. the same.
Simon Glass6e486c22012-10-26 15:43:42 -0700184 gbb_flags: Specification for string containing adjustments to make.
185 force_rw: Force firmware into RW mode.
Simon Glass290a1802011-07-17 13:54:32 -0700186 """
187 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700188 self._gbb_flags = gbb_flags
Simon Glass6e486c22012-10-26 15:43:42 -0700189 self._force_rw = force_rw
Simon Glass290a1802011-07-17 13:54:32 -0700190
191 def CheckOptions(self):
192 """Check provided options and select defaults."""
193 if not self._board:
194 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700195 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700196 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700197 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700198 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700199 base_name = re.sub('_', '-', self._board)
200
201 # In case the name exists with a prefix or suffix, find it.
202 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
203 found_list = glob.glob(self._tools.Filename(wildcard))
204 if len(found_list) == 1:
205 self._fdt_fname = found_list[0]
206 else:
207 # We didn't find anything definite, so set up our expected name.
208 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
209
Simon Glass881964d2012-04-04 11:34:09 -0700210 # Convert things like 'exynos5250-daisy' into a full path.
211 root, ext = os.path.splitext(self._fdt_fname)
212 if not ext and not os.path.dirname(root):
213 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
214
Simon Glass290a1802011-07-17 13:54:32 -0700215 if not self.uboot_fname:
216 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
217 if not self.bct_fname:
218 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700219 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700220 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700221 if not self.exynos_bl1:
222 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
223 if not self.exynos_bl2:
224 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700225 if not self.coreboot_fname:
226 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
227 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700228 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700229 if not self.seabios_fname:
230 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700231 if not self.ecrw_fname:
232 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
233 if not self.ecro_fname:
234 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700235
Simon Glass75759302012-03-15 20:26:53 -0700236 def GetFiles(self):
237 """Get a list of files that we know about.
238
239 This is the opposite of SetFiles except that we may have put in some
240 default names. It returns a dictionary containing the filename for
241 each of a number of pre-defined files.
242
243 Returns:
244 Dictionary, with one entry for each file.
245 """
246 file_list = {
247 'bct' : self.bct_fname,
248 'exynos-bl1' : self.exynos_bl1,
249 'exynos-bl2' : self.exynos_bl2,
250 }
251 return file_list
252
Simon Glass4a887b12012-10-23 16:29:03 -0700253 def DecodeGBBFlagsFromFdt(self):
254 """Get Google Binary Block flags from the FDT.
255
256 These should be in the chromeos-config node, like this:
257
258 chromeos-config {
259 gbb-flag-dev-screen-short-delay;
260 gbb-flag-force-dev-switch-on;
261 gbb-flag-force-dev-boot-usb;
262 gbb-flag-disable-fw-rollback-check;
263 };
264
265 Returns:
266 GBB flags value from FDT.
267 """
268 chromeos_config = self.fdt.GetProps("/chromeos-config")
269 gbb_flags = 0
270 for name in chromeos_config:
271 if name.startswith('gbb-flag-'):
272 flag_value = gbb_flag_properties.get(name[9:])
273 if flag_value:
274 gbb_flags |= flag_value
275 self._out.Notice("FDT: Enabling %s." % name)
276 else:
277 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
278 return gbb_flags
279
Simon Glass157c0662012-10-23 13:52:42 -0700280 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
281 """Decode ajustments to the provided GBB flags.
282
283 We support three options:
284
285 hex value: c2
286 defined value: force-dev-boot-usb,load-option-roms
287 adjust default value: -load-option-roms,+force-dev-boot-usb
288
289 The last option starts from the passed-in GBB flags and adds or removes
290 flags.
291
292 Args:
293 gbb_flags: Base (default) FDT flags.
294 adjustments: String containing adjustments to make.
295
296 Returns:
297 Updated FDT flags.
298 """
299 use_base_value = True
300 if adjustments:
301 try:
302 return int(adjustments, base=16)
303 except:
304 pass
305 for flag in adjustments.split(','):
306 oper = None
307 if flag[0] in ['-', '+']:
308 oper = flag[0]
309 flag = flag[1:]
310 value = gbb_flag_properties.get(flag)
311 if not value:
312 raise ValueError("Invalid GBB flag '%s'" % flag)
313 if oper == '+':
314 gbb_flags |= value
315 elif oper == '-':
316 gbb_flags &= ~value
317 else:
318 if use_base_value:
319 gbb_flags = 0
320 use_base_value = False
321 gbb_flags |= value
322
323 return gbb_flags
324
Simon Glass56577572011-07-19 11:08:06 +1200325 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700326 """Create a GBB for the image.
327
Simon Glass56577572011-07-19 11:08:06 +1200328 Args:
329 hardware_id: Hardware ID to use for this board. If None, then the
330 default from the Fdt will be used
331
Simon Glass89b86b82011-07-17 23:49:49 -0700332 Returns:
333 Path of the created GBB file.
334
335 Raises:
336 CmdError if a command fails.
337 """
Simon Glass56577572011-07-19 11:08:06 +1200338 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800339 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700340 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700341 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700342
Simon Glass4a887b12012-10-23 16:29:03 -0700343 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800344
Simon Glass157c0662012-10-23 13:52:42 -0700345 # Allow command line to override flags
346 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
347
Simon Glass4a887b12012-10-23 16:29:03 -0700348 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700349 self._out.Progress('Creating GBB')
350 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
351 sizes = ['%#x' % size for size in sizes]
352 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700353 keydir = self._tools.Filename(self._keydir)
354 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700355 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200356 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700357 '--rootkey=%s/root_key.vbpubk' % keydir,
358 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700359 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800360 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700361 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700362 cwd=odir)
363 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700364
Simon Glasse13ee2c2011-07-28 08:12:28 +1200365 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700366 """Sign an image so that the Tegra SOC will boot it.
367
368 Args:
369 bct: BCT file to use.
370 bootstub: Boot stub (U-Boot + fdt) file to sign.
371 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700372
373 Returns:
374 filename of signed image.
375
376 Raises:
377 CmdError if a command fails.
378 """
379 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200380 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700381 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200382 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700383 fd = open(config, 'w')
384 fd.write('Version = 1;\n')
385 fd.write('Redundancy = 1;\n')
386 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700387
388 # TODO(dianders): Right now, we don't have enough space in our flash map
389 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
390 # sure what this does for reliability, but at least things will fit...
391 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
392 if is_nand:
393 fd.write('Bctcopy = 1;\n')
394
Simon Glass89b86b82011-07-17 23:49:49 -0700395 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
396 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700397
Simon Glass89b86b82011-07-17 23:49:49 -0700398 fd.close()
399
400 self._tools.Run('cbootimage', [config, signed])
401 self._tools.OutputSize('BCT', bct)
402 self._tools.OutputSize('Signed image', signed)
403 return signed
404
Doug Anderson86ce5f42011-07-27 10:40:18 -0700405 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700406 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700407
408 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700409 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700410 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700411 """
Simon Glass468d8752012-09-19 16:36:19 -0700412 if bootcmd is not None:
413 if bootcmd == 'none':
414 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800415 self.fdt.PutString('/config', 'bootcmd', bootcmd)
416 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700417 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700418
Simon Glassa4934b72012-05-09 13:35:02 -0700419 def SetNodeEnabled(self, node_name, enabled):
420 """Set whether an node is enabled or disabled.
421
422 This simply sets the 'status' property of a node to "ok", or "disabled".
423
424 The node should either be a full path to the node (like '/uart@10200000')
425 or an alias property.
426
427 Aliases are supported like this:
428
429 aliases {
430 console = "/uart@10200000";
431 };
432
433 pointing to a node:
434
435 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700436 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700437 };
438
439 In this case, this function takes the name of the alias ('console' in
440 this case) and updates the status of the node that is pointed to, to
441 either ok or disabled. If the alias does not exist, a warning is
442 displayed.
443
444 Args:
445 node_name: Name of node (e.g. '/uart@10200000') or alias alias
446 (e.g. 'console') to adjust
447 enabled: True to enable, False to disable
448 """
449 # Look up the alias if this is an alias reference
450 if not node_name.startswith('/'):
451 lookup = self.fdt.GetString('/aliases', node_name, '')
452 if not lookup:
453 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
454 return
455 node_name = lookup
456 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700457 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700458 else:
459 status = 'disabled'
460 self.fdt.PutString(node_name, 'status', status)
461
462 def AddEnableList(self, enable_list):
463 """Process a list of nodes to enable/disable.
464
465 Args:
466 config_list: List of (node, value) tuples to add to the fdt. For each
467 tuple:
468 node: The fdt node to write to will be <node> or pointed to by
469 /aliases/<node>. We can tell which
470 value: 0 to disable the node, 1 to enable it
471 """
472 if enable_list:
473 for node_name, enabled in enable_list:
474 try:
475 enabled = int(enabled)
476 if enabled not in (0, 1):
477 raise ValueError
478 except ValueError as str:
479 raise CmdError("Invalid enable option value '%s' "
480 "(should be 0 or 1)" % enabled)
481 self.SetNodeEnabled(node_name, enabled)
482
Simon Glass290a1802011-07-17 13:54:32 -0700483 def AddConfigList(self, config_list, use_int=False):
484 """Add a list of config items to the fdt.
485
486 Normally these values are written to the fdt as strings, but integers
487 are also supported, in which case the values will be converted to integers
488 (if necessary) before being stored.
489
490 Args:
491 config_list: List of (config, value) tuples to add to the fdt. For each
492 tuple:
493 config: The fdt node to write to will be /config/<config>.
494 value: An integer or string value to write.
495 use_int: True to only write integer values.
496
497 Raises:
498 CmdError: if a value is required to be converted to integer but can't be.
499 """
500 if config_list:
501 for config in config_list:
502 value = config[1]
503 if use_int:
504 try:
505 value = int(value)
506 except ValueError as str:
507 raise CmdError("Cannot convert config option '%s' to integer" %
508 value)
509 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800510 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700511 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800512 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700513
Simon Glass7c2d5572011-11-15 14:47:08 -0800514 def DecodeTextBase(self, data):
515 """Look at a U-Boot image and try to decode its TEXT_BASE.
516
517 This works because U-Boot has a header with the value 0x12345678
518 immediately followed by the TEXT_BASE value. We can therefore read this
519 from the image with some certainty. We check only the first 40 words
520 since the header should be within that region.
521
Simon Glass96b50302012-07-20 06:55:28 +0100522 Since upstream Tegra has moved to having a 16KB SPL region at the start,
523 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
524 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
525
Simon Glass7c2d5572011-11-15 14:47:08 -0800526 Args:
527 data: U-Boot binary data
528
529 Returns:
530 Text base (integer) or None if none was found
531 """
532 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100533 for start in (0, 0x4000):
534 for i in range(start, start + 160, 4):
535 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800536
Simon Glass96b50302012-07-20 06:55:28 +0100537 # TODO(sjg): This does not cope with a big-endian target
538 value = struct.unpack('<I', word)[0]
539 if found:
540 return value - start
541 if value == 0x12345678:
542 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800543
544 return None
545
546 def CalcTextBase(self, name, fdt, fname):
547 """Calculate the TEXT_BASE to use for U-Boot.
548
549 Normally this value is in the fdt, so we just read it from there. But as
550 a second check we look at the image itself in case this is different, and
551 switch to that if it is.
552
553 This allows us to flash any U-Boot even if its TEXT_BASE is different.
554 This is particularly useful with upstream U-Boot which uses a different
555 value (which we will move to).
556 """
557 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200558 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800559 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100560 text_base_str = '%#x' % text_base if text_base else 'None'
561 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
562 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800563
564 # If they are different, issue a warning and switch over.
565 if text_base and text_base != fdt_text_base:
566 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
567 "fdt value of %x. Using %x" % (text_base, name,
568 fdt_text_base, text_base))
569 fdt_text_base = text_base
570 return fdt_text_base
571
Simon Glass6dcc2f22011-07-28 15:26:49 +1200572 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700573 """Create a boot stub and a signed boot stub.
574
Simon Glass6dcc2f22011-07-28 15:26:49 +1200575 For postload:
576 We add a /config/postload-text-offset entry to the signed bootstub's
577 fdt so that U-Boot can find the postload code.
578
579 The raw (unsigned) bootstub will have a value of -1 for this since we will
580 simply append the postload code to the bootstub and it can find it there.
581 This will be used for RW A/B firmware.
582
583 For the signed case this value will specify where in the flash to find
584 the postload code. This will be used for RO firmware.
585
Simon Glass89b86b82011-07-17 23:49:49 -0700586 Args:
587 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800588 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200589 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700590
591 Returns:
592 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200593 Full path to bootstub (uboot + fdt(-1) + postload).
594 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700595
596 Raises:
597 CmdError if a command fails.
598 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200599 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800600 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700601 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200602
603 # Make a copy of the fdt for the bootstub
604 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800605 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700606 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200607
Simon Glass89b86b82011-07-17 23:49:49 -0700608 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700609 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
610 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700611 self._tools.OutputSize('Combined binary', bootstub)
612
Simon Glasse13ee2c2011-07-28 08:12:28 +1200613 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700614 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700615 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200616 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200617
618 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
619 data = self._tools.ReadFile(signed)
620
621 if postload:
622 # We must add postload to the bootstub since A and B will need to
623 # be able to find it without the /config/postload-text-offset mechanism.
624 bs_data = self._tools.ReadFile(bootstub)
625 bs_data += self._tools.ReadFile(postload)
626 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
627 self._tools.WriteFile(bootstub, bs_data)
628 self._tools.OutputSize('Combined binary with postload', bootstub)
629
630 # Now that we know the file size, adjust the fdt and re-sign
631 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800632 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200633 fdt_data = self._tools.ReadFile(fdt.fname)
634 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
635 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
636 postload_bootstub, text_base)
637 if len(data) != os.path.getsize(signed):
638 raise CmdError('Signed file size changed from %d to %d after updating '
639 'fdt' % (len(data), os.path.getsize(signed)))
640
641 # Re-read the signed image, and add the post-load binary.
642 data = self._tools.ReadFile(signed)
643 data += self._tools.ReadFile(postload)
644 self._tools.OutputSize('Post-load binary', postload)
645
646 self._tools.WriteFile(signed_postload, data)
647 self._tools.OutputSize('Final bootstub with postload', signed_postload)
648
649 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700650
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700651 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700652 """Create a coreboot boot stub.
653
654 Args:
655 uboot: Path to u-boot.bin (may be chroot-relative)
656 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700657 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700658
659 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100660 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700661
662 Raises:
663 CmdError if a command fails.
664 """
665 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700666
667 # U-Boot itself does not put a .elf extension on the elf file.
668 # The U-Boot ebuild does, but we shouldn't actually require it since
669 # devs may want to just use what U-Boot creates.
670 uboot_elf = uboot.replace('.bin', '')
671 if not os.path.exists(self._tools.Filename(uboot_elf)):
672 uboot_elf = uboot.replace('.bin', '.elf')
673 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Stefan Reinauer1502ea62012-11-01 10:15:38 -0700674 self._tools.Run('cbfstool', [bootstub, 'add-payload', '-f', uboot_elf,
675 '-n', 'fallback/payload', '-c', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100676
677 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700678 return bootstub
679
Simon Glass3b404092012-05-23 13:10:36 -0700680 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700681 """Update the parameters in a BL2 blob.
682
683 We look at the list in the parameter block, extract the value of each
684 from the device tree, and write that value to the parameter block.
685
686 Args:
687 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700688 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700689 data: The BL2 data.
690 pos: The position of the start of the parameter block.
691
692 Returns:
693 The new contents of the parameter block, after updating.
694 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700695 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
696 if version != 1:
697 raise CmdError("Cannot update machine parameter block version '%d'" %
698 version)
699 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700700 raise CmdError("Machine parameter block size %d is invalid: "
701 "pos=%d, size=%d, space=%d, len=%d" %
702 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700703
704 # Move past the header and read the parameter list, which is terminated
705 # with \0.
706 pos += 12
707 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
708 param_len = param_list.find('\0')
709 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700710 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700711
712 # Work through the parameters one at a time, adding each value
713 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700714 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700715 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700716 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glass56583742012-11-06 12:34:47 -0800717
718 # Use this to detect a missing value from the fdt.
719 not_given = 'not-given-invalid-value'
Simon Glassdf95dd22012-03-13 15:46:16 -0700720 if param == 'm' :
Simon Glass56583742012-11-06 12:34:47 -0800721 mem_type = fdt.GetString('/dmc', 'mem-type', not_given)
722 if mem_type == not_given:
723 mem_type = 'ddr3'
724 self._out.Warning("No value for memory type: using '%s'" % mem_type)
Simon Glassdf95dd22012-03-13 15:46:16 -0700725 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
726 if not mem_type in mem_types:
727 raise CmdError("Unknown memory type '%s'" % mem_type)
728 value = mem_types.index(mem_type)
729 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700730 elif param == 'M' :
Simon Glass56583742012-11-06 12:34:47 -0800731 mem_manuf = fdt.GetString('/dmc', 'mem-manuf', not_given)
732 if mem_manuf == not_given:
733 mem_manuf = 'samsung'
734 self._out.Warning("No value for memory manufacturer: using '%s'" %
735 mem_manuf)
Doug Andersonee46cfe2012-05-18 09:53:08 -0700736 mem_manufs = ['autodetect', 'elpida', 'samsung']
737 if not mem_manuf in mem_manufs:
738 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
739 value = mem_manufs.index(mem_manuf)
740 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700741 elif param == 'f' :
Simon Glass56583742012-11-06 12:34:47 -0800742 mem_freq = fdt.GetInt('/dmc', 'clock-frequency', -1)
743 if mem_freq == -1:
744 mem_freq = 800000000
745 self._out.Warning("No value for memory frequency: using '%s'" %
746 mem_freq)
747 mem_freq /= 1000000
Simon Glass158289e2012-09-14 11:42:25 -0700748 if not mem_freq in [533, 667, 800]:
749 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
750 value = mem_freq
751 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700752 elif param == 'v':
753 value = 31
754 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700755 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700756 value = (spl_load_size + 0xfff) & ~0xfff
757 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
758 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700759 elif param == 'b':
760 # These values come from enum boot_mode in U-Boot's cpu.h
761 if self.spl_source == 'straps':
762 value = 32
763 elif self.spl_source == 'emmc':
764 value = 4
765 elif self.spl_source == 'spi':
766 value = 20
767 elif self.spl_source == 'usb':
768 value = 33
769 else:
770 raise CmdError("Invalid boot source '%s'" % self.spl_source)
771 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700772 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700773 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700774 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700775 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700776 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700777
778 # Put the data into our block.
779 data = data[:pos] + new_data + data[pos + len(new_data):]
780 self._out.Info('BL2 configuration complete')
781 return data
782
Simon Glasse5e8afb2012-05-23 11:19:23 -0700783 def _UpdateChecksum(self, data):
784 """Update the BL2 checksum.
785
786 The checksum is a 4 byte sum of all the bytes in the image before the
787 last 4 bytes (which hold the checksum).
788
789 Args:
790 data: The BL2 data to update.
791
792 Returns:
793 The new contents of the BL2 data, after updating the checksum.
794 """
795 checksum = 0
796 for ch in data[:-4]:
797 checksum += ord(ch)
798 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
799
Simon Glass559b6612012-05-23 13:28:45 -0700800 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700801 """Configure an Exynos BL2 binary for our needs.
802
803 We create a new modified BL2 and return its filename.
804
805 Args:
806 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700807 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700808 orig_bl2: Filename of original BL2 file to modify.
809 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700810 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700811 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700812 data = self._tools.ReadFile(orig_bl2)
813 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700814
815 # Locate the parameter block
816 data = self._tools.ReadFile(bl2)
817 marker = struct.pack('<L', 0xdeadbeef)
818 pos = data.rfind(marker)
819 if not pos:
820 raise CmdError("Could not find machine parameter block in '%s'" %
821 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700822 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700823 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700824 self._tools.WriteFile(bl2, data)
825 return bl2
826
Simon Glass89b86b82011-07-17 23:49:49 -0700827 def _PackOutput(self, msg):
828 """Helper function to write output from PackFirmware (verbose level 2).
829
830 This is passed to PackFirmware for it to use to write output.
831
832 Args:
833 msg: Message to display.
834 """
835 self._out.Notice(msg)
836
Simon Glass439fe7a2012-03-09 16:19:34 -0800837 def _BuildBlob(self, pack, fdt, blob_type):
838 """Build the blob data for a particular blob type.
839
840 Args:
841 blob_type: The type of blob to create data for. Supported types are:
842 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
843 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
844 """
845 if blob_type == 'coreboot':
846 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700847 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800848 pack.AddProperty('coreboot', coreboot)
849 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700850 elif blob_type == 'legacy':
851 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800852 elif blob_type == 'signed':
853 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
854 self.postload_fname)
855 pack.AddProperty('bootstub', bootstub)
856 pack.AddProperty('signed', signed)
857 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700858 elif blob_type == 'exynos-bl1':
859 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700860
861 # TODO(sjg@chromium.org): Deprecate ecbin
862 elif blob_type in ['ecrw', 'ecbin']:
863 pack.AddProperty('ecrw', self.ecrw_fname)
864 pack.AddProperty('ecbin', self.ecrw_fname)
865 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700866 # crosbug.com/p/13143
867 # We cannot have an fmap in the EC image since there can be only one,
868 # which is the main fmap describing the whole image.
869 # Ultimately the EC will not have an fmap, since with software sync
870 # there is no flashrom involvement in updating the EC flash, and thus
871 # no need for the fmap.
872 # For now, mangle the fmap name to avoid problems.
873 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
874 data = self._tools.ReadFile(self.ecro_fname)
875 data = re.sub('__FMAP__', '__fMAP__', data)
876 self._tools.WriteFile(updated_ecro, data)
877 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700878 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700879 spl_payload = pack.GetBlobParams(blob_type)
880
881 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
882 # from all flash map files.
883 if not spl_payload:
884 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
885 prop_list = 'boot+dtb'
886
887 # Do this later, when we remove boot+dtb.
888 # raise CmdError("No parameters provided for blob type '%s'" %
889 # blob_type)
890 else:
891 prop_list = spl_payload[0].split(',')
892 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
893 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
894 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700895 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700896 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800897 elif pack.GetProperty(blob_type):
898 pass
899 else:
900 raise CmdError("Unknown blob type '%s' required in flash map" %
901 blob_type)
902
Simon Glass290a1802011-07-17 13:54:32 -0700903 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700904 """Create a full firmware image, along with various by-products.
905
906 This uses the provided u-boot.bin, fdt and bct to create a firmware
907 image containing all the required parts. If the GBB is not supplied
908 then this will just return a signed U-Boot as the image.
909
910 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200911 gbb: Full path to the GBB file, or empty if a GBB is not required.
912 fdt: Fdt object containing required information.
913
914 Returns:
915 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700916
917 Raises:
918 CmdError if a command fails.
919 """
Simon Glass02d124a2012-03-02 14:47:20 -0800920 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700921
Simon Glass439fe7a2012-03-09 16:19:34 -0800922 # Get the flashmap so we know what to build
923 pack = PackFirmware(self._tools, self._out)
924 pack.SelectFdt(fdt)
925
926 # Get all our blobs ready
927 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700928 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700929 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700930
Simon Glass6e486c22012-10-26 15:43:42 -0700931 if self._force_rw:
932 fdt.PutInteger('/flash/rw-a-vblock', 'preamble-flags', 0)
933 fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
934
Simon Glass47817052012-10-20 13:30:07 -0700935 # Let's create some copies of the fdt for vboot. These can be used to
936 # pass a different fdt to each firmware type. For now it is just used to
937 # check that the right fdt comes through.
938 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
939 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
940 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
941 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
942 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
943 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
944 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
945
Simon Glassde9c8072012-07-02 22:29:02 -0700946 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
947 if self.kernel_fname:
948 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
949
Simon Glass50f74602012-03-15 21:04:25 -0700950 # Make a copy of the fdt for the bootstub
951 fdt_data = self._tools.ReadFile(fdt.fname)
952 uboot_data = self._tools.ReadFile(self.uboot_fname)
953 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
954 self._tools.WriteFile(uboot_copy, uboot_data)
955
956 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
957 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700958
959 # TODO(sjg@chromium.org): Deprecate this property when all boards
960 # use a comma-separated list for section contents. We will then
961 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700962 pack.AddProperty('boot+dtb', bootstub)
963
Simon Glass439fe7a2012-03-09 16:19:34 -0800964 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100965 blob_list = pack.GetBlobList()
966 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700967 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800968 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700969
970 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700971 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800972 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800973 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800974 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700975 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800976 pack.AddProperty('fwid', fwid)
977 pack.AddProperty('gbb', gbb)
978 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700979
980 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700981
982 # Record position and size of all blob members in the FDT
983 pack.UpdateBlobPositions(fdt)
984
Simon Glasscbc83552012-07-23 15:26:22 +0100985 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
986 # has created a rom file without the dtb, because until now it is not
987 # complete. Add the dtb here.
988 # A better anwer might be to put the dtb in memory immediately after
989 # U-Boot as is done for ARM and have coreboot load it as a binary file
990 # instead of an elf. However, I need to check whether coreboot supports
991 # this, and whether this is desirable for other reasons.
992 if 'coreboot' in blob_list:
993 bootstub = pack.GetProperty('coreboot')
994 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Stefan Reinauer1502ea62012-11-01 10:15:38 -0700995 self._tools.Run('cbfstool', [bootstub, 'add', '-f', fdt.fname,
996 '-n', 'u-boot.dtb', '-t', '0xac'])
Stefan Reinauer728be822012-10-02 16:54:09 -0700997 bootstub_tmp = bootstub + '.tmp'
998 self._tools.Run('dd', ['if=' + bootstub, 'of=' + bootstub_tmp,
999 'bs=1M', 'skip=7'])
1000 shutil.move(bootstub_tmp, bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +01001001
Simon Glassc90cf582012-03-13 15:40:47 -07001002 image = os.path.join(self._tools.outdir, 'image.bin')
1003 pack.PackImage(self._tools.outdir, image)
1004 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -07001005
Simon Glass439fe7a2012-03-09 16:19:34 -08001006 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -07001007 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -07001008 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -07001009
Simon Glass290a1802011-07-17 13:54:32 -07001010 def SelectFdt(self, fdt_fname):
1011 """Select an FDT to control the firmware bundling
1012
1013 Args:
1014 fdt_fname: The filename of the fdt to use.
1015
Simon Glassc0f3dc62011-08-09 14:19:05 -07001016 Returns:
1017 The Fdt object of the original fdt file, which we will not modify.
1018
Simon Glass290a1802011-07-17 13:54:32 -07001019 We make a copy of this which will include any on-the-fly changes we want
1020 to make.
1021 """
1022 self._fdt_fname = fdt_fname
1023 self.CheckOptions()
1024 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -08001025 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -07001026 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -07001027 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001028
Simon Glassc90cf582012-03-13 15:40:47 -07001029 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001030 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001031
1032 - Checks options, tools, output directory, fdt.
1033 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001034
1035 Args:
Simon Glass56577572011-07-19 11:08:06 +12001036 hardware_id: Hardware ID to use for this board. If None, then the
1037 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001038 output_fname: Output filename for the image. If this is not None, then
1039 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001040 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001041
1042 Returns:
1043 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001044 """
Simon Glass89b86b82011-07-17 23:49:49 -07001045 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -07001046 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +12001047 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001048
1049 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001050 image, pack = self._CreateImage(gbb, self.fdt)
1051 if show_map:
1052 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001053 if output_fname:
1054 shutil.copyfile(image, output_fname)
1055 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001056 return image, pack.props