1# Copyright 2017 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import logging 6import time 7 8from autotest_lib.client.common_lib import error 9from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 10from autotest_lib.server.cros import vboot_constants as vboot 11 12 13class firmware_ECUpdateId(FirmwareTest): 14 """ 15 Servo based EC test for updating EC ID for verifying EC EFS. 16 """ 17 version = 1 18 19 def initialize(self, host, cmdline_args, dev_mode=False): 20 super(firmware_ECUpdateId, self).initialize(host, cmdline_args) 21 # Don't bother if there is no Chrome EC or if the EC is non-EFS. 22 if not self.check_ec_capability(): 23 raise error.TestNAError("Nothing needs to be tested on this device") 24 if not self.faft_client.ec.is_efs(): 25 raise error.TestNAError("Nothing needs to be tested for non-EFS") 26 if self._no_ec_sync: 27 raise error.TestNAError( 28 "User selected to disable EC software sync") 29 # If EC isn't write-protected, it won't do EFS. Should enable WP. 30 self._setup_ec_write_protect(True) 31 # In order to test software sync, it must be enabled. 32 self.clear_set_gbb_flags(vboot.GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC, 0) 33 self.backup_firmware() 34 self.switcher.setup_mode('dev' if dev_mode else 'normal', 35 allow_gbb_force=True) 36 # It makes updater-related RPCs to use the active AP/EC firmware, 37 # instead of the firmware in the shellball. 38 self.setup_firmwareupdate_shellball() 39 self.setup_usbkey(usbkey=False) 40 self.setup_rw_boot() 41 self.setup_ec_rw_to_a() 42 self.dev_mode = dev_mode 43 44 def cleanup(self): 45 # The superclass's cleanup() restores the original WP state. 46 # Do it before restore the firmware. 47 super(firmware_ECUpdateId, self).cleanup() 48 try: 49 if self.is_firmware_saved(): 50 self.restore_firmware() 51 except Exception as e: 52 logging.error("Caught exception: %s", str(e)) 53 54 def setup_ec_rw_to_a(self): 55 """For EC EFS, make EC boot into RW A.""" 56 if self.faft_client.ec.is_efs(): 57 active_copy = self.servo.get_ec_active_copy() 58 if active_copy == 'RW_B': 59 from_section = 'rw_b' 60 to_section = 'rw' 61 logging.info("Copy EC RW from '%s' to '%s'", 62 from_section, to_section) 63 self.faft_client.ec.copy_rw(from_section, to_section) 64 65 logging.info("EC reboot to switch slot. Wait DUT up...") 66 reboot = lambda: self.faft_client.ec.reboot_to_switch_slot() 67 self.switcher.mode_aware_reboot('custom', reboot) 68 69 def get_active_hash(self): 70 """Return the current EC hash.""" 71 ec_hash = self.faft_client.ec.get_active_hash() 72 logging.info("Current EC hash: %s", ec_hash) 73 return ec_hash 74 75 def active_hash_checker(self, expected_hash): 76 """Check if the current EC hash equals to the given one.""" 77 ec_hash = self.get_active_hash() 78 result = ec_hash == expected_hash 79 if not result: 80 logging.info("Expected EC hash %s but now %s", 81 expected_hash, ec_hash) 82 return result 83 84 def active_copy_checker(self, expected_copy): 85 """Check if the EC active copy is matched.""" 86 # Get the active copy via servod (EC console). 87 # The result of crossystem doesn't reflect RW_B. 88 active_copy = self.servo.get_ec_active_copy() 89 result = active_copy == expected_copy 90 if not result: 91 logging.info("Expected EC in %s but now in %s", 92 expected_copy, active_copy) 93 return result 94 95 def corrupt_active_rw(self): 96 """Corrupt the active RW portion.""" 97 section = 'rw' 98 if self.servo.get_ec_active_copy() == 'RW_B': 99 section = 'rw_b' 100 logging.info("Corrupt the EC section: %s", section) 101 self.faft_client.ec.corrupt_body(section) 102 103 def run_once(self): 104 """Execute the main body of the test. 105 """ 106 logging.info("Check the current state and record hash.") 107 self.check_state((self.active_copy_checker, 'RW')) 108 original_hash = self.get_active_hash() 109 110 logging.info("Modify EC ID and flash it back to BIOS...") 111 self.faft_client.updater.modify_ecid_and_flash_to_bios() 112 modified_hash = self.faft_client.updater.get_ec_hash() 113 114 logging.info("Reboot EC. Verify if EFS works as intended.") 115 self.sync_and_ec_reboot('hard') 116 time.sleep(self.faft_config.software_sync_update) 117 self.switcher.wait_for_client() 118 119 logging.info("Expect EC in another RW slot (the modified hash).") 120 self.check_state((self.active_copy_checker, 'RW_B')) 121 self.check_state((self.active_hash_checker, modified_hash)) 122 123 logging.info("Disable EC WP (also reboot)") 124 self.switcher.mode_aware_reboot( 125 'custom', 126 lambda:self.set_ec_write_protect_and_reboot(False)) 127 128 logging.info("Corrupt the active EC RW.") 129 self.corrupt_active_rw() 130 131 logging.info("Re-enable EC WP (also reboot)") 132 self.switcher.mode_aware_reboot( 133 'custom', 134 lambda:self.set_ec_write_protect_and_reboot(True)) 135 136 logging.info("Expect EC recovered.") 137 # * EC performs EC-EFS, jumps to A, and boots AP. 138 # * AP software-sync's to EC B. Reboots. 139 # * EC performs EC-EFS and jumps to B. 140 self.check_state((self.active_copy_checker, 'RW_B')) 141 self.check_state((self.active_hash_checker, modified_hash)) 142 143 logging.info("Restore the original AP firmware and reboot.") 144 self.restore_firmware(restore_ec=False) 145 146 logging.info("Expect EC restored back (the original hash).") 147 # * EC performs EC-EFS, jumps to B, and boots AP. 148 # * AP software-sync's to EC A. Reboots. 149 # * EC performs EC-EFS and jumps to A. 150 self.check_state((self.active_copy_checker, 'RW')) 151 self.check_state((self.active_hash_checker, original_hash)) 152