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.server.cros.faft.cr50_test import Cr50Test
9
10
11class firmware_Cr50Testlab(Cr50Test):
12    """Verify cr50 testlab enable/disable."""
13    version = 1
14    ACCESS_DENIED = 'Access Denied'
15    INVALID_PARAM = 'Parameter 1 invalid'
16    BASIC_ERROR = 'Usage: ccd '
17
18    def initialize(self, host, cmdline_args, full_args):
19        """Initialize servo. Check that it can access cr50"""
20        super(firmware_Cr50Testlab, self).initialize(host, cmdline_args,
21                full_args)
22
23        if not hasattr(self, 'cr50'):
24            raise error.TestNAError('Test can only be run on devices with '
25                                    'access to the Cr50 console')
26        if self.cr50.using_ccd():
27            raise error.TestNAError('Use a flex cable instead of CCD cable.')
28
29        if not self.cr50.has_command('ccdstate'):
30            raise error.TestNAError('Cannot test on Cr50 with old CCD version')
31
32        # Get the current reset count, so we can check that there haven't been
33        # any cr50 resets at any point during the test.
34        self.start_reset_count = self.servo.get('cr50_reset_count')
35
36
37    def try_testlab(self, mode, err=''):
38        """Try to modify ccd testlab mode.
39
40        Args:
41            mode: The testlab command: 'on', 'off', or 'open'
42            err: An empty string if the command should succeed or the error
43                 message.
44
45        Raises:
46            TestFail if setting the ccd testlab mode doesn't match err
47        """
48        logging.info('Setting ccd testlab %s', mode)
49        rv = self.cr50.send_command_get_output('ccd testlab %s' % mode,
50                ['ccd.*>'])[0]
51        logging.info(rv)
52        if err not in rv or (not err and self.BASIC_ERROR in rv):
53            raise error.TestFail('Unexpected result setting "%s": %r' % (mode,
54                    rv))
55        if err:
56            return
57
58        if mode == 'open':
59            if mode != self.cr50.get_ccd_level():
60                raise error.TestFail('ccd testlab open did not open the device')
61        else:
62            self.cr50.run_pp(self.cr50.PP_SHORT)
63            if (mode == 'on') != self.cr50.testlab_is_on():
64                raise error.TestFail('Testlab mode could not be turned %s' %
65                        mode)
66            logging.info('Set ccd testlab %s', mode)
67
68
69    def check_reset_count(self):
70        """Verify there haven't been any cr50 reboots"""
71        reset_count = self.servo.get('cr50_reset_count')
72        if self.start_reset_count != reset_count:
73            raise error.TestFail('Unexpected cr50 reboot')
74
75
76    def reset_ccd(self):
77        """Enable ccd testlab mode and set the privilege level to open"""
78        logging.info('Resetting CCD state')
79        # If testlab mode is enabled, use that to open ccd. It is a lot faster.
80        if self.cr50.testlab_is_on():
81            self.try_testlab('open')
82        else:
83            self.enter_mode_after_checking_tpm_state('dev')
84            self.ccd_open_from_ap()
85        self.try_testlab('on')
86        self.check_reset_count()
87
88
89    def run_once(self):
90        """Try to set testlab mode from different privilege levels."""
91        # Dummy isn't a valid mode. Make sure it fails
92        self.reset_ccd()
93        self.try_testlab('dummy', err=self.INVALID_PARAM)
94
95        # If ccd is locked, ccd testlab dummy should fail with access denied not
96        # invalid param.
97        self.reset_ccd()
98        self.cr50.set_ccd_level('lock')
99        self.try_testlab('dummy', err=self.ACCESS_DENIED)
100
101        # CCD can be opened without physical presence if testlab mode is enabled
102        self.reset_ccd()
103        self.try_testlab('on')
104        self.try_testlab('open')
105        self.check_reset_count()
106
107        # You shouldn't be able to use testlab open if it is disabled
108        self.reset_ccd()
109        self.try_testlab('off')
110        self.try_testlab('open', err=self.ACCESS_DENIED)
111        self.check_reset_count()
112
113        # You can't turn on testlab mode while ccd is locked
114        self.reset_ccd()
115        self.cr50.set_ccd_level('lock')
116        self.try_testlab('on', err=self.ACCESS_DENIED)
117        self.check_reset_count()
118
119        # You can't turn off testlab mode while ccd is locked
120        self.reset_ccd()
121        self.cr50.set_ccd_level('lock')
122        self.try_testlab('off', err=self.ACCESS_DENIED)
123        self.check_reset_count()
124
125        # If testlab mode is enabled, you can open the device without physical
126        # presence by using 'ccd testlab open'.
127        self.reset_ccd()
128        self.try_testlab('on')
129        self.cr50.set_ccd_level('lock')
130        self.try_testlab('open')
131        self.check_reset_count()
132
133        # If testlab mode is disabled, testlab open should fail with access
134        # denied.
135        self.reset_ccd()
136        self.try_testlab('off')
137        self.cr50.set_ccd_level('lock')
138        self.try_testlab('open', err=self.ACCESS_DENIED)
139        self.check_reset_count()
140        logging.info('ccd testlab is accessbile')
141