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