diff options
Diffstat (limited to 'test/tpm_test/ftdi_spi_tpm.c')
-rw-r--r-- | test/tpm_test/ftdi_spi_tpm.c | 495 |
1 files changed, 0 insertions, 495 deletions
diff --git a/test/tpm_test/ftdi_spi_tpm.c b/test/tpm_test/ftdi_spi_tpm.c deleted file mode 100644 index 4fc281aa24..0000000000 --- a/test/tpm_test/ftdi_spi_tpm.c +++ /dev/null @@ -1,495 +0,0 @@ -/* Copyright 2015 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include <endian.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - -#include "ftdi_spi_tpm.h" - -static struct mpsse_context *mpsse_; -static unsigned locality_; /* Set at initialization. */ -static int ftdi_trace_enabled; - -/* Assorted TPM2 registers for interface type FIFO. */ -#define TPM_LOCALITY_0_SPI_BASE 0x00d40000 - -#define TPM_ACCESS_REG (TPM_LOCALITY_0_SPI_BASE + 0) -#define TPM_STS_REG (TPM_LOCALITY_0_SPI_BASE + 0x18) -#define TPM_DATA_FIFO_REG (TPM_LOCALITY_0_SPI_BASE + 0x24) -#define TPM_DID_VID_REG (TPM_LOCALITY_0_SPI_BASE + 0xf00) -#define TPM_RID_REG (TPM_LOCALITY_0_SPI_BASE + 0xf04) -#define TPM_FW_VER (TPM_LOCALITY_0_SPI_BASE + 0xf90) - -static struct swig_string_data empty_string_data = (struct swig_string_data){ - .size = 0, .data = NULL -}; - -/* Locality management bits (in TPM_ACCESS_REG). */ -enum TpmAccessBits { - tpmRegValidSts = (1 << 7), - activeLocality = (1 << 5), - requestUse = (1 << 1), - tpmEstablishment = (1 << 0), -}; - -enum TpmStsBits { - tpmFamilyShift = 26, - tpmFamilyMask = ((1 << 2) - 1), /* 2 bits wide. */ - tpmFamilyTPM2 = 1, - resetEstablishmentBit = (1 << 25), - commandCancel = (1 << 24), - burstCountShift = 8, - burstCountMask = ((1 << 16) - 1), /* 16 bits wide. */ - stsValid = (1 << 7), - commandReady = (1 << 6), - tpmGo = (1 << 5), - dataAvail = (1 << 4), - Expect = (1 << 3), - selfTestDone = (1 << 2), - responseRetry = (1 << 1), -}; - -enum { - false = 0, - true = 1 -}; - -/* - * SPI frame header for TPM transactions is 4 bytes in size, it is described - * in section "6.4.6 Spi Bit Protocol" of the TCG issued "TPM Profile (PTP) - * Specification Revision 00.43. - */ -struct SpiFrameHeader { - unsigned char body[4]; -}; - -void FtdiStop(void) -{ - if (mpsse_) - Close(mpsse_); - - mpsse_ = NULL; -} - -/* - * If the TPM is asleep we may need to poke it once to wake it up. Just assert - * the CS briefly without sending any data, then wait a bit to be sure it's - * awake. - */ -static void FtdiSpiPoke(void) -{ - Start(mpsse_); - usleep(1000); - Stop(mpsse_); - usleep(60000); -} - -static void StartTransaction(int read_write, size_t bytes, unsigned addr) -{ - struct SpiFrameHeader header; - int i; - uint8_t flow_c; - char *transfer_data; - - /* - * give it 10 ms. TODO(vbendeb): remove this once cr50 SPS TPM driver - * performance is fixed. - */ - usleep(10000); - - /* - * The first byte of the frame header encodes the transaction type - * (read or write) and size (set to length - 1). - */ - header.body[0] = (read_write ? 0x80 : 0) | 0x40 | (bytes - 1); - - /* The rest of the frame header is the internal address in the TPM. */ - for (i = 0; i < 3; i++) - header.body[i + 1] = (addr >> (8 * (2 - i))) & 0xff; - - Start(mpsse_); - - transfer_data = - Transfer(mpsse_, (char *)header.body, sizeof(header.body)); - - /* - * The TCG TPM over SPI specification itroduces the notion of SPI flow - * control (Section "6.4.5 Flow Control" of the TCG issued "TPM - * Profile (PTP) Specification Revision 00.43). - * - * The slave (TPM device) expects each transaction to start with a 4 - * byte header trasmitted by master. If the slave needs to stall the - * transaction, it sets the MOSI bit to 0 during the last clock of the - * 4 byte header. In this case the master is supposed to start polling - * the line, byte at time, until the last bit in the received byte - * (transferred during the last clock of the byte) is set to 1. - */ - flow_c = transfer_data[3]; - free(transfer_data); - while (!(flow_c & 1)) { - transfer_data = Read(mpsse_, 1); - flow_c = transfer_data[0]; - free(transfer_data); - } -} - -static void trace_dump(const char *prefix, unsigned reg, size_t bytes, - const uint8_t *buffer) -{ - if (!ftdi_trace_enabled) - return; - printf("%s %2.2x:", prefix, reg); - if (bytes == 4) { - printf(" %8.8x\n", *(const uint32_t *)buffer); - } else { - int i; - - for (i = 0; i < bytes; i++) - printf(" %2.2x", buffer[i]); - printf("\n"); - } -} - -static int FtdiWriteReg(unsigned reg_number, size_t bytes, void *buffer) -{ - if (!mpsse_) - return false; - - trace_dump("W", reg_number, bytes, buffer); - StartTransaction(false, bytes, reg_number + locality_ * 0x10000); - Write(mpsse_, buffer, bytes); - Stop(mpsse_); - return true; -} - -static int FtdiReadReg(unsigned reg_number, size_t bytes, void *buffer) -{ - void *data; - - if (!mpsse_) - return false; - - StartTransaction(true, bytes, reg_number + locality_ * 0x10000); - data = Read(mpsse_, bytes); - if (data) - memcpy(buffer, data, bytes); - free(data); - Stop(mpsse_); - trace_dump("R", reg_number, bytes, buffer); - return true; -} - -static int ReadTpmSts(uint32_t *status) -{ - return FtdiReadReg(TPM_STS_REG, sizeof(*status), status); -} - -static int WriteTpmSts(uint32_t status) -{ - return FtdiWriteReg(TPM_STS_REG, sizeof(status), &status); -} - -static uint32_t GetBurstCount(void) -{ - uint32_t status; - - ReadTpmSts(&status); - return (status >> burstCountShift) & burstCountMask; -} - -static void GetVersion(void) -{ - int chunk_count = 0; - uint32_t chunk = 0; - char vstr[sizeof(chunk) + 1]; /* room for 4 chars + zero */ - - /* - * Does not really matter what's written, this just makes sure - * the version is reported from the beginning. - */ - FtdiWriteReg(TPM_FW_VER, sizeof(chunk), &chunk); - - /* Print it out in 4 byte chunks. */ - vstr[sizeof(vstr) - 1] = 0; - do { - FtdiReadReg(TPM_FW_VER, sizeof(chunk), vstr); - printf("%s", vstr); - - /* - * While string is not over, and no more than 200 - * characters. - * This is likely result in one extra printk() - * invocation with an empty string, not a big deal. - */ - } while (vstr[0] && (chunk_count++ < (400 / sizeof(chunk)))); - - printf("\n"); -} - -int FtdiSpiInit(uint32_t freq, int enable_debug) -{ - uint32_t did_vid, status; - uint8_t cmd; - uint16_t vid; - - if (mpsse_) - return true; - - ftdi_trace_enabled = enable_debug; - - /* round frequency down to the closest 100KHz */ - freq = (freq / (100 * 1000)) * 100 * 1000; - - printf("Starting MPSSE at %d kHz\n", freq / 1000); - mpsse_ = MPSSE(freq, MSB, NULL); - if (!mpsse_) - return false; - - /* Just in case, make sure bootsrap is not triggered. */ - PinLow(mpsse_, GPIOL0); - - FtdiSpiPoke(); - - FtdiReadReg(TPM_DID_VID_REG, sizeof(did_vid), &did_vid); - - vid = did_vid & 0xffff; - if ((vid != 0x15d1) && (vid != 0x1ae0)) { - fprintf(stderr, "unknown did_vid: %#x\n", did_vid); - return false; - } - - /* Try claiming locality zero. */ - FtdiReadReg(TPM_ACCESS_REG, sizeof(cmd), &cmd); - if ((cmd & (activeLocality & tpmRegValidSts)) == - (activeLocality & tpmRegValidSts)) { - /* - * Locality active - maybe reset line is not connected? - * Release the locality and try again - */ - cmd = activeLocality; - FtdiWriteReg(TPM_ACCESS_REG, sizeof(cmd), &cmd); - FtdiReadReg(TPM_ACCESS_REG, sizeof(cmd), &cmd); - } - - /* tpmEstablishment can be either set or not. */ - if ((cmd & ~tpmEstablishment) != tpmRegValidSts) { - fprintf(stderr, "invalid reset status: %#x\n", cmd); - return false; - } - cmd = requestUse; - FtdiWriteReg(TPM_ACCESS_REG, sizeof(cmd), &cmd); - FtdiReadReg(TPM_ACCESS_REG, sizeof(cmd), &cmd); - if ((cmd & ~tpmEstablishment) != (tpmRegValidSts | activeLocality)) { - fprintf(stderr, "failed to claim locality, status: %#x\n", cmd); - return false; - } - - ReadTpmSts(&status); - if (((status >> tpmFamilyShift) & tpmFamilyMask) != tpmFamilyTPM2) { - fprintf(stderr, "unexpected TPM family value, status: %#x\n", - status); - return false; - } - FtdiReadReg(TPM_RID_REG, sizeof(cmd), &cmd); - printf("Connected to device vid:did:rid of %4.4x:%4.4x:%2.2x\n", - did_vid & 0xffff, did_vid >> 16, cmd); - - GetVersion(); - - return true; -} - -/* This is in seconds (prime generation may take several minutes). */ -#define MAX_STATUS_TIMEOUT 900 -static int WaitForStatus(uint32_t statusMask, uint32_t statusExpected) -{ - uint32_t status; - time_t target_time; - static unsigned max_timeout; - - target_time = time(NULL) + MAX_STATUS_TIMEOUT; - do { - usleep(10000); - if (time(NULL) >= target_time) { - fprintf(stderr, "failed to get expected status %x\n", - statusExpected); - return false; - } - ReadTpmSts(&status); - } while ((status & statusMask) != statusExpected); - - /* Calculate time spent waiting */ - target_time = MAX_STATUS_TIMEOUT - target_time + time(NULL); - if (max_timeout < (unsigned)target_time) { - max_timeout = target_time; - printf("New max timeout: %d s\n", max_timeout); - } - - return true; -} - -static void SpinSpinner(void) -{ - static const char *spinner = "\\|/-"; - static int index; - - if (index > strlen(spinner)) - index = 0; - - fprintf(stdout, "%c[1D%c", 0x1b, spinner[index++]); - fflush(stdout); -} - -#define MAX_RESPONSE_SIZE 4096 -#define HEADER_SIZE 6 - -/* tpm_command points at a buffer 4096 bytes in size */ -struct swig_string_data FtdiSendCommandAndWait(char *tpm_command, - int command_size) -{ - uint32_t status; - uint32_t expected_status_bits; - size_t handled_so_far; - uint32_t payload_size; - char message[100]; - int offset = 0; - uint8_t *response; - - if (!mpsse_) { - fprintf(stderr, "attempt to use an uninitialized FTDI TPM!\n"); - return empty_string_data; - } - - response = malloc(MAX_RESPONSE_SIZE); - if (!response) { - fprintf(stderr, "attempt to use an uninitialized FTDI TPM!\n"); - return empty_string_data; - } - - handled_so_far = 0; - - WriteTpmSts(commandReady); - - memcpy(&payload_size, tpm_command + 2, sizeof(payload_size)); - payload_size = be32toh(payload_size); - offset += - snprintf(message, sizeof(message), "Message size %d", payload_size); - - /* - * No need to wait for the sts.Expect bit to be set, at least with the - * 15d1:001b and 1ae0:0028 devices. Let's just write the command into - * FIFO, make sure not to exceed the burst count. - */ - do { - uint32_t transaction_size; - uint32_t burst_count = GetBurstCount(); - - if (burst_count > 64) - burst_count = 64; - - transaction_size = command_size - handled_so_far; - if (transaction_size > burst_count) - transaction_size = burst_count; - - if (transaction_size) { - FtdiWriteReg(TPM_DATA_FIFO_REG, transaction_size, - tpm_command + handled_so_far); - handled_so_far += transaction_size; - } - } while (handled_so_far != command_size); - - /* And tell the device it can start processing it. */ - WriteTpmSts(tpmGo); - - expected_status_bits = stsValid | dataAvail; - if (!WaitForStatus(expected_status_bits, expected_status_bits)) { - size_t i; - - printf("Failed processing. %s:", message); - for (i = 0; i < command_size; i++) { - if (!(i % 16)) - printf("\n"); - printf(" %2.2x", (uint8_t)tpm_command[i]); - } - printf("\n"); - return empty_string_data; - } - - /* - * The tpm_command is ready, let's read it. - * - * First we read the FIFO payload header, to see how much data to - * expect. The header size is fixed to six bytes, the total payload - * size is stored in network order in the last four bytes of the - * header. - */ - FtdiReadReg(TPM_DATA_FIFO_REG, HEADER_SIZE, response); - handled_so_far = HEADER_SIZE; - - /* Figure out the total payload size. */ - memcpy(&payload_size, response + 2, sizeof(payload_size)); - payload_size = be32toh(payload_size); - - if (ftdi_trace_enabled) - printf("%s response size %d\n\n", message, payload_size); - else - SpinSpinner(); - - if (payload_size > MAX_RESPONSE_SIZE) - return empty_string_data; - /* - * Let's read all but the last byte in the FIFO to make sure the - * status register is showing correct flow control bits: 'more data' - * until the last byte and then 'no more data' once the last byte is - * read. - */ - payload_size = payload_size - 1; - do { - uint32_t transaction_size; - uint32_t burst_count = GetBurstCount(); - - if (burst_count > 64) - burst_count = 64; - - transaction_size = payload_size - handled_so_far; - if (transaction_size > burst_count) - transaction_size = burst_count; - - if (transaction_size) { - FtdiReadReg(TPM_DATA_FIFO_REG, transaction_size, - response + handled_so_far); - handled_so_far += transaction_size; - } - } while (handled_so_far != payload_size); - - /* Verify that there is still data to come. */ - ReadTpmSts(&status); - if ((status & expected_status_bits) != expected_status_bits) { - fprintf(stderr, "unexpected status %#x\n", status); - return empty_string_data; - } - - FtdiReadReg(TPM_DATA_FIFO_REG, 1, response + handled_so_far); - - /* Verify that 'data available' is not asseretd any more. */ - ReadTpmSts(&status); - if ((status & expected_status_bits) != stsValid) { - fprintf(stderr, "unexpected status %#x\n", status); - return empty_string_data; - } - - /* Move the TPM back to idle state. */ - WriteTpmSts(commandReady); - - handled_so_far++; - - return (struct swig_string_data) { - .size = handled_so_far, .data = response}; -} |