1# Copyright 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.client.common_lib.cros import cr50_utils, tpm_utils 9from autotest_lib.server.cros.faft.cr50_test import Cr50Test 10 11 12class firmware_Cr50SetBoardId(Cr50Test): 13 """Verify cr50-set-board-id.sh 14 15 Verify cr50-set-board-id sets the correct board id and flags based on the 16 given stage. 17 """ 18 version = 1 19 20 BID_SCRIPT = '/usr/share/cros/cr50-set-board-id.sh' 21 22 # the command to get the brand name 23 GET_BRAND = 'mosys platform brand' 24 25 # Used when the flags were not initialized in the factory. 26 UNKNOWN_FLAGS = 0xff00 27 # Used for dev, proto, EVT, and DVT phases. 28 DEVELOPMENT_FLAGS = 0xff7f 29 # Used for PVT and MP builds. 30 RELEASE_FLAGS = 0x7f80 31 PHASE_FLAGS_DICT = { 32 'unknown' : UNKNOWN_FLAGS, 33 34 'dev' : DEVELOPMENT_FLAGS, 35 'proto' : DEVELOPMENT_FLAGS, 36 'evt' : DEVELOPMENT_FLAGS, 37 'dvt' : DEVELOPMENT_FLAGS, 38 39 'mp' : RELEASE_FLAGS, 40 'pvt' : RELEASE_FLAGS, 41 } 42 43 # The response strings from cr50-set-board-id 44 SUCCESS = ["Successfully updated board ID to 'BID' with phase 'PHASE'.", 45 0] 46 ERROR_UNKNOWN_PHASE = ['Unknown phase (PHASE)', 1] 47 ERROR_INVALID_RLZ = ['Invalid RLZ brand code (BID).', 1] 48 ERROR_ALREADY_SET = ['Board ID and flag have already been set.', 2] 49 ERROR_BID_SET_DIFFERENTLY = ['Board ID has been set differently.', 3] 50 ERROR_FLAG_SET_DIFFERENTLY = ['Flag has been set differently.', 3] 51 52 def initialize(self, host, cmdline_args, dev_path='', bid=''): 53 # Restore the original image, rlz code, and board id during cleanup. 54 super(firmware_Cr50SetBoardId, self).initialize(host, cmdline_args, 55 restore_cr50_state=True, cr50_dev_path=dev_path) 56 if self.cr50.using_ccd(): 57 raise error.TestNAError('Use a flex cable instead of CCD cable.') 58 59 # Update to the dev image so we can erase the board id after we set it. 60 # This test is verifying cr50-set-board-id and not the actual getting/ 61 # setting of the board id on the cr50 side, so it is ok if the cr50 is 62 # running a dev image. 63 self.cr50_update(self.get_saved_cr50_dev_path()) 64 65 if not self.cr50.has_command('bid'): 66 raise error.TestNAError('Cr50 image does not support board id') 67 68 if not self.host.path_exists(self.BID_SCRIPT): 69 raise error.TestNAError('Device does not have "cr50-set-board-id"') 70 71 result = self.host.run(self.GET_BRAND, ignore_status=True) 72 platform_brand = result.stdout.strip() 73 if result.exit_status or not platform_brand: 74 raise error.TestNAError('Could not get "mosys platform brand"') 75 self.platform_brand = platform_brand 76 self.erase_bid() 77 cr50_utils.StopTrunksd(self.host) 78 79 80 def cleanup(self): 81 """Clear the TPM Owner""" 82 super(firmware_Cr50SetBoardId, self).cleanup() 83 tpm_utils.ClearTPMOwnerRequest(self.host) 84 85 86 def erase_bid(self): 87 """Erase the current board id""" 88 self.cr50.send_command('eraseflashinfo') 89 90 91 def run_script(self, expected_result, phase, board_id=''): 92 """Run the bid script with the given phase and board id 93 94 Args: 95 expected_result: a list with the result message and exit status 96 phase: The phase string. 97 board_id: The board id string. 98 99 Raises: 100 TestFail if the expected result message did not match the script 101 output 102 """ 103 message, exit_status = expected_result 104 105 # If we expect an error ignore the exit status 106 ignore_status = not not exit_status 107 108 # Run the script with the phase and board id 109 cmd = '%s %s %s' % (self.BID_SCRIPT, phase, board_id) 110 result = self.host.run(cmd, ignore_status=ignore_status) 111 112 # If we don't give the script a board id, it will use the platform 113 # brand 114 expected_board_id = board_id if board_id else self.platform_brand 115 # Replace the placeholders with the expected board id and phase 116 message = message.replace('BID', expected_board_id) 117 message = message.replace('PHASE', phase) 118 119 # Compare the expected script output to the actual script result 120 if message not in result.stdout or exit_status != result.exit_status: 121 logging.debug(result) 122 raise error.TestFail('Expected "%s" got "%s"' % (message, 123 result.stdout)) 124 logging.info(result.stdout) 125 126 127 def run_once(self): 128 """Verify cr50-set-board-id.sh""" 129 # 'A' is too short to be a valid rlz code 130 self.run_script(self.ERROR_INVALID_RLZ, 'dvt', 'A') 131 # dummy_phase is not a valid phase 132 self.run_script(self.ERROR_UNKNOWN_PHASE, 'dummy_phase') 133 # The rlz code is checked before the phase 134 self.run_script(self.ERROR_INVALID_RLZ, 'dummy_phase', 'A') 135 136 # Set the board id so we can verify cr50-set-board-id has the correct 137 # response to the board id already being set. 138 self.run_script(self.SUCCESS, 'dvt', 'TEST') 139 # mp has different flags than dvt 140 self.run_script(self.ERROR_FLAG_SET_DIFFERENTLY, 'mp', 'TEST') 141 # try setting the dvt flags with a different board id 142 self.run_script(self.ERROR_BID_SET_DIFFERENTLY, 'dvt', 'test') 143 # running with the same phase and board id will raise an error that the 144 # board id is already set 145 self.run_script(self.ERROR_ALREADY_SET, 'dvt', 'TEST') 146 147 # Verify each stage sets the right flags 148 for phase, flags in self.PHASE_FLAGS_DICT.iteritems(): 149 # Erase the board id so we can change it. 150 self.erase_bid() 151 152 # Run the script to set the board id and flags for the given phase. 153 self.run_script(self.SUCCESS, phase) 154 155 # Check that the board id and flags are actually set. 156 cr50_utils.CheckChipBoardId(self.host, self.platform_brand, flags) 157