# Copyright 2018 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import pprint import logging from autotest_lib.client.common_lib import error from autotest_lib.server.cros.faft.cr50_test import Cr50Test class firmware_Cr50CheckCap(Cr50Test): """Verify cr50 capabilities""" version = 1 # The default requirements for these capabilities change between prod and # prepvt images. Make sure they match the expected values. SPECIAL_CAPS = ['OpenNoDevMode', 'OpenFromUSB'] EXPECTED_REQ_PREPVT = 'Always' EXPECTED_REQ_PROD = 'IfOpened' def check_cap_command(self, command, enable_factory, reset_caps): """Verify the cr50 cap response after running the given command""" self.cr50.send_command(command) caps = self.cr50.get_cap_dict() logging.info(caps) in_factory_mode, is_reset = self.cr50.get_cap_overview(caps) if reset_caps and not is_reset: raise error.TestFail('%r did not reset capabilities' % command) if enable_factory and not in_factory_mode: raise error.TestFail('%r did not enable factory mode' % command) def check_cap_req(self, cap_dict, cap, expected_req): """Check the current cap requirement against the expected requirement""" req = cap_dict[cap] if req != expected_req: raise error.TestFail('%r should be %r not %r' % (cap, expected_req, req)) def ccd_ec_uart_works(self): """Returns True if the CCD ec uart works.""" logging.info('checking ec console') try: self.servo.get('ec_board', self._ec_prefix) logging.info('ccd ec console is responsive') return True except: logging.info('ccd ec console is unresponsive') return False def check_cap_accessiblity(self, ccd_level, cap_setting, expect_accessible): """Check setting cap requirements restricts the capabilities correctly. Set each ccd capability to cap_setting. Set the ccd state to ccd_level. Then verify the capability accessiblity matches expect_accessible. Args: ccd_level: a ccd state level: 'lock', 'unlock', or 'open'. cap_setting: A ccd cap setting: 'IfOpened', 'Always', or 'UnlessLocked'. expect_accessible: True if capabilities should be accessible Raises: TestFail if expect_accessible doesn't match the accessibility state. """ # Run testlab open, so we won't have to do physical presence stuff. self.cr50.send_command('ccd testlab open') # Set all capabilities to cap_setting caps = self.cr50.get_cap_dict().keys() cap_settings = {} for cap in caps: cap_settings[cap] = cap_setting self.cr50.set_caps(cap_settings) # Set the ccd state to ccd_level self.cr50.set_ccd_level(ccd_level, self.CCD_PASSWORD) cap_dict = self.cr50.get_cap_dict() logging.info('Cap state with console %r req %r:\n%s', ccd_level, cap_setting, pprint.pformat(cap_dict)) # Check the accessiblity for cap, cap_info in cap_dict.iteritems(): if cap_info[self.cr50.CAP_IS_ACCESSIBLE] != expect_accessible: raise error.TestFail('%r is %raccessible' % (cap, 'not ' if expect_accessible else '')) if (self.check_ec_uart and expect_accessible != self.ccd_ec_uart_works()): raise error.TestFail('EC UART is %saccessible when it should%s be' % ('not ' if expect_accessible else '', '' if expect_accessible else "n't")) def run_once(self, ccd_open_restricted=False): """Check cr50 capabilities work correctly.""" self.fast_ccd_open(enable_testlab=True) self._ec_prefix = '' if self.servo.main_device_is_ccd() else 'ccd_cr50' # Only check EC uart if the board has a working EC and cr50 can detect # servo connect/disconnect. self.check_ec_uart = ( self.check_ec_capability(suppress_warning=True) and self.cr50.check_servo_monitor() and self.servo.has_control('ec_board', self._ec_prefix)) if self.check_ec_uart and self._ec_prefix: try: self.servo.set('active_v4_device', self._ec_prefix) except: self.check_ec_uart = False # Make sure factory reset sets all capabilities to Always self.check_cap_command('ccd reset factory', True, False) # Make sure ccd reset sets all capabilites to Default self.check_cap_command('ccd reset', False, True) expected_req = (self.EXPECTED_REQ_PROD if ccd_open_restricted else self.EXPECTED_REQ_PREPVT) cap_dict = self.cr50.get_cap_dict(info=self.cr50.CAP_REQ) # Make sure the special ccd capabilities match ccd_open_restricted for cap in self.SPECIAL_CAPS: self.check_cap_req(cap_dict, cap, expected_req) # Set the password so we can change the ccd level from the console self.cr50.send_command('ccd testlab open') self.cr50.send_command('ccd reset') self.set_ccd_password(self.CCD_PASSWORD) # Make sure ccd accessiblity behaves as expected based on the cap # settings and the ccd state. self.check_cap_accessiblity('open', 'IfOpened', True) self.check_cap_accessiblity('open', 'UnlessLocked', True) self.check_cap_accessiblity('open', 'Always', True) self.check_cap_accessiblity('unlock', 'IfOpened', False) self.check_cap_accessiblity('unlock', 'UnlessLocked', True) self.check_cap_accessiblity('unlock', 'Always', True) self.check_cap_accessiblity('lock', 'IfOpened', False) self.check_cap_accessiblity('lock', 'UnlessLocked', False) self.check_cap_accessiblity('lock', 'Always', True)