1# Copyright 2019 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 7import os 8 9from autotest_lib.client.common_lib import error 10from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 11 12 13class firmware_WilcoDiagnosticsMode(FirmwareTest): 14 """Corrupt the Wilco diagnostics image and then reinstall it. 15 16 Wilco supports entry into a diagnostics image from recovery mode. The image 17 is stored in the RW_LEGACY firmware section and updated during AP firmware 18 updates. Entry into the image should fail if the image is corrupted. 19 Updating the firmware should restore the diagnostics image. 20 """ 21 version = 1 22 23 # The delay between pressing <F12> to enter diagnostics mode and reaching 24 # the confirmation screen; typically about 10 seconds; overshoot to be safe. 25 DIAGNOSTICS_CONFIRM_SCREEN_DELAY_SECONDS = 15 26 # The delay between pressing <Power> to confirm entry to diagnostics mode 27 # and rebooting into diagnostics mode. 28 DIAGNOSTICS_CONFIRM_REBOOT_DELAY_SECONDS = 8 29 # The delay between rebooting to enter diagnostics mode and rebooting again 30 # if that fails. 31 DIAGNOSTICS_FAIL_REBOOT_DELAY_SECONDS = 8 32 # The name of the diagnostics image file in CBFS. 33 DIAG_CBFS_NAME = 'altfw/diag' 34 35 def initialize(self, host, cmdline_args): 36 super(firmware_WilcoDiagnosticsMode, self).initialize( 37 host, cmdline_args) 38 39 if not self.faft_config.has_diagnostics_image: 40 raise error.TestNAError('No diagnostics image for this board.') 41 42 self.setup_firmwareupdate_shellball(shellball=None) 43 # Make sure that the shellball is retained over subsequent power cycles. 44 self.blocking_sync() 45 self.switcher.setup_mode('normal') 46 47 def cleanup(self): 48 self._client.reset_via_servo() 49 50 super(firmware_WilcoDiagnosticsMode, self).cleanup() 51 52 def _corrupt_diagnostics_image(self): 53 # Extract the diagnostics image from the firmware image, corrupt the 54 # image, and write a new firmware image with that corrupt diagnostics 55 # image. 56 local_filename = 'diag.bin' 57 cbfs_work_dir = self.faft_client.updater.cbfs_setup_work_dir() 58 bios_cbfs_path = os.path.join(cbfs_work_dir, 59 self.faft_client.updater.get_bios_relative_path()) 60 diag_cbfs_path = os.path.join(cbfs_work_dir, local_filename) 61 62 logging.info('Extracting diagnostics') 63 self.faft_client.updater.cbfs_extract_diagnostics(self.DIAG_CBFS_NAME, 64 diag_cbfs_path) 65 66 logging.info('Corrupting diagnostics') 67 self.faft_client.updater.corrupt_diagnostics_image(diag_cbfs_path) 68 69 logging.info('Replacing diagnostics') 70 self.faft_client.updater.cbfs_replace_diagnostics(self.DIAG_CBFS_NAME, 71 diag_cbfs_path) 72 73 logging.info('Writing back BIOS') 74 self.faft_client.bios.write_whole(bios_cbfs_path) 75 self.switcher.mode_aware_reboot() 76 77 def _press_f12(self): 78 self.servo.set_nocheck('arb_key_config', '<f12>') 79 self.servo.set_nocheck('arb_key', 'tab') 80 81 def _enter_diagnostics_mode(self): 82 # Reboot to the recovery screen, press <F12>, and press power to 83 # confirm. 84 logging.info('Rebooting to recovery screen') 85 self.switcher.enable_rec_mode_and_reboot(usb_state='host') 86 time.sleep(self.faft_config.firmware_screen) 87 logging.info('Pressing <F12>') 88 self._press_f12() 89 time.sleep(self.DIAGNOSTICS_CONFIRM_SCREEN_DELAY_SECONDS) 90 logging.info('Pressing <Power> to confirm') 91 self.servo.power_short_press() 92 # At this point, the DUT will try to reboot into diagnostics mode. 93 94 def run_once(self): 95 """Run the body of the test.""" 96 logging.info('Attempting to enter diagnostics mode') 97 self._enter_diagnostics_mode() 98 # Wait long enough that DUT would have rebooted to normal mode if 99 # diagnostics mode failed. 100 time.sleep(self.DIAGNOSTICS_CONFIRM_REBOOT_DELAY_SECONDS + 101 self.DIAGNOSTICS_FAIL_REBOOT_DELAY_SECONDS + 102 self.faft_config.delay_reboot_to_ping) 103 self.switcher.wait_for_client_offline(timeout=5) 104 logging.info('DUT offline after entering diagnostics mode') 105 self._client.reset_via_servo() 106 self.switcher.wait_for_client() 107 108 # Corrupt the diagnostics image, try to reboot into diagnostics mode, 109 # and verify that the DUT ends up in normal mode (indicating failure to 110 # enter diagnostics mode). 111 self._corrupt_diagnostics_image() 112 self._enter_diagnostics_mode() 113 self.switcher.wait_for_client() 114 self.checkers.mode_checker('normal') 115 116 # Update the firmware to restore the diagnostics image, reboot into 117 # diagnostics mode, and verify that the DUT goes down (indicating 118 # success). 119 logging.info('Updating firmware') 120 self.faft_client.updater.run_autoupdate(None) 121 logging.info('Rebooting to apply firmware update') 122 self.switcher.mode_aware_reboot() 123 124 logging.info('Attempting to enter diagnostics mode') 125 self._enter_diagnostics_mode() 126 # Wait long enough that DUT would have rebooted if diagnostics mode 127 # failed. 128 time.sleep(self.DIAGNOSTICS_CONFIRM_REBOOT_DELAY_SECONDS + 129 self.DIAGNOSTICS_FAIL_REBOOT_DELAY_SECONDS + 130 self.faft_config.delay_reboot_to_ping) 131 self.switcher.wait_for_client_offline(timeout=5) 132 logging.info('DUT offline after entering diagnostics mode') 133