1 /*
2 * Implementation of the TCG BIOS extension according to the specification
3 * described in
4 * https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Copyright (C) IBM Corporation, 2006
20 *
21 * Author: Stefan Berger <stefanb@us.ibm.com>
22 */
23 #include "rombios_compat.h"
24 #include "util.h"
25
26 #include "tpm_drivers.h"
27 #include "tcgbios.h"
28
29 #define STS_VALID (1 << 7) /* 0x80 */
30 #define STS_COMMAND_READY (1 << 6) /* 0x40 */
31 #define STS_TPM_GO (1 << 5) /* 0x20 */
32 #define STS_DATA_AVAILABLE (1 << 4) /* 0x10 */
33 #define STS_EXPECT (1 << 3) /* 0x08 */
34 #define STS_RESPONSE_RETRY (1 << 1) /* 0x02 */
35
36 #define ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */
37 #define ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */
38 #define ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */
39 #define ACCESS_SEIZE (1 << 3) /* 0x08 */
40 #define ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */
41 #define ACCESS_REQUEST_USE (1 << 1) /* 0x02 */
42 #define ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */
43
tis_wait_sts(uint8_t * addr,uint32_t time,uint8_t mask,uint8_t expect)44 static uint32_t tis_wait_sts(uint8_t *addr, uint32_t time,
45 uint8_t mask, uint8_t expect)
46 {
47 uint32_t rc = 0;
48 while (time > 0) {
49 uint8_t sts = mmio_readb(&addr[TPM_STS]);
50 if ((sts & mask) == expect) {
51 rc = 1;
52 break;
53 }
54 mssleep(1);
55 time--;
56 }
57 return rc;
58 }
59
tis_activate(uint32_t baseaddr)60 static uint32_t tis_activate(uint32_t baseaddr)
61 {
62 uint32_t rc = 1;
63 uint8_t *tis_addr = (uint8_t*)baseaddr;
64 uint8_t acc;
65 /* request access to locality */
66 tis_addr[TPM_ACCESS] = ACCESS_REQUEST_USE;
67
68 acc = mmio_readb(&tis_addr[TPM_ACCESS]);
69 if ((acc & ACCESS_ACTIVE_LOCALITY) != 0) {
70 tis_addr[TPM_STS] = STS_COMMAND_READY;
71 rc = tis_wait_sts(tis_addr, 100,
72 STS_COMMAND_READY, STS_COMMAND_READY);
73 }
74 return rc;
75 }
76
tis_ready(uint32_t baseaddr)77 static uint32_t tis_ready(uint32_t baseaddr)
78 {
79 uint32_t rc = 0;
80 uint8_t *tis_addr = (uint8_t*)baseaddr;
81
82 tis_addr[TPM_STS] = STS_COMMAND_READY;
83 rc = tis_wait_sts(tis_addr, 100, STS_COMMAND_READY, STS_COMMAND_READY);
84
85 return rc;
86 }
87
tis_senddata(uint32_t baseaddr,unsigned char * data,uint32_t len)88 static uint32_t tis_senddata(uint32_t baseaddr, unsigned char *data, uint32_t len)
89 {
90 uint32_t rc = 0;
91 uint8_t *tis_addr = (uint8_t*)baseaddr;
92 uint32_t offset = 0;
93 uint32_t end = 0;
94
95 do {
96 uint16_t burst = 0;
97 uint32_t ctr = 0;
98 while (burst == 0 && ctr < 2000) {
99 burst = mmio_readw((uint16_t *)&tis_addr[TPM_STS+1]);
100 if (burst == 0) {
101 mssleep(1);
102 ctr++;
103 }
104 }
105
106 if (burst == 0) {
107 rc = TCG_RESPONSE_TIMEOUT;
108 break;
109 }
110
111 while (1) {
112 tis_addr[TPM_DATA_FIFO] = data[offset];
113 offset++;
114 burst--;
115
116 if (burst == 0 || offset == len) {
117 break;
118 }
119 }
120
121 if (offset == len) {
122 end = 1;
123 }
124 } while (end == 0);
125
126 return rc;
127 }
128
tis_readresp(uint32_t baseaddr,unsigned char * buffer,uint32_t len)129 static uint32_t tis_readresp(uint32_t baseaddr, unsigned char *buffer, uint32_t len)
130 {
131 uint32_t rc = 0;
132 uint32_t offset = 0;
133 uint8_t *tis_addr = (uint8_t*)baseaddr;
134 uint32_t sts;
135
136 while (offset < len) {
137 buffer[offset] = mmio_readb(&tis_addr[TPM_DATA_FIFO]);
138 offset++;
139 sts = mmio_readb(&tis_addr[TPM_STS]);
140 /* data left ? */
141 if ((sts & STS_DATA_AVAILABLE) == 0) {
142 break;
143 }
144 }
145 return rc;
146 }
147
148
tis_waitdatavalid(uint32_t baseaddr)149 static uint32_t tis_waitdatavalid(uint32_t baseaddr)
150 {
151 uint8_t *tis_addr = (uint8_t*)baseaddr;
152 uint32_t rc = 0;
153 if (tis_wait_sts(tis_addr, 1000, STS_VALID, STS_VALID) == 0) {
154 rc = TCG_NO_RESPONSE;
155 }
156 return rc;
157 }
158
tis_waitrespready(uint32_t baseaddr,uint32_t timeout)159 static uint32_t tis_waitrespready(uint32_t baseaddr, uint32_t timeout)
160 {
161 uint32_t rc = 0;
162 uint8_t *tis_addr = (uint8_t*)baseaddr;
163 tis_addr[TPM_STS] = STS_TPM_GO;
164 if (tis_wait_sts(tis_addr, timeout,
165 STS_DATA_AVAILABLE, STS_DATA_AVAILABLE) == 0) {
166 rc = TCG_NO_RESPONSE;
167 }
168 return rc;
169 }
170
171 /* if device is not there, return '0', '1' otherwise */
tis_probe(uint32_t baseaddr)172 static uint32_t tis_probe(uint32_t baseaddr)
173 {
174 uint32_t rc = 0;
175 uint8_t *tis_addr = (uint8_t*)baseaddr;
176 uint32_t didvid = mmio_readl((uint32_t *)&tis_addr[TPM_DID_VID]);
177 if ((didvid != 0) && (didvid != 0xffffffff)) {
178 rc = 1;
179 }
180 return rc;
181 }
182
183
184 struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
185 {
186 .baseaddr = TPM_TIS_BASE_ADDRESS,
187 .activate = tis_activate,
188 .ready = tis_ready,
189 .senddata = tis_senddata,
190 .readresp = tis_readresp,
191 .waitdatavalid = tis_waitdatavalid,
192 .waitrespready = tis_waitrespready,
193 .probe = tis_probe,
194 },
195 };
196