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