1# Copyright 2018 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 re 7import time 8 9from autotest_lib.client.common_lib import error, utils 10from autotest_lib.client.common_lib.cros import cr50_utils 11from autotest_lib.server.cros import filesystem_util 12from autotest_lib.server.cros.faft.cr50_test import Cr50Test 13 14 15class firmware_Cr50GetName(Cr50Test): 16 """Verify cr50-get-name.sh 17 18 Verify cr50-get-name sets the correct board id and flags based on the 19 given stage. 20 """ 21 version = 1 22 23 GET_NAME_SCRIPT = '/usr/share/cros/cr50-get-name.sh' 24 # This translates to 'TEST' 25 TEST_BRAND = 0x54455354 26 MAX_VAL = 0xffffffff 27 28 29 def initialize(self, host, cmdline_args, full_args={}): 30 # Restore the original image, rlz code, and board id during cleanup. 31 super(firmware_Cr50GetName, self).initialize(host, cmdline_args, 32 full_args, restore_cr50_image=True, restore_cr50_board_id=True) 33 34 if not self.host.path_exists(self.GET_NAME_SCRIPT): 35 raise error.TestNAError('Device does not have "cr50-get-name"') 36 37 efi_path = self.get_saved_eraseflashinfo_image_path() 38 39 filesystem_util.make_rootfs_writable(self.host) 40 cr50_utils.InstallImage(self.host, efi_path, cr50_utils.CR50_PROD) 41 cr50_utils.InstallImage(self.host, efi_path, cr50_utils.CR50_PREPVT) 42 43 # Update to the eraseflashinfo image so we can erase the board id after 44 # we set it. This test is verifying cr50-get-name, so it is ok if cr50 45 # is running a non-prod image. 46 self.cr50_update(self.get_saved_dbg_image_path()) 47 self.cr50_update(efi_path, rollback=True) 48 49 # Stop trunksd so it wont interfere with the update 50 cr50_utils.StopTrunksd(self.host) 51 52 # Get the current cr50 update messages. The test will keep track of the 53 # last message and separate the current output from actual test results. 54 self.get_result() 55 56 57 def cleanup(self): 58 """Reset the DUT to restore trunksd.""" 59 try: 60 self.host.reset_via_servo() 61 finally: 62 super(firmware_Cr50GetName, self).cleanup() 63 64 65 def get_result(self): 66 """Return the new cr50 update messages from /var/log/messages""" 67 # Get the cr50 messages 68 result = self.host.run('grep cr50 /var/log/messages').stdout.strip() 69 70 if hasattr(self, '_last_message'): 71 result = result.rsplit(self._last_message, 1)[-1] 72 73 # Save the last line. It will be used to separate the current results 74 # from later runs. 75 self._last_message = result.rsplit('\n', 1)[-1] 76 logging.debug('last cr50 update message: "%s"', self._last_message) 77 return result 78 79 80 def get_expected_result_re(self, brand, flags, erased): 81 """Return the expected update message re given the test flags 82 83 Args: 84 brand: The board id value to test. 85 flags: The flag value to test. 86 erased: True if the board id is erased 87 88 Returns: 89 A string with info that must be found in /var/log/messages for valid 90 update results. 91 """ 92 expected_result = [] 93 94 if erased: 95 board_id = 'ffffffff:ffffffff:ffffffff' 96 # If the board id is erased, the device should update to the prod 97 # image. 98 ext = 'prod' 99 expected_result.append('board ID is erased using prod image') 100 else: 101 board_id = '%08x:%08x:%08x' % (brand, brand ^ self.MAX_VAL, flags) 102 ext = 'prepvt' if flags & 0x10 else 'prod' 103 104 flag_str = board_id.rsplit(':', 1)[-1] 105 106 expected_result.append("board_id: '%s' board_flags: '0x%s', extension: " 107 "'%s'" % (board_id, flag_str, ext)) 108 expected_result.append('hashing /opt/google/cr50/firmware/cr50.bin.%s' % 109 ext) 110 return '(%s)' % '\n.*'.join(expected_result) 111 112 113 def check_result(self, brand, flags, erased): 114 """Verify the expected result string is found in the update messages 115 116 Args: 117 brand: The board id value to test. 118 flags: The flag value to test. 119 erased: True if the board id is erased 120 121 Raises: 122 TestFail if the expected result message did not match the update 123 output 124 """ 125 expected_result_re = self.get_expected_result_re(brand, flags, erased) 126 result = self.get_result() 127 match = re.search(expected_result_re, result) 128 129 logging.debug('EXPECT: %s', expected_result_re) 130 logging.debug('GOT: %s', result) 131 132 if not match: 133 raise error.TestFail('Unexpected result during update with %s' % 134 ('erased board id' if erased else '%x:%x' % (brand, flags))) 135 136 logging.info('FOUND UPDATE RESULT:\n%s', match.groups()[0]) 137 138 139 def cr50_update_is_running(self): 140 """Returns True if cr50-update is running on the host""" 141 time.sleep(1) 142 status = self.host.run('status cr50-update').stdout 143 logging.info('cr50-update status: %s', status) 144 return 'running' in status 145 146 147 def run_update(self, brand, flags, clear_bid=False): 148 """Set the board id then run cr50-update 149 150 Args: 151 brand: The board id int to test. 152 flags: The flag int to test. 153 clear_bid: True if the board id should be erased and not reset. 154 """ 155 if not self.cr50.eraseflashinfo(): 156 raise error.TestError('Unable to erase the board id') 157 158 if not clear_bid: 159 cr50_utils.SetChipBoardId(self.host, brand, flags) 160 161 # Get the current cr50 update messages. The test will keep track of the 162 # last message and separate the current output from actual test results. 163 self.get_result() 164 # Run the update script script 165 self.host.run('start cr50-update') 166 utils.wait_for_value(self.cr50_update_is_running, expected_value=False, 167 timeout_sec=30) 168 169 # Make sure cr50 used the right image. 170 self.check_result(brand, flags, clear_bid) 171 172 173 def run_once(self): 174 """Verify cr50-get-name.sh""" 175 # Test the MP flags 176 self.run_update(self.TEST_BRAND, 0x7f00) 177 178 # Test the pre-PVT flags 179 self.run_update(self.TEST_BRAND, 0x7f10) 180 181 # Erase the board id 182 self.run_update(0, 0, clear_bid=True) 183 184 # Make sure the script can tell the difference between an erased board 185 # id and one set to 0xffffffff:0xffffffff. 186 self.run_update(self.MAX_VAL, self.MAX_VAL) 187