TPM fixes and state reporting

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEgWII69YpahbL5iK5gS8AYozs+qIFAmMTcr0ACgkQgS8AYozs
 +qJXaA/8DeQlC30LtlYGiZ567Xp5QST+z8sqHblfHGSCVwzHwq7Sgbs6lqw39eF0
 caiaQfUx2fhT668tB1cR0d3vw3Mz/yrLm4Fj4Rozr4d9EEB4LFJ162OVlnDUHP2t
 +x6dJfKrOe/yXzjHu33OCoggWkZSA4t14ZCqLIqnFRQBhc0IaxHY8llx3FWFhT21
 lwx2zEbOQ+hYAQ8T925RWUdwHPj2zkR0dl06GyLAzak7RiWRJxUieV2Cn925sr0b
 VOAqugzCp+W+or+z1zHK7VHbbB9HVueN5KbvhyK8kHOKu+afgp9eGZIxlxhrgqol
 5zi9FuJkeUZBNzXJzwH5JpwaRIGiCtr5+3wOgTlIzMAsaaSOyTkoh+5UpijaGnmC
 RBwSVMAqQTOqVLLWuJxEl/qIulWGjsBQU0qst1NrH2zSXbALOz+U/VkdrFouBp4u
 /Go7ttyq6HxgJSs8evy7iH27at5U+m5MM/s+n08Vs5eEMwF+YFZs1cjGEmMgA+zb
 JrwLFjOr1lOiWM8W+jYJ7gdZuCjB4A1q6/wmeHB9t9ii2N4IlY0sxwf3MWczUQCj
 0i0M7zBJlRVdM5xQu2KkE1u7JM+fcRl2XpZ3/RWgMfIJz+zDiCKtWicUm1M33IKZ
 IxovEs/QjDV5411d8dDYUVG+/GoodV2x6lO0lmxny+iM5uAZ8Ho=
 =c18c
 -----END PGP SIGNATURE-----

Merge tag 'tpm-03092022' of https://source.denx.de/u-boot/custodians/u-boot-tpm

TPM fixes and state reporting
This commit is contained in:
Tom Rini 2022-09-03 14:55:37 -04:00
commit 427aa3c9b7
16 changed files with 380 additions and 21 deletions

View file

@ -333,6 +333,26 @@ int do_tpm_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
return 0; return 0;
} }
int do_tpm_report_state(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct udevice *dev;
char buf[80];
int rc;
rc = get_tpm(&dev);
if (rc)
return rc;
rc = tpm_report_state(dev, buf, sizeof(buf));
if (rc < 0) {
printf("Couldn't get TPM state (%d)\n", rc);
return CMD_RET_FAILURE;
}
printf("%s\n", buf);
return 0;
}
int do_tpm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) int do_tpm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{ {
struct udevice *dev; struct udevice *dev;

View file

@ -21,6 +21,8 @@ int do_tpm_device(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]); char *const argv[]);
int do_tpm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_tpm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
int do_tpm_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_tpm_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
int do_tpm_report_state(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]);
int do_tpm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_tpm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
#endif /* __TPM_USER_UTILS_H */ #endif /* __TPM_USER_UTILS_H */

View file

@ -131,7 +131,8 @@ static int do_tpm_extend(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_FAILURE; return CMD_RET_FAILURE;
} }
rc = tpm_pcr_extend(dev, index, in_digest, out_digest); rc = tpm_pcr_extend(dev, index, in_digest, sizeof(in_digest),
out_digest, "cmd");
if (!rc) { if (!rc) {
puts("PCR value after execution of the command:\n"); puts("PCR value after execution of the command:\n");
print_byte_string(out_digest, sizeof(out_digest)); print_byte_string(out_digest, sizeof(out_digest));

View file

@ -359,6 +359,7 @@ static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
static struct cmd_tbl tpm2_commands[] = { static struct cmd_tbl tpm2_commands[] = {
U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""), U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""),
U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""), U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
U_BOOT_CMD_MKENT(state, 0, 1, do_tpm_report_state, "", ""),
U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""), U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""),
U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""), U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""),
U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""), U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""),
@ -389,6 +390,8 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
" Show all devices or set the specified device\n" " Show all devices or set the specified device\n"
"info\n" "info\n"
" Show information about the TPM.\n" " Show information about the TPM.\n"
"state\n"
" Show internal state from the TPM (if available)\n"
"init\n" "init\n"
" Initialize the software stack. Always the first command to issue.\n" " Initialize the software stack. Always the first command to issue.\n"
"startup <mode>\n" "startup <mode>\n"

View file

@ -91,7 +91,8 @@ static int test_early_extend(struct udevice *dev)
tpm_init(dev); tpm_init(dev);
TPM_CHECK(tpm_startup(dev, TPM_ST_CLEAR)); TPM_CHECK(tpm_startup(dev, TPM_ST_CLEAR));
TPM_CHECK(tpm_continue_self_test(dev)); TPM_CHECK(tpm_continue_self_test(dev));
TPM_CHECK(tpm_pcr_extend(dev, 1, value_in, value_out)); TPM_CHECK(tpm_pcr_extend(dev, 1, value_in, sizeof(value_in), value_out,
"test"));
printf("done\n"); printf("done\n");
return 0; return 0;
} }
@ -438,7 +439,7 @@ static int test_timing(struct udevice *dev)
100); 100);
TTPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x)), TTPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x)),
100); 100);
TTPM_CHECK(tpm_pcr_extend(dev, 0, in, out), 200); TTPM_CHECK(tpm_pcr_extend(dev, 0, in, sizeof(in), out, "test"), 200);
TTPM_CHECK(tpm_set_global_lock(dev), 50); TTPM_CHECK(tpm_set_global_lock(dev), 50);
TTPM_CHECK(tpm_tsc_physical_presence(dev, PHYS_PRESENCE), 100); TTPM_CHECK(tpm_tsc_physical_presence(dev, PHYS_PRESENCE), 100);
printf("done\n"); printf("done\n");

View file

@ -13,11 +13,13 @@
#include <irq.h> #include <irq.h>
#include <log.h> #include <log.h>
#include <spl.h> #include <spl.h>
#include <tpm-common.h>
#include <tpm-v2.h> #include <tpm-v2.h>
#include <acpi/acpigen.h> #include <acpi/acpigen.h>
#include <acpi/acpi_device.h> #include <acpi/acpi_device.h>
#include <asm/gpio.h> #include <asm/gpio.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/unaligned.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <dm/acpi.h> #include <dm/acpi.h>
@ -37,6 +39,50 @@ enum {
CR50_MAX_BUF_SIZE = 63, CR50_MAX_BUF_SIZE = 63,
}; };
/*
* Operations specific to the Cr50 TPM used on Chromium OS and Android devices
*
* FIXME: below is not enough to differentiate between vendors commands
* of numerous devices. However, the current tpm2 APIs aren't very amenable
* to extending generically because the marshaling code is assuming all
* knowledge of all commands.
*/
#define TPM2_CC_VENDOR_BIT_MASK 0x20000000
#define TPM2_CR50_VENDOR_COMMAND (TPM2_CC_VENDOR_BIT_MASK | 0)
#define TPM2_CR50_SUB_CMD_IMMEDIATE_RESET 19
#define TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS 21
#define TPM2_CR50_SUB_CMD_REPORT_TPM_STATE 23
#define TPM2_CR50_SUB_CMD_TURN_UPDATE_ON 24
#define TPM2_CR50_SUB_CMD_GET_REC_BTN 29
#define TPM2_CR50_SUB_CMD_TPM_MODE 40
#define TPM2_CR50_SUB_CMD_GET_BOOT_MODE 52
#define TPM2_CR50_SUB_CMD_RESET_EC 53
/* Cr50 vendor-specific error codes. */
#define VENDOR_RC_ERR 0x00000500
enum cr50_vendor_rc {
VENDOR_RC_INTERNAL_ERROR = (VENDOR_RC_ERR | 6),
VENDOR_RC_NO_SUCH_SUBCOMMAND = (VENDOR_RC_ERR | 8),
VENDOR_RC_NO_SUCH_COMMAND = (VENDOR_RC_ERR | 127),
};
enum cr50_tpm_mode {
/*
* Default state: TPM is enabled, and may be set to either
* TPM_MODE_ENABLED or TPM_MODE_DISABLED.
*/
TPM_MODE_ENABLED_TENTATIVE = 0,
/* TPM is enabled, and mode may not be changed. */
TPM_MODE_ENABLED = 1,
/* TPM is disabled, and mode may not be changed. */
TPM_MODE_DISABLED = 2,
TPM_MODE_INVALID,
};
/** /**
* struct cr50_priv - Private driver data * struct cr50_priv - Private driver data
* *
@ -54,6 +100,41 @@ struct cr50_priv {
bool use_irq; bool use_irq;
}; };
/*
* The below structure represents the body of the response to the 'report tpm
* state' vendor command.
*
* It is transferred over the wire, so it needs to be serialized/deserialized,
* and it is likely to change, so its contents must be versioned.
*/
#define TPM_STATE_VERSION 1
struct tpm_vendor_state {
u32 version;
/*
* The following three fields are set by the TPM in case of an assert.
* There is no other processing than setting the source code line
* number, error code and the first 4 characters of the function name.
*
* We don't expect this happening, but it is included in the report
* just in case.
*/
u32 fail_line; /* s_failLIne */
u32 fail_code; /* s_failCode */
char func_name[4]; /* s_failFunction, limited to 4 chars */
/*
* The following two fields are the current time filtered value of the
* 'failed tries' TPM counter, and the maximum allowed value of the
* counter.
*
* failed_tries == max_tries is the definition of the TPM lockout
* condition.
*/
u32 failed_tries; /* gp.failedTries */
u32 max_tries; /* gp.maxTries */
/* The below fields are present in version 2 and above */
};
/* Wait for interrupt to indicate TPM is ready */ /* Wait for interrupt to indicate TPM is ready */
static int cr50_i2c_wait_tpm_ready(struct udevice *dev) static int cr50_i2c_wait_tpm_ready(struct udevice *dev)
{ {
@ -573,6 +654,87 @@ static int cr50_i2c_get_desc(struct udevice *dev, char *buf, int size)
return len; return len;
} }
static int stringify_state(char *buf, int len, char *str, size_t max_size)
{
struct tpm_vendor_state state;
size_t text_size = 0;
state.version = get_unaligned_be32(buf +
offsetof(struct tpm_vendor_state, version));
state.fail_line = get_unaligned_be32(buf +
offsetof(struct tpm_vendor_state, fail_line));
state.fail_code = get_unaligned_be32(buf +
offsetof(struct tpm_vendor_state, fail_code));
memcpy(state.func_name,
buf + offsetof(struct tpm_vendor_state, func_name),
sizeof(state.func_name));
state.failed_tries = get_unaligned_be32(buf +
offsetof(struct tpm_vendor_state, failed_tries));
state.max_tries = get_unaligned_be32(buf +
offsetof(struct tpm_vendor_state, max_tries));
text_size += snprintf(str + text_size, max_size - text_size,
"v=%d", state.version);
if (text_size >= max_size)
return -ENOSPC;
if (state.version > TPM_STATE_VERSION)
text_size += snprintf(str + text_size,
max_size - text_size,
" not fully supported\n");
if (text_size >= max_size)
return -ENOSPC;
if (state.version == 0)
return -EINVAL; /* This should never happen */
text_size += snprintf(str + text_size,
max_size - text_size,
" failed_tries=%d max_tries=%d\n",
state.failed_tries, state.max_tries);
if (text_size >= max_size)
return -ENOSPC;
if (state.fail_line) {
/* make sure function name is zero terminated. */
char func_name[sizeof(state.func_name) + 1];
memcpy(func_name, state.func_name, sizeof(state.func_name));
func_name[sizeof(state.func_name)] = '\0';
text_size += snprintf(str + text_size,
max_size - text_size,
"tpm failed: f %s line %d code %d",
func_name,
state.fail_line,
state.fail_code);
if (text_size >= max_size)
return -ENOSPC;
}
return 0;
}
static int cr50_i2c_report_state(struct udevice *dev, char *str, int str_max)
{
char buf[50];
size_t buf_size = sizeof(buf);
int ret;
ret = tpm2_report_state(dev, TPM2_CR50_VENDOR_COMMAND,
TPM2_CR50_SUB_CMD_REPORT_TPM_STATE,
buf, &buf_size);
if (ret)
return ret;
/* TPM responded as expected */
ret = stringify_state(buf, buf_size, str, str_max);
if (ret)
return ret;
return 0;
}
static int cr50_i2c_open(struct udevice *dev) static int cr50_i2c_open(struct udevice *dev)
{ {
char buf[80]; char buf[80];
@ -730,6 +892,7 @@ struct acpi_ops cr50_acpi_ops = {
static const struct tpm_ops cr50_i2c_ops = { static const struct tpm_ops cr50_i2c_ops = {
.open = cr50_i2c_open, .open = cr50_i2c_open,
.get_desc = cr50_i2c_get_desc, .get_desc = cr50_i2c_get_desc,
.report_state = cr50_i2c_report_state,
.send = cr50_i2c_send, .send = cr50_i2c_send,
.recv = cr50_i2c_recv, .recv = cr50_i2c_recv,
.cleanup = cr50_i2c_cleanup, .cleanup = cr50_i2c_cleanup,

View file

@ -49,6 +49,16 @@ int tpm_get_desc(struct udevice *dev, char *buf, int size)
return ops->get_desc(dev, buf, size); return ops->get_desc(dev, buf, size);
} }
int tpm_report_state(struct udevice *dev, char *buf, int size)
{
struct tpm_ops *ops = tpm_get_ops(dev);
if (!ops->report_state)
return -ENOSYS;
return ops->report_state(dev, buf, size);
}
/* Returns max number of milliseconds to wait */ /* Returns max number of milliseconds to wait */
static ulong tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip_priv *priv, static ulong tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip_priv *priv,
u32 ordinal) u32 ordinal)

View file

@ -366,8 +366,10 @@ static int sandbox_tpm2_check_readyness(struct udevice *dev, int command)
break; break;
default: default:
if (!tpm->tests_done) /* Skip this, since the startup may have happened in SPL
return TPM2_RC_NEEDS_TEST; * if (!tpm->tests_done)
* return TPM2_RC_NEEDS_TEST;
*/
break; break;
} }
@ -793,6 +795,16 @@ static int sandbox_tpm2_get_desc(struct udevice *dev, char *buf, int size)
return snprintf(buf, size, "Sandbox TPM2.x"); return snprintf(buf, size, "Sandbox TPM2.x");
} }
static int sandbox_tpm2_report_state(struct udevice *dev, char *buf, int size)
{
struct sandbox_tpm2 *priv = dev_get_priv(dev);
if (size < 40)
return -ENOSPC;
return snprintf(buf, size, "init_done=%d", priv->init_done);
}
static int sandbox_tpm2_open(struct udevice *dev) static int sandbox_tpm2_open(struct udevice *dev)
{ {
struct sandbox_tpm2 *tpm = dev_get_priv(dev); struct sandbox_tpm2 *tpm = dev_get_priv(dev);
@ -832,6 +844,7 @@ static const struct tpm_ops sandbox_tpm2_ops = {
.open = sandbox_tpm2_open, .open = sandbox_tpm2_open,
.close = sandbox_tpm2_close, .close = sandbox_tpm2_close,
.get_desc = sandbox_tpm2_get_desc, .get_desc = sandbox_tpm2_get_desc,
.report_state = sandbox_tpm2_report_state,
.xfer = sandbox_tpm2_xfer, .xfer = sandbox_tpm2_xfer,
}; };

View file

@ -119,6 +119,16 @@ struct tpm_ops {
*/ */
int (*get_desc)(struct udevice *dev, char *buf, int size); int (*get_desc)(struct udevice *dev, char *buf, int size);
/**
* report_state() - Collect information about the current TPM state
*
* @dev: Device to check
* @buf: Buffer to put the string
* @size: Maximum size of buffer
* Return: return code of the operation (0 = success)
*/
int (*report_state)(struct udevice *dev, char *buf, int size);
/** /**
* send() - send data to the TPM * send() - send data to the TPM
* *
@ -234,6 +244,16 @@ u32 tpm_clear_and_reenable(struct udevice *dev);
*/ */
int tpm_get_desc(struct udevice *dev, char *buf, int size); int tpm_get_desc(struct udevice *dev, char *buf, int size);
/**
* tpm_report_state() - Collect information about the current TPM state
*
* @dev: Device to check
* @buf: Buffer to put the string
* @size: Maximum size of buffer
* Return: return code of the operation (0 = success)
*/
int tpm_report_state(struct udevice *dev, char *buf, int size);
/** /**
* tpm_xfer() - send data to the TPM and get response * tpm_xfer() - send data to the TPM and get response
* *

View file

@ -658,4 +658,34 @@ u32 tpm2_disable_platform_hierarchy(struct udevice *dev);
u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf, u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
u8 *recvbuf, size_t *recv_size); u8 *recvbuf, size_t *recv_size);
/**
* tpm_cr50_report_state() - Report the Cr50 internal state
*
* @dev: TPM device
* @vendor_cmd: Vendor command number to send
* @vendor_subcmd: Vendor sub-command number to send
* @recvbuf: Buffer to save the response to
* @recv_size: Pointer to the size of the response buffer
* Return: result of the operation
*/
u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
u8 *recvbuf, size_t *recv_size);
/**
* tpm2_enable_nvcommits() - Tell TPM to commit NV data immediately
*
* For Chromium OS verified boot, we may reboot or reset at different times,
* possibly leaving non-volatile data unwritten by the TPM.
*
* This vendor command is used to indicate that non-volatile data should be
* written to its store immediately.
*
* @dev TPM device
* @vendor_cmd: Vendor command number to send
* @vendor_subcmd: Vendor sub-command number to send
* Return: result of the operation
*/
u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
uint vendor_subcmd);
#endif /* __TPM_V2_H */ #endif /* __TPM_V2_H */

View file

@ -81,14 +81,16 @@ u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
* *
* @param dev TPM device * @param dev TPM device
* @param index index of the PCR * @param index index of the PCR
* @param in_digest 160-bit value representing the event to be * @param in_digest 160/256-bit value representing the event to be
* recorded * recorded
* @param out_digest 160-bit PCR value after execution of the * @param size size of digest in bytes
* @param out_digest 160/256-bit PCR value after execution of the
* command * command
* @param name digest source, used for log output
* Return: return code of the operation * Return: return code of the operation
*/ */
u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest, u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest,
void *out_digest); uint size, void *out_digest, const char *name);
/** /**
* Issue a TPM_PCRRead command. * Issue a TPM_PCRRead command.

View file

@ -456,12 +456,13 @@ u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm)
0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x4,
}; };
const size_t index_offset = 18; const size_t index_offset = 18;
const size_t perm_offset = 60; const size_t perm_offset = 74;
u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
size_t response_length = sizeof(response); size_t response_length = sizeof(response);
u32 err; u32 err;
if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command), if (pack_byte_string(buf, sizeof(buf), "sd",
0, command, sizeof(command),
index_offset, index)) index_offset, index))
return TPM_LIB_ERROR; return TPM_LIB_ERROR;
err = tpm_sendrecv_command(dev, buf, response, &response_length); err = tpm_sendrecv_command(dev, buf, response, &response_length);

View file

@ -89,14 +89,18 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
* Calculate the offset of the nv_policy piece by adding each of the * Calculate the offset of the nv_policy piece by adding each of the
* chunks below. * chunks below.
*/ */
uint offset = 10 + 8 + 13 + 14; const int platform_len = sizeof(u32);
const int session_hdr_len = 13;
const int message_len = 14;
uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
message_len;
u8 command_v2[COMMAND_BUFFER_SIZE] = { u8 command_v2[COMMAND_BUFFER_SIZE] = {
/* header 10 bytes */ /* header 10 bytes */
tpm_u16(TPM2_ST_SESSIONS), /* TAG */ tpm_u16(TPM2_ST_SESSIONS), /* TAG */
tpm_u32(offset + nv_policy_size),/* Length */ tpm_u32(offset + nv_policy_size + 2),/* Length */
tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */ tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
/* handles 8 bytes */ /* handles 4 bytes */
tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
/* session header 13 bytes */ /* session header 13 bytes */
@ -107,12 +111,15 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
tpm_u16(0), /* auth_size */ tpm_u16(0), /* auth_size */
/* message 14 bytes + policy */ /* message 14 bytes + policy */
tpm_u16(12 + nv_policy_size), /* size */ tpm_u16(message_len + nv_policy_size), /* size */
tpm_u32(space_index), tpm_u32(space_index),
tpm_u16(TPM2_ALG_SHA256), tpm_u16(TPM2_ALG_SHA256),
tpm_u32(nv_attributes), tpm_u32(nv_attributes),
tpm_u16(nv_policy_size), tpm_u16(nv_policy_size),
/* nv_policy */ /*
* nv_policy
* space_size
*/
}; };
int ret; int ret;
@ -120,8 +127,9 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
* Fill the command structure starting from the first buffer: * Fill the command structure starting from the first buffer:
* - the password (if any) * - the password (if any)
*/ */
ret = pack_byte_string(command_v2, sizeof(command_v2), "s", ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
offset, nv_policy, nv_policy_size); offset, nv_policy, nv_policy_size,
offset + nv_policy_size, space_size);
if (ret) if (ret)
return TPM_LIB_ERROR; return TPM_LIB_ERROR;
@ -157,6 +165,8 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
}; };
int ret; int ret;
if (!digest)
return -EINVAL;
/* /*
* Fill the command structure starting from the first buffer: * Fill the command structure starting from the first buffer:
* - the digest * - the digest
@ -669,3 +679,49 @@ u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
{ {
return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size); return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
} }
u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
u8 *recvbuf, size_t *recv_size)
{
u8 command_v2[COMMAND_BUFFER_SIZE] = {
/* header 10 bytes */
tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
tpm_u32(10 + 2), /* Length */
tpm_u32(vendor_cmd), /* Command code */
tpm_u16(vendor_subcmd),
};
int ret;
ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
log_debug("ret=%s, %x\n", dev->name, ret);
if (ret)
return ret;
if (*recv_size < 12)
return -ENODATA;
*recv_size -= 12;
memcpy(recvbuf, recvbuf + 12, *recv_size);
return 0;
}
u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
uint vendor_subcmd)
{
u8 command_v2[COMMAND_BUFFER_SIZE] = {
/* header 10 bytes */
tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
tpm_u32(10 + 2), /* Length */
tpm_u32(vendor_cmd), /* Command code */
tpm_u16(vendor_subcmd),
};
int ret;
ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
log_debug("ret=%s, %x\n", dev->name, ret);
if (ret)
return ret;
return 0;
}

View file

@ -140,16 +140,18 @@ u32 tpm_write_lock(struct udevice *dev, u32 index)
} }
u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest, u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest,
void *out_digest) uint size, void *out_digest, const char *name)
{ {
if (tpm_is_v1(dev)) if (tpm_is_v1(dev)) {
return tpm1_extend(dev, index, in_digest, out_digest); return tpm1_extend(dev, index, in_digest, out_digest);
else if (tpm_is_v2(dev)) } else if (tpm_is_v2(dev)) {
return tpm2_pcr_extend(dev, index, TPM2_ALG_SHA256, in_digest, return tpm2_pcr_extend(dev, index, TPM2_ALG_SHA256, in_digest,
TPM2_DIGEST_LEN); TPM2_DIGEST_LEN);
else /* @name is ignored as we do not support the TPM log here */
} else {
return -ENOSYS; return -ENOSYS;
} }
}
u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count) u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
{ {

View file

@ -107,6 +107,7 @@ obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o
obj-$(CONFIG_UT_DM) += tag.o obj-$(CONFIG_UT_DM) += tag.o
obj-$(CONFIG_TEE) += tee.o obj-$(CONFIG_TEE) += tee.o
obj-$(CONFIG_TIMER) += timer.o obj-$(CONFIG_TIMER) += timer.o
obj-$(CONFIG_TPM_V2) += tpm.o
obj-$(CONFIG_DM_USB) += usb.o obj-$(CONFIG_DM_USB) += usb.o
obj-$(CONFIG_DM_VIDEO) += video.o obj-$(CONFIG_DM_VIDEO) += video.o
ifeq ($(CONFIG_VIRTIO_SANDBOX),y) ifeq ($(CONFIG_VIRTIO_SANDBOX),y)

34
test/dm/tpm.c Normal file
View file

@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2022 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <dm.h>
#include <tpm_api.h>
#include <dm/test.h>
#include <test/test.h>
#include <test/ut.h>
/* Basic test of the TPM uclass */
static int dm_test_tpm(struct unit_test_state *uts)
{
struct udevice *dev;
char buf[50];
/* check probe success */
ut_assertok(uclass_first_device_err(UCLASS_TPM, &dev));
ut_assert(tpm_is_v2(dev));
ut_assert(tpm_report_state(dev, buf, sizeof(buf)));
ut_asserteq_str("init_done=0", buf);
ut_assertok(tpm_init(dev));
ut_assert(tpm_report_state(dev, buf, sizeof(buf)));
ut_asserteq_str("init_done=1", buf);
return 0;
}
DM_TEST(dm_test_tpm, UT_TESTF_SCAN_FDT);