1# Copyright (c) 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 6 7from autotest_lib.client.common_lib import error 8from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 9 10 11class firmware_RecoveryCacheBootKeys(FirmwareTest): 12 """ 13 This test ensures that when booting to recovery mode the device will use the 14 cache instead training memory every boot. 15 """ 16 version = 1 17 NEEDS_SERVO_USB = True 18 19 # Message in older mrc_cache driver code 20 USED_CACHE_MSG1 = ('MRC: Hash comparison successful. ' 21 'Using data from RECOVERY_MRC_CACHE') 22 # Message in newer mrc_cache driver code 23 USED_CACHE_MSG2 = ('MRC: Hash idx 0x100b comparison successful.') 24 REBUILD_CACHE_MSG = "MRC: cache data 'RECOVERY_MRC_CACHE' needs update." 25 RECOVERY_CACHE_SECTION = 'RECOVERY_MRC_CACHE' 26 FIRMWARE_LOG_CMD = 'cbmem -1' + ' | grep ' + REBUILD_CACHE_MSG[:3] 27 RECOVERY_REASON_REBUILD_CMD = 'crossystem recovery_request=0xC4' 28 29 def initialize(self, host, cmdline_args, dev_mode=False): 30 super(firmware_RecoveryCacheBootKeys, self).initialize( 31 host, cmdline_args) 32 33 if not self.faft_config.rec_force_mrc: 34 raise error.TestNAError('DUT cannot force memory training.') 35 36 self.client = host 37 self.dev_mode = dev_mode 38 self.switcher.setup_mode('dev' if dev_mode else 'normal', 39 allow_gbb_force=True) 40 self.setup_usbkey(usbkey=True, host=False) 41 42 def cleanup(self): 43 super(firmware_RecoveryCacheBootKeys, self).cleanup() 44 self.switcher.simple_reboot() 45 46 def boot_to_recovery(self, rebuild_mrc_cache=False): 47 """Boots the device into recovery mode.""" 48 if rebuild_mrc_cache: 49 self.switcher.reboot_to_mode(to_mode='rec_force_mrc') 50 else: 51 self.switcher.reboot_to_mode(to_mode='rec') 52 53 self.check_state((self.checkers.crossystem_checker, { 54 'mainfw_type': 'recovery' 55 })) 56 57 def cache_exist(self): 58 """Checks the firmware log to ensure that the recovery cache exists. 59 60 @return True if cache exists 61 """ 62 logging.info("Checking if device has RECOVERY_MRC_CACHE") 63 64 # If flashrom can read the section, this means it exists. 65 command = ('flashrom -p host -r -i %s:/dev/null' 66 % self.RECOVERY_CACHE_SECTION) 67 68 return self.faft_client.system.run_shell_command_check_output( 69 command, 'SUCCESS') 70 71 def check_cache_used(self): 72 """Checks the firmware log to ensure that the recovery cache was used 73 during recovery boot. 74 75 @return True if cache used 76 """ 77 logging.info('Checking if cache was used.') 78 79 return (self.faft_client.system.run_shell_command_check_output( 80 self.FIRMWARE_LOG_CMD, self.USED_CACHE_MSG1) 81 or self.faft_client.system.run_shell_command_check_output( 82 self.FIRMWARE_LOG_CMD, self.USED_CACHE_MSG2)) 83 84 def check_cache_rebuilt(self): 85 """Checks the firmware log to ensure that the recovery cache was rebuilt 86 during recovery boot. 87 88 @return True if cache rebuilt 89 """ 90 logging.info('Checking if cache was rebuilt.') 91 92 return self.faft_client.system.run_shell_command_check_output( 93 self.FIRMWARE_LOG_CMD, self.REBUILD_CACHE_MSG) 94 95 def run_once(self): 96 """Runs a single iteration of the test.""" 97 if not self.cache_exist(): 98 raise error.TestNAError('No RECOVERY_MRC_CACHE was found on DUT.') 99 100 logging.info('Ensure we\'ve done memory training.') 101 self.boot_to_recovery() 102 103 # With EFS, when the EC is in RO and we do a recovery boot, it 104 # causes the EC to do a soft reboot, which will in turn cause 105 # a PMIC reset (double reboot) on SKL/KBL power architectures. 106 # This causes us to lose the request to do MRC training for 107 # this test. The solution is to make sure that the EC is in 108 # RW before doing a recovery boot to ensure that the double 109 # reboot does not occur and information/requests are not lost. 110 self.switcher.simple_reboot('cold') 111 112 logging.info('Checking recovery boot.') 113 self.boot_to_recovery() 114 115 if not self.check_cache_used(): 116 raise error.TestFail('Recovery Cache was not used.') 117 118 self.switcher.simple_reboot('cold') 119 120 logging.info('Checking recovery boot with forced MRC cache training.') 121 self.boot_to_recovery(rebuild_mrc_cache=True) 122 self.switcher.wait_for_client() 123 124 if not self.check_cache_rebuilt(): 125 raise error.TestFail('Recovery Cache was not rebuilt.') 126 127 logging.info('Reboot out of Recovery') 128 self.switcher.simple_reboot() 129