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 pprint 7 8from autotest_lib.client.common_lib import error 9from autotest_lib.server.cros.faft.cr50_test import Cr50Test 10 11 12class firmware_Cr50CheckCap(Cr50Test): 13 """Verify cr50 capabilities""" 14 version = 1 15 16 # The default requirements for these capabilities change between prod and 17 # prepvt images. Make sure they match the expected values. 18 SPECIAL_CAPS = ['OpenNoDevMode', 'OpenFromUSB'] 19 EXPECTED_REQ_PREPVT = 'Always' 20 EXPECTED_REQ_PROD = 'IfOpened' 21 22 def check_cap_command(self, enable_factory, reset_caps): 23 """Verify the cr50 cap response after running the given command""" 24 if enable_factory: 25 self.cr50.ccd_reset_factory() 26 else: 27 # Testlab mode is enabled, so it's ok to reset ccd without enabling 28 # capabilities necessary for ccd. 29 self.cr50.ccd_reset(servo_en=False) 30 caps = self.cr50.get_cap_dict() 31 logging.info(caps) 32 in_factory_mode, is_reset = self.cr50.get_cap_overview(caps) 33 if reset_caps and not is_reset: 34 raise error.TestFail('did not reset capabilities') 35 if enable_factory and not in_factory_mode: 36 raise error.TestFail('did not enable factory mode') 37 38 39 def check_cap_req(self, cap_dict, cap, expected_req): 40 """Check the current cap requirement against the expected requirement""" 41 req = cap_dict[cap] 42 if req != expected_req: 43 raise error.TestFail('%r should be %r not %r' % (cap, expected_req, 44 req)) 45 46 47 def ccd_ec_uart_works(self): 48 """Returns True if the CCD ec uart works.""" 49 logging.info('checking ec console') 50 try: 51 self.servo.get('ec_board', self._ec_prefix) 52 logging.info('ccd ec console is responsive') 53 return True 54 except: 55 logging.info('ccd ec console is unresponsive') 56 return False 57 58 59 def check_cap_accessiblity(self, ccd_level, cap_setting, expect_accessible): 60 """Check setting cap requirements restricts the capabilities correctly. 61 62 Set each ccd capability to cap_setting. Set the ccd state to ccd_level. 63 Then verify the capability accessiblity matches expect_accessible. 64 65 Args: 66 ccd_level: a ccd state level: 'lock', 'unlock', or 'open'. 67 cap_setting: A ccd cap setting: 'IfOpened', 'Always', or 68 'UnlessLocked'. 69 expect_accessible: True if capabilities should be accessible 70 71 Raises: 72 TestFail if expect_accessible doesn't match the accessibility state. 73 """ 74 75 if (ccd_level == 'unlock' or cap_setting == 'UnlessLocked') \ 76 and not self.cr50.unlock_is_supported(): 77 return 78 79 # Run testlab open, so we won't have to do physical presence stuff. 80 self.cr50.send_command('ccd testlab open') 81 82 # Set all capabilities to cap_setting 83 caps = self.cr50.get_cap_dict().keys() 84 cap_settings = {} 85 for cap in caps: 86 cap_settings[cap] = cap_setting 87 self.cr50.set_caps(cap_settings) 88 89 # Set the ccd state to ccd_level 90 self.cr50.set_ccd_level(ccd_level, self.CCD_PASSWORD) 91 cap_dict = self.cr50.get_cap_dict() 92 logging.info('Cap state with console %r req %r:\n%s', ccd_level, 93 cap_setting, pprint.pformat(cap_dict)) 94 95 # Check the accessiblity 96 for cap, cap_info in cap_dict.items(): 97 if cap_info[self.cr50.CAP_IS_ACCESSIBLE] != expect_accessible: 98 raise error.TestFail('%r is %raccessible' % (cap, 99 'not ' if expect_accessible else '')) 100 101 if (self.check_ec_uart and 102 expect_accessible != self.ccd_ec_uart_works()): 103 raise error.TestFail('EC UART is %saccessible when it should%s be' % 104 ('not ' if expect_accessible else '', 105 '' if expect_accessible else "n't")) 106 107 108 def run_once(self, ccd_open_restricted=False): 109 """Check cr50 capabilities work correctly.""" 110 self.fast_ccd_open(enable_testlab=True) 111 112 113 # Check servo monitoring before changing the active device. There's no 114 # need for servo detection if ccd is the only device. 115 servo_detect_ok = (self.servo.main_device_is_ccd() 116 or self.cr50.check_servo_monitor()) 117 118 set_ccd = self.servo.enable_ccd_servo_device() 119 self._ec_prefix = self.servo.get_active_device_prefix() 120 # Only check EC uart if the board has a working EC and cr50 can detect 121 # servo connect/disconnect. 122 self.check_ec_uart = ( 123 set_ccd and servo_detect_ok 124 and self.check_ec_capability(suppress_warning=True) 125 and self.servo.active_device_is_ccd() 126 and self.servo.has_control('ec_board', self._ec_prefix)) 127 128 # Make sure factory reset sets all capabilities to Always 129 self.check_cap_command(True, False) 130 131 # Make sure ccd reset sets all capabilities to Default 132 self.check_cap_command(False, True) 133 134 expected_req = (self.EXPECTED_REQ_PROD if ccd_open_restricted else 135 self.EXPECTED_REQ_PREPVT) 136 cap_dict = self.cr50.get_cap_dict(info=self.cr50.CAP_REQ) 137 # Make sure the special ccd capabilities match ccd_open_restricted 138 for cap in self.SPECIAL_CAPS: 139 self.check_cap_req(cap_dict, cap, expected_req) 140 141 # Set the password so we can change the ccd level from the console 142 self.cr50.send_command('ccd testlab open') 143 # Testlab mode is enabled, so it's ok to reset ccd without enabling 144 # capabilities necessary for ccd. 145 self.cr50.ccd_reset(servo_en=False) 146 self.set_ccd_password(self.CCD_PASSWORD) 147 148 # Make sure ccd accessiblity behaves as expected based on the cap 149 # settings and the ccd state. 150 self.check_cap_accessiblity('open', 'IfOpened', True) 151 self.check_cap_accessiblity('open', 'UnlessLocked', True) 152 self.check_cap_accessiblity('open', 'Always', True) 153 154 self.check_cap_accessiblity('unlock', 'IfOpened', False) 155 self.check_cap_accessiblity('unlock', 'UnlessLocked', True) 156 self.check_cap_accessiblity('unlock', 'Always', True) 157 158 self.check_cap_accessiblity('lock', 'IfOpened', False) 159 self.check_cap_accessiblity('lock', 'UnlessLocked', False) 160 self.check_cap_accessiblity('lock', 'Always', True) 161