1# Copyright (c) 2011 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 time
7
8from autotest_lib.client.bin import test
9from autotest_lib.client.common_lib import error, smogcheck_tpm, \
10    smogcheck_ttci, smogcheck_util
11from autotest_lib.client.cros import service_stopper
12
13
14class hardware_TPMTakeOwnership(test.test):
15    """
16    Autotest test case to measure TPM_TakeOwnership timing data.
17    """
18    version = 1
19
20
21    def initialize(self):
22        smogcheck_util.enableI2C()
23        self.ttci_obj = None
24        self.tpm_obj = None
25        self.attr_dict = dict()  # Attributes to output
26        self.perf_dict = dict()  # Performance measures to output
27        self._services = service_stopper.ServiceStopper(['cryptohomed',
28                                                         'chapsd', 'tcsd'])
29        self._services.stop_services()
30
31
32    def _prepareTpmController(self):
33        """Prepare a TpmController instance for use.
34
35        Returns:
36          an operational TpmControler instance, ready to use.
37
38        Raises:
39          TestFail: if error creating a new TpmController instance.
40        """
41        try:
42            self.tpm_obj = smogcheck_tpm.TpmController()
43        except smogcheck_tpm.SmogcheckError as e:
44            raise error.TestFail('Error creating a TpmController: %s', e)
45
46
47    def _prepareTtciController(self):
48        """Prepare TtciController instances for use.
49
50        Returns:
51          an operational TtciController instance, ready to use.
52
53        Raises:
54          TestFail: if error creating a new TtciController instance.
55        """
56        try:
57            self.ttci_obj = smogcheck_ttci.TtciController()
58        except smogcheck_ttci.TtciError as e:
59            raise error.TestFail('Error creating a TtciController: %s' % e)
60
61
62    def _sleep(self, amount):
63        """Sleeps for 'amount' of time and logs a message.
64
65        Args:
66          amount: an integer or float in seconds.
67        """
68        time.sleep(amount)
69        if amount >= 1:
70            logging.debug('Slept for %0.2f second', amount)
71        elif amount >= 0.001:
72            logging.debug('Slept for %0.2f millisecond', (amount * 1000))
73        else:
74            logging.debug('Slept for %0.2f microsecond', (amount * 1000000))
75
76
77    def run_once(self, loop=-1, max_acceptable_delay=-1):
78        self._prepareTtciController()
79        self._prepareTpmController()
80
81        timestamps = dict()
82        time_list = []
83        try:
84            # Verify TPM is operational before triggering hardware Reset
85            self.tpm_obj.runTpmSelfTest()
86
87            # Activate hardware Reset signal
88            if self.ttci_obj.TTCI_Set_Reset_Control(turn_on=True):
89                raise error.TestFail('TTCI_Set_Reset_Control() error: %s' %
90                                     self.ttci_obj.err)
91            logging.info('TPM hardware Reset signal activated')
92
93            # Wait for 100 milisec
94            self._sleep(0.1)
95
96            # Deactivate hardware Reset signal
97            if self.ttci_obj.TTCI_Set_Reset_Control(turn_on=False):
98                raise error.TestFail('TTCI_Set_Reset_Control() error: %s' %
99                                     self.ttci_obj.err)
100            logging.info('TPM hardware Reset signal DEactivated')
101
102            # Run TPM_Starup
103            smogcheck_util.runInSubprocess(['tpmc', 'startup'])
104
105            # Run TPM_SelfTestFull
106            smogcheck_util.runInSubprocess(['tpmc', 'test'])
107
108            # Run TPM_AssertPhysicalPresence
109            smogcheck_util.runInSubprocess(['tpmc', 'ppon'])
110
111            # Run TPM_OwnerClear
112            smogcheck_util.runInSubprocess(['tpmc', 'clear'])
113
114            for i in range(loop):
115                smogcheck_util.runInSubprocess(['start', 'tcsd'])
116                # Wait 3 sec for tcsd to start
117                self._sleep(3)
118
119                # Run TPM_TakeOwnership and record elapsed time
120                timestamps[i] = self.tpm_obj.takeTpmOwnership()
121
122                smogcheck_util.runInSubprocess(['stop', 'tcsd'])
123                # Wait for 1 sec for tcsd to stop
124                self._sleep(1)
125
126                # Run TPM_OwnerClear
127                smogcheck_util.runInSubprocess(['tpmc', 'clear'])
128
129            # Output timing measurements
130            for k, v in timestamps.items():
131                sec, ms = divmod(v/1000, 1000)
132                key = 'iteration_%d_delay_in_sec' % k
133                delay_float = float(v)/1000000
134                self.perf_dict[key] = delay_float
135                time_list.append(delay_float)
136            self.perf_dict['num_total_iterations'] = len(timestamps)
137            # TODO(tgao): modify generate_test_report to support attr_dict
138            #self.attr_dict['timing_measurement_for'] = 'TPM_TakeOwnership'
139            time_list.sort()
140            time_list.reverse()
141            count = 0
142            for i in time_list:
143                if i <= max_acceptable_delay:
144                    break
145                logging.debug('Actual value (%0.2f) exceeds max (%0.2f)',
146                              i, max_acceptable_delay)
147                count += 1
148            self.perf_dict['num_iterations_exceeding_max_delay'] = count
149            self.perf_dict['max_acceptable_delay_in_sec'] = max_acceptable_delay
150            self.perf_dict['min_delay_in_sec_actual'] = time_list[-1]
151            # Set this attribute last. If it exceeds user-specified limit in
152            # test suite control file, output report would still be complete
153            self.perf_dict['max_delay_in_sec_actual'] = time_list[0]
154
155        except smogcheck_tpm.SmogcheckError as e:
156            raise error.TestFail('Error: %r' % e)
157        finally:
158            # Output attibutes and performance keyval pairs
159            self.write_iteration_keyval(self.attr_dict, self.perf_dict)
160
161            # Close TPM context
162            if self.tpm_obj.closeContext():
163                raise error.TestFail('Error closing tspi context')
164
165
166    def cleanup(self):
167        self._services.restore_services()
168