mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 13:43:28 +00:00
sandbox: tpm: Split out common nvdata code
We want to support nvdata in TPM2 as well. To avoid code duplicating the associated code, move it into a common file. Drop the special-case logic for the kernel space. This can be handled by the higher-level code now, i.e. in vboot itself. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
c03cb02230
commit
974c98f26c
4 changed files with 172 additions and 105 deletions
|
@ -6,11 +6,11 @@ obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm-uclass.o
|
|||
obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o
|
||||
obj-$(CONFIG_TPM_TIS_INFINEON) += tpm_tis_infineon.o
|
||||
obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o
|
||||
obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o
|
||||
obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o sandbox_common.o
|
||||
obj-$(CONFIG_TPM_ST33ZP24_I2C) += tpm_tis_st33zp24_i2c.o
|
||||
obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o
|
||||
|
||||
obj-$(CONFIG_$(SPL_TPL_)TPM2_CR50_I2C) += cr50_i2c.o
|
||||
obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o
|
||||
obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o sandbox_common.o
|
||||
obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_spi.o
|
||||
obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o
|
||||
|
|
66
drivers/tpm/sandbox_common.c
Normal file
66
drivers/tpm/sandbox_common.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Common features for sandbox TPM1 and TPM2 implementations
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY UCLASS_TPM
|
||||
|
||||
#include <common.h>
|
||||
#include <tpm-v1.h>
|
||||
#include <tpm-v2.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "sandbox_common.h"
|
||||
|
||||
#define TPM_ERR_CODE_OFS (2 + 4) /* after tag and size */
|
||||
|
||||
int sb_tpm_index_to_seq(u32 index)
|
||||
{
|
||||
index &= ~HR_NV_INDEX;
|
||||
switch (index) {
|
||||
case FIRMWARE_NV_INDEX:
|
||||
return NV_SEQ_FIRMWARE;
|
||||
case KERNEL_NV_INDEX:
|
||||
return NV_SEQ_KERNEL;
|
||||
case BACKUP_NV_INDEX:
|
||||
return NV_SEQ_BACKUP;
|
||||
case FWMP_NV_INDEX:
|
||||
return NV_SEQ_FWMP;
|
||||
case MRC_REC_HASH_NV_INDEX:
|
||||
return NV_SEQ_REC_HASH;
|
||||
case 0:
|
||||
return NV_SEQ_GLOBAL_LOCK;
|
||||
case TPM_NV_INDEX_LOCK:
|
||||
return NV_SEQ_ENABLE_LOCKING;
|
||||
}
|
||||
|
||||
printf("Invalid nv index %#x\n", index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void sb_tpm_read_data(const struct nvdata_state nvdata[NV_SEQ_COUNT],
|
||||
enum sandbox_nv_space seq, u8 *buf, int data_ofs,
|
||||
int length)
|
||||
{
|
||||
const struct nvdata_state *nvd = &nvdata[seq];
|
||||
|
||||
if (!nvd->present)
|
||||
put_unaligned_be32(TPM_BADINDEX, buf + TPM_ERR_CODE_OFS);
|
||||
else if (length > nvd->length)
|
||||
put_unaligned_be32(TPM_BAD_DATASIZE, buf + TPM_ERR_CODE_OFS);
|
||||
else
|
||||
memcpy(buf + data_ofs, &nvd->data, length);
|
||||
}
|
||||
|
||||
void sb_tpm_write_data(struct nvdata_state nvdata[NV_SEQ_COUNT],
|
||||
enum sandbox_nv_space seq, const u8 *buf, int data_ofs,
|
||||
int length)
|
||||
{
|
||||
struct nvdata_state *nvd = &nvdata[seq];
|
||||
|
||||
if (length > nvd->length)
|
||||
log_err("Invalid length %x (max %x)\n", length, nvd->length);
|
||||
else
|
||||
memcpy(&nvdata[seq].data, buf + data_ofs, length);
|
||||
}
|
96
drivers/tpm/sandbox_common.h
Normal file
96
drivers/tpm/sandbox_common.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Common features for sandbox TPM1 and TPM2 implementations
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*/
|
||||
|
||||
#ifndef __TPM_SANDBOX_COMMON_H
|
||||
#define __TPM_SANDBOX_COMMON_H
|
||||
|
||||
/*
|
||||
* These numbers derive from adding the sizes of command fields as shown in
|
||||
* the TPM commands manual.
|
||||
*/
|
||||
#define TPM_HDR_LEN 10
|
||||
|
||||
/* These are the different non-volatile spaces that we emulate */
|
||||
enum sandbox_nv_space {
|
||||
NV_SEQ_ENABLE_LOCKING,
|
||||
NV_SEQ_GLOBAL_LOCK,
|
||||
NV_SEQ_FIRMWARE,
|
||||
NV_SEQ_KERNEL,
|
||||
NV_SEQ_BACKUP,
|
||||
NV_SEQ_FWMP,
|
||||
NV_SEQ_REC_HASH,
|
||||
|
||||
NV_SEQ_COUNT,
|
||||
};
|
||||
|
||||
/* TPM NVRAM location indices */
|
||||
#define FIRMWARE_NV_INDEX 0x1007
|
||||
#define KERNEL_NV_INDEX 0x1008
|
||||
#define BACKUP_NV_INDEX 0x1009
|
||||
#define FWMP_NV_INDEX 0x100a
|
||||
#define MRC_REC_HASH_NV_INDEX 0x100b
|
||||
|
||||
/* Size of each non-volatile space */
|
||||
#define NV_DATA_SIZE 0x28
|
||||
|
||||
/**
|
||||
* struct nvdata_state - state of a single non-volatile-data 'space'
|
||||
*
|
||||
* @present: true if present
|
||||
* @length: length in bytes (max NV_DATA_SIZE)
|
||||
* @data: contents of non-volatile space
|
||||
*/
|
||||
struct nvdata_state {
|
||||
bool present;
|
||||
int length;
|
||||
u8 data[NV_DATA_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* sb_tpm_index_to_seq() - convert an index into a space sequence number
|
||||
*
|
||||
* This converts the index as used by the vboot code into an internal sequence
|
||||
* number used by the sandbox emulation.
|
||||
*
|
||||
* @index: Index to use (FIRMWARE_NV_INDEX, etc.)
|
||||
* @return associated space (enum sandbox_nv_space)
|
||||
*/
|
||||
int sb_tpm_index_to_seq(uint index);
|
||||
|
||||
/**
|
||||
* sb_tpm_read_data() - Read non-volatile data
|
||||
*
|
||||
* This handles a TPM read of nvdata. If the nvdata is not present, a
|
||||
* TPM_BADINDEX error is put in the buffer. If @length is too large,
|
||||
* TPM_BAD_DATASIZE is put in the buffer.
|
||||
*
|
||||
* @nvdata: Current nvdata state
|
||||
* @seq: Sequence number to read
|
||||
* @recvbuf: Buffer to update with the TPM response, assumed to contain zeroes
|
||||
* @data_ofs: Offset of the 'data' portion of @recvbuf
|
||||
* @length: Number of bytes to read
|
||||
*/
|
||||
void sb_tpm_read_data(const struct nvdata_state nvdata[NV_SEQ_COUNT],
|
||||
enum sandbox_nv_space seq, u8 *recvbuf, int data_ofs,
|
||||
int length);
|
||||
|
||||
/**
|
||||
* sb_tpm_write_data() - Write non-volatile data
|
||||
*
|
||||
* If @length is too large, an error is logged and nothing is written.
|
||||
*
|
||||
* @nvdata: Current nvdata state
|
||||
* @seq: Sequence number to read
|
||||
* @buf: Buffer containing the data to write
|
||||
* @data_ofs: Offset of the 'data' portion of @buf
|
||||
* @length: Number of bytes to write
|
||||
*/
|
||||
void sb_tpm_write_data(struct nvdata_state nvdata[NV_SEQ_COUNT],
|
||||
enum sandbox_nv_space seq, const u8 *buf, int data_ofs,
|
||||
int length);
|
||||
|
||||
#endif
|
|
@ -9,61 +9,10 @@
|
|||
#include <asm/state.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <u-boot/crc.h>
|
||||
|
||||
/* TPM NVRAM location indices. */
|
||||
#define FIRMWARE_NV_INDEX 0x1007
|
||||
#define KERNEL_NV_INDEX 0x1008
|
||||
#define BACKUP_NV_INDEX 0x1009
|
||||
#define FWMP_NV_INDEX 0x100a
|
||||
#define REC_HASH_NV_INDEX 0x100b
|
||||
#define REC_HASH_NV_SIZE VB2_SHA256_DIGEST_SIZE
|
||||
#include "sandbox_common.h"
|
||||
|
||||
#define NV_DATA_PUBLIC_PERMISSIONS_OFFSET 60
|
||||
|
||||
/* Kernel TPM space - KERNEL_NV_INDEX, locked with physical presence */
|
||||
#define ROLLBACK_SPACE_KERNEL_VERSION 2
|
||||
#define ROLLBACK_SPACE_KERNEL_UID 0x4752574C /* 'GRWL' */
|
||||
|
||||
struct rollback_space_kernel {
|
||||
/* Struct version, for backwards compatibility */
|
||||
uint8_t struct_version;
|
||||
/* Unique ID to detect space redefinition */
|
||||
uint32_t uid;
|
||||
/* Kernel versions */
|
||||
uint32_t kernel_versions;
|
||||
/* Reserved for future expansion */
|
||||
uint8_t reserved[3];
|
||||
/* Checksum (v2 and later only) */
|
||||
uint8_t crc8;
|
||||
} __packed rollback_space_kernel;
|
||||
|
||||
/*
|
||||
* These numbers derive from adding the sizes of command fields as shown in
|
||||
* the TPM commands manual.
|
||||
*/
|
||||
#define TPM_REQUEST_HEADER_LENGTH 10
|
||||
#define TPM_RESPONSE_HEADER_LENGTH 10
|
||||
|
||||
/* These are the different non-volatile spaces that we emulate */
|
||||
enum {
|
||||
NV_GLOBAL_LOCK,
|
||||
NV_SEQ_FIRMWARE,
|
||||
NV_SEQ_KERNEL,
|
||||
NV_SEQ_BACKUP,
|
||||
NV_SEQ_FWMP,
|
||||
NV_SEQ_REC_HASH,
|
||||
|
||||
NV_SEQ_COUNT,
|
||||
};
|
||||
|
||||
/* Size of each non-volatile space */
|
||||
#define NV_DATA_SIZE 0x20
|
||||
|
||||
struct nvdata_state {
|
||||
bool present;
|
||||
u8 data[NV_DATA_SIZE];
|
||||
};
|
||||
|
||||
/*
|
||||
* Information about our TPM emulation. This is preserved in the sandbox
|
||||
* state file if enabled.
|
||||
|
@ -140,27 +89,6 @@ static int sandbox_tpm_write_state(void *blob, int node)
|
|||
SANDBOX_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state,
|
||||
sandbox_tpm_write_state);
|
||||
|
||||
static int index_to_seq(uint32_t index)
|
||||
{
|
||||
switch (index) {
|
||||
case FIRMWARE_NV_INDEX:
|
||||
return NV_SEQ_FIRMWARE;
|
||||
case KERNEL_NV_INDEX:
|
||||
return NV_SEQ_KERNEL;
|
||||
case BACKUP_NV_INDEX:
|
||||
return NV_SEQ_BACKUP;
|
||||
case FWMP_NV_INDEX:
|
||||
return NV_SEQ_FWMP;
|
||||
case REC_HASH_NV_INDEX:
|
||||
return NV_SEQ_REC_HASH;
|
||||
case 0:
|
||||
return NV_GLOBAL_LOCK;
|
||||
}
|
||||
|
||||
printf("Invalid nv index %#x\n", index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void handle_cap_flag_space(u8 **datap, uint index)
|
||||
{
|
||||
struct tpm_nv_data_public pub;
|
||||
|
@ -246,48 +174,25 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
|
|||
case TPM_CMD_NV_WRITE_VALUE:
|
||||
index = get_unaligned_be32(sendbuf + 10);
|
||||
length = get_unaligned_be32(sendbuf + 18);
|
||||
seq = index_to_seq(index);
|
||||
seq = sb_tpm_index_to_seq(index);
|
||||
if (seq < 0)
|
||||
return -EINVAL;
|
||||
printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
|
||||
memcpy(&tpm->nvdata[seq].data, sendbuf + 22, length);
|
||||
tpm->nvdata[seq].present = true;
|
||||
*recv_len = 12;
|
||||
memset(recvbuf, '\0', *recv_len);
|
||||
sb_tpm_write_data(tpm->nvdata, seq, sendbuf, 22, length);
|
||||
break;
|
||||
case TPM_CMD_NV_READ_VALUE: /* nvread */
|
||||
index = get_unaligned_be32(sendbuf + 10);
|
||||
length = get_unaligned_be32(sendbuf + 18);
|
||||
seq = index_to_seq(index);
|
||||
seq = sb_tpm_index_to_seq(index);
|
||||
if (seq < 0)
|
||||
return -EINVAL;
|
||||
printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
|
||||
length, seq);
|
||||
*recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
|
||||
length;
|
||||
*recv_len = TPM_HDR_LEN + sizeof(uint32_t) + length;
|
||||
memset(recvbuf, '\0', *recv_len);
|
||||
put_unaligned_be32(length, recvbuf +
|
||||
TPM_RESPONSE_HEADER_LENGTH);
|
||||
if (seq == NV_SEQ_KERNEL) {
|
||||
struct rollback_space_kernel rsk;
|
||||
|
||||
data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
|
||||
sizeof(uint32_t);
|
||||
memset(&rsk, 0, sizeof(struct rollback_space_kernel));
|
||||
rsk.struct_version = 2;
|
||||
rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
|
||||
rsk.crc8 = crc8(0, (unsigned char *)&rsk,
|
||||
offsetof(struct rollback_space_kernel,
|
||||
crc8));
|
||||
memcpy(data, &rsk, sizeof(rsk));
|
||||
} else if (!tpm->nvdata[seq].present) {
|
||||
put_unaligned_be32(TPM_BADINDEX, recvbuf +
|
||||
sizeof(uint16_t) + sizeof(uint32_t));
|
||||
} else {
|
||||
memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH +
|
||||
sizeof(uint32_t), &tpm->nvdata[seq].data,
|
||||
put_unaligned_be32(length, recvbuf + TPM_HDR_LEN);
|
||||
sb_tpm_read_data(tpm->nvdata, seq, recvbuf, TPM_HDR_LEN + 4,
|
||||
length);
|
||||
}
|
||||
break;
|
||||
case TPM_CMD_EXTEND:
|
||||
*recv_len = 30;
|
||||
|
|
Loading…
Reference in a new issue