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