Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / chromite / scripts / crosfw.py
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.
4
5 """crosfw - Chrome OS Firmware build/flash script.
6
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
13 details.
14
15 It can also flash SPI by writing a 'magic flasher' U-Boot with a payload
16 to the board.
17
18 Usage: crosfw [options]
19
20 The script is normally run from within the U-Boot directory which is
21 .../src/third_party/u-boot/files
22
23 Example 1: Build upstream image for coreboot and write to a 'link':
24
25  crosfw -b link
26
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.
29
30  crosfw -b daisy -VS
31  crosfw -b daisy -VSC         (no console output)
32
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)
35
36  crosfw -b peach_pit -VSFx
37
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.
41
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.
45
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.
49
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.
54
55 For an incremental build (faster), run with -i
56
57 To get faster clean builds, install ccache, and create ~/.crosfwrc with
58 this line:
59
60  USE_CCACHE = True
61
62 (make sure ~/.ccache is not on NFS, or set CCACHE_DIR)
63
64 Other options are the default board to build, and verbosity (0-4), e.g.:
65
66  DEFAULT_BOARD = 'daisy'
67  VERBOSE = 1
68
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
71 board:
72
73  SERVO_PORT['link'] = 8888
74  SERVO_PORT['daisy'] = 9999
75  SERVO_PORT['peach_pit'] = 7777
76
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)
80
81 The value for <outdir> defaults to /tmp/crosfw but can be configured in your
82 ~/.crosfwrc file, e.g.:"
83
84  OUT_DIR = '/tmp/u-boot'
85
86 For the -a option here are some useful options:
87
88 --add-blob cros-splash /dev/null
89 --gbb-flags -force-dev-switch-on
90 --add-node-enable /spi@131b0000/cros-ecp@0 1
91 --verify --full-erase
92 --bootcmd "cros_test sha"
93 --gbb-flags -force-dev-switch-on
94 --bmpblk ~/trunk/src/third_party/u-boot/bmp.bin
95
96 For example: -a "--gbb-flags -force-dev-switch-on"
97
98 Note the standard bmpblk is at:
99   /home/$USER/trunk/src/third_party/chromiumos-overlay/sys-boot/
100       chromeos-bootimage/files/bmpblk.bin"
101 """
102
103 from __future__ import print_function
104
105 import glob
106 import logging
107 import multiprocessing
108 import os
109 import re
110 import sys
111
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
117
118
119 arch = None
120 board = None
121 compiler = None
122 default_board = None
123 family = None
124 in_chroot = True
125
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()}
130
131 outdir = ''
132
133  # If you have multiple boards connected on different servo ports, put lines
134 # like 'SERVO_PORT{"peach_pit"} = 7777' in your ~/.crosfwrc
135 SERVO_PORT = {}
136
137 smdk = None
138 src_root = os.path.join(constants.SOURCE_ROOT, 'src')
139 in_chroot = cros_build_lib.IsInsideChroot()
140
141 uboard = ''
142
143 default_board = 'peach_pit'
144 use_ccache = False
145 vendor = None
146 verbose = False
147
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
151 UBOARDS = {
152     'daisy': 'smdk5250',
153     'peach': 'smdk5420',
154 }
155 for b in ['alex', 'butterfly', 'emeraldlake2', 'link', 'lumpy', 'parrot',
156           'stout', 'stumpy']:
157   UBOARDS[b] = 'coreboot-x86'
158   UBOARDS['chromeos_%s' % b] = 'chromeos_coreboot'
159
160 SOCS = {
161     'coreboot-x86': '',
162     'chromeos_coreboot': '',
163     'daisy': 'exynos5250-',
164     'peach': 'exynos5420-',
165 }
166
167 DEFAULT_DTS = {
168     'daisy': 'snow',
169     'daisy_spring': 'spring',
170     'peach_pit': 'peach-pit',
171 }
172
173 OUT_DIR = '/tmp/crosfw'
174
175 rc_file = os.path.expanduser('~/.crosfwrc')
176 if os.path.exists(rc_file):
177   execfile(rc_file)
178
179
180 def Log(msg):
181   """Print out a message if we are in verbose mode.
182
183   Args:
184     msg: Message to print
185   """
186   if verbose:
187     cros_build_lib.Info(msg)
188
189
190 def Dumper(flag, infile, outfile):
191   """Run objdump on an input file.
192
193   Args:
194     flag: Flag to pass objdump (e.g. '-d').
195     infile: Input file to process.
196     outfile: Output file to write to.
197   """
198   result = cros_build_lib.RunCommand(
199       [CompilerTool('objdump'), flag, infile],
200       log_stdout_to_file=outfile, **kwargs)
201   if result.returncode:
202     sys.exit()
203
204
205 def CompilerTool(tool):
206   """Returns the cross-compiler tool filename.
207
208   Args:
209     tool: Tool name to return, e.g. 'size'.
210
211   Returns:
212     Filename of requested tool.
213   """
214   return '%s%s' % (compiler, tool)
215
216
217 def ParseCmdline(argv):
218   """Parse all command line options.
219
220   Args:
221     argv: Arguments to parse.
222
223   Returns:
224     Tuple containing:
225       options: Command line options from optpase
226       args: List of command line arguments
227   """
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)
277
278
279 def SetupBuild(options):
280   """Set up parameters needed for the build.
281
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.
285
286   Args:
287     options: Command line options
288
289   Returns:
290     Base flags to use for U-Boot, as a list.
291   """
292   # pylint: disable=W0603
293   global arch, board, compiler, family, outdir, smdk, uboard, vendor, verbose
294
295   if not verbose:
296     verbose = options.verbose != 0
297
298   logger.setLevel(options.verbose)
299
300   Log('Building for %s' % options.board)
301
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']:
306     board = parts[0]
307   else:
308     board = options.board
309
310   # To allow this to be run from 'cros_sdk'
311   if in_chroot:
312     os.chdir(os.path.join(src_root, 'third_party', 'u-boot', 'files'))
313
314   base_board = board
315
316   if options.verified:
317     base_board = 'chromeos_%s' % base_board
318
319   uboard = UBOARDS.get(base_board, base_board)
320   Log('U-Boot board is %s' % uboard)
321
322   # Pull out some information from the U-Boot boards config file
323   family = None
324   with open('boards.cfg') as f:
325     for line in f:
326       if uboard in line:
327         if line[0] == '#':
328           continue
329         fields = line.split()
330         if not fields:
331           continue
332         arch = fields[1]
333         fields += [None, None, None]
334         smdk = fields[3]
335         vendor = fields[4]
336         family = fields[5]
337         break
338   if not arch:
339     cros_build_lib.Die("Selected board '%s' not found in boards.cfg." % board)
340
341   vboot = os.path.join('build', board, 'usr')
342   if arch == 'x86':
343     family = 'em100'
344     if in_chroot:
345       compiler = 'i686-pc-linux-gnu-'
346     else:
347       compiler = '/opt/i686/bin/i686-unknown-elf-'
348   elif arch == 'arm':
349     if in_chroot:
350       # Use the Chrome OS toolchain
351       compiler = 'armv7a-cros-linux-gnueabi-'
352     else:
353       compiler = glob.glob('/opt/linaro/gcc-linaro-arm-linux-*/bin/*gcc')
354       if not compiler:
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':
362     compiler = ''
363   else:
364     cros_build_lib.Die("Selected arch '%s' not supported." % arch)
365
366   if not options.build:
367     options.incremental = True
368
369   cpus = multiprocessing.cpu_count()
370
371   outdir = os.path.join(OUT_DIR, uboard)
372   base = [
373       'make',
374       '-j%d' % cpus,
375       'O=%s' % outdir,
376       'ARCH=%s' % arch,
377       'CROSS_COMPILE=%s' % compiler,
378       '--no-print-directory',
379       'HOSTSTRIP=true',
380       'DEV_TREE_SRC=%s-%s' % (family, options.dt),
381       'QEMU_ARCH=']
382
383   if options.verbose < 2:
384     base.append('-s')
385
386   if options.ro and options.rw:
387     cros_build_lib.Die('Cannot specify both --ro and --rw options')
388   if options.ro:
389     base.append('CROS_RO=1')
390     options.small = True
391
392   if options.rw:
393     base.append('CROS_RW=1')
394     options.small = True
395
396   if options.small:
397     base.append('CROS_SMALL=1')
398   else:
399     base.append('CROS_FULL=1')
400
401   if options.verified:
402     base += [
403         'VBOOT=%s' % vboot,
404         'MAKEFLAGS_VBOOT=DEBUG=1',
405         'QUIET=1',
406         'CFLAGS_EXTRA_VBOOT=-DUNROLL_LOOPS',
407         'VBOOT_SOURCE=%s/platform/vboot_reference' % src_root]
408     base.append('VBOOT_DEBUG=1')
409
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>',
430                                      capture_output=True,
431                                      **kwargs)
432   if result.returncode == 0:
433     base.append('USE_STDINT=1')
434
435   if options.trace:
436     base.append('FTRACE=1')
437   if options.separate:
438     base.append('DEV_TREE_SEPARATE=1')
439
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
446
447   config_mk = 'include/config.mk'
448   if os.path.exists(config_mk):
449     cros_build_lib.Warning("Warning: '%s' exists, try 'make distclean'"
450                            % config_mk)
451
452   # For when U-Boot supports ccache
453   # See http://patchwork.ozlabs.org/patch/245079/
454   if use_ccache:
455     os.environ['CCACHE'] = 'ccache'
456
457   return base
458
459
460 def RunBuild(options, base, target, queue):
461   """Run the U-Boot build.
462
463   Args:
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.
468   """
469   Log('U-Boot build flags: %s' % ' '.join(base))
470
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:
477       sys.exit()
478
479   # Do the actual build.
480   if options.build:
481     result = cros_build_lib.RunCommand(base + [target], **kwargs)
482     if result.returncode:
483       sys.exit()
484
485   files = ['%s/u-boot' % outdir]
486   spl = glob.glob('%s/spl/u-boot-spl' % outdir)
487   if spl:
488     files += spl
489   if options.size:
490     result = cros_build_lib.RunCommand([CompilerTool('size')] + files,
491                                        **kwargs)
492     if result.returncode:
493       sys.exit()
494
495   # Create disassembly files .dis and .Dis (full dump)
496   for f in files:
497     base = os.path.splitext(f)[0]
498     if options.objdump:
499       queue.put(('-d', f, base + '.dis'))
500       queue.put(('-D', f, base + '.Dis'))
501     else:
502       # Remove old files which otherwise might be confusing
503       osutils.SafeUnlink(base + '.dis')
504       osutils.SafeUnlink(base + '.Dis')
505
506   Log('Output directory %s' % outdir)
507
508
509 def WriteFirmware(options):
510   """Write firmware to the board.
511
512   This uses cros_bundle_firmware to create a firmware image and write it to
513   the board.
514
515   Args:
516     options: Command line options
517   """
518   flash = []
519   kernel = []
520   run = []
521   secure = []
522   servo = []
523   silent = []
524   verbose_arg = []
525   ro_uboot = []
526
527   bl2 = ['--bl2', '%s/spl/%s-spl.bin' % (outdir, smdk)]
528
529   if options.use_defaults:
530     bl1 = []
531     bmpblk = []
532     ecro = []
533     ecrw = []
534     defaults = []
535   else:
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]
540     defaults = ['-D']
541
542   if arch == 'x86':
543     seabios = ['--seabios',
544                '##/build/%s/firmware/seabios.cbfs' % options.board]
545   else:
546     seabios = []
547
548   if options.sdcard:
549     dest = 'sd:.'
550   elif arch == 'x86':
551     dest = 'em100'
552   elif arch == 'sandbox':
553     dest = ''
554   else:
555     dest = 'usb'
556
557   port = SERVO_PORT.get(options.board, '')
558   if port:
559     servo = ['--servo', '%d' % port]
560
561   if options.flash:
562     flash = ['-F', 'spi']
563
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
566     # case.
567     if options.small:
568       cros_build_lib.Warning('Using standard U-Boot as flasher')
569       flash += ['-U', '##/build/%s/firmware/u-boot.bin' % options.board]
570
571   if options.mmc:
572     flash = ['-F', 'sdmmc']
573
574   if options.verbose:
575     verbose_arg = ['-v', '%s' % options.verbose]
576
577   if options.secure:
578     secure += ['--bootsecure', '--bootcmd', 'vboot_twostop']
579
580   if not options.verified:
581     # Make a small image, without GBB, etc.
582     secure.append('-s')
583
584   if options.kernel:
585     kernel = ['--kernel', '##/build/%s/boot/vmlinux.uimg' % options.board]
586
587   if not options.console:
588     silent = ['--add-config-int', 'silent-console', '1']
589
590   if not options.run:
591     run = ['--bootcmd', 'none']
592
593   if arch != 'sandbox' and not in_chroot and servo:
594     if dest == 'usb':
595       cros_build_lib.Warning('Image cannot be written to board')
596       dest = ''
597       servo = []
598     elif dest == 'em100':
599       cros_build_lib.Warning('Please reset the board manually to boot firmware')
600       servo = []
601
602     if not servo:
603       cros_build_lib.Warning('(sadly dut-control does not work outside chroot)')
604
605   if dest:
606     dest = ['-w', dest]
607   else:
608     dest = []
609
610   soc = SOCS.get(board)
611   if not soc:
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)
616
617   if arch == 'sandbox':
618     uboot_fname = '%s/u-boot' % outdir
619   else:
620     uboot_fname = '%s/u-boot.bin' % outdir
621
622   if options.ro:
623     # RO U-Boot is passed through as blob 'ro-boot'. We use the standard
624     # ebuild one as RW.
625     # TODO(sjg@chromium.org): Option to build U-Boot a second time to get
626     # a fresh RW U-Boot.
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,
631          '-b', options.board,
632          '-d', dts_file,
633          '-I', 'arch/%s/dts' % arch, '-I', 'cros/dts',
634          '-u', uboot_fname,
635          '-O', '%s/out' % outdir,
636          '-M', family]
637
638   for other in [bl1, bl2, bmpblk, defaults, dest, ecro, ecrw, flash, kernel,
639                 run, seabios, secure, servo, silent, verbose_arg, ro_uboot]:
640     if other:
641       cbf += other
642   if options.cbfargs:
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))
647   Log(' '.join(cbf))
648   result = cros_build_lib.RunCommand(cbf, **kwargs)
649   if result.returncode:
650     cros_build_lib.Die('cros_bundle_firmware failed')
651
652   if not dest or not result.returncode:
653     cros_build_lib.Info('Image is available at %s/out/image.bin' % outdir)
654   else:
655     if result.returncode:
656       cros_build_lib.Die('Failed to write image to board')
657     else:
658       cros_build_lib.Info('Image written to board with %s' %
659                           ' '.join(dest + servo))
660
661
662 def main(argv):
663   """Main function for script to build/write firmware.
664
665   Args:
666     argv: Program arguments.
667   """
668   options, args = ParseCmdline(argv)
669   base = SetupBuild(options)
670
671   with parallel.BackgroundTaskRunner(Dumper) as queue:
672     target = args[0] if args else 'all'
673     RunBuild(options, base, target, queue)
674
675     if options.write:
676       WriteFirmware(options)
677
678     if options.objdump:
679       Log('Writing diasssembly files')