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
34namespace trunks {
35
36// Locality management bits (in TPM_ACCESS_REG)
37enum TpmAccessBits {
38  tpmRegValidSts = (1 << 7),
39  activeLocality = (1 << 5),
40  requestUse = (1 << 1),
41  tpmEstablishment = (1 << 0),
42};
43
44enum 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.
64struct SpiFrameHeader {
65  unsigned char body[4];
66};
67
68TrunksFtdiSpi::~TrunksFtdiSpi() {
69  if (mpsse_)
70    Close(mpsse_);
71
72  mpsse_ = NULL;
73}
74
75bool TrunksFtdiSpi::ReadTpmSts(uint32_t* status) {
76  return FtdiReadReg(TPM_STS_REG, sizeof(*status), status);
77}
78
79bool TrunksFtdiSpi::WriteTpmSts(uint32_t status) {
80  return FtdiWriteReg(TPM_STS_REG, sizeof(status), &status);
81}
82
83void 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
124bool 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
136bool 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
153size_t TrunksFtdiSpi::GetBurstCount(void) {
154  uint32_t status;
155
156  ReadTpmSts(&status);
157  return (size_t)((status >> burstCountShift) & burstCountMask);
158}
159
160bool 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
213void TrunksFtdiSpi::SendCommand(const std::string& command,
214                                const ResponseCallback& callback) {
215  printf("%s invoked\n", __func__);
216}
217
218bool 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
237std::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