blob: 3cf180dd3accd1b9467e647fccf9086facbe8ec2 [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 Glass157c0662012-10-23 13:52:42 -0700177 def SetOptions(self, small, gbb_flags):
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.
184 """
185 self._small = small
Simon Glass157c0662012-10-23 13:52:42 -0700186 self._gbb_flags = gbb_flags
Simon Glass290a1802011-07-17 13:54:32 -0700187
188 def CheckOptions(self):
189 """Check provided options and select defaults."""
190 if not self._board:
191 raise ValueError('No board defined - please define a board to use')
Simon Glass493163b2011-09-14 11:19:57 -0700192 build_root = os.path.join('##', 'build', self._board, 'firmware')
Simon Glass881964d2012-04-04 11:34:09 -0700193 dir_name = os.path.join(build_root, 'dts')
Simon Glass290a1802011-07-17 13:54:32 -0700194 if not self._fdt_fname:
Simon Glassceff3ff2012-04-04 11:23:45 -0700195 # Figure out where the file should be, and the name we expect.
Simon Glassceff3ff2012-04-04 11:23:45 -0700196 base_name = re.sub('_', '-', self._board)
197
198 # In case the name exists with a prefix or suffix, find it.
199 wildcard = os.path.join(dir_name, '*%s*.dts' % base_name)
200 found_list = glob.glob(self._tools.Filename(wildcard))
201 if len(found_list) == 1:
202 self._fdt_fname = found_list[0]
203 else:
204 # We didn't find anything definite, so set up our expected name.
205 self._fdt_fname = os.path.join(dir_name, '%s.dts' % base_name)
206
Simon Glass881964d2012-04-04 11:34:09 -0700207 # Convert things like 'exynos5250-daisy' into a full path.
208 root, ext = os.path.splitext(self._fdt_fname)
209 if not ext and not os.path.dirname(root):
210 self._fdt_fname = os.path.join(dir_name, '%s.dts' % root)
211
Simon Glass290a1802011-07-17 13:54:32 -0700212 if not self.uboot_fname:
213 self.uboot_fname = os.path.join(build_root, 'u-boot.bin')
214 if not self.bct_fname:
215 self.bct_fname = os.path.join(build_root, 'bct', 'board.bct')
Simon Glass2a7f0b32011-08-26 11:25:17 -0700216 if not self.bmpblk_fname:
David Hendricksbdecc542012-08-21 13:53:58 -0700217 self.bmpblk_fname = os.path.join(build_root, 'bmpblk.bin')
Simon Glass1d376832012-03-15 20:50:54 -0700218 if not self.exynos_bl1:
219 self.exynos_bl1 = os.path.join(build_root, 'E5250.nbl1.bin')
220 if not self.exynos_bl2:
221 self.exynos_bl2 = os.path.join(build_root, 'smdk5250-spl.bin')
Simon Glass07267952012-06-08 12:45:13 -0700222 if not self.coreboot_fname:
223 self.coreboot_fname = os.path.join(build_root, 'coreboot.rom')
224 if not self.skeleton_fname:
Stefan Reinauer728be822012-10-02 16:54:09 -0700225 self.skeleton_fname = os.path.join(build_root, 'coreboot.rom')
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700226 if not self.seabios_fname:
227 self.seabios_fname = 'seabios.cbfs'
Simon Glassbe0bc002012-08-16 12:50:48 -0700228 if not self.ecrw_fname:
229 self.ecrw_fname = os.path.join(build_root, 'ec.RW.bin')
230 if not self.ecro_fname:
231 self.ecro_fname = os.path.join(build_root, 'ec.RO.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700232
Simon Glass75759302012-03-15 20:26:53 -0700233 def GetFiles(self):
234 """Get a list of files that we know about.
235
236 This is the opposite of SetFiles except that we may have put in some
237 default names. It returns a dictionary containing the filename for
238 each of a number of pre-defined files.
239
240 Returns:
241 Dictionary, with one entry for each file.
242 """
243 file_list = {
244 'bct' : self.bct_fname,
245 'exynos-bl1' : self.exynos_bl1,
246 'exynos-bl2' : self.exynos_bl2,
247 }
248 return file_list
249
Simon Glass4a887b12012-10-23 16:29:03 -0700250 def DecodeGBBFlagsFromFdt(self):
251 """Get Google Binary Block flags from the FDT.
252
253 These should be in the chromeos-config node, like this:
254
255 chromeos-config {
256 gbb-flag-dev-screen-short-delay;
257 gbb-flag-force-dev-switch-on;
258 gbb-flag-force-dev-boot-usb;
259 gbb-flag-disable-fw-rollback-check;
260 };
261
262 Returns:
263 GBB flags value from FDT.
264 """
265 chromeos_config = self.fdt.GetProps("/chromeos-config")
266 gbb_flags = 0
267 for name in chromeos_config:
268 if name.startswith('gbb-flag-'):
269 flag_value = gbb_flag_properties.get(name[9:])
270 if flag_value:
271 gbb_flags |= flag_value
272 self._out.Notice("FDT: Enabling %s." % name)
273 else:
274 raise ValueError("FDT contains invalid GBB flags '%s'" % name)
275 return gbb_flags
276
Simon Glass157c0662012-10-23 13:52:42 -0700277 def DecodeGBBFlagsFromOptions(self, gbb_flags, adjustments):
278 """Decode ajustments to the provided GBB flags.
279
280 We support three options:
281
282 hex value: c2
283 defined value: force-dev-boot-usb,load-option-roms
284 adjust default value: -load-option-roms,+force-dev-boot-usb
285
286 The last option starts from the passed-in GBB flags and adds or removes
287 flags.
288
289 Args:
290 gbb_flags: Base (default) FDT flags.
291 adjustments: String containing adjustments to make.
292
293 Returns:
294 Updated FDT flags.
295 """
296 use_base_value = True
297 if adjustments:
298 try:
299 return int(adjustments, base=16)
300 except:
301 pass
302 for flag in adjustments.split(','):
303 oper = None
304 if flag[0] in ['-', '+']:
305 oper = flag[0]
306 flag = flag[1:]
307 value = gbb_flag_properties.get(flag)
308 if not value:
309 raise ValueError("Invalid GBB flag '%s'" % flag)
310 if oper == '+':
311 gbb_flags |= value
312 elif oper == '-':
313 gbb_flags &= ~value
314 else:
315 if use_base_value:
316 gbb_flags = 0
317 use_base_value = False
318 gbb_flags |= value
319
320 return gbb_flags
321
Simon Glass56577572011-07-19 11:08:06 +1200322 def _CreateGoogleBinaryBlock(self, hardware_id):
Simon Glass89b86b82011-07-17 23:49:49 -0700323 """Create a GBB for the image.
324
Simon Glass56577572011-07-19 11:08:06 +1200325 Args:
326 hardware_id: Hardware ID to use for this board. If None, then the
327 default from the Fdt will be used
328
Simon Glass89b86b82011-07-17 23:49:49 -0700329 Returns:
330 Path of the created GBB file.
331
332 Raises:
333 CmdError if a command fails.
334 """
Simon Glass56577572011-07-19 11:08:06 +1200335 if not hardware_id:
Simon Glass02d124a2012-03-02 14:47:20 -0800336 hardware_id = self.fdt.GetString('/config', 'hwid')
Simon Glass89b86b82011-07-17 23:49:49 -0700337 gbb_size = self.fdt.GetFlashPartSize('ro', 'gbb')
Simon Glass290a1802011-07-17 13:54:32 -0700338 odir = self._tools.outdir
Simon Glass89b86b82011-07-17 23:49:49 -0700339
Simon Glass4a887b12012-10-23 16:29:03 -0700340 gbb_flags = self.DecodeGBBFlagsFromFdt()
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800341
Simon Glass157c0662012-10-23 13:52:42 -0700342 # Allow command line to override flags
343 gbb_flags = self.DecodeGBBFlagsFromOptions(gbb_flags, self._gbb_flags)
344
Simon Glass4a887b12012-10-23 16:29:03 -0700345 self._out.Notice("GBB flags value %#x" % gbb_flags)
Simon Glass89b86b82011-07-17 23:49:49 -0700346 self._out.Progress('Creating GBB')
347 sizes = [0x100, 0x1000, gbb_size - 0x2180, 0x1000]
348 sizes = ['%#x' % size for size in sizes]
349 gbb = 'gbb.bin'
Simon Glass290a1802011-07-17 13:54:32 -0700350 keydir = self._tools.Filename(self._keydir)
351 self._tools.Run('gbb_utility', ['-c', ','.join(sizes), gbb], cwd=odir)
Simon Glass89b86b82011-07-17 23:49:49 -0700352 self._tools.Run('gbb_utility', ['-s',
Simon Glass56577572011-07-19 11:08:06 +1200353 '--hwid=%s' % hardware_id,
Simon Glass89b86b82011-07-17 23:49:49 -0700354 '--rootkey=%s/root_key.vbpubk' % keydir,
355 '--recoverykey=%s/recovery_key.vbpubk' % keydir,
Simon Glass2a7f0b32011-08-26 11:25:17 -0700356 '--bmpfv=%s' % self._tools.Filename(self.bmpblk_fname),
Stefan Reinauer975e68f2012-02-27 13:27:08 -0800357 '--flags=%d' % gbb_flags,
Simon Glass89b86b82011-07-17 23:49:49 -0700358 gbb],
Simon Glass290a1802011-07-17 13:54:32 -0700359 cwd=odir)
360 return os.path.join(odir, gbb)
Simon Glass89b86b82011-07-17 23:49:49 -0700361
Simon Glasse13ee2c2011-07-28 08:12:28 +1200362 def _SignBootstub(self, bct, bootstub, text_base):
Simon Glass89b86b82011-07-17 23:49:49 -0700363 """Sign an image so that the Tegra SOC will boot it.
364
365 Args:
366 bct: BCT file to use.
367 bootstub: Boot stub (U-Boot + fdt) file to sign.
368 text_base: Address of text base for image.
Simon Glass89b86b82011-07-17 23:49:49 -0700369
370 Returns:
371 filename of signed image.
372
373 Raises:
374 CmdError if a command fails.
375 """
376 # First create a config file - this is how we instruct cbootimage
Simon Glasse13ee2c2011-07-28 08:12:28 +1200377 signed = os.path.join(self._tools.outdir, 'signed.bin')
Simon Glass89b86b82011-07-17 23:49:49 -0700378 self._out.Progress('Signing Bootstub')
Simon Glasse13ee2c2011-07-28 08:12:28 +1200379 config = os.path.join(self._tools.outdir, 'boot.cfg')
Simon Glass89b86b82011-07-17 23:49:49 -0700380 fd = open(config, 'w')
381 fd.write('Version = 1;\n')
382 fd.write('Redundancy = 1;\n')
383 fd.write('Bctfile = %s;\n' % bct)
Doug Anderson0eeb0742011-09-15 18:11:40 -0700384
385 # TODO(dianders): Right now, we don't have enough space in our flash map
386 # for two copies of the BCT when we're using NAND, so hack it to 1. Not
387 # sure what this does for reliability, but at least things will fit...
388 is_nand = "NvBootDevType_Nand" in self._tools.Run('bct_dump', [bct])
389 if is_nand:
390 fd.write('Bctcopy = 1;\n')
391
Simon Glass89b86b82011-07-17 23:49:49 -0700392 fd.write('BootLoader = %s,%#x,%#x,Complete;\n' % (bootstub, text_base,
393 text_base))
Doug Anderson0eeb0742011-09-15 18:11:40 -0700394
Simon Glass89b86b82011-07-17 23:49:49 -0700395 fd.close()
396
397 self._tools.Run('cbootimage', [config, signed])
398 self._tools.OutputSize('BCT', bct)
399 self._tools.OutputSize('Signed image', signed)
400 return signed
401
Doug Anderson86ce5f42011-07-27 10:40:18 -0700402 def SetBootcmd(self, bootcmd, bootsecure):
Simon Glass290a1802011-07-17 13:54:32 -0700403 """Set the boot command for U-Boot.
Simon Glass89b86b82011-07-17 23:49:49 -0700404
405 Args:
Simon Glass290a1802011-07-17 13:54:32 -0700406 bootcmd: Boot command to use, as a string (if None this this is a nop).
Doug Anderson86ce5f42011-07-27 10:40:18 -0700407 bootsecure: We'll set '/config/bootsecure' to 1 if True and 0 if False.
Simon Glass89b86b82011-07-17 23:49:49 -0700408 """
Simon Glass468d8752012-09-19 16:36:19 -0700409 if bootcmd is not None:
410 if bootcmd == 'none':
411 bootcmd = ''
Simon Glass02d124a2012-03-02 14:47:20 -0800412 self.fdt.PutString('/config', 'bootcmd', bootcmd)
413 self.fdt.PutInteger('/config', 'bootsecure', int(bootsecure))
Simon Glass290a1802011-07-17 13:54:32 -0700414 self._out.Info('Boot command: %s' % bootcmd)
Simon Glass89b86b82011-07-17 23:49:49 -0700415
Simon Glassa4934b72012-05-09 13:35:02 -0700416 def SetNodeEnabled(self, node_name, enabled):
417 """Set whether an node is enabled or disabled.
418
419 This simply sets the 'status' property of a node to "ok", or "disabled".
420
421 The node should either be a full path to the node (like '/uart@10200000')
422 or an alias property.
423
424 Aliases are supported like this:
425
426 aliases {
427 console = "/uart@10200000";
428 };
429
430 pointing to a node:
431
432 uart@10200000 {
Simon Glass4c5066f2012-06-20 16:51:19 -0700433 status = "okay";
Simon Glassa4934b72012-05-09 13:35:02 -0700434 };
435
436 In this case, this function takes the name of the alias ('console' in
437 this case) and updates the status of the node that is pointed to, to
438 either ok or disabled. If the alias does not exist, a warning is
439 displayed.
440
441 Args:
442 node_name: Name of node (e.g. '/uart@10200000') or alias alias
443 (e.g. 'console') to adjust
444 enabled: True to enable, False to disable
445 """
446 # Look up the alias if this is an alias reference
447 if not node_name.startswith('/'):
448 lookup = self.fdt.GetString('/aliases', node_name, '')
449 if not lookup:
450 self._out.Warning("Cannot find alias '%s' - ignoring" % node_name)
451 return
452 node_name = lookup
453 if enabled:
Simon Glass4c5066f2012-06-20 16:51:19 -0700454 status = 'okay'
Simon Glassa4934b72012-05-09 13:35:02 -0700455 else:
456 status = 'disabled'
457 self.fdt.PutString(node_name, 'status', status)
458
459 def AddEnableList(self, enable_list):
460 """Process a list of nodes to enable/disable.
461
462 Args:
463 config_list: List of (node, value) tuples to add to the fdt. For each
464 tuple:
465 node: The fdt node to write to will be <node> or pointed to by
466 /aliases/<node>. We can tell which
467 value: 0 to disable the node, 1 to enable it
468 """
469 if enable_list:
470 for node_name, enabled in enable_list:
471 try:
472 enabled = int(enabled)
473 if enabled not in (0, 1):
474 raise ValueError
475 except ValueError as str:
476 raise CmdError("Invalid enable option value '%s' "
477 "(should be 0 or 1)" % enabled)
478 self.SetNodeEnabled(node_name, enabled)
479
Simon Glass290a1802011-07-17 13:54:32 -0700480 def AddConfigList(self, config_list, use_int=False):
481 """Add a list of config items to the fdt.
482
483 Normally these values are written to the fdt as strings, but integers
484 are also supported, in which case the values will be converted to integers
485 (if necessary) before being stored.
486
487 Args:
488 config_list: List of (config, value) tuples to add to the fdt. For each
489 tuple:
490 config: The fdt node to write to will be /config/<config>.
491 value: An integer or string value to write.
492 use_int: True to only write integer values.
493
494 Raises:
495 CmdError: if a value is required to be converted to integer but can't be.
496 """
497 if config_list:
498 for config in config_list:
499 value = config[1]
500 if use_int:
501 try:
502 value = int(value)
503 except ValueError as str:
504 raise CmdError("Cannot convert config option '%s' to integer" %
505 value)
506 if type(value) == type(1):
Simon Glass02d124a2012-03-02 14:47:20 -0800507 self.fdt.PutInteger('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700508 else:
Simon Glass02d124a2012-03-02 14:47:20 -0800509 self.fdt.PutString('/config', '%s' % config[0], value)
Simon Glass290a1802011-07-17 13:54:32 -0700510
Simon Glass7c2d5572011-11-15 14:47:08 -0800511 def DecodeTextBase(self, data):
512 """Look at a U-Boot image and try to decode its TEXT_BASE.
513
514 This works because U-Boot has a header with the value 0x12345678
515 immediately followed by the TEXT_BASE value. We can therefore read this
516 from the image with some certainty. We check only the first 40 words
517 since the header should be within that region.
518
Simon Glass96b50302012-07-20 06:55:28 +0100519 Since upstream Tegra has moved to having a 16KB SPL region at the start,
520 and currently this does holds the U-Boot text base (e.g. 0x10c000) instead
521 of the SPL one (e.g. 0x108000), we search in the U-Boot part as well.
522
Simon Glass7c2d5572011-11-15 14:47:08 -0800523 Args:
524 data: U-Boot binary data
525
526 Returns:
527 Text base (integer) or None if none was found
528 """
529 found = False
Simon Glass96b50302012-07-20 06:55:28 +0100530 for start in (0, 0x4000):
531 for i in range(start, start + 160, 4):
532 word = data[i:i + 4]
Simon Glass7c2d5572011-11-15 14:47:08 -0800533
Simon Glass96b50302012-07-20 06:55:28 +0100534 # TODO(sjg): This does not cope with a big-endian target
535 value = struct.unpack('<I', word)[0]
536 if found:
537 return value - start
538 if value == 0x12345678:
539 found = True
Simon Glass7c2d5572011-11-15 14:47:08 -0800540
541 return None
542
543 def CalcTextBase(self, name, fdt, fname):
544 """Calculate the TEXT_BASE to use for U-Boot.
545
546 Normally this value is in the fdt, so we just read it from there. But as
547 a second check we look at the image itself in case this is different, and
548 switch to that if it is.
549
550 This allows us to flash any U-Boot even if its TEXT_BASE is different.
551 This is particularly useful with upstream U-Boot which uses a different
552 value (which we will move to).
553 """
554 data = self._tools.ReadFile(fname)
Simon Glassa7844ed2012-07-11 14:30:08 +0200555 fdt_text_base = fdt.GetInt('/chromeos-config', 'textbase', 0)
Simon Glass7c2d5572011-11-15 14:47:08 -0800556 text_base = self.DecodeTextBase(data)
Simon Glass96b50302012-07-20 06:55:28 +0100557 text_base_str = '%#x' % text_base if text_base else 'None'
558 self._out.Info('TEXT_BASE: fdt says %#x, %s says %s' % (fdt_text_base,
559 fname, text_base_str))
Simon Glass7c2d5572011-11-15 14:47:08 -0800560
561 # If they are different, issue a warning and switch over.
562 if text_base and text_base != fdt_text_base:
563 self._out.Warning("TEXT_BASE %x in %sU-Boot doesn't match "
564 "fdt value of %x. Using %x" % (text_base, name,
565 fdt_text_base, text_base))
566 fdt_text_base = text_base
567 return fdt_text_base
568
Simon Glass6dcc2f22011-07-28 15:26:49 +1200569 def _CreateBootStub(self, uboot, base_fdt, postload):
Simon Glass89b86b82011-07-17 23:49:49 -0700570 """Create a boot stub and a signed boot stub.
571
Simon Glass6dcc2f22011-07-28 15:26:49 +1200572 For postload:
573 We add a /config/postload-text-offset entry to the signed bootstub's
574 fdt so that U-Boot can find the postload code.
575
576 The raw (unsigned) bootstub will have a value of -1 for this since we will
577 simply append the postload code to the bootstub and it can find it there.
578 This will be used for RW A/B firmware.
579
580 For the signed case this value will specify where in the flash to find
581 the postload code. This will be used for RO firmware.
582
Simon Glass89b86b82011-07-17 23:49:49 -0700583 Args:
584 uboot: Path to u-boot.bin (may be chroot-relative)
Simon Glass29b96ad2012-03-09 15:34:33 -0800585 base_fdt: Fdt object containing the flat device tree.
Simon Glass6dcc2f22011-07-28 15:26:49 +1200586 postload: Path to u-boot-post.bin, or None if none.
Simon Glass89b86b82011-07-17 23:49:49 -0700587
588 Returns:
589 Tuple containing:
Simon Glass6dcc2f22011-07-28 15:26:49 +1200590 Full path to bootstub (uboot + fdt(-1) + postload).
591 Full path to signed (uboot + fdt(flash pos) + bct) + postload.
Simon Glass89b86b82011-07-17 23:49:49 -0700592
593 Raises:
594 CmdError if a command fails.
595 """
Simon Glasse13ee2c2011-07-28 08:12:28 +1200596 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
Simon Glass7c2d5572011-11-15 14:47:08 -0800597 text_base = self.CalcTextBase('', self.fdt, uboot)
Simon Glass89b86b82011-07-17 23:49:49 -0700598 uboot_data = self._tools.ReadFile(uboot)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200599
600 # Make a copy of the fdt for the bootstub
601 fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
Simon Glass02d124a2012-03-02 14:47:20 -0800602 fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff);
Simon Glass290a1802011-07-17 13:54:32 -0700603 fdt_data = self._tools.ReadFile(fdt.fname)
Simon Glasse13ee2c2011-07-28 08:12:28 +1200604
Simon Glass89b86b82011-07-17 23:49:49 -0700605 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass290a1802011-07-17 13:54:32 -0700606 self._tools.OutputSize('U-Boot binary', self.uboot_fname)
607 self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
Simon Glass89b86b82011-07-17 23:49:49 -0700608 self._tools.OutputSize('Combined binary', bootstub)
609
Simon Glasse13ee2c2011-07-28 08:12:28 +1200610 # Sign the bootstub; this is a combination of the board specific
Simon Glass89b86b82011-07-17 23:49:49 -0700611 # bct and the stub u-boot image.
Simon Glass290a1802011-07-17 13:54:32 -0700612 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
Simon Glasse13ee2c2011-07-28 08:12:28 +1200613 bootstub, text_base)
Simon Glass6dcc2f22011-07-28 15:26:49 +1200614
615 signed_postload = os.path.join(self._tools.outdir, 'signed-postload.bin')
616 data = self._tools.ReadFile(signed)
617
618 if postload:
619 # We must add postload to the bootstub since A and B will need to
620 # be able to find it without the /config/postload-text-offset mechanism.
621 bs_data = self._tools.ReadFile(bootstub)
622 bs_data += self._tools.ReadFile(postload)
623 bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt-postload.bin')
624 self._tools.WriteFile(bootstub, bs_data)
625 self._tools.OutputSize('Combined binary with postload', bootstub)
626
627 # Now that we know the file size, adjust the fdt and re-sign
628 postload_bootstub = os.path.join(self._tools.outdir, 'postload.bin')
Simon Glass02d124a2012-03-02 14:47:20 -0800629 fdt.PutInteger('/config', 'postload-text-offset', len(data))
Simon Glass6dcc2f22011-07-28 15:26:49 +1200630 fdt_data = self._tools.ReadFile(fdt.fname)
631 self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
632 signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
633 postload_bootstub, text_base)
634 if len(data) != os.path.getsize(signed):
635 raise CmdError('Signed file size changed from %d to %d after updating '
636 'fdt' % (len(data), os.path.getsize(signed)))
637
638 # Re-read the signed image, and add the post-load binary.
639 data = self._tools.ReadFile(signed)
640 data += self._tools.ReadFile(postload)
641 self._tools.OutputSize('Post-load binary', postload)
642
643 self._tools.WriteFile(signed_postload, data)
644 self._tools.OutputSize('Final bootstub with postload', signed_postload)
645
646 return bootstub, signed_postload
Simon Glass89b86b82011-07-17 23:49:49 -0700647
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700648 def _CreateCorebootStub(self, uboot, coreboot):
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700649 """Create a coreboot boot stub.
650
651 Args:
652 uboot: Path to u-boot.bin (may be chroot-relative)
653 coreboot: Path to coreboot.rom
Vincent Palatinf7286772011-10-12 14:31:53 -0700654 seabios: Path to SeaBIOS payload binary or None
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700655
656 Returns:
Simon Glasscbc83552012-07-23 15:26:22 +0100657 Full path to bootstub (coreboot + uboot).
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700658
659 Raises:
660 CmdError if a command fails.
661 """
662 bootstub = os.path.join(self._tools.outdir, 'coreboot-full.rom')
Simon Glassf2b3a5c2012-06-07 14:02:36 -0700663
664 # U-Boot itself does not put a .elf extension on the elf file.
665 # The U-Boot ebuild does, but we shouldn't actually require it since
666 # devs may want to just use what U-Boot creates.
667 uboot_elf = uboot.replace('.bin', '')
668 if not os.path.exists(self._tools.Filename(uboot_elf)):
669 uboot_elf = uboot.replace('.bin', '.elf')
670 shutil.copyfile(self._tools.Filename(coreboot), bootstub)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700671 self._tools.Run('cbfstool', [bootstub, 'add-payload', uboot_elf,
Vincent Palatinf7286772011-10-12 14:31:53 -0700672 'fallback/payload', 'lzma'])
Simon Glasscbc83552012-07-23 15:26:22 +0100673
674 # Don't add the fdt yet since it is not in final form
Stefan Reinauerc2e1e4d2011-08-23 14:50:59 -0700675 return bootstub
676
Simon Glass3b404092012-05-23 13:10:36 -0700677 def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
Simon Glassdf95dd22012-03-13 15:46:16 -0700678 """Update the parameters in a BL2 blob.
679
680 We look at the list in the parameter block, extract the value of each
681 from the device tree, and write that value to the parameter block.
682
683 Args:
684 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700685 spl_load_size: Size of U-Boot image that SPL must load
Simon Glassdf95dd22012-03-13 15:46:16 -0700686 data: The BL2 data.
687 pos: The position of the start of the parameter block.
688
689 Returns:
690 The new contents of the parameter block, after updating.
691 """
Simon Glassdf95dd22012-03-13 15:46:16 -0700692 version, size = struct.unpack('<2L', data[pos + 4:pos + 12])
693 if version != 1:
694 raise CmdError("Cannot update machine parameter block version '%d'" %
695 version)
696 if size < 0 or pos + size > len(data):
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700697 raise CmdError("Machine parameter block size %d is invalid: "
698 "pos=%d, size=%d, space=%d, len=%d" %
699 (size, pos, size, len(data) - pos, len(data)))
Simon Glassdf95dd22012-03-13 15:46:16 -0700700
701 # Move past the header and read the parameter list, which is terminated
702 # with \0.
703 pos += 12
704 param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
705 param_len = param_list.find('\0')
706 param_list = param_list[:param_len]
Simon Glass66c1a9f2012-03-22 19:15:53 -0700707 pos += (param_len + 4) & ~3
Simon Glassdf95dd22012-03-13 15:46:16 -0700708
709 # Work through the parameters one at a time, adding each value
710 new_data = ''
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700711 upto = 0
Simon Glassdf95dd22012-03-13 15:46:16 -0700712 for param in param_list:
Simon Glass2c48ddf2012-03-23 16:55:22 -0700713 value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]
Simon Glassdf95dd22012-03-13 15:46:16 -0700714 if param == 'm' :
Simon Glass1a77ded2012-03-15 21:00:49 -0700715 mem_type = fdt.GetString('/dmc', 'mem-type')
Simon Glassdf95dd22012-03-13 15:46:16 -0700716 mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3']
717 if not mem_type in mem_types:
718 raise CmdError("Unknown memory type '%s'" % mem_type)
719 value = mem_types.index(mem_type)
720 self._out.Info(' Memory type: %s (%d)' % (mem_type, value))
Doug Andersonee46cfe2012-05-18 09:53:08 -0700721 elif param == 'M' :
722 mem_manuf = fdt.GetString('/dmc', 'mem-manuf')
723 mem_manufs = ['autodetect', 'elpida', 'samsung']
724 if not mem_manuf in mem_manufs:
725 raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf)
726 value = mem_manufs.index(mem_manuf)
727 self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value))
Simon Glass158289e2012-09-14 11:42:25 -0700728 elif param == 'f' :
729 mem_freq = fdt.GetInt('/dmc', 'clock-frequency') / 1000000
730 if not mem_freq in [533, 667, 800]:
731 self._out.Warning("Unexpected memory speed '%s'" % mem_freq)
732 value = mem_freq
733 self._out.Info(' Memory speed: %d' % mem_freq)
Simon Glassdf95dd22012-03-13 15:46:16 -0700734 elif param == 'v':
735 value = 31
736 self._out.Info(' Memory interleave: %#0x' % value)
Simon Glass8e1fdb22012-03-15 21:02:10 -0700737 elif param == 'u':
Simon Glass3b404092012-05-23 13:10:36 -0700738 value = (spl_load_size + 0xfff) & ~0xfff
739 self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
740 (value, spl_load_size))
Simon Glass559b6612012-05-23 13:28:45 -0700741 elif param == 'b':
742 # These values come from enum boot_mode in U-Boot's cpu.h
743 if self.spl_source == 'straps':
744 value = 32
745 elif self.spl_source == 'emmc':
746 value = 4
747 elif self.spl_source == 'spi':
748 value = 20
749 elif self.spl_source == 'usb':
750 value = 33
751 else:
752 raise CmdError("Invalid boot source '%s'" % self.spl_source)
753 self._out.Info(' Boot source: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700754 else:
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700755 self._out.Warning("Unknown machine parameter type '%s'" % param)
Simon Glass2c48ddf2012-03-23 16:55:22 -0700756 self._out.Info(' Unknown value: %#0x' % value)
Simon Glassdf95dd22012-03-13 15:46:16 -0700757 new_data += struct.pack('<L', value)
Simon Glass7dbdf5b2012-03-15 20:58:04 -0700758 upto += 4
Simon Glassdf95dd22012-03-13 15:46:16 -0700759
760 # Put the data into our block.
761 data = data[:pos] + new_data + data[pos + len(new_data):]
762 self._out.Info('BL2 configuration complete')
763 return data
764
Simon Glasse5e8afb2012-05-23 11:19:23 -0700765 def _UpdateChecksum(self, data):
766 """Update the BL2 checksum.
767
768 The checksum is a 4 byte sum of all the bytes in the image before the
769 last 4 bytes (which hold the checksum).
770
771 Args:
772 data: The BL2 data to update.
773
774 Returns:
775 The new contents of the BL2 data, after updating the checksum.
776 """
777 checksum = 0
778 for ch in data[:-4]:
779 checksum += ord(ch)
780 return data[:-4] + struct.pack('<L', checksum & 0xffffffff)
781
Simon Glass559b6612012-05-23 13:28:45 -0700782 def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
Simon Glass7e199222012-03-13 15:51:18 -0700783 """Configure an Exynos BL2 binary for our needs.
784
785 We create a new modified BL2 and return its filename.
786
787 Args:
788 fdt: Device tree containing the parameter values.
Simon Glass3b404092012-05-23 13:10:36 -0700789 spl_load_size: Size of U-Boot image that SPL must load
Simon Glass7e199222012-03-13 15:51:18 -0700790 orig_bl2: Filename of original BL2 file to modify.
791 """
Simon Glass66c1a9f2012-03-22 19:15:53 -0700792 self._out.Info('Configuring BL2')
Simon Glass559b6612012-05-23 13:28:45 -0700793 bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
Simon Glass66c1a9f2012-03-22 19:15:53 -0700794 data = self._tools.ReadFile(orig_bl2)
795 self._tools.WriteFile(bl2, data)
Simon Glass7e199222012-03-13 15:51:18 -0700796
797 # Locate the parameter block
798 data = self._tools.ReadFile(bl2)
799 marker = struct.pack('<L', 0xdeadbeef)
800 pos = data.rfind(marker)
801 if not pos:
802 raise CmdError("Could not find machine parameter block in '%s'" %
803 orig_bl2)
Simon Glass3b404092012-05-23 13:10:36 -0700804 data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
Simon Glasse5e8afb2012-05-23 11:19:23 -0700805 data = self._UpdateChecksum(data)
Simon Glass7e199222012-03-13 15:51:18 -0700806 self._tools.WriteFile(bl2, data)
807 return bl2
808
Simon Glass89b86b82011-07-17 23:49:49 -0700809 def _PackOutput(self, msg):
810 """Helper function to write output from PackFirmware (verbose level 2).
811
812 This is passed to PackFirmware for it to use to write output.
813
814 Args:
815 msg: Message to display.
816 """
817 self._out.Notice(msg)
818
Simon Glass439fe7a2012-03-09 16:19:34 -0800819 def _BuildBlob(self, pack, fdt, blob_type):
820 """Build the blob data for a particular blob type.
821
822 Args:
823 blob_type: The type of blob to create data for. Supported types are:
824 coreboot A coreboot image (ROM plus U-boot and .dtb payloads).
825 signed Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
826 """
827 if blob_type == 'coreboot':
828 coreboot = self._CreateCorebootStub(self.uboot_fname,
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700829 self.coreboot_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800830 pack.AddProperty('coreboot', coreboot)
831 pack.AddProperty('image', coreboot)
Stefan Reinauer9ad54842012-10-10 12:25:23 -0700832 elif blob_type == 'legacy':
833 pack.AddProperty('legacy', self.seabios_fname)
Simon Glass439fe7a2012-03-09 16:19:34 -0800834 elif blob_type == 'signed':
835 bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
836 self.postload_fname)
837 pack.AddProperty('bootstub', bootstub)
838 pack.AddProperty('signed', signed)
839 pack.AddProperty('image', signed)
Simon Glass7e199222012-03-13 15:51:18 -0700840 elif blob_type == 'exynos-bl1':
841 pack.AddProperty(blob_type, self.exynos_bl1)
Simon Glassbe0bc002012-08-16 12:50:48 -0700842
843 # TODO(sjg@chromium.org): Deprecate ecbin
844 elif blob_type in ['ecrw', 'ecbin']:
845 pack.AddProperty('ecrw', self.ecrw_fname)
846 pack.AddProperty('ecbin', self.ecrw_fname)
847 elif blob_type == 'ecro':
Simon Glass693b40f2012-08-28 10:51:05 -0700848 # crosbug.com/p/13143
849 # We cannot have an fmap in the EC image since there can be only one,
850 # which is the main fmap describing the whole image.
851 # Ultimately the EC will not have an fmap, since with software sync
852 # there is no flashrom involvement in updating the EC flash, and thus
853 # no need for the fmap.
854 # For now, mangle the fmap name to avoid problems.
855 updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
856 data = self._tools.ReadFile(self.ecro_fname)
857 data = re.sub('__FMAP__', '__fMAP__', data)
858 self._tools.WriteFile(updated_ecro, data)
859 pack.AddProperty(blob_type, updated_ecro)
Simon Glass7e199222012-03-13 15:51:18 -0700860 elif blob_type == 'exynos-bl2':
Simon Glass7d2542f2012-06-21 07:10:59 -0700861 spl_payload = pack.GetBlobParams(blob_type)
862
863 # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
864 # from all flash map files.
865 if not spl_payload:
866 spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
867 prop_list = 'boot+dtb'
868
869 # Do this later, when we remove boot+dtb.
870 # raise CmdError("No parameters provided for blob type '%s'" %
871 # blob_type)
872 else:
873 prop_list = spl_payload[0].split(',')
874 spl_load_size = len(pack.ConcatPropContents(prop_list)[0])
875 self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
876 (', '.join(prop_list), spl_load_size, spl_load_size))
Simon Glass3b404092012-05-23 13:10:36 -0700877 bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
Simon Glass7e199222012-03-13 15:51:18 -0700878 pack.AddProperty(blob_type, bl2)
Simon Glass439fe7a2012-03-09 16:19:34 -0800879 elif pack.GetProperty(blob_type):
880 pass
881 else:
882 raise CmdError("Unknown blob type '%s' required in flash map" %
883 blob_type)
884
Simon Glass290a1802011-07-17 13:54:32 -0700885 def _CreateImage(self, gbb, fdt):
Simon Glass89b86b82011-07-17 23:49:49 -0700886 """Create a full firmware image, along with various by-products.
887
888 This uses the provided u-boot.bin, fdt and bct to create a firmware
889 image containing all the required parts. If the GBB is not supplied
890 then this will just return a signed U-Boot as the image.
891
892 Args:
Simon Glasse13ee2c2011-07-28 08:12:28 +1200893 gbb: Full path to the GBB file, or empty if a GBB is not required.
894 fdt: Fdt object containing required information.
895
896 Returns:
897 Path to image file
Simon Glass89b86b82011-07-17 23:49:49 -0700898
899 Raises:
900 CmdError if a command fails.
901 """
Simon Glass02d124a2012-03-02 14:47:20 -0800902 self._out.Notice("Model: %s" % fdt.GetString('/', 'model'))
Simon Glass89b86b82011-07-17 23:49:49 -0700903
Simon Glass439fe7a2012-03-09 16:19:34 -0800904 # Get the flashmap so we know what to build
905 pack = PackFirmware(self._tools, self._out)
906 pack.SelectFdt(fdt)
907
908 # Get all our blobs ready
909 pack.AddProperty('boot', self.uboot_fname)
Simon Glass07267952012-06-08 12:45:13 -0700910 pack.AddProperty('skeleton', self.skeleton_fname)
Simon Glass3b85f712012-06-21 07:06:46 -0700911 pack.AddProperty('dtb', fdt.fname)
Simon Glass50f74602012-03-15 21:04:25 -0700912
Simon Glass47817052012-10-20 13:30:07 -0700913 # Let's create some copies of the fdt for vboot. These can be used to
914 # pass a different fdt to each firmware type. For now it is just used to
915 # check that the right fdt comes through.
916 fdt_rwa = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwa.dtb'))
917 fdt_rwa.PutString('/chromeos-config', 'firmware-type', 'rw-a')
918 pack.AddProperty('dtb-rwa', fdt_rwa.fname)
919 fdt_rwb = fdt.Copy(os.path.join(self._tools.outdir, 'updated-rwb.dtb'))
920 fdt_rwb.PutString('/chromeos-config', 'firmware-type', 'rw-b')
921 pack.AddProperty('dtb-rwb', fdt_rwb.fname)
922 fdt.PutString('/chromeos-config', 'firmware-type', 'ro')
923
Simon Glassde9c8072012-07-02 22:29:02 -0700924 # If we are writing a kernel, add its offset from TEXT_BASE to the fdt.
925 if self.kernel_fname:
926 fdt.PutInteger('/config', 'kernel-offset', pack.image_size)
927
Simon Glass50f74602012-03-15 21:04:25 -0700928 # Make a copy of the fdt for the bootstub
929 fdt_data = self._tools.ReadFile(fdt.fname)
930 uboot_data = self._tools.ReadFile(self.uboot_fname)
931 uboot_copy = os.path.join(self._tools.outdir, 'u-boot.bin')
932 self._tools.WriteFile(uboot_copy, uboot_data)
933
934 bootstub = os.path.join(self._tools.outdir, 'u-boot-dtb.bin')
935 self._tools.WriteFile(bootstub, uboot_data + fdt_data)
Simon Glass3b85f712012-06-21 07:06:46 -0700936
937 # TODO(sjg@chromium.org): Deprecate this property when all boards
938 # use a comma-separated list for section contents. We will then
939 # use only 'boot,dtb' instead of 'boot+dtb'
Simon Glass50f74602012-03-15 21:04:25 -0700940 pack.AddProperty('boot+dtb', bootstub)
941
Simon Glass439fe7a2012-03-09 16:19:34 -0800942 pack.AddProperty('gbb', self.uboot_fname)
Simon Glass9d088d92012-07-16 16:27:11 +0100943 blob_list = pack.GetBlobList()
944 self._out.Info('Building blobs %s\n' % blob_list)
Simon Glass07267952012-06-08 12:45:13 -0700945 for blob_type in pack.GetBlobList():
Simon Glass439fe7a2012-03-09 16:19:34 -0800946 self._BuildBlob(pack, fdt, blob_type)
Simon Glass89b86b82011-07-17 23:49:49 -0700947
948 if gbb:
Simon Glasse76bf7b2012-03-13 15:34:41 -0700949 pack.RequireAllEntries()
Hung-Te Lina7462e72011-07-27 19:17:10 +0800950 fwid = '.'.join([
Simon Glass02d124a2012-03-02 14:47:20 -0800951 re.sub('[ ,]+', '_', fdt.GetString('/', 'model')),
Hung-Te Lina7462e72011-07-27 19:17:10 +0800952 self._tools.GetChromeosVersion()])
Simon Glass89b86b82011-07-17 23:49:49 -0700953 self._out.Notice('Firmware ID: %s' % fwid)
Simon Glass439fe7a2012-03-09 16:19:34 -0800954 pack.AddProperty('fwid', fwid)
955 pack.AddProperty('gbb', gbb)
956 pack.AddProperty('keydir', self._keydir)
Simon Glassc90cf582012-03-13 15:40:47 -0700957
958 pack.CheckProperties()
Simon Glass8884b982012-06-21 12:41:41 -0700959
960 # Record position and size of all blob members in the FDT
961 pack.UpdateBlobPositions(fdt)
962
Simon Glasscbc83552012-07-23 15:26:22 +0100963 # TODO(sjg@chromium.org): This is not in a good place. _CreateCorebootStub
964 # has created a rom file without the dtb, because until now it is not
965 # complete. Add the dtb here.
966 # A better anwer might be to put the dtb in memory immediately after
967 # U-Boot as is done for ARM and have coreboot load it as a binary file
968 # instead of an elf. However, I need to check whether coreboot supports
969 # this, and whether this is desirable for other reasons.
970 if 'coreboot' in blob_list:
971 bootstub = pack.GetProperty('coreboot')
972 fdt = fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
973 self._tools.Run('cbfstool', [bootstub, 'add', fdt.fname, 'u-boot.dtb',
974 '0xac'])
Stefan Reinauer728be822012-10-02 16:54:09 -0700975 bootstub_tmp = bootstub + '.tmp'
976 self._tools.Run('dd', ['if=' + bootstub, 'of=' + bootstub_tmp,
977 'bs=1M', 'skip=7'])
978 shutil.move(bootstub_tmp, bootstub)
Simon Glasscbc83552012-07-23 15:26:22 +0100979
Simon Glassc90cf582012-03-13 15:40:47 -0700980 image = os.path.join(self._tools.outdir, 'image.bin')
981 pack.PackImage(self._tools.outdir, image)
982 pack.AddProperty('image', image)
Simon Glass89b86b82011-07-17 23:49:49 -0700983
Simon Glass439fe7a2012-03-09 16:19:34 -0800984 image = pack.GetProperty('image')
Simon Glass89b86b82011-07-17 23:49:49 -0700985 self._tools.OutputSize('Final image', image)
Simon Glassc90cf582012-03-13 15:40:47 -0700986 return image, pack
Simon Glass89b86b82011-07-17 23:49:49 -0700987
Simon Glass290a1802011-07-17 13:54:32 -0700988 def SelectFdt(self, fdt_fname):
989 """Select an FDT to control the firmware bundling
990
991 Args:
992 fdt_fname: The filename of the fdt to use.
993
Simon Glassc0f3dc62011-08-09 14:19:05 -0700994 Returns:
995 The Fdt object of the original fdt file, which we will not modify.
996
Simon Glass290a1802011-07-17 13:54:32 -0700997 We make a copy of this which will include any on-the-fly changes we want
998 to make.
999 """
1000 self._fdt_fname = fdt_fname
1001 self.CheckOptions()
1002 fdt = Fdt(self._tools, self._fdt_fname)
Simon Glass29b96ad2012-03-09 15:34:33 -08001003 fdt.Compile()
Simon Glass290a1802011-07-17 13:54:32 -07001004 self.fdt = fdt.Copy(os.path.join(self._tools.outdir, 'updated.dtb'))
Simon Glassc0f3dc62011-08-09 14:19:05 -07001005 return fdt
Simon Glass290a1802011-07-17 13:54:32 -07001006
Simon Glassc90cf582012-03-13 15:40:47 -07001007 def Start(self, hardware_id, output_fname, show_map):
Simon Glass290a1802011-07-17 13:54:32 -07001008 """This creates a firmware bundle according to settings provided.
Simon Glass89b86b82011-07-17 23:49:49 -07001009
1010 - Checks options, tools, output directory, fdt.
1011 - Creates GBB and image.
Simon Glass290a1802011-07-17 13:54:32 -07001012
1013 Args:
Simon Glass56577572011-07-19 11:08:06 +12001014 hardware_id: Hardware ID to use for this board. If None, then the
1015 default from the Fdt will be used
Simon Glass290a1802011-07-17 13:54:32 -07001016 output_fname: Output filename for the image. If this is not None, then
1017 the final image will be copied here.
Simon Glassc90cf582012-03-13 15:40:47 -07001018 show_map: Show a flash map, with each area's name and position
Simon Glass290a1802011-07-17 13:54:32 -07001019
1020 Returns:
1021 Filename of the resulting image (not the output_fname copy).
Simon Glass89b86b82011-07-17 23:49:49 -07001022 """
Simon Glass89b86b82011-07-17 23:49:49 -07001023 gbb = ''
Simon Glass290a1802011-07-17 13:54:32 -07001024 if not self._small:
Simon Glass56577572011-07-19 11:08:06 +12001025 gbb = self._CreateGoogleBinaryBlock(hardware_id)
Simon Glass89b86b82011-07-17 23:49:49 -07001026
1027 # This creates the actual image.
Simon Glassc90cf582012-03-13 15:40:47 -07001028 image, pack = self._CreateImage(gbb, self.fdt)
1029 if show_map:
1030 pack.ShowMap()
Simon Glass290a1802011-07-17 13:54:32 -07001031 if output_fname:
1032 shutil.copyfile(image, output_fname)
1033 self._out.Notice("Output image '%s'" % output_fname)
Simon Glass794217e2012-06-07 11:40:37 -07001034 return image, pack.props