From 4c87a1868835d05f1cadae7b8ad6a7c95d9d9c0e Mon Sep 17 00:00:00 2001 From: Ross Philipson Date: Tue, 14 Mar 2017 15:40:33 -0400 Subject: Initial commit of EFI TBOOT work from internal project. Signed-off-by: Ross Philipson --- tboot/tpm.c | 911 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 911 insertions(+) create mode 100644 tboot/tpm.c (limited to 'tboot/tpm.c') diff --git a/tboot/tpm.c b/tboot/tpm.c new file mode 100644 index 0000000..d4e0b08 --- /dev/null +++ b/tboot/tpm.c @@ -0,0 +1,911 @@ +/* + * tpm.c: TPM-related support functions + * + * Copyright (c) 2006-2010, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__data struct tpm_if *g_tpm = NULL; +u16 tboot_alg_list[2] = {TB_HALG_SHA1, TB_HALG_SHA256}; + + + + + + +/* Global variables for TPM status register */ +static tpm20_reg_sts_t g_reg_sts, *g_reg_sts_20 = &g_reg_sts; +static tpm12_reg_sts_t *g_reg_sts_12 = (tpm12_reg_sts_t *)&g_reg_sts; + +uint8_t g_tpm_family = 0; + +/* TPM_DATA_FIFO_x */ +#define TPM_REG_DATA_FIFO 0x24 +typedef union { + uint8_t _raw[1]; /* 1-byte reg */ +} tpm_reg_data_fifo_t; + +typedef union { + uint8_t _raw[1]; +} tpm_reg_data_crb_t; + +#define TPM_ACTIVE_LOCALITY_TIME_OUT \ + (TIMEOUT_UNIT * g_tpm->timeout.timeout_a) /* according to spec */ +#define TPM_CMD_READY_TIME_OUT \ + (TIMEOUT_UNIT * g_tpm->timeout.timeout_b) /* according to spec */ +#define TPM_CMD_WRITE_TIME_OUT \ + (TIMEOUT_UNIT * g_tpm->timeout.timeout_d) /* let it long enough */ +#define TPM_DATA_AVAIL_TIME_OUT \ + (TIMEOUT_UNIT * g_tpm->timeout.timeout_c) /* let it long enough */ +#define TPM_RSP_READ_TIME_OUT \ + (TIMEOUT_UNIT * g_tpm->timeout.timeout_d) /* let it long enough */ +#define TPM_VALIDATE_LOCALITY_TIME_OUT 0x100 + +#define read_tpm_sts_reg(locality) { \ +if ( g_tpm_family == 0 ) \ + read_tpm_reg(locality, TPM_REG_STS, g_reg_sts_12); \ +else \ + read_tpm_reg(locality, TPM_REG_STS, g_reg_sts_20); \ +} + +#define write_tpm_sts_reg(locality) { \ +if ( g_tpm_family == 0 ) \ + write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_12); \ +else \ + write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_20); \ +} + +static void tpm_send_cmd_ready_status(uint32_t locality) +{ + /* write 1 to TPM_STS_x.commandReady to let TPM enter ready state */ + memset((void *)&g_reg_sts, 0, sizeof(g_reg_sts)); + g_reg_sts.command_ready = 1; + write_tpm_sts_reg(locality); +} + + +static bool tpm_send_cmd_ready_status_crb(uint32_t locality) +{ + tpm_reg_ctrl_request_t reg_ctrl_request; + tpm_reg_ctrl_sts_t reg_ctrl_sts; + + read_tpm_reg(locality, TPM_CRB_CTRL_STS, ®_ctrl_sts); + +#ifdef TPM_TRACE + printk(TBOOT_INFO"1. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle); + printk(TBOOT_INFO"1. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts); +#endif + + if ( reg_ctrl_sts.tpmidle== 1) { + reg_ctrl_request._raw[0] = 0; + reg_ctrl_request.cmdReady = 1; + write_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + + return true; + } + + reg_ctrl_request._raw[0] = 0; + reg_ctrl_request.goIdle = 1; + write_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + + uint32_t i = 0; + do { + read_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + if ( reg_ctrl_request.goIdle == 0) + break; + else { + cpu_relax(); + read_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + +#ifdef TPM_TRACE + printk(TBOOT_INFO"1. reg_ctrl_request.goIdle: 0x%x\n", reg_ctrl_request.goIdle); + printk(TBOOT_INFO"1. reg_ctrl_request.cmdReady: 0x%x\n", reg_ctrl_request.cmdReady); +#endif + + } + i++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT); + + if ( i > TPM_DATA_AVAIL_TIME_OUT ) { + printk(TBOOT_ERR"TPM: reg_ctrl_request.goidle timeout!\n"); + return false; + } + + read_tpm_reg(locality, TPM_CRB_CTRL_STS, ®_ctrl_sts); + +#ifdef TPM_TRACE + printk(TBOOT_INFO"2. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle); + printk(TBOOT_INFO"2. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts); +#endif + + reg_ctrl_request._raw[0] = 0; + reg_ctrl_request.cmdReady = 1; + write_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + +#ifdef TPM_TRACE + printk(TBOOT_INFO"2. reg_ctrl_request.goIdle: 0x%x\n", reg_ctrl_request.goIdle); + printk(TBOOT_INFO"2. reg_ctrl_request.cmdReady: 0x%x\n", reg_ctrl_request.cmdReady); +#endif + + read_tpm_reg(locality, TPM_CRB_CTRL_STS, ®_ctrl_sts); + +#ifdef TPM_TRACE + printk(TBOOT_INFO"2. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle); + printk(TBOOT_INFO"2. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts); +#endif + + return true; + +} + +static bool tpm_check_cmd_ready_status_crb(uint32_t locality) +{ + tpm_reg_ctrl_request_t reg_ctrl_request; + read_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + +#ifdef TPM_TRACE + printk(TBOOT_INFO"3. reg_ctrl_request.goIdle: 0x%x\n", reg_ctrl_request.goIdle); + printk(TBOOT_INFO"3. reg_ctrl_request.cmdReady: 0x%x\n", reg_ctrl_request.cmdReady); +#endif + + if ( reg_ctrl_request.cmdReady == 0) + return true; + else + return false; + +} + +static bool tpm_check_cmd_ready_status(uint32_t locality) +{ + read_tpm_sts_reg(locality); +#ifdef TPM_TRACE + printk(TBOOT_INFO"."); +#endif + return g_reg_sts.command_ready; +} + +static void tpm_print_status_register(void) +{ + if ( g_tpm_family == 0 ) + { + printk(TBOOT_DETA"TPM: status reg content: %02x %02x %02x\n", + (uint32_t)g_reg_sts_12->_raw[0], + (uint32_t)g_reg_sts_12->_raw[1], + (uint32_t)g_reg_sts_12->_raw[2]); + } + else + { + printk(TBOOT_DETA"TPM: status reg content: %02x %02x %02x %02x\n", + (uint32_t)g_reg_sts_20->_raw[0], + (uint32_t)g_reg_sts_20->_raw[1], + (uint32_t)g_reg_sts_20->_raw[2], + (uint32_t)g_reg_sts_20->_raw[3]); + } +} + +static u16 tpm_get_burst_count(uint32_t locality) +{ + read_tpm_sts_reg(locality); + return g_reg_sts.burst_count; +} + +static bool tpm_check_expect_status(uint32_t locality) +{ + read_tpm_sts_reg(locality); +#ifdef TPM_TRACE + printk(TBOOT_INFO"Wait on Expect = 0, Status register %02x\n", g_reg_sts._raw[0]); +#endif + return g_reg_sts.sts_valid == 1 && g_reg_sts.expect == 0; +} + +static bool tpm_check_da_status(uint32_t locality) +{ + read_tpm_sts_reg(locality); +#ifdef TPM_TRACE + printk(TBOOT_INFO"Waiting for DA Flag, Status register %02x\n", g_reg_sts._raw[0]); +#endif + return g_reg_sts.sts_valid == 1 && g_reg_sts.data_avail == 1; +} + +static void tpm_execute_cmd(uint32_t locality) +{ + memset((void *)&g_reg_sts, 0, sizeof(g_reg_sts)); + g_reg_sts.tpm_go = 1; + write_tpm_sts_reg(locality); +} + +bool tpm_validate_locality(uint32_t locality) +{ + uint32_t i; + tpm_reg_access_t reg_acc; + + for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) { + /* + * TCG spec defines reg_acc.tpm_reg_valid_sts bit to indicate whether + * other bits of access reg are valid.( but this bit will also be 1 + * while this locality is not available, so check seize bit too) + * It also defines that reading reg_acc.seize should always return 0 + */ + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.tpm_reg_valid_sts == 1 && reg_acc.seize == 0) + return true; + cpu_relax(); + } + if ( i <= 0 ) + printk(TBOOT_ERR"TPM: tpm_validate_locality timeout\n"); + + return false; +} + +bool tpm_validate_locality_crb(uint32_t locality) +{ + uint32_t i; + tpm_reg_loc_state_t reg_loc_state; + + for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) { + /* + * Platfrom Tpm Profile for TPM 2.0 SPEC + */ + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); + if ( reg_loc_state.tpm_reg_valid_sts == 1 && reg_loc_state.loc_assigned == 1 && reg_loc_state.active_locality == locality) { + printk(TBOOT_INFO"TPM: reg_loc_state._raw[0]: 0x%x\n", reg_loc_state._raw[0]); + return true; + } + cpu_relax(); + } + + printk(TBOOT_ERR"TPM: tpm_validate_locality_crb timeout\n"); + printk(TBOOT_INFO"TPM: reg_loc_state._raw[0]: 0x%x\n", reg_loc_state._raw[0]); + return false; +} + + +bool tpm_wait_cmd_ready(uint32_t locality) +{ + uint32_t i; + tpm_reg_access_t reg_acc; + +#if 0 /* some tpms doesn't always return 1 for reg_acc.tpm_reg_valid_sts */ + /* and this bit was checked in tpm_validate_locality() already, */ + /* so safe to skip the check here */ + /* ensure the contents of the ACCESS register are valid */ + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); +#ifdef TPM_TRACE + printk(TBOOT_INFO"TPM: Access reg content: 0x%02x\n", (uint32_t)reg_acc._raw[0]); +#endif + if ( reg_acc.tpm_reg_valid_sts == 0 ) { + printk(TBOOT_ERR"TPM: Access reg not valid\n"); + return false; + } +#endif + /* request access to the TPM from locality N */ + reg_acc._raw[0] = 0; + reg_acc.request_use = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality == 1 ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT); + + if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) { + printk(TBOOT_ERR"TPM: FIFO_INF access reg request use timeout\n"); + return false; + } + + /* ensure the TPM is ready to accept a command */ +#ifdef TPM_TRACE + printk(TBOOT_INFO"TPM: wait for cmd ready \n"); +#endif + i = 0; + do { + tpm_send_cmd_ready_status(locality); + cpu_relax(); + /* then see if it has */ + + if ( tpm_check_cmd_ready_status(locality) ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_CMD_READY_TIME_OUT ); +#ifdef TPM_TRACE + printk(TBOOT_INFO"\n"); +#endif + + if ( i > TPM_CMD_READY_TIME_OUT ) { + tpm_print_status_register(); + printk(TBOOT_INFO"TPM: tpm timeout for command_ready\n"); + goto RelinquishControl; + } + + return true; + +RelinquishControl: + /* deactivate current locality */ + reg_acc._raw[0] = 0; + reg_acc.active_locality = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + + return false; +} + +static bool tpm_wait_cmd_ready_crb(uint32_t locality) +{ + uint32_t i; + + /* ensure the TPM is ready to accept a command */ +#ifdef TPM_TRACE + printk(TBOOT_INFO"TPM: wait for cmd ready \n"); +#endif + tpm_send_cmd_ready_status_crb(locality); + i = 0; + do { + if ( tpm_check_cmd_ready_status_crb(locality) ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_CMD_READY_TIME_OUT ); + + if ( i > TPM_CMD_READY_TIME_OUT ) { + //tpm_print_status_register(); + printk(TBOOT_INFO"TPM: tpm timeout for command_ready\n"); + goto RelinquishControl; + } + + return true; + +RelinquishControl: + /* deactivate current locality */ + //tpm_reg_loc_ctrl_t reg_loc_ctrl; + //reg_loc_ctrl._raw[0] = 0; + //reg_loc_ctrl.relinquish = 1; + //write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); + + return false; +} + +bool tpm_submit_cmd(u32 locality, u8 *in, u32 in_size, u8 *out, u32 *out_size) +{ + u32 i, rsp_size, offset; + u16 row_size; + tpm_reg_access_t reg_acc; + bool ret = true; + + if ( locality >= TPM_NR_LOCALITIES ) { + printk(TBOOT_WARN"TPM: Invalid locality for tpm_write_cmd_fifo()\n"); + return false; + } + if ( in == NULL || out == NULL || out_size == NULL ) { + printk(TBOOT_WARN"TPM: Invalid parameter for tpm_write_cmd_fifo()\n"); + return false; + } + if ( in_size < CMD_HEAD_SIZE || *out_size < RSP_HEAD_SIZE ) { + printk(TBOOT_WARN"TPM: in/out buf size must be larger than 10 bytes\n"); + return false; + } + + if ( !tpm_validate_locality(locality) ) { + printk(TBOOT_WARN"TPM: Locality %d is not open\n", locality); + return false; + } + + if ( !tpm_wait_cmd_ready(locality) ) return false; + +#ifdef TPM_TRACE + { + printk(TBOOT_DETA"TPM: cmd size = 0x%x\nTPM: cmd content: ", in_size); + print_hex("TPM: \t", in, in_size); + } +#endif + + /* write the command to the TPM FIFO */ + offset = 0; + do { + i = 0; + do { + /* find out how many bytes the TPM can accept in a row */ + row_size = tpm_get_burst_count(locality); + if ( row_size > 0 ) break; + else cpu_relax(); + i++; + } while ( i <= TPM_CMD_WRITE_TIME_OUT ); + if ( i > TPM_CMD_WRITE_TIME_OUT ) { + printk(TBOOT_ERR"TPM: write cmd timeout\n"); + ret = false; + goto RelinquishControl; + } + + for ( ; row_size > 0 && offset < in_size; row_size--, offset++ ) write_tpm_reg(locality, TPM_REG_DATA_FIFO, (tpm_reg_data_fifo_t *)&in[offset]); + } while ( offset < in_size ); + + i = 0; + do { + if ( tpm_check_expect_status(locality) ) break; + else cpu_relax(); + i++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); + if ( i > TPM_DATA_AVAIL_TIME_OUT ) { + printk(TBOOT_ERR"TPM: wait for expect becoming 0 timeout\n"); + ret = false; + goto RelinquishControl; + } + + /* command has been written to the TPM, it is time to execute it. */ + tpm_execute_cmd(locality); + + /* check for data available */ + i = 0; + do { + if ( tpm_check_da_status(locality) ) break; + else cpu_relax(); + i++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); + if ( i > TPM_DATA_AVAIL_TIME_OUT ) { + printk(TBOOT_ERR"TPM: wait for data available timeout\n"); + ret = false; + goto RelinquishControl; + } + + rsp_size = 0; + offset = 0; + do { + /* find out how many bytes the TPM returned in a row */ + i = 0; + do { + row_size = tpm_get_burst_count(locality); + if ( row_size > 0 ) break; + else cpu_relax(); + i++; + } while ( i <= TPM_RSP_READ_TIME_OUT ); + if ( i > TPM_RSP_READ_TIME_OUT ) { + printk(TBOOT_ERR"TPM: read rsp timeout\n"); + ret = false; + goto RelinquishControl; + } + + for ( ; row_size > 0 && offset < *out_size; row_size--, offset++ ) { + if ( offset < *out_size ) read_tpm_reg(locality, TPM_REG_DATA_FIFO, (tpm_reg_data_fifo_t *)&out[offset]); + else { + /* discard the responded bytes exceeding out buf size */ + tpm_reg_data_fifo_t discard; + read_tpm_reg(locality, TPM_REG_DATA_FIFO, (tpm_reg_data_fifo_t *)&discard); + } + + /* get outgoing data size */ + if ( offset == RSP_RST_OFFSET - 1 ) { + reverse_copy(&rsp_size, &out[RSP_SIZE_OFFSET], sizeof(rsp_size)); + } + } + } while ( offset < RSP_RST_OFFSET || (offset < rsp_size && offset < *out_size) ); + + *out_size = (*out_size > rsp_size) ? rsp_size : *out_size; + +#ifdef TPM_TRACE + { + printk(TBOOT_INFO"TPM: response size = %d\n", *out_size); + printk(TBOOT_DETA"TPM: response content: "); + print_hex("TPM: \t", out, *out_size); + } +#endif + + tpm_send_cmd_ready_status(locality); + +RelinquishControl: + /* deactivate current locality */ + reg_acc._raw[0] = 0; + reg_acc.active_locality = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + + return ret; +} + + +bool tpm_submit_cmd_crb(u32 locality, u8 *in, u32 in_size, u8 *out, u32 *out_size) +{ + uint32_t i; + + bool ret = true; + + //tpm_reg_loc_ctrl_t reg_loc_ctrl; + tpm_reg_ctrl_start_t start; + + tpm_reg_ctrl_cmdsize_t CmdSize; + tpm_reg_ctrl_cmdaddr_t CmdAddr; + tpm_reg_ctrl_rspsize_t RspSize; + tpm_reg_ctrl_rspaddr_t RspAddr; + uint32_t tpm_crb_data_buffer_base; + + if ( locality >= TPM_NR_LOCALITIES ) { + printk(TBOOT_WARN"TPM: Invalid locality for tpm_submit_cmd_crb()\n"); + return false; + } + if ( in == NULL || out == NULL || out_size == NULL ) { + printk(TBOOT_WARN"TPM: Invalid parameter for tpm_submit_cmd_crb()\n"); + return false; + } + if ( in_size < CMD_HEAD_SIZE || *out_size < RSP_HEAD_SIZE ) { + printk(TBOOT_WARN"TPM: in/out buf size must be larger than 10 bytes\n"); + return false; + } + + if ( !tpm_validate_locality_crb(locality) ) { + printk(TBOOT_WARN"TPM: CRB Interface Locality %d is not open\n", locality); + return false; + } + + if ( !tpm_wait_cmd_ready_crb(locality) ) { + printk(TBOOT_WARN"TPM: tpm_wait_cmd_read_crb failed\n"); + return false; + } + +#ifdef TPM_TRACE + { + printk(TBOOT_DETA"TPM: Before submit, cmd size = 0x%x\nTPM: Before submit, cmd content: ", in_size); + print_hex("TPM: \t", in, in_size); + } +#endif + + /* write the command to the TPM CRB buffer 01-04-2016 */ +//copy *in and size to crb buffer + + + + CmdAddr.cmdladdr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; + CmdAddr.cmdhaddr = 0; + RspAddr.rspaddr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; + CmdSize.cmdsize = TPMCRBBUF_LEN; + RspSize.rspsize = TPMCRBBUF_LEN; + tpm_crb_data_buffer_base = TPM_CRB_DATA_BUFFER; + + + #ifdef TPM_TRACE + printk(TBOOT_INFO"CmdAddr.cmdladdr is 0x%x\n",CmdAddr.cmdladdr); + printk(TBOOT_INFO"CmdAddr.cmdhaddr is 0x%x\n",CmdAddr.cmdhaddr); + + printk(TBOOT_INFO"CmdSize.cmdsize is 0x%x\n",CmdSize.cmdsize); + printk(TBOOT_INFO"RspAddr.rspaddr is 0x%Lx\n",RspAddr.rspaddr); + printk(TBOOT_INFO"RspSize.rspsize is 0x%x\n",RspSize.rspsize); + +#endif + + write_tpm_reg(locality, TPM_CRB_CTRL_CMD_ADDR, &CmdAddr); + write_tpm_reg(locality, TPM_CRB_CTRL_CMD_SIZE, &CmdSize); + write_tpm_reg(locality, TPM_CRB_CTRL_RSP_ADDR, &RspAddr); + write_tpm_reg(locality, TPM_CRB_CTRL_RSP_SIZE, &RspSize); + // write the command to the buffer + for ( i = 0 ; i< in_size; i++ ) { + write_tpm_reg(locality, tpm_crb_data_buffer_base++, (tpm_reg_data_crb_t *)&in[i]); + //tpm_crb_data_buffer_base++; + } + + /* command has been written to the TPM, it is time to execute it. */ + start.start = 1; + write_tpm_reg(locality, TPM_CRB_CTRL_START, &start); + //read_tpm_reg(locality, TPM_CRB_CTRL_START, &start); + printk(TBOOT_INFO"tpm_ctrl_start.start is 0x%x\n",start.start); + + /* check for data available */ + i = 0; + do { + read_tpm_reg(locality, TPM_CRB_CTRL_START, &start); + //printk(TBOOT_INFO"tpm_ctrl_start.start is 0x%x\n",start.start); + if ( start.start == 0 ) break; + else cpu_relax(); + i++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); + + if ( i > TPM_DATA_AVAIL_TIME_OUT ) { + printk(TBOOT_ERR"TPM: wait for data available timeout\n"); + ret = false; + goto RelinquishControl; + } + + tpm_crb_data_buffer_base = TPM_CRB_DATA_BUFFER; + + for ( i = 0 ; i< *out_size; i++ ) { + read_tpm_reg(locality, tpm_crb_data_buffer_base++, (tpm_reg_data_crb_t *)&out[i]); + //tpm_crb_data_buffer_base++; + } + + + +#ifdef TPM_TRACE + { + printk(TBOOT_INFO"TPM: After cmd submit, response size = 0x%x\n", *out_size); + printk(TBOOT_DETA"TPM: After cmd submit, response content: "); + print_hex("TPM: \t", out, *out_size); + } +#endif + + //tpm_send_cmd_ready_status_crb(locality); + +RelinquishControl: + /* deactivate current locality */ + // reg_loc_ctrl._raw[0] = 0; + //reg_loc_ctrl.relinquish = 1; + //write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); + + return ret; + +} + + +bool release_locality(uint32_t locality) +{ + uint32_t i; +#ifdef TPM_TRACE + printk(TBOOT_DETA"TPM: releasing locality %u\n", locality); +#endif + + if ( !tpm_validate_locality(locality) ) return true; + + tpm_reg_access_t reg_acc; + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality == 0 ) return true; + + /* make inactive by writing a 1 */ + reg_acc._raw[0] = 0; + reg_acc.active_locality = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality == 0 ) + return true; + else + cpu_relax(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); + + printk(TBOOT_INFO"TPM: access reg release locality timeout\n"); + return false; +} + +bool tpm_relinquish_locality_crb(uint32_t locality) +{ + uint32_t i; + tpm_reg_loc_state_t reg_loc_state; + tpm_reg_loc_ctrl_t reg_loc_ctrl; + +#ifdef TPM_TRACE + printk(TBOOT_DETA"TPM: releasing CRB_INF locality %u\n", locality); +#endif + + if ( !tpm_validate_locality_crb(locality) ) return true; + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); + if ( reg_loc_state.loc_assigned == 0 ) return true; + + /* make inactive by writing a 1 */ + reg_loc_ctrl._raw[0] = 0; + reg_loc_ctrl.relinquish = 1; + write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); + if ( reg_loc_state.loc_assigned == 0 ) return true; + else cpu_relax(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); + + printk(TBOOT_INFO"TPM: CRB_INF release locality timeout\n"); + return false; +} + + + +bool is_tpm_crb(void) +{ + tpm_crb_interface_id_t crb_interface; + read_tpm_reg(0, TPM_INTERFACE_ID, &crb_interface); + if (crb_interface.interface_type == TPM_INTERFACE_ID_CRB ) { + printk(TBOOT_INFO"TPM: PTP CRB interface is active...\n"); + if (g_tpm_family != TPM_IF_20_CRB ) g_tpm_family = TPM_IF_20_CRB; + return true; + } + if (crb_interface.interface_type == TPM_INTERFACE_ID_FIFO_20) { + printk(TBOOT_INFO"TPM: TPM 2.0 FIFO interface is active...\n"); + if (g_tpm_family != TPM_IF_20_FIFO) g_tpm_family = TPM_IF_20_FIFO; + } + return false; +} + + +bool prepare_tpm(void) +{ + /* + * must ensure TPM_ACCESS_0.activeLocality bit is clear + * (: locality is not active) + */ + if (is_tpm_crb()) +// return release_locality_crb(0); + return true; + else + return release_locality(0); +} + +bool tpm_request_locality_crb(uint32_t locality){ + + uint32_t i; + tpm_reg_loc_state_t reg_loc_state; + tpm_reg_loc_ctrl_t reg_loc_ctrl; + /* request access to the TPM from locality N */ + reg_loc_ctrl._raw[0] = 0; + reg_loc_ctrl.requestAccess = 1; + write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); + if ( reg_loc_state.active_locality == locality && reg_loc_state.loc_assigned == 1) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT); + + if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) { + printk(TBOOT_ERR"TPM: access loc request use timeout\n"); + return false; + } + + return true; + +} + +bool tpm_workaround_crb(void) +{ + tpm_reg_ctrl_cmdsize_t CmdSize; + tpm_reg_ctrl_cmdaddr_t CmdAddr; + tpm_reg_ctrl_rspsize_t RspSize; + tpm_reg_ctrl_rspaddr_t RspAddr; + u32 locality = 0; + + if (!tpm_request_locality_crb(locality)) + return false; + + CmdAddr.cmdladdr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; + CmdAddr.cmdhaddr = 0; + RspAddr.rspaddr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; + CmdSize.cmdsize = TPMCRBBUF_LEN; + RspSize.rspsize = TPMCRBBUF_LEN; + + write_tpm_reg(locality, TPM_CRB_CTRL_CMD_ADDR, &CmdAddr); + write_tpm_reg(locality, TPM_CRB_CTRL_CMD_SIZE, &CmdSize); + write_tpm_reg(locality, TPM_CRB_CTRL_RSP_ADDR, &RspAddr); + write_tpm_reg(locality, TPM_CRB_CTRL_RSP_SIZE, &RspSize); + + return true; +} + +bool tpm_detect(void) +{ + if (is_tpm_crb()) { + printk(TBOOT_INFO"TPM: This is Intel PTT, TPM Family 0x%d\n", g_tpm_family); + if (!txt_is_launched()) { + if ( tpm_validate_locality_crb(0) ) + printk(TBOOT_INFO"TPM: CRB_INF Locality 0 is open\n"); + else { + printk(TBOOT_INFO"TPM: CRB_INF request access to Locality 0...\n"); + if (!tpm_request_locality_crb(0)) { + printk(TBOOT_ERR"TPM: CRB_INF Locality 0 request failed...\n"); + return false; + } + } + } + else { + if ( tpm_validate_locality_crb(2) ) + printk(TBOOT_INFO"TPM: CRB_INF Locality 2 is open\n"); + else { + printk(TBOOT_INFO"TPM: CRB_INF request access to Locality 2...\n"); + if (!tpm_request_locality_crb(2)) { + printk(TBOOT_ERR"TPM: CRB_INF Locality 2 request failed...\n"); + return false; + } + } + } + } + else { + g_tpm = &tpm_12_if; /* Don't leave g_tpm as NULL*/ + if ( tpm_validate_locality(0) ) printk(TBOOT_INFO"TPM: FIFO_INF Locality 0 is open\n"); + else { + printk(TBOOT_ERR"TPM: FIFO_INF Locality 0 is not open\n"); + return false; + } + /* determine TPM family from command check */ + if ( g_tpm->check() ) { + g_tpm_family = TPM_IF_12; + printk(TBOOT_INFO"TPM: discrete TPM1.2 Family 0x%d\n", g_tpm_family); + } + else { + g_tpm_family = TPM_IF_20_FIFO; + printk(TBOOT_INFO"TPM: discrete TPM2.0 Family 0x%d\n", g_tpm_family); + } + } + + if (g_tpm_family == TPM_IF_12) g_tpm = &tpm_12_if; + if (g_tpm_family == TPM_IF_20_FIFO) g_tpm = &tpm_20_if; + if (g_tpm_family == TPM_IF_20_CRB) g_tpm = &tpm_20_if; + + /* if (!txt_is_launched()) + g_tpm->cur_loc = 0; + else + g_tpm->cur_loc = 2; + + g_tpm->timeout.timeout_a = TIMEOUT_A; + g_tpm->timeout.timeout_b = TIMEOUT_B; + g_tpm->timeout.timeout_c = TIMEOUT_C; + g_tpm->timeout.timeout_d = TIMEOUT_D; +*/ + return g_tpm->init(g_tpm); +} + +void tpm_print(struct tpm_if *ti) +{ + if ( ti == NULL ) + return; + + printk(TBOOT_INFO"TPM attribute:\n"); + printk(TBOOT_INFO"\t extend policy: %d\n", ti->extpol); + printk(TBOOT_INFO"\t current alg id: 0x%x\n", ti->cur_alg); + printk(TBOOT_INFO"\t timeout values: A: %u, B: %u, C: %u, D: %u\n", ti->timeout.timeout_a, ti->timeout.timeout_b, ti->timeout.timeout_c, ti->timeout.timeout_d); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ -- cgit v1.2.3