mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00:00
sandbox: tpm: Enhance to support the latest Chromium OS
This driver was originally written against Chromium OS circa 2012. A few new features have been added. Enhance the TPM driver to match. This mostly includes a few new messages and properly modelling whether a particular 'space' is present or not. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
998af31903
commit
ef8a25006d
2 changed files with 116 additions and 15 deletions
|
@ -13,6 +13,10 @@
|
|||
/* 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
|
||||
|
||||
|
@ -45,18 +49,28 @@ 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.
|
||||
*/
|
||||
static struct tpm_state {
|
||||
uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE];
|
||||
bool valid;
|
||||
struct nvdata_state nvdata[NV_SEQ_COUNT];
|
||||
} g_state;
|
||||
|
||||
/**
|
||||
|
@ -82,9 +96,12 @@ static int sandbox_tpm_read_state(const void *blob, int node)
|
|||
|
||||
sprintf(prop_name, "nvdata%d", i);
|
||||
prop = fdt_getprop(blob, node, prop_name, &len);
|
||||
if (prop && len == NV_DATA_SIZE)
|
||||
memcpy(g_state.nvdata[i], prop, NV_DATA_SIZE);
|
||||
if (prop && len == NV_DATA_SIZE) {
|
||||
memcpy(g_state.nvdata[i].data, prop, NV_DATA_SIZE);
|
||||
g_state.nvdata[i].present = true;
|
||||
}
|
||||
}
|
||||
g_state.valid = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -110,9 +127,11 @@ static int sandbox_tpm_write_state(void *blob, int node)
|
|||
for (i = 0; i < NV_SEQ_COUNT; i++) {
|
||||
char prop_name[20];
|
||||
|
||||
sprintf(prop_name, "nvdata%d", i);
|
||||
fdt_setprop(blob, node, prop_name, g_state.nvdata[i],
|
||||
NV_DATA_SIZE);
|
||||
if (g_state.nvdata[i].present) {
|
||||
sprintf(prop_name, "nvdata%d", i);
|
||||
fdt_setprop(blob, node, prop_name,
|
||||
g_state.nvdata[i].data, NV_DATA_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -128,6 +147,12 @@ static int index_to_seq(uint32_t 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;
|
||||
}
|
||||
|
@ -136,6 +161,21 @@ static int index_to_seq(uint32_t index)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static void handle_cap_flag_space(u8 **datap, uint index)
|
||||
{
|
||||
struct tpm_nv_data_public pub;
|
||||
|
||||
/* TPM_NV_PER_PPWRITE */
|
||||
memset(&pub, '\0', sizeof(pub));
|
||||
pub.nv_index = __cpu_to_be32(index);
|
||||
pub.pcr_info_read.pcr_selection.size_of_select = __cpu_to_be16(
|
||||
sizeof(pub.pcr_info_read.pcr_selection.pcr_select));
|
||||
pub.permission.attributes = __cpu_to_be32(1);
|
||||
pub.pcr_info_write = pub.pcr_info_read;
|
||||
memcpy(*datap, &pub, sizeof(pub));
|
||||
*datap += sizeof(pub);
|
||||
}
|
||||
|
||||
static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
|
||||
size_t send_size, uint8_t *recvbuf,
|
||||
size_t *recv_len)
|
||||
|
@ -159,19 +199,35 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
|
|||
printf("Get flags index %#02x\n", index);
|
||||
*recv_len = 22;
|
||||
memset(recvbuf, '\0', *recv_len);
|
||||
put_unaligned_be32(22, recvbuf +
|
||||
TPM_RESPONSE_HEADER_LENGTH);
|
||||
data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
|
||||
sizeof(uint32_t);
|
||||
switch (index) {
|
||||
case FIRMWARE_NV_INDEX:
|
||||
break;
|
||||
case KERNEL_NV_INDEX:
|
||||
/* TPM_NV_PER_PPWRITE */
|
||||
put_unaligned_be32(1, data +
|
||||
NV_DATA_PUBLIC_PERMISSIONS_OFFSET);
|
||||
handle_cap_flag_space(&data, index);
|
||||
*recv_len = data - recvbuf -
|
||||
TPM_RESPONSE_HEADER_LENGTH -
|
||||
sizeof(uint32_t);
|
||||
break;
|
||||
case TPM_CAP_FLAG_PERMANENT: {
|
||||
struct tpm_permanent_flags *pflags;
|
||||
|
||||
pflags = (struct tpm_permanent_flags *)data;
|
||||
memset(pflags, '\0', sizeof(*pflags));
|
||||
put_unaligned_be32(TPM_TAG_PERMANENT_FLAGS,
|
||||
&pflags->tag);
|
||||
*recv_len = TPM_HEADER_SIZE + 4 +
|
||||
sizeof(*pflags);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf(" ** Unknown flags index %x\n", index);
|
||||
return -ENOSYS;
|
||||
}
|
||||
put_unaligned_be32(*recv_len,
|
||||
recvbuf +
|
||||
TPM_RESPONSE_HEADER_LENGTH);
|
||||
break;
|
||||
case TPM_CAP_NV_INDEX:
|
||||
index = get_unaligned_be32(sendbuf + 18);
|
||||
|
@ -192,7 +248,8 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
|
|||
if (seq < 0)
|
||||
return -EINVAL;
|
||||
printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
|
||||
memcpy(&tpm->nvdata[seq], sendbuf + 22, length);
|
||||
memcpy(&tpm->nvdata[seq].data, sendbuf + 22, length);
|
||||
tpm->nvdata[seq].present = true;
|
||||
*recv_len = 12;
|
||||
memset(recvbuf, '\0', *recv_len);
|
||||
break;
|
||||
|
@ -202,7 +259,8 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
|
|||
seq = index_to_seq(index);
|
||||
if (seq < 0)
|
||||
return -EINVAL;
|
||||
printf("tpm: nvread index=%#02x, len=%#02x\n", index, length);
|
||||
printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
|
||||
length, seq);
|
||||
*recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
|
||||
length;
|
||||
memset(recvbuf, '\0', *recv_len);
|
||||
|
@ -220,17 +278,26 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
|
|||
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], length);
|
||||
sizeof(uint32_t), &tpm->nvdata[seq].data,
|
||||
length);
|
||||
}
|
||||
break;
|
||||
case TPM_CMD_EXTEND: /* tpm extend */
|
||||
case TPM_CMD_EXTEND:
|
||||
*recv_len = 30;
|
||||
memset(recvbuf, '\0', *recv_len);
|
||||
break;
|
||||
case TPM_CMD_NV_DEFINE_SPACE:
|
||||
case 0x15: /* pcr read */
|
||||
case 0x5d: /* force clear */
|
||||
case 0x6f: /* physical enable */
|
||||
case 0x72: /* physical set deactivated */
|
||||
case 0x99: /* startup */
|
||||
case 0x50: /* self test full */
|
||||
case 0x4000000a: /* assert physical presence */
|
||||
*recv_len = 12;
|
||||
memset(recvbuf, '\0', *recv_len);
|
||||
|
|
|
@ -245,6 +245,40 @@ struct tpm_permanent_flags {
|
|||
u8 disable_full_da_logic_info;
|
||||
} __packed;
|
||||
|
||||
#define TPM_SHA1_160_HASH_LEN 0x14
|
||||
|
||||
struct __packed tpm_composite_hash {
|
||||
u8 digest[TPM_SHA1_160_HASH_LEN];
|
||||
};
|
||||
|
||||
struct __packed tpm_pcr_selection {
|
||||
__be16 size_of_select;
|
||||
u8 pcr_select[3]; /* matches vboot's struct */
|
||||
};
|
||||
|
||||
struct __packed tpm_pcr_info_short {
|
||||
struct tpm_pcr_selection pcr_selection;
|
||||
u8 locality_at_release;
|
||||
struct tpm_composite_hash digest_at_release;
|
||||
};
|
||||
|
||||
struct __packed tpm_nv_attributes {
|
||||
__be16 tag;
|
||||
__be32 attributes;
|
||||
};
|
||||
|
||||
struct __packed tpm_nv_data_public {
|
||||
__be16 tag;
|
||||
__be32 nv_index;
|
||||
struct tpm_pcr_info_short pcr_info_read;
|
||||
struct tpm_pcr_info_short pcr_info_write;
|
||||
struct tpm_nv_attributes permission;
|
||||
u8 read_st_clear;
|
||||
u8 write_st_clear;
|
||||
u8 write_define;
|
||||
__be32 data_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Issue a TPM_Startup command.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue