159 lines
6.4 KiB
Python
159 lines
6.4 KiB
Python
# Copyright 2019 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
|
|
from autotest_lib.server.cros.faft.firmware_test import ConnectionError
|
|
|
|
|
|
class firmware_UpdaterModes(FirmwareTest):
|
|
"""RO+RW firmware update using chromeos-firmwareupdate with various modes.
|
|
|
|
This test uses --emulate, to avoid writing repeatedly to the flash.
|
|
"""
|
|
|
|
version = 1
|
|
|
|
SHELLBALL = '/usr/sbin/chromeos-firmwareupdate'
|
|
|
|
def initialize(self, host, cmdline_args, ec_wp=None):
|
|
"""
|
|
During initialization, back up the firmware, in case --emulate ever
|
|
breaks in a way that causes real writes.
|
|
"""
|
|
super(firmware_UpdaterModes, self).initialize(host, cmdline_args, ec_wp)
|
|
self.backup_firmware()
|
|
|
|
def cleanup(self):
|
|
"""Restore the original firmware, if it was somehow overwritten."""
|
|
try:
|
|
if self.is_firmware_saved():
|
|
self.restore_firmware()
|
|
except ConnectionError:
|
|
logging.error("ERROR: DUT did not come up after firmware restore!")
|
|
finally:
|
|
super(firmware_UpdaterModes, self).cleanup()
|
|
|
|
def get_bios_fwids(self, path):
|
|
"""Return the BIOS fwids for the given file"""
|
|
return self.faft_client.updater.get_image_fwids('bios', path)
|
|
|
|
def run_case(self, mode, write_protected, written, modify_ro=True,
|
|
should_abort=False, writes_gbb=False):
|
|
"""Run chromeos-firmwareupdate with given sub-case
|
|
|
|
@param mode: factory or recovery or autoupdate
|
|
@param write_protected: is the flash write protected (--wp)?
|
|
@param modify_ro: should ro fwid be modified?
|
|
@param written: list of bios areas expected to change
|
|
@param should_abort: if True, the updater should abort with no changes
|
|
@param writes_gbb: if True, the updater should rewrite gbb flags.
|
|
@return: a list of failure messages for the case
|
|
"""
|
|
self.faft_client.updater.reset_shellball()
|
|
|
|
fake_bios_path = self.faft_client.updater.copy_bios('fake-bios.bin')
|
|
self.faft_client.updater.set_image_gbb_flags(0, fake_bios_path)
|
|
|
|
before_fwids = {'bios': self.get_bios_fwids(fake_bios_path)}
|
|
before_gbb = self.faft_client.updater.get_image_gbb_flags(
|
|
fake_bios_path)
|
|
|
|
case_desc = ('chromeos-firmwareupdate --mode=%s --wp=%s'
|
|
% (mode, write_protected))
|
|
|
|
if modify_ro:
|
|
append = 'ro+rw'
|
|
else:
|
|
case_desc += ' [rw-only]'
|
|
append = 'rw'
|
|
|
|
# Repack the shellball with modded fwids
|
|
self.modify_shellball(append, modify_ro)
|
|
modded_fwids = self.identify_shellball()
|
|
image_gbb = self.faft_client.updater.get_image_gbb_flags()
|
|
|
|
options = ['--emulate', fake_bios_path, '--wp=%s' % write_protected]
|
|
|
|
logging.info("%s (should write %s)", case_desc,
|
|
', '.join(written).upper() or 'nothing')
|
|
|
|
errors = []
|
|
result = self.run_chromeos_firmwareupdate(mode, append, options,
|
|
ignore_status=True)
|
|
if result.exit_status == 0:
|
|
if should_abort:
|
|
errors.append(
|
|
"...updater: with current mode and write-protect value,"
|
|
" should abort (rc!=0) and not modify anything")
|
|
else:
|
|
if should_abort:
|
|
logging.debug('updater aborted as expected')
|
|
else:
|
|
errors.append('...updater: unexpectedly failed (rc!=0)')
|
|
|
|
after_fwids = {'bios': self.get_bios_fwids(fake_bios_path)}
|
|
after_gbb = self.faft_client.updater.get_image_gbb_flags(fake_bios_path)
|
|
expected_written = {'bios': written or []}
|
|
|
|
errors += self.check_fwids_written(
|
|
before_fwids, modded_fwids, after_fwids, expected_written)
|
|
|
|
if not errors:
|
|
logging.debug('...bios versions correct: %s', after_fwids['bios'])
|
|
|
|
if writes_gbb:
|
|
if after_gbb != image_gbb:
|
|
# Expect rewritten, but it might not be different from before
|
|
errors.append(
|
|
"...GBB flags weren't rewritten to match the image: "
|
|
"before=0x%x, image=0x%x, after=0x%x."
|
|
% (before_gbb, image_gbb, after_gbb))
|
|
else:
|
|
if after_gbb != before_gbb:
|
|
errors.append(
|
|
"...GBB flags were unexpectedly rewritten: "
|
|
"before=0x%x, image=0x%x, after=0x%x."
|
|
% (before_gbb, image_gbb, after_gbb))
|
|
|
|
if self.restore_firmware():
|
|
# If real writes happen, fail immediately to avoid flash wear.
|
|
raise error.TestFail(
|
|
'With chromeos-firmwareupdate --emulate, real flash device '
|
|
'was unexpectedly modified.')
|
|
|
|
if errors:
|
|
case_message = '%s:\n%s' % (case_desc, '\n'.join(errors))
|
|
logging.error('%s', case_message)
|
|
return [case_message]
|
|
return []
|
|
|
|
def run_once(self, host):
|
|
"""Run test, iterating through combinations of mode and write-protect"""
|
|
errors = []
|
|
|
|
# factory: update A, B, and RO; reset gbb flags. If WP=1, abort.
|
|
errors += self.run_case('factory', 0, ['ro', 'a', 'b'], writes_gbb=True)
|
|
errors += self.run_case('factory', 1, [], should_abort=True)
|
|
|
|
# recovery: update A and B, and RO if WP=0.
|
|
errors += self.run_case('recovery', 0, ['ro', 'a', 'b'])
|
|
errors += self.run_case('recovery', 1, ['a', 'b'])
|
|
|
|
# autoupdate with changed ro: same as recovery (modify ro only if WP=0)
|
|
errors += self.run_case('autoupdate', 0, ['ro', 'a', 'b'])
|
|
errors += self.run_case('autoupdate', 1, ['b'])
|
|
|
|
# autoupdate with unchanged ro: update inactive slot
|
|
errors += self.run_case('autoupdate', 0, ['b'], modify_ro=False)
|
|
errors += self.run_case('autoupdate', 1, ['b'], modify_ro=False)
|
|
|
|
if len(errors) == 1:
|
|
raise error.TestFail(errors[0])
|
|
elif errors:
|
|
raise error.TestFail(
|
|
'%s combinations of mode and write-protect failed:\n%s' %
|
|
(len(errors), '\n'.join(errors)))
|