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
@ -13,6 +13,10 @@
|
|||||||
/* TPM NVRAM location indices. */
|
/* TPM NVRAM location indices. */
|
||||||
#define FIRMWARE_NV_INDEX 0x1007
|
#define FIRMWARE_NV_INDEX 0x1007
|
||||||
#define KERNEL_NV_INDEX 0x1008
|
#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
|
||||||
|
|
||||||
@ -45,18 +49,28 @@ enum {
|
|||||||
NV_GLOBAL_LOCK,
|
NV_GLOBAL_LOCK,
|
||||||
NV_SEQ_FIRMWARE,
|
NV_SEQ_FIRMWARE,
|
||||||
NV_SEQ_KERNEL,
|
NV_SEQ_KERNEL,
|
||||||
|
NV_SEQ_BACKUP,
|
||||||
|
NV_SEQ_FWMP,
|
||||||
|
NV_SEQ_REC_HASH,
|
||||||
|
|
||||||
NV_SEQ_COUNT,
|
NV_SEQ_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Size of each non-volatile space */
|
/* Size of each non-volatile space */
|
||||||
#define NV_DATA_SIZE 0x20
|
#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.
|
||||||
*/
|
*/
|
||||||
static struct tpm_state {
|
static struct tpm_state {
|
||||||
uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE];
|
bool valid;
|
||||||
|
struct nvdata_state nvdata[NV_SEQ_COUNT];
|
||||||
} g_state;
|
} g_state;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,9 +96,12 @@ static int sandbox_tpm_read_state(const void *blob, int node)
|
|||||||
|
|
||||||
sprintf(prop_name, "nvdata%d", i);
|
sprintf(prop_name, "nvdata%d", i);
|
||||||
prop = fdt_getprop(blob, node, prop_name, &len);
|
prop = fdt_getprop(blob, node, prop_name, &len);
|
||||||
if (prop && len == NV_DATA_SIZE)
|
if (prop && len == NV_DATA_SIZE) {
|
||||||
memcpy(g_state.nvdata[i], prop, 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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -110,9 +127,11 @@ static int sandbox_tpm_write_state(void *blob, int node)
|
|||||||
for (i = 0; i < NV_SEQ_COUNT; i++) {
|
for (i = 0; i < NV_SEQ_COUNT; i++) {
|
||||||
char prop_name[20];
|
char prop_name[20];
|
||||||
|
|
||||||
sprintf(prop_name, "nvdata%d", i);
|
if (g_state.nvdata[i].present) {
|
||||||
fdt_setprop(blob, node, prop_name, g_state.nvdata[i],
|
sprintf(prop_name, "nvdata%d", i);
|
||||||
NV_DATA_SIZE);
|
fdt_setprop(blob, node, prop_name,
|
||||||
|
g_state.nvdata[i].data, NV_DATA_SIZE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -128,6 +147,12 @@ static int index_to_seq(uint32_t index)
|
|||||||
return NV_SEQ_FIRMWARE;
|
return NV_SEQ_FIRMWARE;
|
||||||
case KERNEL_NV_INDEX:
|
case KERNEL_NV_INDEX:
|
||||||
return NV_SEQ_KERNEL;
|
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:
|
case 0:
|
||||||
return NV_GLOBAL_LOCK;
|
return NV_GLOBAL_LOCK;
|
||||||
}
|
}
|
||||||
@ -136,6 +161,21 @@ static int index_to_seq(uint32_t index)
|
|||||||
return -1;
|
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,
|
static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
|
||||||
size_t send_size, uint8_t *recvbuf,
|
size_t send_size, uint8_t *recvbuf,
|
||||||
size_t *recv_len)
|
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);
|
printf("Get flags index %#02x\n", index);
|
||||||
*recv_len = 22;
|
*recv_len = 22;
|
||||||
memset(recvbuf, '\0', *recv_len);
|
memset(recvbuf, '\0', *recv_len);
|
||||||
put_unaligned_be32(22, recvbuf +
|
|
||||||
TPM_RESPONSE_HEADER_LENGTH);
|
|
||||||
data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
|
data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
|
||||||
sizeof(uint32_t);
|
sizeof(uint32_t);
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case FIRMWARE_NV_INDEX:
|
case FIRMWARE_NV_INDEX:
|
||||||
break;
|
break;
|
||||||
case KERNEL_NV_INDEX:
|
case KERNEL_NV_INDEX:
|
||||||
/* TPM_NV_PER_PPWRITE */
|
handle_cap_flag_space(&data, index);
|
||||||
put_unaligned_be32(1, data +
|
*recv_len = data - recvbuf -
|
||||||
NV_DATA_PUBLIC_PERMISSIONS_OFFSET);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
printf(" ** Unknown flags index %x\n", index);
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
put_unaligned_be32(*recv_len,
|
||||||
|
recvbuf +
|
||||||
|
TPM_RESPONSE_HEADER_LENGTH);
|
||||||
break;
|
break;
|
||||||
case TPM_CAP_NV_INDEX:
|
case TPM_CAP_NV_INDEX:
|
||||||
index = get_unaligned_be32(sendbuf + 18);
|
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)
|
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], sendbuf + 22, length);
|
memcpy(&tpm->nvdata[seq].data, sendbuf + 22, length);
|
||||||
|
tpm->nvdata[seq].present = true;
|
||||||
*recv_len = 12;
|
*recv_len = 12;
|
||||||
memset(recvbuf, '\0', *recv_len);
|
memset(recvbuf, '\0', *recv_len);
|
||||||
break;
|
break;
|
||||||
@ -202,7 +259,8 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
|
|||||||
seq = index_to_seq(index);
|
seq = index_to_seq(index);
|
||||||
if (seq < 0)
|
if (seq < 0)
|
||||||
return -EINVAL;
|
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) +
|
*recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
|
||||||
length;
|
length;
|
||||||
memset(recvbuf, '\0', *recv_len);
|
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,
|
offsetof(struct rollback_space_kernel,
|
||||||
crc8));
|
crc8));
|
||||||
memcpy(data, &rsk, sizeof(rsk));
|
memcpy(data, &rsk, sizeof(rsk));
|
||||||
|
} else if (!tpm->nvdata[seq].present) {
|
||||||
|
put_unaligned_be32(TPM_BADINDEX, recvbuf +
|
||||||
|
sizeof(uint16_t) + sizeof(uint32_t));
|
||||||
} else {
|
} else {
|
||||||
memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH +
|
memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH +
|
||||||
sizeof(uint32_t), &tpm->nvdata[seq], length);
|
sizeof(uint32_t), &tpm->nvdata[seq].data,
|
||||||
|
length);
|
||||||
}
|
}
|
||||||
break;
|
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 0x15: /* pcr read */
|
||||||
case 0x5d: /* force clear */
|
case 0x5d: /* force clear */
|
||||||
case 0x6f: /* physical enable */
|
case 0x6f: /* physical enable */
|
||||||
case 0x72: /* physical set deactivated */
|
case 0x72: /* physical set deactivated */
|
||||||
case 0x99: /* startup */
|
case 0x99: /* startup */
|
||||||
|
case 0x50: /* self test full */
|
||||||
case 0x4000000a: /* assert physical presence */
|
case 0x4000000a: /* assert physical presence */
|
||||||
*recv_len = 12;
|
*recv_len = 12;
|
||||||
memset(recvbuf, '\0', *recv_len);
|
memset(recvbuf, '\0', *recv_len);
|
||||||
|
@ -245,6 +245,40 @@ struct tpm_permanent_flags {
|
|||||||
u8 disable_full_da_logic_info;
|
u8 disable_full_da_logic_info;
|
||||||
} __packed;
|
} __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.
|
* Issue a TPM_Startup command.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user