Home | History | Annotate | Download | only in trunks
      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