1bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// 2bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// Copyright (C) 2015 The Android Open Source Project 3bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// 4bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// Licensed under the Apache License, Version 2.0 (the "License"); 5bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// you may not use this file except in compliance with the License. 6bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// You may obtain a copy of the License at 7bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// 8bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// http://www.apache.org/licenses/LICENSE-2.0 9bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// 10bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// Unless required by applicable law or agreed to in writing, software 11bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// distributed under the License is distributed on an "AS IS" BASIS, 12bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// See the License for the specific language governing permissions and 14bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// limitations under the License. 15bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// 16c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury 17c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury#include <algorithm> 18b21ea123afb354647305411a51d318067544606cVadim Bendebury#include <ctime> 19c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury#include <string> 2095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury#include <unistd.h> 2195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 2295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury#include <base/logging.h> 23c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury 24c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury#include "trunks/tpm_generated.h" 25c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury#include "trunks/trunks_ftdi_spi.h" 26c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury 2795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury// Assorted TPM2 registers for interface type FIFO. 284dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn#define TPM_ACCESS_REG 0 294dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn#define TPM_STS_REG 0x18 306b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury#define TPM_DATA_FIFO_REG 0x24 314dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn#define TPM_DID_VID_REG 0xf00 324dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn#define TPM_RID_REG 0xf04 3395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 34c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendeburynamespace trunks { 35c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury 3695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury// Locality management bits (in TPM_ACCESS_REG) 3795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendeburyenum TpmAccessBits { 3895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury tpmRegValidSts = (1 << 7), 3995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury activeLocality = (1 << 5), 4095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury requestUse = (1 << 1), 4195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury tpmEstablishment = (1 << 0), 4295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury}; 4395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 446b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendeburyenum TpmStsBits { 456b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury tpmFamilyShift = 26, 466b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury tpmFamilyMask = ((1 << 2) - 1), // 2 bits wide 476b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury tpmFamilyTPM2 = 1, 486b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury resetEstablishmentBit = (1 << 25), 496b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury commandCancel = (1 << 24), 506b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury burstCountShift = 8, 514dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn burstCountMask = ((1 << 16) - 1), // 16 bits wide 526b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury stsValid = (1 << 7), 536b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury commandReady = (1 << 6), 546b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury tpmGo = (1 << 5), 556b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury dataAvail = (1 << 4), 566b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury Expect = (1 << 3), 576b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury selfTestDone = (1 << 2), 586b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury responseRetry = (1 << 1), 596b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury}; 606b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury 614dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn// SPI frame header for TPM transactions is 4 bytes in size, it is described 624dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn// in section "6.4.6 Spi Bit Protocol" of the TCG issued "TPM Profile (PTP) 634dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn// Specification Revision 00.43. 6495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendeburystruct SpiFrameHeader { 6595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury unsigned char body[4]; 6695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury}; 6795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 6895146cebd9272c71e3b3b48e12d658e57e7a328bVadim BendeburyTrunksFtdiSpi::~TrunksFtdiSpi() { 6995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury if (mpsse_) 7095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury Close(mpsse_); 7195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 7295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury mpsse_ = NULL; 7395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury} 7495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 754dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahnbool TrunksFtdiSpi::ReadTpmSts(uint32_t* status) { 7632f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury return FtdiReadReg(TPM_STS_REG, sizeof(*status), status); 776b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury} 786b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury 796b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendeburybool TrunksFtdiSpi::WriteTpmSts(uint32_t status) { 806b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury return FtdiWriteReg(TPM_STS_REG, sizeof(status), &status); 816b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury} 826b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury 8395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendeburyvoid TrunksFtdiSpi::StartTransaction(bool read_write, 844dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn size_t bytes, 854dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn unsigned addr) { 864dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn unsigned char* response; 8795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury SpiFrameHeader header; 8895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 8970e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury usleep(10000); // give it 10 ms. TODO(vbendeb): remove this once 9070e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury // cr50 SPS TPM driver performance is fixed. 9170e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury 9295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // The first byte of the frame header encodes the transaction type (read or 9395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // write) and size (set to lenth - 1). 9495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury header.body[0] = (read_write ? 0x80 : 0) | 0x40 | (bytes - 1); 9595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 9695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // The rest of the frame header is the internal address in the TPM 9795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury for (int i = 0; i < 3; i++) 9895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury header.body[i + 1] = (addr >> (8 * (2 - i))) & 0xff; 9995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 10095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury Start(mpsse_); 10195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 10295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury response = Transfer(mpsse_, header.body, sizeof(header.body)); 10395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 10495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // The TCG TPM over SPI specification itroduces the notion of SPI flow 10595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // control (Section "6.4.5 Flow Control" of the TCG issued "TPM Profile 10695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // (PTP) Specification Revision 00.43). 10795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 10895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // The slave (TPM device) expects each transaction to start with a 4 byte 10995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // header trasmitted by master. If the slave needs to stall the transaction, 11095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // it sets the MOSI bit to 0 during the last clock of the 4 byte header. In 11195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // this case the master is supposed to start polling the line, byte at time, 11295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // until the last bit in the received byte (transferred during the last 11395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // clock of the byte) is set to 1. 11495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury while (!(response[3] & 1)) { 1154dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn unsigned char* poll_state; 11695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 11795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury poll_state = Read(mpsse_, 1); 11895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury response[3] = *poll_state; 11995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury free(poll_state); 12095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury } 12195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury free(response); 12295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury} 123c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury 1244dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahnbool TrunksFtdiSpi::FtdiWriteReg(unsigned reg_number, 1254dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn size_t bytes, 1264dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn const void* buffer) { 12795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury if (!mpsse_) 12895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury return false; 12995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 130ea14a6e1838ea01103d88cbc9ccc2eb7e57483ddVadim Bendebury StartTransaction(false, bytes, reg_number + locality_ * 0x10000); 13195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury Write(mpsse_, buffer, bytes); 13295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury Stop(mpsse_); 13395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury return true; 13495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury} 13595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 1364dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahnbool TrunksFtdiSpi::FtdiReadReg(unsigned reg_number, 1374dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn size_t bytes, 1384dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn void* buffer) { 1394dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn unsigned char* value; 14095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 14195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury if (!mpsse_) 14295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury return false; 14395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 144ea14a6e1838ea01103d88cbc9ccc2eb7e57483ddVadim Bendebury StartTransaction(true, bytes, reg_number + locality_ * 0x10000); 14595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury value = Read(mpsse_, bytes); 14695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury if (buffer) 14795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury memcpy(buffer, value, bytes); 14895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury free(value); 14995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury Stop(mpsse_); 15095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury return true; 15195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury} 152c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury 153c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendeburysize_t TrunksFtdiSpi::GetBurstCount(void) { 154c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury uint32_t status; 155c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury 156c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury ReadTpmSts(&status); 157c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury return (size_t)((status >> burstCountShift) & burstCountMask); 158c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury} 159c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury 160c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendeburybool TrunksFtdiSpi::Init() { 1616b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury uint32_t did_vid, status; 16295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury uint8_t cmd; 16395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 16495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury if (mpsse_) 16595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury return true; 16695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 167d3cd697fc61df7347db8c1d3589a1fee50ed90f0Vadim Bendebury mpsse_ = MPSSE(SPI0, ONE_MHZ, MSB); 16895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury if (!mpsse_) 16995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury return false; 17095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 17195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // Reset the TPM using GPIOL0, issue a 100 ms long pulse. 17295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury PinLow(mpsse_, GPIOL0); 17395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury usleep(100000); 17495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury PinHigh(mpsse_, GPIOL0); 17595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 17695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury FtdiReadReg(TPM_DID_VID_REG, sizeof(did_vid), &did_vid); 17795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 17870e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury uint16_t vid = did_vid & 0xffff; 17970e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury if ((vid != 0x15d1) && (vid != 0x1ae0)) { 18070e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury LOG(ERROR) << "unknown did_vid: 0x" << std::hex << did_vid; 18195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury return false; 18295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury } 18395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 18495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury // Try claiming locality zero. 18595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury FtdiReadReg(TPM_ACCESS_REG, sizeof(cmd), &cmd); 18670e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury // tpmEstablishment can be either set or not. 18770e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury if ((cmd & ~tpmEstablishment) != tpmRegValidSts) { 18895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury LOG(ERROR) << "invalid reset status: 0x" << std::hex << (unsigned)cmd; 18995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury return false; 19095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury } 19195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury cmd = requestUse; 19295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury FtdiWriteReg(TPM_ACCESS_REG, sizeof(cmd), &cmd); 19395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury FtdiReadReg(TPM_ACCESS_REG, sizeof(cmd), &cmd); 1944dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn if ((cmd & ~tpmEstablishment) != (tpmRegValidSts | activeLocality)) { 19595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury LOG(ERROR) << "failed to claim locality, status: 0x" << std::hex 19695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury << (unsigned)cmd; 19795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury return false; 19895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury } 19995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 2006b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury ReadTpmSts(&status); 2016b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury if (((status >> tpmFamilyShift) & tpmFamilyMask) != tpmFamilyTPM2) { 2026b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury LOG(ERROR) << "unexpected TPM family value, status: 0x" << std::hex 2036b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury << status; 2046b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury return false; 2056b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury } 20695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury FtdiReadReg(TPM_RID_REG, sizeof(cmd), &cmd); 20795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury printf("Connected to device vid:did:rid of %4.4x:%4.4x:%2.2x\n", 20895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury did_vid & 0xffff, did_vid >> 16, cmd); 20995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury 21095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury return true; 211c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury} 212c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury 213c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendeburyvoid TrunksFtdiSpi::SendCommand(const std::string& command, 214c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury const ResponseCallback& callback) { 21595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury printf("%s invoked\n", __func__); 216c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury} 217c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury 21832f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendeburybool TrunksFtdiSpi::WaitForStatus(uint32_t statusMask, 2194dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn uint32_t statusExpected, 2204dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn int timeout_ms) { 22132f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury uint32_t status; 222b21ea123afb354647305411a51d318067544606cVadim Bendebury time_t target_time; 223b21ea123afb354647305411a51d318067544606cVadim Bendebury 224b21ea123afb354647305411a51d318067544606cVadim Bendebury target_time = time(NULL) + timeout_ms / 1000; 225c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury do { 226c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury usleep(10000); // 10 ms polling period. 227c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury if (time(NULL) >= target_time) { 228c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury LOG(ERROR) << "failed to get expected status " << std::hex 229c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury << statusExpected; 230c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury return false; 231c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury } 232c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury ReadTpmSts(&status); 233c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury } while ((status & statusMask) != statusExpected); 234c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury return true; 23532f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury} 23632f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury 237c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendeburystd::string TrunksFtdiSpi::SendCommandAndWait(const std::string& command) { 23832f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury uint32_t status; 23932f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury uint32_t expected_status_bits; 240c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury size_t transaction_size, handled_so_far(0); 241c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury 24232f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury std::string rv(""); 24332f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury 2445ece90471dd12922f9f35ee4bf6bb6a336d4ea92Vadim Bendebury if (!mpsse_) { 2455ece90471dd12922f9f35ee4bf6bb6a336d4ea92Vadim Bendebury LOG(ERROR) << "attempt to use an uninitialized FTDI TPM!"; 2465ece90471dd12922f9f35ee4bf6bb6a336d4ea92Vadim Bendebury return rv; 2475ece90471dd12922f9f35ee4bf6bb6a336d4ea92Vadim Bendebury } 2485ece90471dd12922f9f35ee4bf6bb6a336d4ea92Vadim Bendebury 24932f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury WriteTpmSts(commandReady); 25032f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury 25132f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury // No need to wait for the sts.Expect bit to be set, at least with the 252c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury // 15d1:001b device, let's just write the command into FIFO, not exceeding 253c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury // the minimum of the two values - burst_count and 64 (which is the protocol 254c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury // limitation) 255c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury do { 2564dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn transaction_size = std::min( 2574dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn std::min(command.size() - handled_so_far, GetBurstCount()), (size_t)64); 258c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury 259c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury if (transaction_size) { 260c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury LOG(INFO) << "will transfer " << transaction_size << " bytes"; 261c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury FtdiWriteReg(TPM_DATA_FIFO_REG, transaction_size, 262c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury command.c_str() + handled_so_far); 263c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury handled_so_far += transaction_size; 264c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury } 265c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury } while (handled_so_far != command.size()); 26632f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury 26732f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury // And tell the device it can start processing it. 26832f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury WriteTpmSts(tpmGo); 26932f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury 27032f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury expected_status_bits = stsValid | dataAvail; 27132f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury if (!WaitForStatus(expected_status_bits, expected_status_bits)) 2724dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn return rv; 27332f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury 27478f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury // The response is ready, let's read it. 27578f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury // First we read the FIFO payload header, to see how much data to expect. 27678f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury // The header size is fixed to six bytes, the total payload size is stored 27778f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury // in network order in the last four bytes of the header. 27878f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury char data_header[6]; 27978f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury 28078f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury // Let's read the header first. 28178f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury FtdiReadReg(TPM_DATA_FIFO_REG, sizeof(data_header), data_header); 28278f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury 28378f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury // Figure out the total payload size. 284c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury uint32_t payload_size; 28578f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury memcpy(&payload_size, data_header + 2, sizeof(payload_size)); 28678f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury payload_size = be32toh(payload_size); 287c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury // A FIFO message with the minimum required header and contents can not be 288c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury // less than 10 bytes long. It also should never be more than 4096 bytes 289c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury // long. 290c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury if ((payload_size < 10) || (payload_size > MAX_RESPONSE_SIZE)) { 291c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury // Something must be wrong... 292c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury LOG(ERROR) << "Bad total payload size value: " << payload_size; 293c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury return rv; 294c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury } 295c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury 29678f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury LOG(INFO) << "Total payload size " << payload_size; 29778f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury 298c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury // Let's read all but the last byte in the FIFO to make sure the status 299c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury // register is showing correct flow control bits: 'more data' until the last 300c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury // byte and then 'no more data' once the last byte is read. 301c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury handled_so_far = 0; 30278f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury payload_size = payload_size - sizeof(data_header) - 1; 303c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury // Allow room for the last byte too. 3044dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn uint8_t* payload = new uint8_t[payload_size + 1]; 305c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury do { 3064dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn transaction_size = std::min( 3074dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn std::min(payload_size - handled_so_far, GetBurstCount()), (size_t)64); 308c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury 309c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury if (transaction_size) { 310c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury FtdiReadReg(TPM_DATA_FIFO_REG, transaction_size, 311c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury payload + handled_so_far); 312c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury handled_so_far += transaction_size; 313c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury } 314c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury } while (handled_so_far != payload_size); 31578f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury 31678f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury // Verify that there is still data to come. 31778f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury ReadTpmSts(&status); 31878f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury if ((status & expected_status_bits) != expected_status_bits) { 31978f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury LOG(ERROR) << "unexpected status 0x" << std::hex << status; 32078f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury delete[] payload; 321c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury return rv; 32278f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury } 32332f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury 32478f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury // Now, read the last byte of the payload. 325c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury FtdiReadReg(TPM_DATA_FIFO_REG, sizeof(uint8_t), payload + payload_size); 32678f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury 32778f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury // Verify that 'data available' is not asseretd any more. 32878f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury ReadTpmSts(&status); 32978f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury if ((status & expected_status_bits) != stsValid) { 33078f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury LOG(ERROR) << "unexpected status 0x" << std::hex << status; 33178f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury delete[] payload; 332c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury return rv; 33378f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury } 334c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury 335c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury rv = std::string(data_header, sizeof(data_header)) + 3364dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn std::string(reinterpret_cast<char*>(payload), payload_size + 1); 33732f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury 338d3cd697fc61df7347db8c1d3589a1fee50ed90f0Vadim Bendebury /* Move the TPM back to idle state. */ 339d3cd697fc61df7347db8c1d3589a1fee50ed90f0Vadim Bendebury WriteTpmSts(commandReady); 340d3cd697fc61df7347db8c1d3589a1fee50ed90f0Vadim Bendebury 34178f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury delete[] payload; 34232f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury return rv; 343c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury} 344c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury 345c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury} // namespace trunks 346