blob: 51cc1958e2ed69b12d52378f1e4105c80cb919dd [file] [log] [blame]
# Copyright 2015 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.
import logging
from autotest_lib.client.common_lib import error
from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
class firmware_FWupdateWP(FirmwareTest):
"""RO+RW firmware update using chromeos-firmware, with WP=1 and with WP=0.
It modifies the FWIDs of the current firmware before flashing, and restores
the firmware after the test.
"""
# Region to use for flashrom wp-region commands
WP_REGION = 'WP_RO'
MODE = 'recovery'
def initialize(self, host, cmdline_args):
self.flashed = False
super(firmware_FWupdateWP, self).initialize(host, cmdline_args)
self._old_bios_wp = self.faft_client.bios.get_write_protect_status()
stripped_bios = self.faft_client.bios.strip_modified_fwids()
if stripped_bios:
logging.warn(
"Fixed the previously modified BIOS FWID(s): %s",
stripped_bios)
if self.faft_config.chrome_ec:
stripped_ec = self.faft_client.ec.strip_modified_fwids()
if stripped_ec:
logging.warn(
"Fixed the previously modified EC FWID(s): %s",
stripped_ec)
self.backup_firmware()
self.set_hardware_write_protect(False)
self.faft_client.bios.set_write_protect_region(self.WP_REGION, True)
self.set_hardware_write_protect(True)
def get_installed_versions(self):
"""Get the installed versions of BIOS and EC firmware.
@return: A nested dict keyed by target ('bios' or 'ec') and then section
@rtype: dict
"""
vers = dict()
vers['bios'] = self.faft_client.updater.get_device_fwids('bios')
if self.faft_config.chrome_ec:
vers['ec'] = self.faft_client.updater.get_device_fwids('ec')
return vers
def run_case(self, append, write_protected, before_fwids, image_fwids):
"""Run chromeos-firmwareupdate with given sub-case
@param append: additional piece to add to shellball name
@param write_protected: is the flash write protected (--wp)?
@param before_fwids: fwids before flashing ('bios' and 'ec' as keys)
@param image_fwids: fwids in image ('bios' and 'ec' as keys)
@return: a list of failure messages for the case
"""
cmd_desc = ('chromeos-firmwareupdate --mode=%s [wp=%s]'
% (self.MODE, write_protected))
# Unlock the protection of the wp-enable and wp-range registers
self.set_hardware_write_protect(False)
if write_protected:
self.faft_client.bios.set_write_protect_region(self.WP_REGION, True)
self.set_hardware_write_protect(True)
else:
self.faft_client.bios.set_write_protect_region(
self.WP_REGION, False)
expected_written = {}
if write_protected:
bios_written = ['a', 'b']
ec_written = [] # EC write is all-or-nothing
else:
bios_written = ['ro', 'a', 'b']
ec_written = ['ro', 'rw']
expected_written['bios'] = bios_written
if self.faft_config.chrome_ec and ec_written:
expected_written['ec'] = ec_written
# bios: [a, b], ec: [ro, rw]
written_desc = repr(expected_written).replace("'", "")[1:-1]
logging.debug('Before(%s): %s', append, before_fwids)
logging.debug('Image(%s): %s', append, image_fwids)
logging.info("Run %s (should write %s)", cmd_desc, written_desc)
# make sure we restore firmware after the test, if it tried to flash.
self.flashed = True
errors = []
options = ['--quirks=ec_partial_recovery=0']
result = self.run_chromeos_firmwareupdate(
self.MODE, append, options, ignore_status=True)
if result.exit_status == 255:
logging.info("DUT network dropped during update.")
elif result.exit_status != 0:
if (image_fwids == before_fwids and
'Good. It seems nothing was changed.' in result.stdout):
logging.info("DUT already matched the image; updater aborted.")
else:
errors.append('...updater: unexpectedly failed (rc=%s)' %
result.exit_status)
after_fwids = self.get_installed_versions()
logging.debug('After(%s): %s', append, after_fwids)
errors += self.check_fwids_written(
before_fwids, image_fwids, after_fwids, expected_written)
if errors:
logging.debug('%s', '\n'.join(errors))
return ["%s (should write %s)\n%s"
% (cmd_desc, written_desc, '\n'.join(errors))]
else:
return []
def run_once(self, host):
"""Run chromeos-firmwareupdate with recovery or factory mode.
@param host: host to run on
"""
append = 'new'
have_ec = bool(self.faft_config.chrome_ec)
self.faft_client.updater.extract_shellball()
before_fwids = self.get_installed_versions()
# Modify the stock image
logging.info(
"Using the currently running firmware, with modified fwids")
self.setup_firmwareupdate_shellball()
self.faft_client.updater.reload_images()
self.modify_shellball(append, modify_ro=True, modify_ec=have_ec)
modded_fwids = self.identify_shellball(include_ec=have_ec)
fail_msg = "Section contents didn't show the expected changes."
errors = []
# no args specified, so check both wp=1 and wp=0
errors += self.run_case(append, 1, before_fwids, modded_fwids)
errors += self.run_case(append, 0, before_fwids, modded_fwids)
if errors:
raise error.TestFail("%s\n%s" % (fail_msg, '\n'.join(errors)))
def cleanup(self):
"""
Restore firmware from the backup taken before flashing.
No EC reboot is needed, because the test doesn't actually reboot the EC
with the "new" firmware.
"""
self.set_hardware_write_protect(False)
self.faft_client.bios.set_write_protect_range(0, 0, False)
if self.flashed:
logging.info("Restoring firmware")
self.restore_firmware()
# Restore the old write-protection value at the end of the test.
self.faft_client.bios.set_write_protect_range(
self._old_bios_wp['start'],
self._old_bios_wp['length'],
self._old_bios_wp['enabled'])
super(firmware_FWupdateWP, self).cleanup()