| # 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() |
| |
| # TODO(dgoyette): move this into the general FirmwareTest init? |
| 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() |