157 lines
6.3 KiB
Python
157 lines
6.3 KiB
Python
# 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):
|
|
# If EC isn't write-protected, it won't do EFS. Should enable WP.
|
|
super(firmware_ECUpdateId, self).initialize(host, cmdline_args,
|
|
ec_wp=True)
|
|
# 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")
|
|
# 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')
|
|
# 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 wait_software_sync_and_boot(self):
|
|
"""Wait for software sync to update EC."""
|
|
if self.dev_mode:
|
|
time.sleep(self.faft_config.software_sync_update +
|
|
self.faft_config.firmware_screen)
|
|
self.servo.ctrl_d()
|
|
else:
|
|
time.sleep(self.faft_config.software_sync_update)
|
|
|
|
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')
|
|
self.wait_software_sync_and_boot()
|
|
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))
|