1 //
2 // Copyright (C) 2015 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include <algorithm>
18 #include <ctime>
19 #include <string>
20 #include <unistd.h>
21
22 #include <base/logging.h>
23
24 #include "trunks/tpm_generated.h"
25 #include "trunks/trunks_ftdi_spi.h"
26
27 // Assorted TPM2 registers for interface type FIFO.
28 #define TPM_ACCESS_REG 0
29 #define TPM_STS_REG 0x18
30 #define TPM_DATA_FIFO_REG 0x24
31 #define TPM_DID_VID_REG 0xf00
32 #define TPM_RID_REG 0xf04
33
34 namespace trunks {
35
36 // Locality management bits (in TPM_ACCESS_REG)
37 enum TpmAccessBits {
38 tpmRegValidSts = (1 << 7),
39 activeLocality = (1 << 5),
40 requestUse = (1 << 1),
41 tpmEstablishment = (1 << 0),
42 };
43
44 enum TpmStsBits {
45 tpmFamilyShift = 26,
46 tpmFamilyMask = ((1 << 2) - 1), // 2 bits wide
47 tpmFamilyTPM2 = 1,
48 resetEstablishmentBit = (1 << 25),
49 commandCancel = (1 << 24),
50 burstCountShift = 8,
51 burstCountMask = ((1 << 16) -1), // 16 bits wide
52 stsValid = (1 << 7),
53 commandReady = (1 << 6),
54 tpmGo = (1 << 5),
55 dataAvail = (1 << 4),
56 Expect = (1 << 3),
57 selfTestDone = (1 << 2),
58 responseRetry = (1 << 1),
59 };
60
61 // SPI frame header for TPM transactions is 4 bytes in size, it is described
62 // in section "6.4.6 Spi Bit Protocol" of the TCG issued "TPM Profile (PTP)
63 // Specification Revision 00.43.
64 struct SpiFrameHeader {
65 unsigned char body[4];
66 };
67
~TrunksFtdiSpi()68 TrunksFtdiSpi::~TrunksFtdiSpi() {
69 if (mpsse_)
70 Close(mpsse_);
71
72 mpsse_ = NULL;
73 }
74
ReadTpmSts(uint32_t * status)75 bool TrunksFtdiSpi::ReadTpmSts(uint32_t *status) {
76 return FtdiReadReg(TPM_STS_REG, sizeof(*status), status);
77 }
78
WriteTpmSts(uint32_t status)79 bool TrunksFtdiSpi::WriteTpmSts(uint32_t status) {
80 return FtdiWriteReg(TPM_STS_REG, sizeof(status), &status);
81 }
82
StartTransaction(bool read_write,size_t bytes,unsigned addr)83 void TrunksFtdiSpi::StartTransaction(bool read_write,
84 size_t bytes, unsigned addr) {
85 unsigned char *response;
86 SpiFrameHeader header;
87
88 usleep(10000); // give it 10 ms. TODO(vbendeb): remove this once
89 // cr50 SPS TPM driver performance is fixed.
90
91 // The first byte of the frame header encodes the transaction type (read or
92 // write) and size (set to lenth - 1).
93 header.body[0] = (read_write ? 0x80 : 0) | 0x40 | (bytes - 1);
94
95 // The rest of the frame header is the internal address in the TPM
96 for (int i = 0; i < 3; i++)
97 header.body[i + 1] = (addr >> (8 * (2 - i))) & 0xff;
98
99 Start(mpsse_);
100
101 response = Transfer(mpsse_, header.body, sizeof(header.body));
102
103 // The TCG TPM over SPI specification itroduces the notion of SPI flow
104 // control (Section "6.4.5 Flow Control" of the TCG issued "TPM Profile
105 // (PTP) Specification Revision 00.43).
106
107 // The slave (TPM device) expects each transaction to start with a 4 byte
108 // header trasmitted by master. If the slave needs to stall the transaction,
109 // it sets the MOSI bit to 0 during the last clock of the 4 byte header. In
110 // this case the master is supposed to start polling the line, byte at time,
111 // until the last bit in the received byte (transferred during the last
112 // clock of the byte) is set to 1.
113 while (!(response[3] & 1)) {
114 unsigned char *poll_state;
115
116 poll_state = Read(mpsse_, 1);
117 response[3] = *poll_state;
118 free(poll_state);
119 }
120 free(response);
121 }
122
FtdiWriteReg(unsigned reg_number,size_t bytes,const void * buffer)123 bool TrunksFtdiSpi::FtdiWriteReg(unsigned reg_number, size_t bytes,
124 const void *buffer) {
125 if (!mpsse_)
126 return false;
127
128 StartTransaction(false, bytes, reg_number + locality_ * 0x10000);
129 Write(mpsse_, buffer, bytes);
130 Stop(mpsse_);
131 return true;
132 }
133
FtdiReadReg(unsigned reg_number,size_t bytes,void * buffer)134 bool TrunksFtdiSpi::FtdiReadReg(unsigned reg_number, size_t bytes,
135 void *buffer) {
136 unsigned char *value;
137
138 if (!mpsse_)
139 return false;
140
141 StartTransaction(true, bytes, reg_number + locality_ * 0x10000);
142 value = Read(mpsse_, bytes);
143 if (buffer)
144 memcpy(buffer, value, bytes);
145 free(value);
146 Stop(mpsse_);
147 return true;
148 }
149
GetBurstCount(void)150 size_t TrunksFtdiSpi::GetBurstCount(void) {
151 uint32_t status;
152
153 ReadTpmSts(&status);
154 return (size_t)((status >> burstCountShift) & burstCountMask);
155 }
156
Init()157 bool TrunksFtdiSpi::Init() {
158 uint32_t did_vid, status;
159 uint8_t cmd;
160
161 if (mpsse_)
162 return true;
163
164 mpsse_ = MPSSE(SPI0, ONE_MHZ, MSB);
165 if (!mpsse_)
166 return false;
167
168 // Reset the TPM using GPIOL0, issue a 100 ms long pulse.
169 PinLow(mpsse_, GPIOL0);
170 usleep(100000);
171 PinHigh(mpsse_, GPIOL0);
172
173 FtdiReadReg(TPM_DID_VID_REG, sizeof(did_vid), &did_vid);
174
175 uint16_t vid = did_vid & 0xffff;
176 if ((vid != 0x15d1) && (vid != 0x1ae0)) {
177 LOG(ERROR) << "unknown did_vid: 0x" << std::hex << did_vid;
178 return false;
179 }
180
181 // Try claiming locality zero.
182 FtdiReadReg(TPM_ACCESS_REG, sizeof(cmd), &cmd);
183 // tpmEstablishment can be either set or not.
184 if ((cmd & ~tpmEstablishment) != tpmRegValidSts) {
185 LOG(ERROR) << "invalid reset status: 0x" << std::hex << (unsigned)cmd;
186 return false;
187 }
188 cmd = requestUse;
189 FtdiWriteReg(TPM_ACCESS_REG, sizeof(cmd), &cmd);
190 FtdiReadReg(TPM_ACCESS_REG, sizeof(cmd), &cmd);
191 if ((cmd & ~tpmEstablishment) != (tpmRegValidSts | activeLocality)) {
192 LOG(ERROR) << "failed to claim locality, status: 0x" << std::hex
193 << (unsigned)cmd;
194 return false;
195 }
196
197 ReadTpmSts(&status);
198 if (((status >> tpmFamilyShift) & tpmFamilyMask) != tpmFamilyTPM2) {
199 LOG(ERROR) << "unexpected TPM family value, status: 0x" << std::hex
200 << status;
201 return false;
202 }
203 FtdiReadReg(TPM_RID_REG, sizeof(cmd), &cmd);
204 printf("Connected to device vid:did:rid of %4.4x:%4.4x:%2.2x\n",
205 did_vid & 0xffff, did_vid >> 16, cmd);
206
207 return true;
208 }
209
SendCommand(const std::string & command,const ResponseCallback & callback)210 void TrunksFtdiSpi::SendCommand(const std::string& command,
211 const ResponseCallback& callback) {
212 printf("%s invoked\n", __func__);
213 }
214
WaitForStatus(uint32_t statusMask,uint32_t statusExpected,int timeout_ms)215 bool TrunksFtdiSpi::WaitForStatus(uint32_t statusMask,
216 uint32_t statusExpected, int timeout_ms) {
217 uint32_t status;
218 time_t target_time;
219
220 target_time = time(NULL) + timeout_ms / 1000;
221 do {
222 usleep(10000); // 10 ms polling period.
223 if (time(NULL) >= target_time) {
224 LOG(ERROR) << "failed to get expected status " << std::hex
225 << statusExpected;
226 return false;
227 }
228 ReadTpmSts(&status);
229 } while ((status & statusMask) != statusExpected);
230 return true;
231 }
232
SendCommandAndWait(const std::string & command)233 std::string TrunksFtdiSpi::SendCommandAndWait(const std::string& command) {
234 uint32_t status;
235 uint32_t expected_status_bits;
236 size_t transaction_size, handled_so_far(0);
237
238 std::string rv("");
239
240 if (!mpsse_) {
241 LOG(ERROR) << "attempt to use an uninitialized FTDI TPM!";
242 return rv;
243 }
244
245 WriteTpmSts(commandReady);
246
247 // No need to wait for the sts.Expect bit to be set, at least with the
248 // 15d1:001b device, let's just write the command into FIFO, not exceeding
249 // the minimum of the two values - burst_count and 64 (which is the protocol
250 // limitation)
251 do {
252 transaction_size = std::min(std::min(command.size() - handled_so_far,
253 GetBurstCount()),
254 (size_t)64);
255
256 if (transaction_size) {
257 LOG(INFO) << "will transfer " << transaction_size << " bytes";
258 FtdiWriteReg(TPM_DATA_FIFO_REG, transaction_size,
259 command.c_str() + handled_so_far);
260 handled_so_far += transaction_size;
261 }
262 } while (handled_so_far != command.size());
263
264 // And tell the device it can start processing it.
265 WriteTpmSts(tpmGo);
266
267 expected_status_bits = stsValid | dataAvail;
268 if (!WaitForStatus(expected_status_bits, expected_status_bits))
269 return rv;
270
271 // The response is ready, let's read it.
272 // First we read the FIFO payload header, to see how much data to expect.
273 // The header size is fixed to six bytes, the total payload size is stored
274 // in network order in the last four bytes of the header.
275 char data_header[6];
276
277 // Let's read the header first.
278 FtdiReadReg(TPM_DATA_FIFO_REG, sizeof(data_header), data_header);
279
280 // Figure out the total payload size.
281 uint32_t payload_size;
282 memcpy(&payload_size, data_header + 2, sizeof(payload_size));
283 payload_size = be32toh(payload_size);
284 // A FIFO message with the minimum required header and contents can not be
285 // less than 10 bytes long. It also should never be more than 4096 bytes
286 // long.
287 if ((payload_size < 10) || (payload_size > MAX_RESPONSE_SIZE)) {
288 // Something must be wrong...
289 LOG(ERROR) << "Bad total payload size value: " << payload_size;
290 return rv;
291 }
292
293 LOG(INFO) << "Total payload size " << payload_size;
294
295
296 // Let's read all but the last byte in the FIFO to make sure the status
297 // register is showing correct flow control bits: 'more data' until the last
298 // byte and then 'no more data' once the last byte is read.
299 handled_so_far = 0;
300 payload_size = payload_size - sizeof(data_header) - 1;
301 // Allow room for the last byte too.
302 uint8_t *payload = new uint8_t[payload_size + 1];
303 do {
304 transaction_size = std::min(std::min(payload_size - handled_so_far,
305 GetBurstCount()),
306 (size_t)64);
307
308 if (transaction_size) {
309 FtdiReadReg(TPM_DATA_FIFO_REG, transaction_size,
310 payload + handled_so_far);
311 handled_so_far += transaction_size;
312 }
313 } while (handled_so_far != payload_size);
314
315 // Verify that there is still data to come.
316 ReadTpmSts(&status);
317 if ((status & expected_status_bits) != expected_status_bits) {
318 LOG(ERROR) << "unexpected status 0x" << std::hex << status;
319 delete[] payload;
320 return rv;
321 }
322
323 // Now, read the last byte of the payload.
324 FtdiReadReg(TPM_DATA_FIFO_REG, sizeof(uint8_t), payload + payload_size);
325
326 // Verify that 'data available' is not asseretd any more.
327 ReadTpmSts(&status);
328 if ((status & expected_status_bits) != stsValid) {
329 LOG(ERROR) << "unexpected status 0x" << std::hex << status;
330 delete[] payload;
331 return rv;
332 }
333
334 rv = std::string(data_header, sizeof(data_header)) +
335 std::string(reinterpret_cast<char *>(payload), payload_size + 1);
336
337 /* Move the TPM back to idle state. */
338 WriteTpmSts(commandReady);
339
340 delete[] payload;
341 return rv;
342 }
343
344 } // namespace trunks
345