mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
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:
commit
427aa3c9b7
16 changed files with 380 additions and 21 deletions
|
@ -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;
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
70
lib/tpm-v2.c
70
lib/tpm-v2.c
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
34
test/dm/tpm.c
Normal 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);
|
Loading…
Reference in a new issue