faft: Implement a test to verify EC EFS
Implementat a new test to verify EC EFS by creating a slightly
different RW slot (different EC ID) in AP firmware.
It checks the next boot if the new RW gets software-synced to
the non-active slot and then reboot into it. It checks the EC
hash should change.
Also add steps to check if it gets recovered from corruption.
And do another update by restoring to its original firmware.
BUG=b:69921268
TEST=Ran the new-added firwmare_ECUpdateId test on Fizz (both
RW-A-boot and RW-B-boot).
Change-Id: Ief047279b49e79e1222daa018dd565c56309aa29
Reviewed-on: https://chromium-review.googlesource.com/818085
Commit-Ready: Wai-Hong Tam <[email protected]>
Tested-by: Wai-Hong Tam <[email protected]>
Reviewed-by: Daisuke Nojiri <[email protected]>
diff --git a/server/site_tests/firmware_ECUpdateId/control b/server/site_tests/firmware_ECUpdateId/control
new file mode 100644
index 0000000..568c26d
--- /dev/null
+++ b/server/site_tests/firmware_ECUpdateId/control
@@ -0,0 +1,33 @@
+# 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.
+
+from autotest_lib.server import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "firmware_ECUpdateId"
+PURPOSE = "Servo based EC test for updating EC ID for verifying EC EFS"
+CRITERIA = "This test will fail if EC EFS misbehaves"
+ATTRIBUTES = "suite:faft, suite:faft_ec, suite:faft_ec_au_1, suite:faft_ec_au_2, suite:faft_ec_au_3, suite:faft_ec_tot"
+TIME = "SHORT"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "firmware"
+TEST_TYPE = "server"
+DEPENDENCIES = "ec:cros"
+JOB_RETRIES = 4
+
+DOC = """
+This test modifies the EC ID in AP firmware, reboots EC, and checks the next
+boot that software sync and EFS works as intended or not. It also corrupts
+one RW slot and checks if it is recovered.
+"""
+
+args_dict = utils.args_to_dict(args)
+servo_args = hosts.CrosHost.get_servo_arguments(args_dict)
+
+def run_ecupdateid(machine):
+ host = hosts.create_host(machine, servo_args=servo_args)
+ job.run_test("firmware_ECUpdateId", host=host, cmdline_args=args,
+ disable_sysinfo=True, dev_mode=False, tag="normal")
+
+parallel_simple(run_ecupdateid, machines)
diff --git a/server/site_tests/firmware_ECUpdateId/control.dev b/server/site_tests/firmware_ECUpdateId/control.dev
new file mode 100644
index 0000000..5732b22
--- /dev/null
+++ b/server/site_tests/firmware_ECUpdateId/control.dev
@@ -0,0 +1,33 @@
+# 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.
+
+from autotest_lib.server import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "firmware_ECUpdateId"
+PURPOSE = "Servo based EC test for updating EC ID for verifying EC EFS"
+CRITERIA = "This test will fail if EC EFS misbehaves"
+ATTRIBUTES = "suite:faft, suite:faft_ec, suite:faft_ec_au_1, suite:faft_ec_au_2, suite:faft_ec_au_3, suite:faft_ec_tot"
+TIME = "SHORT"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "firmware"
+TEST_TYPE = "server"
+DEPENDENCIES = "ec:cros"
+JOB_RETRIES = 4
+
+DOC = """
+This test modifies the EC ID in AP firmware, reboots EC, and checks the next
+boot that software sync and EFS works as intended or not. It also corrupts
+one RW slot and checks if it is recovered.
+"""
+
+args_dict = utils.args_to_dict(args)
+servo_args = hosts.CrosHost.get_servo_arguments(args_dict)
+
+def run_ecupdateid(machine):
+ host = hosts.create_host(machine, servo_args=servo_args)
+ job.run_test("firmware_ECUpdateId", host=host, cmdline_args=args,
+ disable_sysinfo=True, dev_mode=True, tag="dev")
+
+parallel_simple(run_ecupdateid, machines)
diff --git a/server/site_tests/firmware_ECUpdateId/firmware_ECUpdateId.py b/server/site_tests/firmware_ECUpdateId/firmware_ECUpdateId.py
new file mode 100644
index 0000000..cf27ca2
--- /dev/null
+++ b/server/site_tests/firmware_ECUpdateId/firmware_ECUpdateId.py
@@ -0,0 +1,138 @@
+# 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):
+ # This test tries to corrupt EC firmware. Should disable EC WP.
+ super(firmware_ECUpdateId, self).initialize(host, cmdline_args,
+ ec_wp=False)
+ # 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):
+ try:
+ self.restore_firmware()
+ except Exception as e:
+ logging.error("Caught exception: %s", str(e))
+ super(firmware_ECUpdateId, self).cleanup()
+
+ 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):
+ if not self.faft_client.ec.is_efs():
+ raise error.TestNAError("Nothing needs to be tested for non-EFS")
+
+ 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()
+ 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("Corrupt the active EC RW.")
+ self.corrupt_active_rw()
+
+ logging.info("Reboot EC. Verify if EFS works as intended.")
+ self.sync_and_ec_reboot()
+ self.wait_software_sync_and_boot()
+ self.switcher.wait_for_client()
+
+ logging.info("Expect EC recovered.")
+ self.check_state((self.active_copy_checker, 'RW'))
+ 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).")
+ self.check_state((self.active_copy_checker, 'RW_B'))
+ self.check_state((self.active_hash_checker, original_hash))