# Copyright 2017 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 import time from autotest_lib.client.common_lib import error from autotest_lib.server.cros.faft.firmware_test import FirmwareTest from autotest_lib.server.cros import vboot_constants as vboot class firmware_ECUpdateId(FirmwareTest): """ Servo based EC test for updating EC ID for verifying EC EFS. """ version = 1 def initialize(self, host, cmdline_args, dev_mode=False): super(firmware_ECUpdateId, self).initialize(host, cmdline_args) # Don't bother if there is no Chrome EC or if the EC is non-EFS. if not self.check_ec_capability(): raise error.TestNAError("Nothing needs to be tested on this device") if not self.faft_client.ec.is_efs(): raise error.TestNAError("Nothing needs to be tested for non-EFS") if self._no_ec_sync: raise error.TestNAError( "User selected to disable EC software sync") # If EC isn't write-protected, it won't do EFS. Should enable WP. self._setup_ec_write_protect(True) # In order to test software sync, it must be enabled. self.clear_set_gbb_flags(vboot.GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC, 0) self.backup_firmware() self.switcher.setup_mode('dev' if dev_mode else 'normal', allow_gbb_force=True) # It makes updater-related RPCs to use the active AP/EC firmware, # instead of the firmware in the shellball. self.setup_firmwareupdate_shellball() self.setup_usbkey(usbkey=False) self.setup_rw_boot() self.setup_ec_rw_to_a() self.dev_mode = dev_mode def cleanup(self): # The superclass's cleanup() restores the original WP state. # Do it before restore the firmware. super(firmware_ECUpdateId, self).cleanup() try: if self.is_firmware_saved(): self.restore_firmware() except Exception as e: logging.error("Caught exception: %s", str(e)) def setup_ec_rw_to_a(self): """For EC EFS, make EC boot into RW A.""" if self.faft_client.ec.is_efs(): active_copy = self.servo.get_ec_active_copy() if active_copy == 'RW_B': from_section = 'rw_b' to_section = 'rw' logging.info("Copy EC RW from '%s' to '%s'", from_section, to_section) self.faft_client.ec.copy_rw(from_section, to_section) logging.info("EC reboot to switch slot. Wait DUT up...") reboot = lambda: self.faft_client.ec.reboot_to_switch_slot() self.switcher.mode_aware_reboot('custom', reboot) def get_active_hash(self): """Return the current EC hash.""" ec_hash = self.faft_client.ec.get_active_hash() logging.info("Current EC hash: %s", ec_hash) return ec_hash def active_hash_checker(self, expected_hash): """Check if the current EC hash equals to the given one.""" ec_hash = self.get_active_hash() result = ec_hash == expected_hash if not result: logging.info("Expected EC hash %s but now %s", expected_hash, ec_hash) return result def active_copy_checker(self, expected_copy): """Check if the EC active copy is matched.""" # Get the active copy via servod (EC console). # The result of crossystem doesn't reflect RW_B. active_copy = self.servo.get_ec_active_copy() result = active_copy == expected_copy if not result: logging.info("Expected EC in %s but now in %s", expected_copy, active_copy) return result def corrupt_active_rw(self): """Corrupt the active RW portion.""" section = 'rw' if self.servo.get_ec_active_copy() == 'RW_B': section = 'rw_b' logging.info("Corrupt the EC section: %s", section) self.faft_client.ec.corrupt_body(section) def run_once(self): """Execute the main body of the test. """ logging.info("Check the current state and record hash.") self.check_state((self.active_copy_checker, 'RW')) original_hash = self.get_active_hash() logging.info("Modify EC ID and flash it back to BIOS...") self.faft_client.updater.modify_ecid_and_flash_to_bios() modified_hash = self.faft_client.updater.get_ec_hash() logging.info("Reboot EC. Verify if EFS works as intended.") self.sync_and_ec_reboot('hard') time.sleep(self.faft_config.software_sync_update) self.switcher.wait_for_client() logging.info("Expect EC in another RW slot (the modified hash).") self.check_state((self.active_copy_checker, 'RW_B')) self.check_state((self.active_hash_checker, modified_hash)) logging.info("Disable EC WP (also reboot)") self.switcher.mode_aware_reboot( 'custom', lambda:self.set_ec_write_protect_and_reboot(False)) logging.info("Corrupt the active EC RW.") self.corrupt_active_rw() logging.info("Re-enable EC WP (also reboot)") self.switcher.mode_aware_reboot( 'custom', lambda:self.set_ec_write_protect_and_reboot(True)) logging.info("Expect EC recovered.") # * EC performs EC-EFS, jumps to A, and boots AP. # * AP software-sync's to EC B. Reboots. # * EC performs EC-EFS and jumps to B. self.check_state((self.active_copy_checker, 'RW_B')) self.check_state((self.active_hash_checker, modified_hash)) logging.info("Restore the original AP firmware and reboot.") self.restore_firmware(restore_ec=False) logging.info("Expect EC restored back (the original hash).") # * EC performs EC-EFS, jumps to B, and boots AP. # * AP software-sync's to EC A. Reboots. # * EC performs EC-EFS and jumps to A. self.check_state((self.active_copy_checker, 'RW')) self.check_state((self.active_hash_checker, original_hash))