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,
85 unsigned addr) {
86 unsigned char* response;
87 SpiFrameHeader header;
88
89 usleep(10000); // give it 10 ms. TODO(vbendeb): remove this once
90 // cr50 SPS TPM driver performance is fixed.
91
92 // The first byte of the frame header encodes the transaction type (read or
93 // write) and size (set to lenth - 1).
94 header.body[0] = (read_write ? 0x80 : 0) | 0x40 | (bytes - 1);
95
96 // The rest of the frame header is the internal address in the TPM
97 for (int i = 0; i < 3; i++)
98 header.body[i + 1] = (addr >> (8 * (2 - i))) & 0xff;
99
100 Start(mpsse_);
101
102 response = Transfer(mpsse_, header.body, sizeof(header.body));
103
104 // The TCG TPM over SPI specification itroduces the notion of SPI flow
105 // control (Section "6.4.5 Flow Control" of the TCG issued "TPM Profile
106 // (PTP) Specification Revision 00.43).
107
108 // The slave (TPM device) expects each transaction to start with a 4 byte
109 // header trasmitted by master. If the slave needs to stall the transaction,
110 // it sets the MOSI bit to 0 during the last clock of the 4 byte header. In
111 // this case the master is supposed to start polling the line, byte at time,
112 // until the last bit in the received byte (transferred during the last
113 // clock of the byte) is set to 1.
114 while (!(response[3] & 1)) {
115 unsigned char* poll_state;
116
117 poll_state = Read(mpsse_, 1);
118 response[3] = *poll_state;
119 free(poll_state);
120 }
121 free(response);
122 }
123
FtdiWriteReg(unsigned reg_number,size_t bytes,const void * buffer)124 bool TrunksFtdiSpi::FtdiWriteReg(unsigned reg_number,
125 size_t bytes,
126 const void* buffer) {
127 if (!mpsse_)
128 return false;
129
130 StartTransaction(false, bytes, reg_number + locality_ * 0x10000);
131 Write(mpsse_, buffer, bytes);
132 Stop(mpsse_);
133 return true;
134 }
135
FtdiReadReg(unsigned reg_number,size_t bytes,void * buffer)136 bool TrunksFtdiSpi::FtdiReadReg(unsigned reg_number,
137 size_t bytes,
138 void* buffer) {
139 unsigned char* value;
140
141 if (!mpsse_)
142 return false;
143
144 StartTransaction(true, bytes, reg_number + locality_ * 0x10000);
145 value = Read(mpsse_, bytes);
146 if (buffer)
147 memcpy(buffer, value, bytes);
148 free(value);
149 Stop(mpsse_);
150 return true;
151 }
152
GetBurstCount(void)153 size_t TrunksFtdiSpi::GetBurstCount(void) {
154 uint32_t status;
155
156 ReadTpmSts(&status);
157 return (size_t)((status >> burstCountShift) & burstCountMask);
158 }
159
Init()160 bool TrunksFtdiSpi::Init() {
161 uint32_t did_vid, status;
162 uint8_t cmd;
163
164 if (mpsse_)
165 return true;
166
167 mpsse_ = MPSSE(SPI0, ONE_MHZ, MSB);
168 if (!mpsse_)
169 return false;
170
171 // Reset the TPM using GPIOL0, issue a 100 ms long pulse.
172 PinLow(mpsse_, GPIOL0);
173 usleep(100000);
174 PinHigh(mpsse_, GPIOL0);
175
176 FtdiReadReg(TPM_DID_VID_REG, sizeof(did_vid), &did_vid);
177
178 uint16_t vid = did_vid & 0xffff;
179 if ((vid != 0x15d1) && (vid != 0x1ae0)) {
180 LOG(ERROR) << "unknown did_vid: 0x" << std::hex << did_vid;
181 return false;
182 }
183
184 // Try claiming locality zero.
185 FtdiReadReg(TPM_ACCESS_REG, sizeof(cmd), &cmd);
186 // tpmEstablishment can be either set or not.
187 if ((cmd & ~tpmEstablishment) != tpmRegValidSts) {
188 LOG(ERROR) << "invalid reset status: 0x" << std::hex << (unsigned)cmd;
189 return false;
190 }
191 cmd = requestUse;
192 FtdiWriteReg(TPM_ACCESS_REG, sizeof(cmd), &cmd);
193 FtdiReadReg(TPM_ACCESS_REG, sizeof(cmd), &cmd);
194 if ((cmd & ~tpmEstablishment) != (tpmRegValidSts | activeLocality)) {
195 LOG(ERROR) << "failed to claim locality, status: 0x" << std::hex
196 << (unsigned)cmd;
197 return false;
198 }
199
200 ReadTpmSts(&status);
201 if (((status >> tpmFamilyShift) & tpmFamilyMask) != tpmFamilyTPM2) {
202 LOG(ERROR) << "unexpected TPM family value, status: 0x" << std::hex
203 << status;
204 return false;
205 }
206 FtdiReadReg(TPM_RID_REG, sizeof(cmd), &cmd);
207 printf("Connected to device vid:did:rid of %4.4x:%4.4x:%2.2x\n",
208 did_vid & 0xffff, did_vid >> 16, cmd);
209
210 return true;
211 }
212
SendCommand(const std::string & command,const ResponseCallback & callback)213 void TrunksFtdiSpi::SendCommand(const std::string& command,
214 const ResponseCallback& callback) {
215 printf("%s invoked\n", __func__);
216 }
217
WaitForStatus(uint32_t statusMask,uint32_t statusExpected,int timeout_ms)218 bool TrunksFtdiSpi::WaitForStatus(uint32_t statusMask,
219 uint32_t statusExpected,
220 int timeout_ms) {
221 uint32_t status;
222 time_t target_time;
223
224 target_time = time(NULL) + timeout_ms / 1000;
225 do {
226 usleep(10000); // 10 ms polling period.
227 if (time(NULL) >= target_time) {
228 LOG(ERROR) << "failed to get expected status " << std::hex
229 << statusExpected;
230 return false;
231 }
232 ReadTpmSts(&status);
233 } while ((status & statusMask) != statusExpected);
234 return true;
235 }
236
SendCommandAndWait(const std::string & command)237 std::string TrunksFtdiSpi::SendCommandAndWait(const std::string& command) {
238 uint32_t status;
239 uint32_t expected_status_bits;
240 size_t transaction_size, handled_so_far(0);
241
242 std::string rv("");
243
244 if (!mpsse_) {
245 LOG(ERROR) << "attempt to use an uninitialized FTDI TPM!";
246 return rv;
247 }
248
249 WriteTpmSts(commandReady);
250
251 // No need to wait for the sts.Expect bit to be set, at least with the
252 // 15d1:001b device, let's just write the command into FIFO, not exceeding
253 // the minimum of the two values - burst_count and 64 (which is the protocol
254 // limitation)
255 do {
256 transaction_size = std::min(
257 std::min(command.size() - handled_so_far, GetBurstCount()), (size_t)64);
258
259 if (transaction_size) {
260 LOG(INFO) << "will transfer " << transaction_size << " bytes";
261 FtdiWriteReg(TPM_DATA_FIFO_REG, transaction_size,
262 command.c_str() + handled_so_far);
263 handled_so_far += transaction_size;
264 }
265 } while (handled_so_far != command.size());
266
267 // And tell the device it can start processing it.
268 WriteTpmSts(tpmGo);
269
270 expected_status_bits = stsValid | dataAvail;
271 if (!WaitForStatus(expected_status_bits, expected_status_bits))
272 return rv;
273
274 // The response is ready, let's read it.
275 // First we read the FIFO payload header, to see how much data to expect.
276 // The header size is fixed to six bytes, the total payload size is stored
277 // in network order in the last four bytes of the header.
278 char data_header[6];
279
280 // Let's read the header first.
281 FtdiReadReg(TPM_DATA_FIFO_REG, sizeof(data_header), data_header);
282
283 // Figure out the total payload size.
284 uint32_t payload_size;
285 memcpy(&payload_size, data_header + 2, sizeof(payload_size));
286 payload_size = be32toh(payload_size);
287 // A FIFO message with the minimum required header and contents can not be
288 // less than 10 bytes long. It also should never be more than 4096 bytes
289 // long.
290 if ((payload_size < 10) || (payload_size > MAX_RESPONSE_SIZE)) {
291 // Something must be wrong...
292 LOG(ERROR) << "Bad total payload size value: " << payload_size;
293 return rv;
294 }
295
296 LOG(INFO) << "Total payload size " << payload_size;
297
298 // Let's read all but the last byte in the FIFO to make sure the status
299 // register is showing correct flow control bits: 'more data' until the last
300 // byte and then 'no more data' once the last byte is read.
301 handled_so_far = 0;
302 payload_size = payload_size - sizeof(data_header) - 1;
303 // Allow room for the last byte too.
304 uint8_t* payload = new uint8_t[payload_size + 1];
305 do {
306 transaction_size = std::min(
307 std::min(payload_size - handled_so_far, GetBurstCount()), (size_t)64);
308
309 if (transaction_size) {
310 FtdiReadReg(TPM_DATA_FIFO_REG, transaction_size,
311 payload + handled_so_far);
312 handled_so_far += transaction_size;
313 }
314 } while (handled_so_far != payload_size);
315
316 // Verify that there is still data to come.
317 ReadTpmSts(&status);
318 if ((status & expected_status_bits) != expected_status_bits) {
319 LOG(ERROR) << "unexpected status 0x" << std::hex << status;
320 delete[] payload;
321 return rv;
322 }
323
324 // Now, read the last byte of the payload.
325 FtdiReadReg(TPM_DATA_FIFO_REG, sizeof(uint8_t), payload + payload_size);
326
327 // Verify that 'data available' is not asseretd any more.
328 ReadTpmSts(&status);
329 if ((status & expected_status_bits) != stsValid) {
330 LOG(ERROR) << "unexpected status 0x" << std::hex << status;
331 delete[] payload;
332 return rv;
333 }
334
335 rv = std::string(data_header, sizeof(data_header)) +
336 std::string(reinterpret_cast<char*>(payload), payload_size + 1);
337
338 /* Move the TPM back to idle state. */
339 WriteTpmSts(commandReady);
340
341 delete[] payload;
342 return rv;
343 }
344
345 } // namespace trunks
346