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