Skip to content

Commit e6ef0de

Browse files
Sae86npmitche
authored andcommitted
Add TPM2 support
Signed-off-by: Sara Batllori <sara.batllori@intel.com>
1 parent 9324c71 commit e6ef0de

7 files changed

Lines changed: 1098 additions & 403 deletions

File tree

chipsec/hal/tpm.py

Lines changed: 57 additions & 319 deletions
Large diffs are not rendered by default.

chipsec/hal/tpm_interface.py

Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
#CHIPSEC: Platform Security Assessment Framework
2+
#Copyright (c) 2010-2021, Intel Corporation
3+
#
4+
#This program is free software; you can redistribute it and/or
5+
#modify it under the terms of the GNU General Public License
6+
#as published by the Free Software Foundation; Version 2.
7+
#
8+
#This program is distributed in the hope that it will be useful,
9+
#but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
#GNU General Public License for more details.
12+
#
13+
#You should have received a copy of the GNU General Public License
14+
#along with this program; if not, write to the Free Software
15+
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16+
#
17+
#Contact information:
18+
#chipsec@intel.com
19+
#
20+
21+
22+
"""
23+
Trusted Platform Module (TPM) HAL component
24+
25+
https://trustedcomputinggroup.org
26+
"""
27+
28+
import struct
29+
from typing import Tuple
30+
31+
from chipsec.library.logger import print_buffer
32+
from chipsec.hal import hal_base
33+
from chipsec.library.tpm import tpm_defines
34+
35+
36+
class TPM_BASE(hal_base.HALBase):
37+
def __init__(self, cs):
38+
super(TPM_BASE, self).__init__(cs)
39+
self.TPM_BASE = self.cs.Cfg.MEMORY_RANGES['TPM']['address']
40+
self.access_address = 0x0
41+
42+
#def get_registers(self) -> list:
43+
# return self.list_of_registers
44+
45+
def request_locality(self, Locality: int) -> bool:
46+
self.access_address = self.TPM_BASE | Locality | tpm_defines.TPM_ACCESS
47+
if self.helper.read_mmio_reg(self.access_address, 4) == tpm_defines.BEENSEIZED:
48+
self.helper.write_mmio_reg(self.access_address, 4, tpm_defines.REQUESTUSE)
49+
return True
50+
return False
51+
52+
def command(self, commandName: str, locality: str, *command_argv: str) -> None:
53+
raise NotImplementedError()
54+
55+
def send_command(self, Locality: int, command: bytes, size: int) -> None:
56+
raise NotImplementedError()
57+
58+
def read_response(self, Locality: int) -> Tuple[tpm_defines.tpm1_commands.TPM_RESPONSE_HEADER, bytes, bytearray, bytearray]:
59+
raise NotImplementedError()
60+
61+
62+
class TPM1(TPM_BASE):
63+
def __init__(self, cs):
64+
super(TPM1, self).__init__(cs)
65+
self.helper = cs.helper
66+
67+
def command(self, commandName: str, locality: str, *command_argv: str) -> None:
68+
"""Send command to the TPM and receive data"""
69+
try:
70+
Locality = tpm_defines.LOCALITY[locality]
71+
except:
72+
if self.logger.HAL: self.logger.log_bad("Invalid locality value\n")
73+
return
74+
75+
requestedUse = self.request_locality(Locality)
76+
77+
#
78+
# Build command (big endian) and send/receive
79+
#
80+
(command, size) = tpm_defines.COMMANDS_12[commandName](command_argv)
81+
self.send_command(Locality, command, size)
82+
83+
(header, _, _, data_blob) = self.read_response(Locality)
84+
self.logger.log(str(header))
85+
print_buffer(str(data_blob))
86+
self.logger.log('\n')
87+
88+
#
89+
# Release locality if needed
90+
#
91+
if requestedUse:
92+
self.helper.write_mmio_reg(self.access_address, 4, tpm_defines.BEENSEIZED)
93+
self.helper.write_mmio_reg(self.access_address, 1, tpm_defines.ACTIVELOCALITY)
94+
95+
def send_command(self, Locality: int, command: bytes, size: int) -> None:
96+
"""Send a command to the TPM using the locality specified"""
97+
count = 0
98+
99+
datafifo_address = self.TPM_BASE | Locality | tpm_defines.TPM_DATAFIFO
100+
sts_address = self.TPM_BASE | Locality | tpm_defines.TPM_STS
101+
self.access_address = self.TPM_BASE | Locality | tpm_defines.TPM_ACCESS
102+
103+
self.helper.write_mmio_reg(self.access_address, 1, tpm_defines.REQUESTUSE)
104+
#
105+
# Set status to command ready
106+
#
107+
sts_value = self.helper.read_mmio_reg(sts_address, 1)
108+
while (0 == (sts_value & tpm_defines.COMMANDREADY)):
109+
self.helper.write_mmio_reg(sts_address, 1, tpm_defines.COMMANDREADY)
110+
sts_value = self.helper.read_mmio_reg(sts_address, 1)
111+
112+
while count < size:
113+
sts_value = self.helper.read_mmio_reg(sts_address, 4)
114+
burst_count = ((sts_value>>8) & 0xFFFFFF)
115+
burst_index = 0
116+
while (burst_index < burst_count) and (count < size):
117+
datafifo_value = command[count]
118+
self.helper.write_mmio_reg(datafifo_address, 1, datafifo_value)
119+
count += 1
120+
burst_index += 0x1
121+
122+
self.helper.write_mmio_reg(sts_address, 1, tpm_defines.TPMGO)
123+
124+
def read_response(self, Locality: int) -> Tuple[tpm_defines.tpm1_commands.TPM_RESPONSE_HEADER, bytes, bytearray, bytearray]:
125+
"""Read the TPM's response using the specified locality"""
126+
count = 0
127+
header = ""
128+
header_blob = bytearray()
129+
data = ""
130+
data_blob = bytearray()
131+
#
132+
# Build FIFO address
133+
#
134+
datafifo_address = self.TPM_BASE | Locality | tpm_defines.TPM_DATAFIFO
135+
self.access_address = self.TPM_BASE | Locality| tpm_defines.TPM_ACCESS
136+
sts_address = self.TPM_BASE | Locality| tpm_defines.TPM_STS
137+
138+
sts_value = self.helper.read_mmio_reg(sts_address, 1)
139+
data_avail = bin(sts_value & (1<<4))[2]
140+
#
141+
# Read data available
142+
#
143+
# watchdog?
144+
while data_avail == '0':
145+
sts_value = self.helper.read_mmio_reg(sts_address, 1)
146+
self.helper.write_mmio_reg(sts_address, 1, tpm_defines.DATAAVAIL)
147+
data_avail = bin(sts_value & (1<<4))[2]
148+
149+
while count < tpm_defines.HEADERSIZE:
150+
sts_value = self.helper.read_mmio_reg(sts_address, 4)
151+
burst_count = ((sts_value>>8) & 0xFFFFFF)
152+
burst_index = 0
153+
while (burst_index < burst_count) and (count < tpm_defines.HEADERSIZE):
154+
header_blob.append(self.helper.read_mmio_reg(datafifo_address, 1))
155+
count += 1
156+
burst_index += 0x1
157+
158+
header = tpm_defines.COMMANDS_12['header'](*struct.unpack_from(tpm_defines.HEADERFORMAT, header_blob))
159+
160+
count = 0
161+
if header.DataSize > 10 and header.ReturnCode == 0:
162+
length = header.DataSize - tpm_defines.HEADERSIZE
163+
while count < length:
164+
sts_value = self.helper.read_mmio_reg(sts_address, 4)
165+
burst_count = ((sts_value>>8) & 0xFFFFFF)
166+
burst_index = 0
167+
while (burst_index < burst_count) and (count < length):
168+
data_blob.append(self.helper.read_mmio_reg(datafifo_address, 1))
169+
count += 1
170+
burst_index += 0x1
171+
172+
return (header, data, header_blob, data_blob)
173+
174+
175+
class TPM2(TPM_BASE):
176+
def __init__(self, cs, buffer_type = 'fifo_legacy'):
177+
super(TPM2, self).__init__(cs)
178+
self.helper = cs.helper
179+
self.buffer_type = buffer_type
180+
181+
def command(self, commandName: str, locality: str, *command_argv: str) -> None:
182+
"""Send command to the TPM and receive data"""
183+
try:
184+
Locality = tpm_defines.LOCALITY[locality]
185+
except Exception as e:
186+
self.logger.log_bad(f"Invalid locality value\n\t{e}")
187+
return
188+
189+
requestedUse = self.request_locality(Locality)
190+
191+
#
192+
# Build command (big endian) and send/receive
193+
#
194+
try:
195+
(command, size) = tpm_defines.COMMANDS_20[commandName](command_argv)
196+
except Exception as e:
197+
self.logger.log_bad(f'Unable to build command\n\t{e}')
198+
return
199+
200+
try:
201+
self.send_command(Locality, command, size)
202+
except Exception as e:
203+
self.logger.log_bad(f'Unable to send command\n\t{e}')
204+
return
205+
(header, _, _, data_blob) = self.read_response(Locality)
206+
self.logger.log(str(header))
207+
print_buffer(str(data_blob))
208+
self.logger.log('\n')
209+
210+
#
211+
# Release locality if needed
212+
#
213+
if requestedUse:
214+
self.helper.write_mmio_reg(self.access_address, 4, tpm_defines.BEENSEIZED)
215+
self.helper.write_mmio_reg(self.access_address, 1, tpm_defines.ACTIVELOCALITY)
216+
217+
def send_command(self, Locality: int, command: bytes, size: int) -> None:
218+
"""Send a command to the TPM using the locality specified"""
219+
count = 0
220+
221+
datafifo_address = self.TPM_BASE | Locality | tpm_defines.TPM_DATAFIFO
222+
sts_address = self.TPM_BASE | Locality | tpm_defines.TPM_STS
223+
self.access_address = self.TPM_BASE | Locality | tpm_defines.TPM_ACCESS
224+
225+
self.helper.write_mmio_reg(self.access_address, 1, tpm_defines.REQUESTUSE)
226+
#
227+
# Set status to command ready
228+
#
229+
sts_value = self.helper.read_mmio_reg(sts_address, 1)
230+
while (0 == (sts_value & tpm_defines.COMMANDREADY)):
231+
self.helper.write_mmio_reg(sts_address, 1, tpm_defines.COMMANDREADY)
232+
sts_value = self.helper.read_mmio_reg(sts_address, 1)
233+
234+
while count < size:
235+
sts_value = self.helper.read_mmio_reg(sts_address, 4)
236+
burst_count = ((sts_value>>8) & 0xFFFFFF)
237+
burst_index = 0
238+
while (burst_index < burst_count) and (count < size):
239+
datafifo_value = command[count]
240+
self.helper.write_mmio_reg(datafifo_address, 1, datafifo_value)
241+
count += 1
242+
burst_index += 0x1
243+
244+
self.helper.write_mmio_reg(sts_address, 1, tpm_defines.TPMGO)
245+
246+
def read_response(self, Locality: int) -> Tuple[tpm_defines.tpm2_commands.TPM_RESPONSE_HEADER, bytes, bytearray, bytearray]:
247+
"""Read the TPM's response using the specified locality"""
248+
count = 0
249+
header = ""
250+
header_blob = bytearray()
251+
data = ""
252+
data_blob = bytearray()
253+
#
254+
# Build FIFO address
255+
#
256+
datafifo_address = self.TPM_BASE | Locality | tpm_defines.TPM_DATAFIFO
257+
self.access_address = self.TPM_BASE | Locality| tpm_defines.TPM_ACCESS
258+
sts_address = self.TPM_BASE | Locality| tpm_defines.TPM_STS
259+
260+
sts_value = self.helper.read_mmio_reg(sts_address, 1)
261+
data_avail = bin(sts_value & (1<<4))[2]
262+
#
263+
# Read data available
264+
#
265+
# watchdog?
266+
while data_avail == '0':
267+
sts_value = self.helper.read_mmio_reg(sts_address, 1)
268+
self.helper.write_mmio_reg(sts_address, 1, tpm_defines.DATAAVAIL)
269+
data_avail = bin(sts_value & (1<<4))[2]
270+
271+
while count < tpm_defines.HEADERSIZE:
272+
sts_value = self.helper.read_mmio_reg(sts_address, 4)
273+
burst_count = ((sts_value>>8) & 0xFFFFFF)
274+
burst_index = 0
275+
while (burst_index < burst_count) and (count < tpm_defines.HEADERSIZE):
276+
header_blob.append(self.helper.read_mmio_reg(datafifo_address, 1))
277+
count += 1
278+
burst_index += 0x1
279+
280+
header = tpm_defines.COMMANDS_20['header'](*struct.unpack_from(tpm_defines.HEADERFORMAT, header_blob))
281+
282+
count = 0
283+
if header.DataSize > 10 and header.ReturnCode == 0:
284+
length = header.DataSize - tpm_defines.HEADERSIZE
285+
while count < length:
286+
sts_value = self.helper.read_mmio_reg(sts_address, 4)
287+
burst_count = ((sts_value>>8) & 0xFFFFFF)
288+
burst_index = 0
289+
while (burst_index < burst_count) and (count < length):
290+
data_blob.append(self.helper.read_mmio_reg(datafifo_address, 1))
291+
count += 1
292+
burst_index += 0x1
293+
294+
return (header, data, header_blob, data_blob)
295+
296+
297+
# class TPM2_CRB(TPM_BASE):
298+
# def __init__(self, cs):
299+
# super(TPM2_CRB, self).__init__(cs)
300+
# self.helper = cs.helper
301+
# self.TPM_BASE = self.cs.Cfg.MEMORY_RANGES['TPM']['address']
302+
# self.list_of_registers = []
303+
304+
# def send_command(self, Locality: int, command: bytes, size: int) -> None:
305+
# raise NotImplementedError()
306+
307+
# def read_response(self, Locality: int) -> Tuple[TPM_RESPONSE_HEADER, bytes, bytearray, bytearray]:
308+
# raise NotImplementedError()
309+
310+
311+
# class TPM2_FIFO_LEGACY(TPM1):
312+
# def __init__(self, cs):
313+
# super(TPM2_FIFO_LEGACY, self).__init__(cs)
314+
# self.helper = cs.helper
315+
# self.TPM_BASE = self.cs.Cfg.MEMORY_RANGES['TPM']['address']
316+
# self.list_of_registers = ['TPM_ACCESS', 'TPM_STS', 'TPM_DID_VID', 'TPM_RID', 'TPM_INTF_CAPABILITY', 'TPM_INT_ENABLE']

0 commit comments

Comments
 (0)