1c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# Use of this source code is governed by a BSD-style license that can be
3c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# found in the LICENSE file.
4c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
5be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam"""A module containing TPM handler class used by SAFT."""
6c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
7c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong TamFW_NV_ADDRESS = 0x1007
8c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong TamKERNEL_NV_ADDRESS = 0x1008
9c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
10c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass TpmError(Exception):
11c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    pass
12c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
13c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass TpmNvRam(object):
14be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam    """An object representing TPM NvRam.
15c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
16c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    Attributes:
17c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    addr: a number, NvRAm address in TPM.
18c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    size: a number, count of bites in this NvRam section.
19ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam    os_if: an instance of the OS interface (os_interface or a mock object).
20c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    version_offset: - a number, offset into the NvRam contents where the the
21c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        versions are stored. The total version field size is 4 bytes, the
22c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        first two bytes are the body version, the second two bytes are the key
23c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        version. Numbers are stored in little endian format.
24c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    pattern: optional, a tuple of two elements, the first element is the
25c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam       offset of the pattern expected to be present in the NvRam, and the
26c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam       second element is an array of bytes the pattern must match.
27c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    contents: an array of bytes, the contents of the NvRam.
28be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam    """
29c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
30c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def __init__(self, addr, size, version_offset, data_pattern=None):
31c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.addr = addr
32c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.size = size
33c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.os_if = None
34c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.version_offset = version_offset
35c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.pattern = data_pattern
36c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.contents = []
37c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
38c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def init(self, os_if):
39c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.os_if = os_if
40c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        cmd = 'tpmc read 0x%x 0x%x' % (self.addr, self.size)
41c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        nvram_data = self.os_if.run_shell_command_get_output(cmd)[0].split()
42c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.contents = [int(x, 16) for x in nvram_data]
43c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if self.pattern:
44c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            pattern_offset = self.pattern[0]
45c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            pattern_data = self.pattern[1]
46c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            contents_pattern = self.contents[pattern_offset:pattern_offset +
47c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                                             len(pattern_data)]
48c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if contents_pattern != pattern_data:
49c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                raise TpmError('Nvram pattern does not match')
50c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
51c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_body_version(self):
52c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return self.contents[
53c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self.version_offset + 1] * 256 + self.contents[self.version_offset]
54c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
55c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_key_version(self):
56c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return self.contents[
57c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self.version_offset + 3] * 256 + self.contents[
58c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self.version_offset + 2]
59c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
60c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass TpmHandler(object):
61be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam    """An object to control TPM device's NVRAM.
62c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
63c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    Attributes:
64ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam      os_if: an instance of the OS interface (os_interface or a mock object).
65c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      nvrams: A dictionary where the keys are the nvram names, and the values
66c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          are instances of TpmNvRam objects, providing access to the
67c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          appropriate TPM NvRam sections.
68be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam    """
69c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
70c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def __init__(self):
71ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam        self.os_if = None
72c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.nvrams = {
73c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            'kernel': TpmNvRam(KERNEL_NV_ADDRESS, 13, 5, (
74c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    1, [0x4c, 0x57, 0x52, 0x47])),
75c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            'bios': TpmNvRam(FW_NV_ADDRESS, 10, 2)
76c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            }
77d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        self.trunksd_started = False
78d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        self.tcsd_started = False
79c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
80ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam    def init(self, os_if):
81ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam        self.os_if = os_if
82d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        self.stop_daemon()
83c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for nvram in self.nvrams.itervalues():
84ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam            nvram.init(self.os_if)
85d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        self.restart_daemon()
8648d92dcbae5b30b14bb7af84652af7a8b0eb8612Wai-Hong Tam
87c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_fw_version(self):
88c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return self.nvrams['bios'].get_body_version()
89c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
9073d6adec5d387c330b85c4fd7e0473c84f651435Wai-Hong Tam    def get_fw_key_version(self):
91a4f655312719707e3df448bc5ff4e28eab9d388fChun-ting Chang        return self.nvrams['bios'].get_key_version()
92a4f655312719707e3df448bc5ff4e28eab9d388fChun-ting Chang
93c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_kernel_version(self):
94c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return self.nvrams['kernel'].get_body_version()
9573d6adec5d387c330b85c4fd7e0473c84f651435Wai-Hong Tam
9673d6adec5d387c330b85c4fd7e0473c84f651435Wai-Hong Tam    def get_kernel_key_version(self):
9773d6adec5d387c330b85c4fd7e0473c84f651435Wai-Hong Tam        return self.nvrams['kernel'].get_key_version()
98d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam
99d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam    def stop_daemon(self):
100d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        """Stop TPM related daemon."""
101d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        if self.trunksd_started or self.tcsd_started:
102d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam            raise TpmError('Called stop_daemon() before')
103d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam
104d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        cmd = 'initctl status tcsd || initctl status trunksd'
105d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        status = self.os_if.run_shell_command_get_output(cmd) or ['']
106d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        # Expected status is like ['trunksd start/running, process 2375']
107d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        self.trunksd_started = status[0].startswith('trunksd start/running')
108d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        if self.trunksd_started:
109d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam            self.os_if.run_shell_command('stop trunksd')
110d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        else:
111d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam            self.tcsd_started = status[0].startswith('tcsd start/running')
112d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam            if self.tcsd_started:
113d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam                self.os_if.run_shell_command('stop tcsd')
114d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam
115d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam    def restart_daemon(self):
116d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        """Restart TPM related daemon which was stopped by stop_daemon()."""
117d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        if self.trunksd_started:
118d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam            self.os_if.run_shell_command('start trunksd')
119d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam            self.trunksd_started = False
120d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam        elif self.tcsd_started:
121d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam            self.os_if.run_shell_command('start tcsd')
122d2eaa3f3af3f86aa7df0aed3726a0bff8ca526a2Wai-Hong Tam            self.tcsd_started = False
123