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 six 7 8from autotest_lib.client.common_lib import error 9from autotest_lib.client.common_lib.cros import cr50_utils 10from autotest_lib.server.cros.faft.cr50_test import Cr50Test 11 12 13class firmware_Cr50PartialBoardId(Cr50Test): 14 """Verify cr50 partial board id. 15 16 17 Verify the board id flags can be set alone and the brand can be set later. 18 """ 19 version = 1 20 21 # Brand used for testing. It doesn't matter what this is. 22 DEFAULT_BRAND = 'ZZAF' 23 24 ALLOW_FLAGS = 0x3f80 25 OTHER_FLAGS = 0x7f7f 26 27 SUCCESS = '' 28 ERR_ALREADY_SET = 'Error 7 while setting board id' 29 ERR_BID_MISMATCH = 'Error 5 while setting board id' 30 31 32 def initialize(self, host, cmdline_args, full_args, bid=''): 33 """Generate the test flags and verify the device setup.""" 34 # Restore the original image, rlz code, and board id during cleanup. 35 super(firmware_Cr50PartialBoardId, self).initialize( 36 host, cmdline_args, full_args, restore_cr50_image=True, 37 restore_cr50_board_id=True) 38 if self.servo.main_device_is_ccd(): 39 raise error.TestNAError('Use a flex cable instead of CCD cable.') 40 41 running_ver = self.get_saved_cr50_original_version() 42 logging.info('Cr50 Version: %s', running_ver) 43 bid = running_ver[2] 44 brand = self.get_device_brand() 45 self.test_brand = brand if brand else self.DEFAULT_BRAND 46 logging.info('Test Brand: %r', self.test_brand) 47 self.image_flags = int(bid.rsplit(':', 1)[-1], 16) if bid else 0 48 # The image may have non-zero flags. Use test flags as close to the 49 # allowed flags as possible, but make sure they can be used with 50 # the running image. 51 self.test_flags = self.ALLOW_FLAGS | self.image_flags 52 self.other_flags = self.OTHER_FLAGS | self.image_flags 53 54 55 def eraseflashinfo(self): 56 """Eraseflashinfo if the board id is set.""" 57 if cr50_utils.GetChipBoardId(self.host) == cr50_utils.ERASED_CHIP_BID: 58 return 59 # Erase the board id so we can change it. 60 self.eraseflashinfo_and_restore_image() 61 62 63 def set_bid_with_dbg_image(self, bid): 64 """Use the console command on the DBG image to set the board id.""" 65 self.eraseflashinfo_and_restore_image(self.get_saved_dbg_image_path()) 66 self.cr50.set_board_id(int(bid[0], 16), bid[2]) 67 self.cr50_update(self.get_saved_cr50_original_path(), rollback=True) 68 69 70 @staticmethod 71 def get_bid_str(bid): 72 """Returns a string representation of the board id tuple.""" 73 bid_str_fields = [] 74 for field in bid: 75 if isinstance(field, six.string_types): 76 bid_str_fields.append(field) 77 elif isinstance(field, int): 78 bid_str_fields.append(hex(field)) 79 else: 80 bid_str_fields.append(str(field)) 81 return ':'.join(bid_str_fields) 82 83 84 def set_board_id_check_response(self, set_bid, expected_bid, expected_msg): 85 """Try to set the board id and verify the response. 86 87 @param set_bid: a tuple of the board id to set (brand, brand_inv, 88 flags). brand_inv is ignored, but it's included to be 89 consistent with expected_bid. The flags should be an 90 integer. 91 @param expected_bid: a tuple of the board id cr50 should have (brand, 92 brand_inv, flags). brand_inv is ignored if it's 93 None. The flags should be an integer. 94 @param expected_msg: The expected response from setting the board id 95 with gsctool. 96 @raises TestFail if the cr50 board id doesn't match expected_bid or 97 the gsctool doesn't contain expected_msg. 98 """ 99 logging.info('Set BID %s.', self.get_bid_str(set_bid)) 100 logging.info('Expect BID %s (%s)', self.get_bid_str(expected_bid), 101 expected_msg) 102 board_id_arg = '%s:0x%08x' % (set_bid[0], set_bid[2]) 103 104 result = cr50_utils.GSCTool(self.host, ['-a', '-i', board_id_arg], 105 ignore_status=True) 106 107 stderr = result.stderr.strip() 108 result_msg = stderr if stderr else result.stdout.strip() 109 logging.info('Response: BID %s %s', board_id_arg, 110 ('(%s)' % result_msg) if result_msg else '') 111 if expected_msg and expected_msg not in result_msg: 112 err = ('Unexpected response setting %r (%d): got %r expected %r' % 113 (board_id_arg, result.exit_status, result_msg, 114 expected_msg)) 115 raise error.TestFail(err) 116 cr50_utils.CheckChipBoardId(self.host, expected_bid[0], expected_bid[2], 117 board_id_inv=expected_bid[1]) 118 119 120 def run_once(self): 121 """Verify partial board id""" 122 self.eraseflashinfo() 123 # Basic check. Setting board id fails if it's already been fully set. 124 bid = (self.test_brand, None, self.test_flags) 125 self.set_board_id_check_response(bid, bid, self.SUCCESS) 126 self.set_board_id_check_response(bid, bid, self.ERR_ALREADY_SET) 127 128 self.eraseflashinfo() 129 # No special behavior for flags that are 0xffffffff. The flags cannot 130 # be changed if the board id is set even if the flags are 0xffffffff. 131 original_bid = (self.test_brand, None, cr50_utils.ERASED_BID_INT) 132 second_bid = (self.test_brand, None, self.test_flags) 133 self.set_board_id_check_response(original_bid, original_bid, 134 self.SUCCESS) 135 self.set_board_id_check_response(second_bid, original_bid, 136 self.ERR_ALREADY_SET) 137 138 self.eraseflashinfo() 139 # Flags can be set if board_id_type and board_id_type_inv are 0xffffffff 140 partial_bid = (cr50_utils.ERASED_BID_STR, None, self.test_flags) 141 stored_partial_bid = (cr50_utils.ERASED_BID_STR, 142 cr50_utils.ERASED_BID_STR, self.test_flags) 143 self.set_board_id_check_response(partial_bid, stored_partial_bid, 144 self.SUCCESS) 145 set_brand = (self.test_brand, None, self.other_flags) 146 updated_brand_bid = (self.test_brand, None, self.test_flags) 147 self.set_board_id_check_response(set_brand, updated_brand_bid, 148 self.SUCCESS) 149 150 # Setting the board id type to 0xffffffff on the console will set the 151 # type to 0xffffffff and type_inv to 0. This isn't considered a partial 152 # board id. Setting the board id a second time will fail. 153 bid = (cr50_utils.ERASED_BID_STR, '00000000', self.test_flags) 154 new_bid = (self.test_brand, None, self.other_flags) 155 self.set_bid_with_dbg_image(bid) 156 self.set_board_id_check_response(new_bid, bid, self.ERR_ALREADY_SET) 157 if not self.image_flags: 158 logging.info('Image is not board id locked. Done') 159 return 160 161 self.eraseflashinfo() 162 # Plain whitelabel flags will run on any board id locked image. 163 bid = (cr50_utils.ERASED_BID_STR, None, self.ALLOW_FLAGS) 164 self.set_board_id_check_response(bid, cr50_utils.ERASED_CHIP_BID, 165 self.ERR_BID_MISMATCH) 166 # Previous board id was rejected. The board id can still be set. 167 basic_bid = (self.test_brand, None, self.image_flags) 168 self.set_board_id_check_response(basic_bid, basic_bid, self.SUCCESS) 169