• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2010 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"""A module containing TPM handler class used by SAFT."""
5
6FW_NV_ADDRESS = 0x1007
7KERNEL_NV_ADDRESS = 0x1008
8
9
10class TpmError(Exception):
11    """An object to represent TPM errors"""
12    pass
13
14
15class TpmNvRam(object):
16    """An object representing TPM NvRam.
17
18    @ivar addr: a number, NvRAm address in TPM.
19    @ivar size: a number, count of bites in this NvRam section.
20    @ivar os_if: an instance of the OS interface (os_interface or a mock object)
21    @ivar version_offset: - a number, offset into the NvRam contents where the
22        the versions are stored. The total version field size is 4 bytes, the
23        first two bytes are the body version, the second two bytes are the key
24        version. Numbers are stored in little endian format.
25    @ivar pattern: optional, a tuple of two elements, the first element is the
26       offset of the pattern expected to be present in the NvRam, and the
27       second element is an array of bytes the pattern must match.
28    @ivar contents: an array of bytes, the contents of the NvRam.
29    @type os_if: autotest_lib.client.cros.faft.utils.os_interface.OSInterface
30    """
31
32    def __init__(self, os_if, addr, size, version_offset, data_pattern=None):
33        self.os_if = os_if
34        self.addr = addr
35        self.size = size
36        self.version_offset = version_offset
37        self.pattern = data_pattern
38        self.contents = []
39
40    def init(self):
41        """Initialize the object, loading tpm nvram information from the device.
42        """
43        cmd = 'tpmc read 0x%x 0x%x' % (self.addr, self.size)
44        nvram_data = self.os_if.run_shell_command_get_output(cmd)[0].split()
45        self.contents = [int(x, 16) for x in nvram_data]
46        if self.pattern:
47            pattern_offset = self.pattern[0]
48            pattern_data = self.pattern[1]
49            contents_pattern = self.contents[pattern_offset:pattern_offset +
50                                             len(pattern_data)]
51            if contents_pattern != pattern_data:
52                raise TpmError('Nvram pattern does not match')
53
54    def get_body_version(self):
55        return self.contents[self.version_offset + 1] * 256 + self.contents[
56                self.version_offset]
57
58    def get_key_version(self):
59        return self.contents[self.version_offset + 3] * 256 + self.contents[
60                self.version_offset + 2]
61
62
63class TpmHandler(object):
64    """An object to control TPM device's NVRAM.
65
66    @ivar os_if: an instance of the OS interface (os_interface or a mock object)
67    @ivar nvrams: A dictionary where the keys are nvram names, and the values
68          are instances of TpmNvRam objects, providing access to the
69          appropriate TPM NvRam sections.
70    @ivar tpm_version: Either "1.2" or "2.0".
71    @type os_if: autotest_lib.client.cros.faft.utils.os_interface.OSInterface
72    """
73
74    def __init__(self, os_if):
75        self.os_if = os_if
76        self.nvrams = {
77                'kernel':
78                TpmNvRam(
79                        self.os_if,
80                        addr=KERNEL_NV_ADDRESS,
81                        size=13,
82                        version_offset=5,
83                        data_pattern=(1, [0x4c, 0x57, 0x52, 0x47])),
84                'bios':
85                TpmNvRam(
86                        self.os_if,
87                        addr=FW_NV_ADDRESS,
88                        size=10,
89                        version_offset=2)
90        }
91        self.tpm_version = None
92        self.trunksd_started = False
93        self.tcsd_started = False
94        self.initialized = False
95
96    def init(self):
97        """Initialize the values of the nvram sections.
98
99        This is separate from object creation so it can be done only when a test
100        actually uses it.
101        """
102        self.stop_daemon()
103        for nvram in self.nvrams.itervalues():
104            nvram.init()
105        self.restart_daemon()
106        self.initialized = True
107
108    def get_fw_version(self):
109        return self.nvrams['bios'].get_body_version()
110
111    def get_fw_key_version(self):
112        return self.nvrams['bios'].get_key_version()
113
114    def get_kernel_version(self):
115        return self.nvrams['kernel'].get_body_version()
116
117    def get_kernel_key_version(self):
118        return self.nvrams['kernel'].get_key_version()
119
120    def get_tpm_version(self):
121        if self.tpm_version is None:
122            self.tpm_version = self.os_if.run_shell_command_get_output(
123                    'tpmc tpmver')[0]
124        return self.tpm_version
125
126    def stop_daemon(self):
127        """Stop TPM related daemon."""
128        if self.trunksd_started or self.tcsd_started:
129            raise TpmError('Called stop_daemon() before')
130
131        cmd = 'initctl status tcsd || initctl status trunksd'
132        status = self.os_if.run_shell_command_get_output(cmd) or ['']
133        # Expected status is like ['trunksd start/running, process 2375']
134        self.trunksd_started = status[0].startswith('trunksd start/running')
135        if self.trunksd_started:
136            self.os_if.run_shell_command('stop trunksd')
137        else:
138            self.tcsd_started = status[0].startswith('tcsd start/running')
139            if self.tcsd_started:
140                self.os_if.run_shell_command('stop tcsd')
141
142    def restart_daemon(self):
143        """Restart TPM related daemon which was stopped by stop_daemon()."""
144        if self.trunksd_started:
145            self.os_if.run_shell_command('start trunksd')
146            self.trunksd_started = False
147        elif self.tcsd_started:
148            self.os_if.run_shell_command('start tcsd')
149            self.tcsd_started = False
150