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 68 TrunksFtdiSpi::~TrunksFtdiSpi() { 69 if (mpsse_) 70 Close(mpsse_); 71 72 mpsse_ = NULL; 73 } 74 75 bool TrunksFtdiSpi::ReadTpmSts(uint32_t *status) { 76 return FtdiReadReg(TPM_STS_REG, sizeof(*status), status); 77 } 78 79 bool TrunksFtdiSpi::WriteTpmSts(uint32_t status) { 80 return FtdiWriteReg(TPM_STS_REG, sizeof(status), &status); 81 } 82 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 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 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 150 size_t TrunksFtdiSpi::GetBurstCount(void) { 151 uint32_t status; 152 153 ReadTpmSts(&status); 154 return (size_t)((status >> burstCountShift) & burstCountMask); 155 } 156 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 210 void TrunksFtdiSpi::SendCommand(const std::string& command, 211 const ResponseCallback& callback) { 212 printf("%s invoked\n", __func__); 213 } 214 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 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