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