mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-11 07:04:22 +00:00

Add tpm2 drivers to tf-a with adequate framework -implement a fifo spi interface that works with discrete tpm chip. -implement tpm command layer interfaces that are used to initialize, start and make measurements and close the interface. -tpm drivers are built using their own make file to allow for ease in porting across platforms, and across different interfaces. Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com> Signed-off-by: Abhi Singh <abhi.singh@arm.com> Change-Id: Ie1a189f45c80f26f4dea16c3bd71b1503709e0ea
222 lines
5.5 KiB
C
222 lines
5.5 KiB
C
/*
|
|
* Copyright (c) 2025, Arm Limited. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
#include <lib/libc/endian.h>
|
|
|
|
#include <drivers/delay_timer.h>
|
|
#include <drivers/tpm/tpm2.h>
|
|
#include <drivers/tpm/tpm2_chip.h>
|
|
#include <drivers/tpm/tpm2_interface.h>
|
|
|
|
#define CMD_SIZE_OFFSET 6
|
|
|
|
#define SINGLE_BYTE 1
|
|
#define TWO_BYTES 2
|
|
#define FOUR_BYTES 4
|
|
|
|
static struct interface_ops *interface;
|
|
|
|
static int tpm_xfer(struct tpm_chip_data *chip_data, const tpm_cmd *send, tpm_cmd *receive)
|
|
{
|
|
int ret;
|
|
|
|
ret = interface->send(chip_data, send);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = interface->receive(chip_data, receive);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
return TPM_SUCCESS;
|
|
}
|
|
|
|
int tpm_interface_init(struct tpm_chip_data *chip_data, uint8_t locality)
|
|
{
|
|
int err;
|
|
|
|
interface = tpm_interface_getops(chip_data, locality);
|
|
|
|
err = interface->request_access(chip_data, locality);
|
|
if (err != 0) {
|
|
return err;
|
|
}
|
|
|
|
return interface->get_info(chip_data, locality);
|
|
}
|
|
|
|
int tpm_interface_close(struct tpm_chip_data *chip_data, uint8_t locality)
|
|
{
|
|
return interface->release_locality(chip_data, locality);
|
|
}
|
|
|
|
static int tpm_update_buffer(tpm_cmd *buf, uint32_t new_data, size_t new_len)
|
|
{
|
|
int i, j, start;
|
|
uint32_t command_size;
|
|
|
|
union {
|
|
uint8_t var8;
|
|
uint16_t var16;
|
|
uint32_t var32;
|
|
uint8_t array[4];
|
|
} tpm_new_data;
|
|
|
|
command_size = be32toh(buf->header.cmd_size);
|
|
|
|
if (command_size + new_len > MAX_SIZE_CMDBUF) {
|
|
ERROR("%s: buf size exceeded, increase MAX_SIZE_CMDBUF\n",
|
|
__func__);
|
|
return TPM_INVALID_PARAM;
|
|
}
|
|
/*
|
|
* Subtract the cmd header size from the current command size
|
|
* so the data buffer is written to starting at index 0.
|
|
*/
|
|
start = command_size - TPM_HEADER_SIZE;
|
|
|
|
/*
|
|
* The TPM, according to the TCG spec, processes data in BE byte order,
|
|
* in the case where the Host is LE, htobe correctly handles the byte order.
|
|
* When updating the buffer, keep in mind to only pass sizeof(new_data) or
|
|
* the variable type size for the new_len function parameter. This ensures
|
|
* there is only the possiblility of writing 1, 2, or 4 bytes to the buffer,
|
|
* and that the correct number of bytes are written to data[i].
|
|
*/
|
|
if (new_len == SINGLE_BYTE) {
|
|
tpm_new_data.var8 = new_data & 0xFF;
|
|
} else if (new_len == TWO_BYTES) {
|
|
tpm_new_data.var16 = htobe16(new_data & 0xFFFF);
|
|
} else if (new_len == FOUR_BYTES) {
|
|
tpm_new_data.var32 = htobe32(new_data);
|
|
} else {
|
|
ERROR("%s: Invalid data length\n", __func__);
|
|
return TPM_INVALID_PARAM;
|
|
}
|
|
|
|
for (i = start, j = 0; i < start + new_len; i++, j++) {
|
|
buf->data[i] = tpm_new_data.array[j];
|
|
}
|
|
buf->header.cmd_size = htobe32(command_size + new_len);
|
|
|
|
return TPM_SUCCESS;
|
|
}
|
|
|
|
|
|
int tpm_startup(struct tpm_chip_data *chip_data, uint16_t mode)
|
|
{
|
|
tpm_cmd startup_cmd, startup_response;
|
|
uint32_t tpm_rc;
|
|
int ret;
|
|
|
|
memset(&startup_cmd, 0, sizeof(startup_cmd));
|
|
memset(&startup_response, 0, sizeof(startup_response));
|
|
|
|
startup_cmd.header.tag = htobe16(TPM_ST_NO_SESSIONS);
|
|
startup_cmd.header.cmd_size = htobe32(sizeof(tpm_cmd_hdr));
|
|
startup_cmd.header.cmd_code = htobe32(TPM_CMD_STARTUP);
|
|
|
|
ret = tpm_update_buffer(&startup_cmd, mode, sizeof(mode));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = tpm_xfer(chip_data, &startup_cmd, &startup_response);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
tpm_rc = be32toh(startup_response.header.cmd_code);
|
|
if (tpm_rc != TPM_RESPONSE_SUCCESS) {
|
|
ERROR("%s: response code contains error = %X\n", __func__, tpm_rc);
|
|
return TPM_ERR_RESPONSE;
|
|
}
|
|
|
|
return TPM_SUCCESS;
|
|
}
|
|
|
|
int tpm_pcr_extend(struct tpm_chip_data *chip_data, uint32_t index,
|
|
uint16_t algorithm, const uint8_t *digest,
|
|
uint32_t digest_len)
|
|
{
|
|
tpm_cmd pcr_extend_cmd, pcr_extend_response;
|
|
uint32_t tpm_rc;
|
|
int ret;
|
|
|
|
memset(&pcr_extend_cmd, 0, sizeof(pcr_extend_cmd));
|
|
memset(&pcr_extend_response, 0, sizeof(pcr_extend_response));
|
|
|
|
if (digest == NULL) {
|
|
return TPM_INVALID_PARAM;
|
|
}
|
|
pcr_extend_cmd.header.tag = htobe16(TPM_ST_SESSIONS);
|
|
pcr_extend_cmd.header.cmd_size = htobe32(sizeof(tpm_cmd_hdr));
|
|
pcr_extend_cmd.header.cmd_code = htobe32(TPM_CMD_PCR_EXTEND);
|
|
|
|
/* handle (PCR Index)*/
|
|
ret = tpm_update_buffer(&pcr_extend_cmd, index, sizeof(index));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
/* authorization size , session handle, nonce size, attributes*/
|
|
ret = tpm_update_buffer(&pcr_extend_cmd, TPM_MIN_AUTH_SIZE, sizeof(uint32_t));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
ret = tpm_update_buffer(&pcr_extend_cmd, TPM_RS_PW, sizeof(uint32_t));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ZERO_NONCE_SIZE, sizeof(uint16_t));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ATTRIBUTES_DISABLE, sizeof(uint8_t));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
/* hmac/password size */
|
|
ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ZERO_HMAC_SIZE, sizeof(uint16_t));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
/* hashes count */
|
|
ret = tpm_update_buffer(&pcr_extend_cmd, TPM_SINGLE_HASH_COUNT, sizeof(uint32_t));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
/* hash algorithm */
|
|
ret = tpm_update_buffer(&pcr_extend_cmd, algorithm, sizeof(algorithm));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
/* digest */
|
|
for (int i = 0; i < digest_len; i++) {
|
|
ret = tpm_update_buffer(&pcr_extend_cmd, digest[i], sizeof(uint8_t));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
ret = tpm_xfer(chip_data, &pcr_extend_cmd, &pcr_extend_response);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
tpm_rc = be32toh(pcr_extend_response.header.cmd_code);
|
|
if (tpm_rc != TPM_RESPONSE_SUCCESS) {
|
|
ERROR("%s: response code contains error = %X\n", __func__, tpm_rc);
|
|
return TPM_ERR_RESPONSE;
|
|
}
|
|
|
|
return TPM_SUCCESS;
|
|
}
|