# Copyright 2019 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 import os from autotest_lib.client.common_lib import error from autotest_lib.server.cros.faft.firmware_test import FirmwareTest class firmware_WilcoDiagnosticsMode(FirmwareTest): """Corrupt the Wilco diagnostics image and then reinstall it. Wilco supports entry into a diagnostics image from recovery mode. The image is stored in the RW_LEGACY firmware section and updated during AP firmware updates. Entry into the image should fail if the image is corrupted. Updating the firmware should restore the diagnostics image. """ version = 1 # The delay between pressing to enter diagnostics mode and reaching # the confirmation screen; typically about 10 seconds; overshoot to be safe. DIAGNOSTICS_CONFIRM_SCREEN_DELAY_SECONDS = 15 # The delay between pressing to confirm entry to diagnostics mode # and rebooting into diagnostics mode. DIAGNOSTICS_CONFIRM_REBOOT_DELAY_SECONDS = 8 # The delay between rebooting to enter diagnostics mode and rebooting again # if that fails. DIAGNOSTICS_FAIL_REBOOT_DELAY_SECONDS = 8 # The name of the diagnostics image file in CBFS. DIAG_CBFS_NAME = 'altfw/diag' def initialize(self, host, cmdline_args): super(firmware_WilcoDiagnosticsMode, self).initialize( host, cmdline_args) if not self.faft_config.has_diagnostics_image: raise error.TestNAError('No diagnostics image for this board.') self.setup_firmwareupdate_shellball(shellball=None) # Make sure that the shellball is retained over subsequent power cycles. self.blocking_sync() self.switcher.setup_mode('normal') def cleanup(self): self.servo.get_power_state_controller().reset() super(firmware_WilcoDiagnosticsMode, self).cleanup() def _corrupt_diagnostics_image(self): # Extract the diagnostics image from the firmware image, corrupt the # image, and write a new firmware image with that corrupt diagnostics # image. local_filename = 'diag.bin' cbfs_work_dir = self.faft_client.updater.cbfs_setup_work_dir() bios_cbfs_path = os.path.join(cbfs_work_dir, self.faft_client.updater.get_bios_relative_path()) diag_cbfs_path = os.path.join(cbfs_work_dir, local_filename) logging.info('Extracting diagnostics') self.faft_client.updater.cbfs_extract_diagnostics(self.DIAG_CBFS_NAME, local_filename) logging.info('Corrupting diagnostics') self.faft_client.updater.corrupt_diagnostics_image(local_filename) logging.info('Replacing diagnostics') self.faft_client.updater.cbfs_replace_diagnostics(self.DIAG_CBFS_NAME, local_filename) logging.info('Writing back BIOS') self.faft_client.bios.write_whole(bios_cbfs_path) self.switcher.mode_aware_reboot() def _press_f12(self): self.servo.set_nocheck('arb_key_config', '') self.servo.set_nocheck('arb_key', 'tab') def _enter_diagnostics_mode(self): # Reboot to the recovery screen, press , and press power to # confirm. logging.info('Rebooting to recovery screen') self.switcher.enable_rec_mode_and_reboot(usb_state='host') time.sleep(self.faft_config.firmware_screen) logging.info('Pressing ') self._press_f12() time.sleep(self.DIAGNOSTICS_CONFIRM_SCREEN_DELAY_SECONDS) logging.info('Pressing to confirm') self.servo.power_short_press() # At this point, the DUT will try to reboot into diagnostics mode. def run_once(self): """Run the body of the test.""" logging.info('Attempting to enter diagnostics mode') self._enter_diagnostics_mode() # Wait long enough that DUT would have rebooted to normal mode if # diagnostics mode failed. time.sleep(self.DIAGNOSTICS_CONFIRM_REBOOT_DELAY_SECONDS + self.DIAGNOSTICS_FAIL_REBOOT_DELAY_SECONDS + self.faft_config.delay_reboot_to_ping) self.switcher.wait_for_client_offline(timeout=5) logging.info('DUT offline after entering diagnostics mode') self.servo.get_power_state_controller().reset() self.switcher.wait_for_client() # Corrupt the diagnostics image, try to reboot into diagnostics mode, # and verify that the DUT ends up in normal mode (indicating failure to # enter diagnostics mode). self._corrupt_diagnostics_image() self._enter_diagnostics_mode() self.switcher.wait_for_client() self.checkers.mode_checker('normal') # Update the firmware to restore the diagnostics image, reboot into # diagnostics mode, and verify that the DUT goes down (indicating # success). logging.info('Updating firmware') self.faft_client.updater.run_autoupdate(None) logging.info('Rebooting to apply firmware update') self.switcher.mode_aware_reboot() logging.info('Attempting to enter diagnostics mode') self._enter_diagnostics_mode() # Wait long enough that DUT would have rebooted if diagnostics mode # failed. time.sleep(self.DIAGNOSTICS_CONFIRM_REBOOT_DELAY_SECONDS + self.DIAGNOSTICS_FAIL_REBOOT_DELAY_SECONDS + self.faft_config.delay_reboot_to_ping) self.switcher.wait_for_client_offline(timeout=5) logging.info('DUT offline after entering diagnostics mode')