mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 07:31:15 +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_ATMEL_TWI) += tpm_atmel_twi.o
|
||||||
obj-$(CONFIG_TPM_TIS_INFINEON) += tpm_tis_infineon.o
|
obj-$(CONFIG_TPM_TIS_INFINEON) += tpm_tis_infineon.o
|
||||||
obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.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_I2C) += tpm_tis_st33zp24_i2c.o
|
||||||
obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o
|
obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o
|
||||||
|
|
||||||
obj-$(CONFIG_$(SPL_TPL_)TPM2_CR50_I2C) += cr50_i2c.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_TIS_SPI) += tpm2_tis_spi.o
|
||||||
obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.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/state.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
#include <u-boot/crc.h>
|
#include <u-boot/crc.h>
|
||||||
|
#include "sandbox_common.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
|
|
||||||
|
|
||||||
#define NV_DATA_PUBLIC_PERMISSIONS_OFFSET 60
|
#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
|
* Information about our TPM emulation. This is preserved in the sandbox
|
||||||
* state file if enabled.
|
* 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_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state,
|
||||||
sandbox_tpm_write_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)
|
static void handle_cap_flag_space(u8 **datap, uint index)
|
||||||
{
|
{
|
||||||
struct tpm_nv_data_public pub;
|
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:
|
case TPM_CMD_NV_WRITE_VALUE:
|
||||||
index = get_unaligned_be32(sendbuf + 10);
|
index = get_unaligned_be32(sendbuf + 10);
|
||||||
length = get_unaligned_be32(sendbuf + 18);
|
length = get_unaligned_be32(sendbuf + 18);
|
||||||
seq = index_to_seq(index);
|
seq = sb_tpm_index_to_seq(index);
|
||||||
if (seq < 0)
|
if (seq < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
|
printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
|
||||||
memcpy(&tpm->nvdata[seq].data, sendbuf + 22, length);
|
sb_tpm_write_data(tpm->nvdata, seq, sendbuf, 22, length);
|
||||||
tpm->nvdata[seq].present = true;
|
|
||||||
*recv_len = 12;
|
|
||||||
memset(recvbuf, '\0', *recv_len);
|
|
||||||
break;
|
break;
|
||||||
case TPM_CMD_NV_READ_VALUE: /* nvread */
|
case TPM_CMD_NV_READ_VALUE: /* nvread */
|
||||||
index = get_unaligned_be32(sendbuf + 10);
|
index = get_unaligned_be32(sendbuf + 10);
|
||||||
length = get_unaligned_be32(sendbuf + 18);
|
length = get_unaligned_be32(sendbuf + 18);
|
||||||
seq = index_to_seq(index);
|
seq = sb_tpm_index_to_seq(index);
|
||||||
if (seq < 0)
|
if (seq < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
|
printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
|
||||||
length, seq);
|
length, seq);
|
||||||
*recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
|
*recv_len = TPM_HDR_LEN + sizeof(uint32_t) + length;
|
||||||
length;
|
|
||||||
memset(recvbuf, '\0', *recv_len);
|
memset(recvbuf, '\0', *recv_len);
|
||||||
put_unaligned_be32(length, recvbuf +
|
put_unaligned_be32(length, recvbuf + TPM_HDR_LEN);
|
||||||
TPM_RESPONSE_HEADER_LENGTH);
|
sb_tpm_read_data(tpm->nvdata, seq, recvbuf, TPM_HDR_LEN + 4,
|
||||||
if (seq == NV_SEQ_KERNEL) {
|
length);
|
||||||
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,
|
|
||||||
length);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case TPM_CMD_EXTEND:
|
case TPM_CMD_EXTEND:
|
||||||
*recv_len = 30;
|
*recv_len = 30;
|
||||||
|
|
Loading…
Reference in a new issue