summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorScott <scollyer@chromium.org>2016-08-23 14:46:52 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-09-05 23:22:16 -0700
commit7edd3827cf9d2174bc9d173c878379e0ad81c990 (patch)
tree82c2887b5f547851c7f606edf90ac67b6e771623 /common
parentef4ccb2318cafb040be782bffac6f2e836e17961 (diff)
downloadchrome-ec-7edd3827cf9d2174bc9d173c878379e0ad81c990.tar.gz
Cr50: I2CS TPM: Changes to support fifo and version registers read
This CL adds support for reading of TPM fifo registers. Since I2C does not provide means to communicate how many bytes the host wants to read there must be some handshake involved between the host and Cr50. The method added by this CL to allow Host reads of the TPM fifo assumes the following steps: 1. Host reads burstcount from Cr50 (which will be set to default 63) 2. Host reads 1st 10 bytes of the TPM response. 3. Cr50 will copy MIN(burstcount, msg_len) bytes into its I2CS HW fifo 4. Host computes msg_len and calculates amount of data still buffered 5. Host does a TPM fifo read of buffered data only (The following steps are repeated until the response read is complete) 6. Host reads burstcount from STS register. 7. Host issues read of burscount bytes from TPM fifo 8. I2CS will copy burstcount amount of bytes in to I2CS HW fifo 9. TPM layer sets burstcount to MIN(63, remaining msg bytes) The version register is treated similar to a fifo access. The data written or the number of bytes is a don't care, but there must be at least one byte of data written with the version register write. In the case of reads, the host must read burstcount bytes of the version register. If burstcount is longer than the Cr50 version string there is no issue because the version register read function always returns the number of bytes requested, stuffing in 0s once the end of the version string is reached. BRANCH=none BUG=chrome-os-partner:40397 TEST=manual Created test code in coreboot that exercises TPM register reads and writes. In addition, created a means to spoof a TPM cmd send and response read by Host. For these tests the header length is defined as 10 bytes and used 3 different payload lengths. The results for a payload length of 256 and 39 (message < 63) are shown below. Note the 0xaa and 0x55 have been inserted by the TPM spoof code on the host to mark the end of the header. ================================================= Cr50 TPM Register Read tests TPM Access = 0x0 TPM2 STS = 0x4003f80 TPM2 DID_VID = 0x281ae0 DID = 0x28, VID = 0x1ae0 Ver segment read 1, ret = 0 Version: B2:0 RO_A:0.0.1/84e2dde7 RW_A:0.0.1/cr50_v1.1.5151-acaef21+ ================================================= TPM Cmd: 266 bytes, Hdr = 10, Payload = 256 (last = ff) TPM STS: Sending command_ready fifo wr: burstcount = 63 fifo wr: Sent TPM Cmd: len = 266 bytes TPM STS: Sending TPM GO TPM STS: data_avail set TPM STS: 04 00 3f d0: burst = 63 fifo rd: Msg_len = 266 fifo rd: Hdr Len = 10, fifo_adjust = 53 fifo rd: Drained Cr50 HW fifo of 53 bytes fifo rd: burst = 63 fifo rd: burst = 63 fifo rd: burst = 63 fifo rd: burst = 14 fifo rd: complete 266 byte msg read [0000]: 00 00 00 00 01 0a 00 00 aa 55 00 01 02 03 04 05 [0010]: 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 [0020]: 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 [0030]: 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 [0040]: 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 [0050]: 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 [0060]: 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 [0070]: 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 [0080]: 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 [0090]: 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 [00a0]: 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 [00b0]: a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 [00c0]: b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 [00d0]: c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 [00e0]: d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 [00f0]: e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 [0100]: f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 ================================================= TPM Cmd: 49 bytes, Hdr = 10, Payload = 39 (last = 26) TPM STS: Sending command_ready fifo wr: burstcount = 63 fifo wr: Sent TPM Cmd: len = 49 bytes TPM STS: Sending TPM GO TPM STS: data_avail set TPM STS: 04 00 3f d0: burst = 63 fifo rd: Msg_len = 49 fifo rd: Hdr Len = 10, fifo_adjust = 39 fifo rd: Drained Cr50 HW fifo of 39 bytes fifo rd: complete 49 byte msg read [0000]: 02 00 00 00 00 31 00 00 aa 55 00 01 02 03 04 05 [0010]: 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 [0020]: 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 [0030]: 26 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Change-Id: I0e05156d6012c6dc86844e4c0ea80cc04f45734a Signed-off-by: Scott <scollyer@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/374528 Commit-Ready: Scott Collyer <scollyer@chromium.org> Tested-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Diffstat (limited to 'common')
-rw-r--r--common/i2cs_tpm.c20
-rw-r--r--common/tpm_registers.c13
2 files changed, 28 insertions, 5 deletions
diff --git a/common/i2cs_tpm.c b/common/i2cs_tpm.c
index dfc89ea822..87a075a9a9 100644
--- a/common/i2cs_tpm.c
+++ b/common/i2cs_tpm.c
@@ -74,7 +74,7 @@ static const struct i2c_tpm_reg_map i2c_to_tpm[] = {
{6, 4, 0xf00}, /* TPM DID VID */
{0xa, 4, 0x14}, /* TPM TPM_INTF_CAPABILITY */
{0xe, 1, 0xf04}, /* TPM RID */
- {0xf, 4, 0xf90}, /* TPM_FW_VER */
+ {0xf, 0, 0xf90}, /* TPM_FW_VER */
};
static void wr_complete_handler(void *i2cs_data, size_t i2cs_data_size)
@@ -150,6 +150,24 @@ static void wr_complete_handler(void *i2cs_data, size_t i2cs_data_size)
* burst size field of the tpm status register.
*/
reg_size = tpm_get_burst_size();
+
+ /* For TPM fifo reads, if there is already data pending in the
+ * I2CS hw fifo, then don't read any more TPM fifo data until
+ * the I2CS hw fifo has been fully drained.
+ *
+ * The Host will only read only enough data to extract the full
+ * TPM message length. However, Cr50 will fill the I2CS hw fifo
+ * with 'burstsize' amount of bytes. The 2nd fifo access for a
+ * given TPM repsonse by the Host will extract the queued up
+ * data. Following this, the Host will then read 'burstcount'
+ * amount of data for subsequent fifo accesses until the
+ * response has been fully read.
+ *
+ */
+ if (i2cs_get_read_fifo_buffer_depth())
+ /* Data is already in the queue, just return */
+ return;
+
/*
* Now, this is a hack, but we are short on SRAM, so let's
* reuse the receive buffer for the FIFO data sotrage. We know
diff --git a/common/tpm_registers.c b/common/tpm_registers.c
index 95071c10c9..615f7013bd 100644
--- a/common/tpm_registers.c
+++ b/common/tpm_registers.c
@@ -387,8 +387,6 @@ void tpm_register_put(uint32_t regaddr, const uint8_t *data, uint32_t data_size)
fifo_reg_write(data, data_size);
break;
case TPM_FW_VER:
- /* Reload versions, in case something has been updated */
- set_version_string();
/* Reset read byte count */
tpm_fw_ver_index = 0;
break;
@@ -419,7 +417,7 @@ void fifo_reg_read(uint8_t *dest, uint32_t data_size)
tpm_sts &= ~(burst_count_mask << burst_count_shift);
if (tpm_.fifo_write_index == tpm_.fifo_read_index) {
tpm_sts &= ~(data_avail | command_ready);
- /* Birst size for the following write requests. */
+ /* Burst size for the following write requests. */
tpm_sts |= 63 << burst_count_shift;
} else {
/*
@@ -494,12 +492,19 @@ static void tpm_init(void)
{
set_tpm_state(tpm_state_idle);
tpm_.regs.access = tpm_reg_valid_sts;
+ /*
+ * I2CS writes must limit the burstsize to 63 for fifo writes to work
+ * properly. For I2CS fifo writes the first byte is the I2C TPM address
+ * and the next up to 62 bytes are the data to write to that register.
+ */
tpm_.regs.sts = (tpm_family_tpm2 << tpm_family_shift) |
- (64 << burst_count_shift) | sts_valid;
+ (63 << burst_count_shift) | sts_valid;
/* TPM2 library functions. */
_plat__Signal_PowerOn();
+ /* Create version string to be read by host */
+ set_version_string();
/*
* Make sure NV RAM metadata is initialized, needed to check