blob: c3a4649b8de9fbbf0399d16eefcdc99318402872 [file] [log] [blame]
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
A module to support automatic firmware update.
See FirmwareUpdater object below.
"""
import os
class FirmwareUpdater(object):
"""
An object to support firmware update.
This object will create a temporary directory in /var/tmp/faft/autest with
two subdirectory keys/ and work/. You can modify the keys in keys/
directory. If you want to provide a given shellball to do firmware update,
put shellball under /var/tmp/faft/autest with name chromeos-firmwareupdate.
"""
def __init__(self, os_if):
self.os_if = os_if
self._temp_path = '/var/tmp/faft/autest'
self._keys_path = os.path.join(self._temp_path, 'keys')
self._work_path = os.path.join(self._temp_path, 'work')
if not self.os_if.is_dir(self._temp_path):
self._setup_temp_dir()
def _setup_temp_dir(self):
"""Setup temporary directory.
Devkeys are copied to _key_path. Then, shellball (default:
/usr/sbin/chromeos-firmwareupdate) is extracted to _work_path.
"""
self.cleanup_temp_dir()
self.os_if.create_dir(self._temp_path)
self.os_if.create_dir(self._work_path)
self.os_if.copy_dir('/usr/share/vboot/devkeys', self._keys_path)
original_shellball = '/usr/sbin/chromeos-firmwareupdate'
working_shellball = os.path.join(self._temp_path,
'chromeos-firmwareupdate')
self.os_if.copy_file(original_shellball, working_shellball)
self.extract_shellball()
def cleanup_temp_dir(self):
"""Cleanup temporary directory."""
if self.os_if.is_dir(self._temp_path):
self.os_if.remove_dir(self._temp_path)
def retrieve_fwid(self):
"""Retrieve shellball's fwid.
This method should be called after setup_firmwareupdate_temp_dir.
Returns:
Shellball's fwid.
"""
self.os_if.run_shell_command('dump_fmap -x %s %s' %
(os.path.join(self._work_path, 'bios.bin'), 'RW_FWID_A'))
[fwid] = self.os_if.run_shell_command_get_output(
"cat RW_FWID_A | tr '\\0' '\\t' | cut -f1")
return fwid
def resign_firmware(self, version):
"""Resign firmware with version.
Args:
version: new firmware version number.
"""
ro_normal = 0
self.os_if.run_shell_command(
'/usr/share/vboot/bin/resign_firmwarefd.sh '
'%s %s %s %s %s %s %s %d %d' % (
os.path.join(self._work_path, 'bios.bin'),
os.path.join(self._temp_path, 'output.bin'),
os.path.join(self._keys_path, 'firmware_data_key.vbprivk'),
os.path.join(self._keys_path, 'firmware.keyblock'),
os.path.join(self._keys_path, 'dev_firmware_data_key.vbprivk'),
os.path.join(self._keys_path, 'dev_firmware.keyblock'),
os.path.join(self._keys_path, 'kernel_subkey.vbpubk'),
version,
ro_normal))
self.os_if.copy_file('%s' % os.path.join(self._temp_path, 'output.bin'),
'%s' % os.path.join(self._work_path, 'bios.bin'))
def extract_shellball(self, append=None):
"""Extract the working shellball.
Args:
append: decide which shellball to use with format
chromeos-firmwareupdate-[append]. Use 'chromeos-firmwareupdate'
if append is None.
"""
working_shellball = os.path.join(self._temp_path,
'chromeos-firmwareupdate')
if append:
working_shellball = working_shellball + '-%s' % append
self.os_if.run_shell_command('sh %s --sb_extract %s' % (
working_shellball, self._work_path))
def repack_shellball(self, append=None):
"""Repack shellball with new fwid.
New fwid follows the rule: [orignal_fwid]-[append].
Args:
append: save the new shellball with a suffix, for example,
chromeos-firmwareupdate-[append]. Use 'chromeos-firmwareupdate'
if append is None.
"""
working_shellball = os.path.join(self._temp_path,
'chromeos-firmwareupdate')
if append:
self.os_if.copy_file(working_shellball,
working_shellball + '-%s' % append)
working_shellball = working_shellball + '-%s' % append
self.os_if.run_shell_command('sh %s --sb_repack %s' % (
working_shellball, self._work_path))
if append:
args = ['-i']
args.append(
'"s/TARGET_FWID=\\"\\(.*\\)\\"/TARGET_FWID=\\"\\1.%s\\"/g"'
% append)
args.append(working_shellball)
cmd = 'sed %s' % ' '.join(args)
self.os_if.run_shell_command(cmd)
args = ['-i']
args.append('"s/TARGET_UNSTABLE=\\".*\\"/TARGET_UNSTABLE=\\"\\"/g"')
args.append(working_shellball)
cmd = 'sed %s' % ' '.join(args)
self.os_if.run_shell_command(cmd)
def run_firmwareupdate(self, mode, updater_append=None, options=[]):
"""Do firmwareupdate with updater in temp_dir.
Args:
updater_append: decide which shellball to use with format
chromeos-firmwareupdate-[append]. Use'chromeos-firmwareupdate'
if updater_append is None.
mode: ex.'autoupdate', 'recovery', 'bootok', 'factory_install'...
options: ex. ['--noupdate_ec', '--nocheck_rw_compatible'] or [] for
no option.
"""
if updater_append:
updater = os.path.join(
self._temp_path, 'chromeos-firmwareupdate-%s' % updater_append)
else:
updater = os.path.join(self._temp_path, 'chromeos-firmwareupdate')
self.os_if.run_shell_command(
'/bin/sh %s --mode %s %s' % (updater, mode, ' '.join(options)))
def get_temp_path(self):
"""Get temp directory path."""
return self._temp_path
def get_keys_path(self):
"""Get keys directory path."""
return self._keys_path
def get_work_path(self):
"""Get work directory path."""
return self._work_path