Home | History | Annotate | Download | only in utils
      1 # Copyright (c) 2012 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 """
      6 A module to support automatic firmware update.
      7 
      8 See FirmwareUpdater object below.
      9 """
     10 
     11 import os
     12 
     13 class FirmwareUpdater(object):
     14     """
     15     An object to support firmware update.
     16 
     17     This object will create a temporary directory in /var/tmp/faft/autest with
     18     two subdirectory keys/ and work/. You can modify the keys in keys/
     19     directory. If you want to provide a given shellball to do firmware update,
     20     put shellball under /var/tmp/faft/autest with name chromeos-firmwareupdate.
     21     """
     22 
     23     def __init__(self, os_if):
     24         self.os_if = os_if
     25         self._temp_path = '/var/tmp/faft/autest'
     26         self._keys_path = os.path.join(self._temp_path, 'keys')
     27         self._work_path = os.path.join(self._temp_path, 'work')
     28 
     29         if not self.os_if.is_dir(self._temp_path):
     30             self._setup_temp_dir()
     31 
     32 
     33     def _setup_temp_dir(self):
     34         """Setup temporary directory.
     35 
     36         Devkeys are copied to _key_path. Then, shellball (default:
     37         /usr/sbin/chromeos-firmwareupdate) is extracted to _work_path.
     38         """
     39         self.cleanup_temp_dir()
     40 
     41         self.os_if.create_dir(self._temp_path)
     42         self.os_if.create_dir(self._work_path)
     43         self.os_if.copy_dir('/usr/share/vboot/devkeys', self._keys_path)
     44 
     45         original_shellball = '/usr/sbin/chromeos-firmwareupdate'
     46         working_shellball = os.path.join(self._temp_path,
     47                                          'chromeos-firmwareupdate')
     48         self.os_if.copy_file(original_shellball, working_shellball)
     49         self.os_if.run_shell_command(
     50             'sh %s --sb_extract %s' % (working_shellball, self._work_path))
     51 
     52 
     53     def cleanup_temp_dir(self):
     54         """Cleanup temporary directory."""
     55         if self.os_if.is_dir(self._temp_path):
     56             self.os_if.remove_dir(self._temp_path)
     57 
     58 
     59     def retrieve_fwid(self):
     60         """Retrieve shellball's fwid.
     61 
     62         This method should be called after setup_firmwareupdate_temp_dir.
     63 
     64         Returns:
     65             Shellball's fwid.
     66         """
     67         self.os_if.run_shell_command('dump_fmap -x %s %s' %
     68             (os.path.join(self._work_path, 'bios.bin'), 'RW_FWID_A'))
     69 
     70         [fwid] = self.os_if.run_shell_command_get_output(
     71             "cat RW_FWID_A | tr '\\0' '\\t' | cut -f1")
     72         return fwid
     73 
     74 
     75     def resign_firmware(self, version):
     76         """Resign firmware with version.
     77 
     78         Args:
     79             version: new firmware version number.
     80         """
     81         ro_normal = 0
     82         self.os_if.run_shell_command(
     83                 '/usr/share/vboot/bin/resign_firmwarefd.sh '
     84                 '%s %s %s %s %s %s %s %d %d' % (
     85                     os.path.join(self._work_path, 'bios.bin'),
     86                     os.path.join(self._temp_path, 'output.bin'),
     87                     os.path.join(self._keys_path, 'firmware_data_key.vbprivk'),
     88                     os.path.join(self._keys_path, 'firmware.keyblock'),
     89                     os.path.join(self._keys_path, 'dev_firmware_data_key.vbprivk'),
     90                     os.path.join(self._keys_path, 'dev_firmware.keyblock'),
     91                     os.path.join(self._keys_path, 'kernel_subkey.vbpubk'),
     92                     version,
     93                     ro_normal))
     94         self.os_if.copy_file('%s' % os.path.join(self._temp_path, 'output.bin'),
     95                              '%s' % os.path.join(self._work_path, 'bios.bin'))
     96 
     97 
     98     def repack_shellball(self, append):
     99         """Repack shellball with new fwid.
    100 
    101         New fwid follows the rule: [orignal_fwid]-[append].
    102 
    103         Args:
    104             append: use for new fwid naming.
    105         """
    106         self.os_if.copy_file(
    107                 '/usr/sbin/chromeos-firmwareupdate',
    108                 os.path.join(self._temp_path,
    109                              'chromeos-firmwareupdate-%s' % append))
    110 
    111         self.os_if.run_shell_command('sh %s --sb_repack %s' % (
    112             os.path.join(self._temp_path,
    113                          'chromeos-firmwareupdate-%s' % append),
    114             self._work_path))
    115 
    116         args = ['-i']
    117         args.append('"s/TARGET_FWID=\\"\\(.*\\)\\"/TARGET_FWID=\\"\\1.%s\\"/g"'
    118                     % append)
    119         args.append(os.path.join(self._temp_path,
    120                                  'chromeos-firmwareupdate-%s' % append))
    121         cmd = 'sed %s' % ' '.join(args)
    122         self.os_if.run_shell_command(cmd)
    123 
    124         args = ['-i']
    125         args.append('"s/TARGET_UNSTABLE=\\".*\\"/TARGET_UNSTABLE=\\"\\"/g"')
    126         args.append(os.path.join(self._temp_path,
    127                                  'chromeos-firmwareupdate-%s' % append))
    128         cmd = 'sed %s' % ' '.join(args)
    129         self.os_if.run_shell_command(cmd)
    130 
    131 
    132     def run_firmwareupdate(self, mode, updater_append=None, options=[]):
    133         """Do firmwareupdate with updater in temp_dir.
    134 
    135         Args:
    136             updater_append: decide which shellball to use with format
    137                 chromeos-firmwareupdate-[append]. Use'chromeos-firmwareupdate'
    138                 if updater_append is None.
    139             mode: ex.'autoupdate', 'recovery', 'bootok', 'factory_install'...
    140             options: ex. ['--noupdate_ec', '--nocheck_rw_compatible'] or [] for
    141                 no option.
    142         """
    143         if updater_append:
    144             updater = os.path.join(
    145                 self._temp_path, 'chromeos-firmwareupdate-%s' % updater_append)
    146         else:
    147             updater = os.path.join(self._temp_path, 'chromeos-firmwareupdate')
    148 
    149         self.os_if.run_shell_command(
    150             '/bin/sh %s --mode %s %s' % (updater, mode, ' '.join(options)))
    151 
    152 
    153     def get_temp_path(self):
    154         """Get temp directory path."""
    155         return self._temp_path
    156 
    157 
    158     def get_keys_path(self):
    159         """Get keys directory path."""
    160         return self._keys_path
    161 
    162 
    163     def get_work_path(self):
    164         """Get work directory path."""
    165         return self._work_path
    166