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 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 = 'cros_config / brand-code' 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 = 0x7f7f 29 # Used for PVT and MP builds. 30 RELEASE_FLAGS = 0x7f80 31 TEST_MP_FLAGS = 0x10000 32 PHASE_FLAGS_DICT = { 33 'unknown' : UNKNOWN_FLAGS, 34 35 'dev' : DEVELOPMENT_FLAGS, 36 'proto' : DEVELOPMENT_FLAGS, 37 'evt' : DEVELOPMENT_FLAGS, 38 'dvt' : DEVELOPMENT_FLAGS, 39 40 'mp' : RELEASE_FLAGS, 41 'pvt' : RELEASE_FLAGS, 42 } 43 44 # The response strings from cr50-set-board-id 45 SUCCESS = ["Successfully updated board ID to 'BID' with phase 'PHASE'.", 46 0] 47 ERROR_UNKNOWN_PHASE = ['Unknown phase (PHASE)', 1] 48 ERROR_INVALID_RLZ = ['Invalid RLZ brand code (BID).', 1] 49 ERROR_ALREADY_SET = ['Board ID and flag have already been set.', 2] 50 ERROR_BID_SET_DIFFERENTLY = ['Board ID has been set differently.', 3] 51 ERROR_FLAG_SET_DIFFERENTLY = ['Flag has been set differently.', 3] 52 ERROR_BID_MISMATCH = ['Error 5 while setting board id', 1] 53 54 def initialize(self, host, cmdline_args, full_args, bid=''): 55 # Restore the original image, rlz code, and board id during cleanup. 56 super(firmware_Cr50SetBoardId, self).initialize(host, cmdline_args, 57 full_args, restore_cr50_image=True, restore_cr50_board_id=True) 58 if self.servo.main_device_is_ccd(): 59 raise error.TestNAError('Use a flex cable instead of CCD cable.') 60 61 result = self.host.run(self.GET_BRAND, ignore_status=True) 62 platform_brand = result.stdout.strip() 63 if result.exit_status or not platform_brand: 64 raise error.TestNAError('Could not get "cros_config / brand-code"') 65 self.platform_brand = platform_brand 66 67 bid = self.get_saved_cr50_original_version()[2] 68 self._bid_flags = int(bid.rsplit(':', 1)[-1], 16) if bid else 0 69 if self._bid_flags == self.TEST_MP_FLAGS: 70 raise error.TestNAError('cr50-set-board-id cannot be used with ' 71 'test mp images.') 72 self.make_rootfs_writable() 73 self.host.run('rm %s' % cr50_utils.CR50_PREPVT, ignore_status=True) 74 self.host.run('rm %s' % cr50_utils.CR50_PROD, ignore_status=True) 75 76 77 def run_script(self, expected_result, phase, board_id=''): 78 """Run the bid script with the given phase and board id 79 80 Args: 81 expected_result: a list with the result message and exit status 82 phase: The phase string. 83 board_id: The board id string. 84 85 Raises: 86 TestFail if the expected result message did not match the script 87 output 88 """ 89 message, exit_status = expected_result 90 91 # If we expect an error ignore the exit status 92 ignore_status = not not exit_status 93 94 # Run the script with the phase and board id 95 cmd = '%s %s %s' % (self.BID_SCRIPT, phase, board_id) 96 result = self.host.run(cmd, ignore_status=ignore_status) 97 98 # If we don't give the script a board id, it will use the platform 99 # brand 100 expected_board_id = board_id if board_id else self.platform_brand 101 # Replace the placeholders with the expected board id and phase 102 message = message.replace('BID', expected_board_id) 103 message = message.replace('PHASE', phase) 104 105 logging.info(result.stdout) 106 # Compare the expected script output to the actual script result 107 if message not in result.stdout or exit_status != result.exit_status: 108 logging.debug(result) 109 raise error.TestFail('Expected "%s" got "%s"' % (message, 110 result.stdout)) 111 112 113 def eraseflashinfo(self): 114 """Eraseflashinfo if the board id is set.""" 115 if cr50_utils.GetChipBoardId(self.host) == cr50_utils.ERASED_CHIP_BID: 116 return 117 # Erase the board id so we can change it. 118 self.eraseflashinfo_and_restore_image() 119 120 121 def run_once(self): 122 """Verify cr50-set-board-id.sh""" 123 self.eraseflashinfo() 124 # 'A' is too short to be a valid rlz code 125 self.run_script(self.ERROR_INVALID_RLZ, 'dvt', 'A') 126 # dummy_phase is not a valid phase 127 self.run_script(self.ERROR_UNKNOWN_PHASE, 'dummy_phase') 128 # The rlz code is checked after the phase 129 self.run_script(self.ERROR_UNKNOWN_PHASE, 'dummy_phase', 'A') 130 131 self.eraseflashinfo() 132 # Set the board id so we can verify cr50-set-board-id has the correct 133 # response to the board id already being set. 134 self.run_script(self.SUCCESS, 'dvt', 'TEST') 135 # mp has different flags than dvt 136 self.run_script(self.ERROR_FLAG_SET_DIFFERENTLY, 'mp', 'TEST') 137 # try setting the dvt flags with a different board id 138 self.run_script(self.ERROR_BID_SET_DIFFERENTLY, 'dvt', 'test') 139 # running with the same phase and board id will raise an error that the 140 # board id is already set 141 self.run_script(self.ERROR_ALREADY_SET, 'dvt', 'TEST') 142 143 # Verify each stage sets the right flags 144 for phase, flags in self.PHASE_FLAGS_DICT.items(): 145 self.eraseflashinfo() 146 147 expected_response = self.SUCCESS 148 expected_brand = self.platform_brand 149 expected_flags = flags 150 if self._bid_flags & flags != self._bid_flags: 151 expected_response = self.ERROR_BID_MISMATCH 152 expected_brand = cr50_utils.ERASED_BID_INT 153 expected_flags = cr50_utils.ERASED_BID_INT 154 logging.info('%s phase mismatch with current image', phase) 155 # Run the script to set the board id and flags for the given phase. 156 self.run_script(expected_response, phase) 157 158 # Check that the board id and flags are actually set. 159 cr50_utils.CheckChipBoardId(self.host, expected_brand, 160 expected_flags) 161