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,
     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 
    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 
    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 
    153 size_t TrunksFtdiSpi::GetBurstCount(void) {
    154   uint32_t status;
    155 
    156   ReadTpmSts(&status);
    157   return (size_t)((status >> burstCountShift) & burstCountMask);
    158 }
    159 
    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 
    213 void TrunksFtdiSpi::SendCommand(const std::string& command,
    214                                 const ResponseCallback& callback) {
    215   printf("%s invoked\n", __func__);
    216 }
    217 
    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 
    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