1 # Copyright (c) 2013 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.
5 """crosfw - Chrome OS Firmware build/flash script.
7 Builds a firmware image for any board and writes it to the board. The image
8 can be pure upstream or include Chrome OS components (-V). Some device
9 tree parameters can be provided, including silent console (-C) and secure
10 boot (-S). Use -i for a faster incremental build. The image is written to
11 the board by default using USB/em100 (or sdcard with -x). Use -b to specify
12 the board to build. Options can be added to ~/.crosfwrc - see the script for
15 It can also flash SPI by writing a 'magic flasher' U-Boot with a payload
18 Usage: crosfw [options]
20 The script is normally run from within the U-Boot directory which is
21 .../src/third_party/u-boot/files
23 Example 1: Build upstream image for coreboot and write to a 'link':
27 Example 2: Build verified boot image (V) for daisy/snow and boot in secure
28 mode (S) so that breaking in on boot is not possible.
31 crosfw -b daisy -VSC (no console output)
33 Example 3: Build a magic flasher (F) with full verified boot for peach_pit,
34 but with console enabled, write to SD card (x)
36 crosfw -b peach_pit -VSFx
38 This sript does not use an ebuild. It does a similar thing to the
39 chromeos-u-boot ebuild, and runs cros_bundle_firmware to produce various
40 types of image, a little like the chromeos-bootimage ebuild.
42 The purpose of this script is to make it easier and faster to perform
43 common firmware build tasks without changing boards, manually updating
44 device tree files or lots of USE flags and complexity in the ebuilds.
46 This script has been tested with snow, link and peach_pit. It builds for
47 peach_pit by default. Note that it will also build any upstream ARM
48 board - e.g. "-b snapper9260" will build an image for that board.
50 Mostly you can use the script inside and outside the chroot. The main
51 limitation is that dut-control doesn't really work outside the chroot,
52 so writing the image to the board over USB is not possible, nor can the
53 board be automatically reset on x86 platforms.
55 For an incremental build (faster), run with -i
57 To get faster clean builds, install ccache, and create ~/.crosfwrc with
62 (make sure ~/.ccache is not on NFS, or set CCACHE_DIR)
64 Other options are the default board to build, and verbosity (0-4), e.g.:
66 DEFAULT_BOARD = 'daisy'
69 It is possible to use multiple servo boards, each on its own port. Add
70 these lines to your ~/.crosfwrc to set the servo port to use for each
73 SERVO_PORT['link'] = 8888
74 SERVO_PORT['daisy'] = 9999
75 SERVO_PORT['peach_pit'] = 7777
77 All builds appear in the <outdir>/<board> subdirectory and images are written
78 to <outdir>/<uboard>/out, where <uboard> is the U-Boot name for the board (in
79 the U-Boot boards.cfg file)
81 The value for <outdir> defaults to /tmp/crosfw but can be configured in your
82 ~/.crosfwrc file, e.g.:"
84 OUT_DIR = '/tmp/u-boot'
86 For the -a option here are some useful options:
88 --add-blob cros-splash /dev/null
89 --gbb-flags -force-dev-switch-on
90 --add-node-enable /spi@131b0000/cros-ecp@0 1
92 --bootcmd "cros_test sha"
93 --gbb-flags -force-dev-switch-on
94 --bmpblk ~/trunk/src/third_party/u-boot/bmp.bin
96 For example: -a "--gbb-flags -force-dev-switch-on"
98 Note the standard bmpblk is at:
99 /home/$USER/trunk/src/third_party/chromiumos-overlay/sys-boot/
100 chromeos-bootimage/files/bmpblk.bin"
103 from __future__ import print_function
107 import multiprocessing
112 from chromite.cbuildbot import constants
113 from chromite.lib import commandline
114 from chromite.lib import cros_build_lib
115 from chromite.lib import osutils
116 from chromite.lib import parallel
126 logger = logging.getLogger('chromite')
127 logging.basicConfig(format='%(message)s')
128 kwargs = {'print_cmd': False, 'error_code_ok': True,
129 'debug_level': logger.getEffectiveLevel()}
133 # If you have multiple boards connected on different servo ports, put lines
134 # like 'SERVO_PORT{"peach_pit"} = 7777' in your ~/.crosfwrc
138 src_root = os.path.join(constants.SOURCE_ROOT, 'src')
139 in_chroot = cros_build_lib.IsInsideChroot()
143 default_board = 'peach_pit'
148 # Special cases for the U-Boot board config, the SOCs and default device tree
149 # since the naming is not always consistent.
150 # x86 has a lot of boards, but to U-Boot they are all the same
155 for b in ['alex', 'butterfly', 'emeraldlake2', 'link', 'lumpy', 'parrot',
157 UBOARDS[b] = 'coreboot-x86'
158 UBOARDS['chromeos_%s' % b] = 'chromeos_coreboot'
162 'chromeos_coreboot': '',
163 'daisy': 'exynos5250-',
164 'peach': 'exynos5420-',
169 'daisy_spring': 'spring',
170 'peach_pit': 'peach-pit',
173 OUT_DIR = '/tmp/crosfw'
175 rc_file = os.path.expanduser('~/.crosfwrc')
176 if os.path.exists(rc_file):
181 """Print out a message if we are in verbose mode.
184 msg: Message to print
187 cros_build_lib.Info(msg)
190 def Dumper(flag, infile, outfile):
191 """Run objdump on an input file.
194 flag: Flag to pass objdump (e.g. '-d').
195 infile: Input file to process.
196 outfile: Output file to write to.
198 result = cros_build_lib.RunCommand(
199 [CompilerTool('objdump'), flag, infile],
200 log_stdout_to_file=outfile, **kwargs)
201 if result.returncode:
205 def CompilerTool(tool):
206 """Returns the cross-compiler tool filename.
209 tool: Tool name to return, e.g. 'size'.
212 Filename of requested tool.
214 return '%s%s' % (compiler, tool)
217 def ParseCmdline(argv):
218 """Parse all command line options.
221 argv: Arguments to parse.
225 options: Command line options from optpase
226 args: List of command line arguments
228 parser = commandline.OptionParser(__doc__)
229 parser.add_option('-a', '--cbfargs', action='append',
230 help='Pass extra arguments to cros_bundle_firmware')
231 parser.add_option('-b', '--board', type='string', default=default_board,
232 help='Select board to build (daisy/peach_pit/link)')
233 parser.add_option('-B', '--build', action='store_false', default=True,
234 help="Don't build U-Boot, just configure device tree")
235 parser.add_option('-C', '--console', action='store_false', default=True,
236 help='Permit console output')
237 parser.add_option('-d', '--dt', default='seaboard',
238 help='Select name of device tree file to use')
239 parser.add_option('-D', '--nodefaults', dest='use_defaults',
240 action='store_false', default=True,
241 help="Don't select default filenames for those not given")
242 parser.add_option('-F', '--flash', action='store_true', default=False,
243 help='Create magic flasher for SPI flash')
244 parser.add_option('-M', '--mmc', action='store_true', default=False,
245 help='Create magic flasher for eMMC')
246 parser.add_option('-i', '--incremental', action='store_true', default=False,
247 help="Don't reconfigure and clean")
248 parser.add_option('-k', '--kernel', action='store_true', default=False,
249 help='Send kernel to board also')
250 parser.add_option('-O', '--objdump', action='store_true', default=False,
251 help='Write disassembly output')
252 parser.add_option('-r', '--run', action='store_false', default=True,
253 help='Run the boot command')
254 parser.add_option('--ro', action='store_true', default=False,
255 help='Create Chrome OS read-only image')
256 parser.add_option('--rw', action='store_true', default=False,
257 help='Create Chrome OS read-write image')
258 parser.add_option('-s', '--separate', action='store_false', default=True,
259 help='Link device tree into U-Boot, instead of separate')
260 parser.add_option('-S', '--secure', action='store_true', default=False,
261 help='Use vboot_twostop secure boot')
262 parser.add_option('--small', action='store_true', default=False,
263 help='Create Chrome OS small image')
264 parser.add_option('-t', '--trace', action='store_true', default=False,
265 help='Enable trace support')
266 parser.add_option('-v', '--verbose', type='int', default=0,
267 help='Make cros_bundle_firmware verbose')
268 parser.add_option('-V', '--verified', action='store_true', default=False,
269 help='Include Chrome OS verified boot components')
270 parser.add_option('-w', '--write', action='store_false', default=True,
271 help="Don't write image to board using usb/em100")
272 parser.add_option('-x', '--sdcard', action='store_true', default=False,
273 help='Write to SD card instead of USB/em100')
274 parser.add_option('-z', '--size', action='store_true', default=False,
275 help='Display U-Boot image size')
276 return parser.parse_args(argv)
279 def SetupBuild(options):
280 """Set up parameters needed for the build.
282 This checks the current environment and options and sets up various things
283 needed for the build, including 'base' which holds the base flags for
284 passing to the U-Boot Makefile.
287 options: Command line options
290 Base flags to use for U-Boot, as a list.
292 # pylint: disable=W0603
293 global arch, board, compiler, family, outdir, smdk, uboard, vendor, verbose
296 verbose = options.verbose != 0
298 logger.setLevel(options.verbose)
300 Log('Building for %s' % options.board)
302 # Separate out board_variant string: "peach_pit" becomes "peach", "pit".
303 # But don't mess up upstream boards which use _ in their name.
304 parts = options.board.split('_')
305 if parts[0] in ['daisy', 'peach']:
308 board = options.board
310 # To allow this to be run from 'cros_sdk'
312 os.chdir(os.path.join(src_root, 'third_party', 'u-boot', 'files'))
317 base_board = 'chromeos_%s' % base_board
319 uboard = UBOARDS.get(base_board, base_board)
320 Log('U-Boot board is %s' % uboard)
322 # Pull out some information from the U-Boot boards config file
324 with open('boards.cfg') as f:
329 fields = line.split()
333 fields += [None, None, None]
339 cros_build_lib.Die("Selected board '%s' not found in boards.cfg." % board)
341 vboot = os.path.join('build', board, 'usr')
345 compiler = 'i686-pc-linux-gnu-'
347 compiler = '/opt/i686/bin/i686-unknown-elf-'
350 # Use the Chrome OS toolchain
351 compiler = 'armv7a-cros-linux-gnueabi-'
353 compiler = glob.glob('/opt/linaro/gcc-linaro-arm-linux-*/bin/*gcc')
355 cros_build_lib.Die("""Please install an ARM toolchain for your machine.
356 'Install a Linaro toolchain from:'
357 'https://launchpad.net/linaro-toolchain-binaries'
358 'or see cros/commands/cros_chrome_sdk.py.""")
359 compiler = compiler[0]
360 compiler = re.sub('gcc$', '', compiler)
361 elif arch == 'sandbox':
364 cros_build_lib.Die("Selected arch '%s' not supported." % arch)
366 if not options.build:
367 options.incremental = True
369 cpus = multiprocessing.cpu_count()
371 outdir = os.path.join(OUT_DIR, uboard)
377 'CROSS_COMPILE=%s' % compiler,
378 '--no-print-directory',
380 'DEV_TREE_SRC=%s-%s' % (family, options.dt),
383 if options.verbose < 2:
386 if options.ro and options.rw:
387 cros_build_lib.Die('Cannot specify both --ro and --rw options')
389 base.append('CROS_RO=1')
393 base.append('CROS_RW=1')
397 base.append('CROS_SMALL=1')
399 base.append('CROS_FULL=1')
404 'MAKEFLAGS_VBOOT=DEBUG=1',
406 'CFLAGS_EXTRA_VBOOT=-DUNROLL_LOOPS',
407 'VBOOT_SOURCE=%s/platform/vboot_reference' % src_root]
408 base.append('VBOOT_DEBUG=1')
410 # Handle the Chrome OS USE_STDINT workaround. Vboot needs <stdint.h> due
411 # to a recent change, the need for which I didn't fully understand. But
412 # U-Boot doesn't normally use this. We have added an option to U-Boot to
413 # enable use of <stdint.h> and without it vboot will fail to build. So we
414 # need to enable it where ww can. We can't just enable it always since
415 # that would prevent this script from building other non-Chrome OS boards
416 # with a different (older) toolchain, or Chrome OS boards without vboot.
417 # So use USE_STDINT if the toolchain supports it, and not if not. This
418 # file was originally part of glibc but has recently migrated to the
419 # compiler so it is reasonable to use it with a stand-alone program like
420 # U-Boot. At this point the comment has got long enough that we may as
421 # well include some poetry which seems to be sorely lacking the code base,
422 # so this is from Ogden Nash:
423 # To keep your marriage brimming
424 # With love in the loving cup,
425 # Whenever you're wrong, admit it;
426 # Whenever you're right, shut up.
427 cmd = [CompilerTool('gcc'), '-ffreestanding', '-x', 'c', '-c', '-']
428 result = cros_build_lib.RunCommand(cmd,
429 input='#include <stdint.h>',
432 if result.returncode == 0:
433 base.append('USE_STDINT=1')
436 base.append('FTRACE=1')
438 base.append('DEV_TREE_SEPARATE=1')
440 if options.incremental:
441 # Get the correct board for cros_write_firmware
442 config_mk = '%s/include/config.mk' % outdir
443 if not os.path.exists(config_mk):
444 cros_build_lib.Warning('No build found for %s - dropping -i' % board)
445 options.incremental = False
447 config_mk = 'include/config.mk'
448 if os.path.exists(config_mk):
449 cros_build_lib.Warning("Warning: '%s' exists, try 'make distclean'"
452 # For when U-Boot supports ccache
453 # See http://patchwork.ozlabs.org/patch/245079/
455 os.environ['CCACHE'] = 'ccache'
460 def RunBuild(options, base, target, queue):
461 """Run the U-Boot build.
464 options: Command line options.
465 base: Base U-Boot flags.
466 target: Target to build.
467 queue: A parallel queue to add jobs to.
469 Log('U-Boot build flags: %s' % ' '.join(base))
471 # Reconfigure U-Boot.
472 if not options.incremental:
473 # Ignore any error from this, some older U-Boots fail on this.
474 cros_build_lib.RunCommand(base + ['distclean'], **kwargs)
475 result = cros_build_lib.RunCommand(base + ['%s_config' % uboard], **kwargs)
476 if result.returncode:
479 # Do the actual build.
481 result = cros_build_lib.RunCommand(base + [target], **kwargs)
482 if result.returncode:
485 files = ['%s/u-boot' % outdir]
486 spl = glob.glob('%s/spl/u-boot-spl' % outdir)
490 result = cros_build_lib.RunCommand([CompilerTool('size')] + files,
492 if result.returncode:
495 # Create disassembly files .dis and .Dis (full dump)
497 base = os.path.splitext(f)[0]
499 queue.put(('-d', f, base + '.dis'))
500 queue.put(('-D', f, base + '.Dis'))
502 # Remove old files which otherwise might be confusing
503 osutils.SafeUnlink(base + '.dis')
504 osutils.SafeUnlink(base + '.Dis')
506 Log('Output directory %s' % outdir)
509 def WriteFirmware(options):
510 """Write firmware to the board.
512 This uses cros_bundle_firmware to create a firmware image and write it to
516 options: Command line options
527 bl2 = ['--bl2', '%s/spl/%s-spl.bin' % (outdir, smdk)]
529 if options.use_defaults:
536 bl1 = ['--bl1', '##/build/%s/firmware/u-boot.bl1.bin' % options.board]
537 bmpblk = ['--bmpblk', '##/build/%s/firmware/bmpblk.bin' % options.board]
538 ecro = ['--ecro', '##/build/%s/firmware/ec.RO.bin' % options.board]
539 ecrw = ['--ec', '##/build/%s/firmware/ec.RW.bin' % options.board]
543 seabios = ['--seabios',
544 '##/build/%s/firmware/seabios.cbfs' % options.board]
552 elif arch == 'sandbox':
557 port = SERVO_PORT.get(options.board, '')
559 servo = ['--servo', '%d' % port]
562 flash = ['-F', 'spi']
564 # The small builds don't have the command line interpreter so cannot
565 # run the magic flasher script. So use the standard U-Boot in this
568 cros_build_lib.Warning('Using standard U-Boot as flasher')
569 flash += ['-U', '##/build/%s/firmware/u-boot.bin' % options.board]
572 flash = ['-F', 'sdmmc']
575 verbose_arg = ['-v', '%s' % options.verbose]
578 secure += ['--bootsecure', '--bootcmd', 'vboot_twostop']
580 if not options.verified:
581 # Make a small image, without GBB, etc.
585 kernel = ['--kernel', '##/build/%s/boot/vmlinux.uimg' % options.board]
587 if not options.console:
588 silent = ['--add-config-int', 'silent-console', '1']
591 run = ['--bootcmd', 'none']
593 if arch != 'sandbox' and not in_chroot and servo:
595 cros_build_lib.Warning('Image cannot be written to board')
598 elif dest == 'em100':
599 cros_build_lib.Warning('Please reset the board manually to boot firmware')
603 cros_build_lib.Warning('(sadly dut-control does not work outside chroot)')
610 soc = SOCS.get(board)
612 soc = SOCS.get(uboard, '')
613 dt_name = DEFAULT_DTS.get(options.board, options.board)
614 dts_file = 'board/%s/dts/%s%s.dts' % (vendor, soc, dt_name)
615 Log('Device tree: %s' % dts_file)
617 if arch == 'sandbox':
618 uboot_fname = '%s/u-boot' % outdir
620 uboot_fname = '%s/u-boot.bin' % outdir
623 # RO U-Boot is passed through as blob 'ro-boot'. We use the standard
625 # TODO(sjg@chromium.org): Option to build U-Boot a second time to get
627 cros_build_lib.Warning('Using standard U-Boot for RW')
628 ro_uboot = ['--add-blob', 'ro-boot', uboot_fname]
629 uboot_fname = '##/build/%s/firmware/u-boot.bin' % options.board
630 cbf = ['%s/platform/dev/host/cros_bundle_firmware' % src_root,
633 '-I', 'arch/%s/dts' % arch, '-I', 'cros/dts',
635 '-O', '%s/out' % outdir,
638 for other in [bl1, bl2, bmpblk, defaults, dest, ecro, ecrw, flash, kernel,
639 run, seabios, secure, servo, silent, verbose_arg, ro_uboot]:
643 for item in options.cbfargs:
644 cbf += item.split(' ')
645 os.environ['PYTHONPATH'] = ('%s/platform/dev/host/lib:%s/..' %
646 (src_root, src_root))
648 result = cros_build_lib.RunCommand(cbf, **kwargs)
649 if result.returncode:
650 cros_build_lib.Die('cros_bundle_firmware failed')
652 if not dest or not result.returncode:
653 cros_build_lib.Info('Image is available at %s/out/image.bin' % outdir)
655 if result.returncode:
656 cros_build_lib.Die('Failed to write image to board')
658 cros_build_lib.Info('Image written to board with %s' %
659 ' '.join(dest + servo))
663 """Main function for script to build/write firmware.
666 argv: Program arguments.
668 options, args = ParseCmdline(argv)
669 base = SetupBuild(options)
671 with parallel.BackgroundTaskRunner(Dumper) as queue:
672 target = args[0] if args else 'all'
673 RunBuild(options, base, target, queue)
676 WriteFirmware(options)
679 Log('Writing diasssembly files')