185 lines
6.7 KiB
Python
185 lines
6.7 KiB
Python
# 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_ap_write_protect_and_reboot(False)
|
|
self.faft_client.bios.set_write_protect_region(self.WP_REGION, True)
|
|
self.set_ap_write_protect_and_reboot(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_ap_write_protect_and_reboot(False)
|
|
|
|
if write_protected:
|
|
self.faft_client.bios.set_write_protect_region(self.WP_REGION, True)
|
|
self.set_ap_write_protect_and_reboot(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_ap_write_protect_and_reboot(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()
|