diff options
30 files changed, 448 insertions, 50 deletions
diff --git a/arch/arm/dts/r7s72100-gr-peach-u-boot.dts b/arch/arm/dts/r7s72100-gr-peach-u-boot.dts index f48121a..5b176a9 100644 --- a/arch/arm/dts/r7s72100-gr-peach-u-boot.dts +++ b/arch/arm/dts/r7s72100-gr-peach-u-boot.dts @@ -46,8 +46,8 @@ }; - rpc: rpc@ee200000 { - compatible = "renesas,rpc-r7s72100", "renesas,rpc"; + rpc: spi@ee200000 { + compatible = "renesas,r7s72100-rpc-if"; reg = <0x3fefa000 0x100>, <0x18000000 0x08000000>; bank-width = <2>; num-cs = <1>; diff --git a/arch/arm/dts/r8a774c0-u-boot.dtsi b/arch/arm/dts/r8a774c0-u-boot.dtsi index af1c861..d296106 100644 --- a/arch/arm/dts/r8a774c0-u-boot.dtsi +++ b/arch/arm/dts/r8a774c0-u-boot.dtsi @@ -10,8 +10,8 @@ / { soc { - rpc: rpc@ee200000 { - compatible = "renesas,rcar-gen3-rpc", "renesas,rpc-r8a774c0"; + rpc: spi@ee200000 { + compatible = "renesas,r8a774c0-rpc-if", "renesas,rcar-gen3-rpc-if"; reg = <0 0xee200000 0 0x100>, <0 0x08000000 0 0x04000000>; clocks = <&cpg CPG_MOD 917>; bank-width = <2>; diff --git a/arch/arm/dts/r8a77950-u-boot.dtsi b/arch/arm/dts/r8a77950-u-boot.dtsi index 5a11651..2306c7b 100644 --- a/arch/arm/dts/r8a77950-u-boot.dtsi +++ b/arch/arm/dts/r8a77950-u-boot.dtsi @@ -13,8 +13,8 @@ / { soc { - rpc: rpc@ee200000 { - compatible = "renesas,rpc-r8a7795", "renesas,rpc"; + rpc: spi@ee200000 { + compatible = "renesas,r8a7795-rpc-if", "renesas,rcar-gen3-rpc-if"; reg = <0 0xee200000 0 0x100>, <0 0x08000000 0 0>; clocks = <&cpg CPG_MOD 917>; bank-width = <2>; diff --git a/arch/arm/dts/r8a77960-u-boot.dtsi b/arch/arm/dts/r8a77960-u-boot.dtsi index f1cae1c..f64e5a4 100644 --- a/arch/arm/dts/r8a77960-u-boot.dtsi +++ b/arch/arm/dts/r8a77960-u-boot.dtsi @@ -13,8 +13,8 @@ / { soc { - rpc: rpc@ee200000 { - compatible = "renesas,rpc-r8a7796", "renesas,rpc"; + rpc: spi@ee200000 { + compatible = "renesas,r8a7796-rpc-if", "renesas,rcar-gen3-rpc-if"; reg = <0 0xee200000 0 0x100>, <0 0x08000000 0 0>; clocks = <&cpg CPG_MOD 917>; bank-width = <2>; diff --git a/arch/arm/dts/r8a77965-u-boot.dtsi b/arch/arm/dts/r8a77965-u-boot.dtsi index 9cc6f20..c4abcc5 100644 --- a/arch/arm/dts/r8a77965-u-boot.dtsi +++ b/arch/arm/dts/r8a77965-u-boot.dtsi @@ -13,8 +13,8 @@ / { soc { - rpc: rpc@ee200000 { - compatible = "renesas,rpc-r8a77965", "renesas,rpc"; + rpc: spi@ee200000 { + compatible = "renesas,r8a77965-rpc-if", "renesas,rcar-gen3-rpc-if"; reg = <0 0xee200000 0 0x100>, <0 0x08000000 0 0>; clocks = <&cpg CPG_MOD 917>; bank-width = <2>; diff --git a/arch/arm/dts/r8a77970-u-boot.dtsi b/arch/arm/dts/r8a77970-u-boot.dtsi index ac3c6be..614caa9 100644 --- a/arch/arm/dts/r8a77970-u-boot.dtsi +++ b/arch/arm/dts/r8a77970-u-boot.dtsi @@ -13,8 +13,8 @@ / { soc { - rpc: rpc@ee200000 { - compatible = "renesas,rpc-r8a77970", "renesas,rpc"; + rpc: spi@ee200000 { + compatible = "renesas,r8a77970-rpc-if", "renesas,rcar-gen3-rpc-if"; reg = <0 0xee200000 0 0x100>, <0 0x08000000 0 0>; clocks = <&cpg CPG_MOD 917>; bank-width = <2>; diff --git a/arch/arm/dts/r8a77980-u-boot.dtsi b/arch/arm/dts/r8a77980-u-boot.dtsi index 365d40a..54f01c9 100644 --- a/arch/arm/dts/r8a77980-u-boot.dtsi +++ b/arch/arm/dts/r8a77980-u-boot.dtsi @@ -13,8 +13,8 @@ / { soc { - rpc: rpc@ee200000 { - compatible = "renesas,rpc-r8a77980", "renesas,rpc"; + rpc: spi@ee200000 { + compatible = "renesas,r8a77980-rpc-if", "renesas,rcar-gen3-rpc-if"; reg = <0 0xee200000 0 0x100>, <0 0x08000000 0 0>; clocks = <&cpg CPG_MOD 917>; bank-width = <2>; diff --git a/arch/arm/dts/r8a77990-u-boot.dtsi b/arch/arm/dts/r8a77990-u-boot.dtsi index 6655abe..50bbbe1 100644 --- a/arch/arm/dts/r8a77990-u-boot.dtsi +++ b/arch/arm/dts/r8a77990-u-boot.dtsi @@ -9,8 +9,8 @@ / { soc { - rpc: rpc@ee200000 { - compatible = "renesas,rpc-r8a77990", "renesas,rpc"; + rpc: spi@ee200000 { + compatible = "renesas,r8a77990-rpc-if", "renesas,rcar-gen3-rpc-if"; reg = <0 0xee200000 0 0x100>, <0 0x08000000 0 0>; clocks = <&cpg CPG_MOD 917>; bank-width = <2>; diff --git a/arch/arm/dts/r8a77995-u-boot.dtsi b/arch/arm/dts/r8a77995-u-boot.dtsi index 0917a80..347b59a 100644 --- a/arch/arm/dts/r8a77995-u-boot.dtsi +++ b/arch/arm/dts/r8a77995-u-boot.dtsi @@ -9,8 +9,8 @@ / { soc { - rpc: rpc@ee200000 { - compatible = "renesas,rpc-r8a77995", "renesas,rpc"; + rpc: spi@ee200000 { + compatible = "renesas,r8a77995-rpc-if", "renesas,rcar-gen3-rpc-if"; reg = <0 0xee200000 0 0x100>, <0 0x08000000 0 0>; clocks = <&cpg CPG_MOD 917>; bank-width = <2>; diff --git a/arch/arm/dts/r8a779a0-u-boot.dtsi b/arch/arm/dts/r8a779a0-u-boot.dtsi index 83dbe3f..9f2772a 100644 --- a/arch/arm/dts/r8a779a0-u-boot.dtsi +++ b/arch/arm/dts/r8a779a0-u-boot.dtsi @@ -10,7 +10,7 @@ / { soc { rpc: spi@ee200000 { - compatible = "renesas,rpc-r8a779a0", "renesas,rcar-gen3-rpc"; + compatible = "renesas,r8a779a0-rpc-if", "renesas,rcar-gen3-rpc-if"; reg = <0 0xee200000 0 0x200>, <0 0x08000000 0 0x04000000>; clocks = <&cpg CPG_MOD 629>; bank-width = <2>; diff --git a/board/renesas/rcar-common/common.c b/board/renesas/rcar-common/common.c index 0352d34..daa1beb 100644 --- a/board/renesas/rcar-common/common.c +++ b/board/renesas/rcar-common/common.c @@ -9,6 +9,7 @@ #include <common.h> #include <dm.h> +#include <fdt_support.h> #include <init.h> #include <asm/global_data.h> #include <dm/uclass-internal.h> @@ -19,9 +20,11 @@ DECLARE_GLOBAL_DATA_PTR; -/* If the firmware passed a device tree use it for U-Boot DRAM setup. */ +/* If the firmware passed a device tree use it for e.g. U-Boot DRAM setup. */ extern u64 rcar_atf_boot_args[]; +#define FDT_RPC_PATH "/soc/spi@ee200000" + int fdtdec_board_setup(const void *fdt_blob) { void *atf_fdt_blob = (void *)(rcar_atf_boot_args[1]); @@ -81,7 +84,7 @@ static int is_mem_overlap(void *blob, int first_mem_node, int curr_mem_node) return 0; } -int ft_board_setup(void *blob, struct bd_info *bd) +static void scrub_duplicate_memory(void *blob) { /* * Scrub duplicate /memory@* node entries here. Some R-Car DTs might @@ -119,6 +122,45 @@ int ft_board_setup(void *blob, struct bd_info *bd) first_mem_node = 0; mem = 0; } +} + +static void update_rpc_status(void *blob) +{ + void *atf_fdt_blob = (void *)(rcar_atf_boot_args[1]); + int offset, enabled; + + /* + * Check if the DT fragment received from TF-A had its RPC-IF device node + * enabled. + */ + if (fdt_magic(atf_fdt_blob) != FDT_MAGIC) + return; + + offset = fdt_path_offset(atf_fdt_blob, FDT_RPC_PATH); + if (offset < 0) + return; + + enabled = fdtdec_get_is_enabled(atf_fdt_blob, offset); + if (!enabled) + return; + + /* + * Find the RPC-IF device node, and enable it if it has a flash subnode. + */ + offset = fdt_path_offset(blob, FDT_RPC_PATH); + if (offset < 0) + return; + + if (fdt_subnode_offset(blob, offset, "flash") < 0) + return; + + fdt_status_okay(blob, offset); +} + +int ft_board_setup(void *blob, struct bd_info *bd) +{ + scrub_duplicate_memory(blob); + update_rpc_status(blob); return 0; } diff --git a/cmd/tpm-common.c b/cmd/tpm-common.c index 47adaff..d0c63ca 100644 --- a/cmd/tpm-common.c +++ b/cmd/tpm-common.c @@ -333,6 +333,26 @@ int do_tpm_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) 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[]) { struct udevice *dev; diff --git a/cmd/tpm-user-utils.h b/cmd/tpm-user-utils.h index 358ddff..de4a934 100644 --- a/cmd/tpm-user-utils.h +++ b/cmd/tpm-user-utils.h @@ -21,6 +21,8 @@ int do_tpm_device(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_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[]); #endif /* __TPM_USER_UTILS_H */ diff --git a/cmd/tpm-v1.c b/cmd/tpm-v1.c index bf238a9..0efb079 100644 --- a/cmd/tpm-v1.c +++ b/cmd/tpm-v1.c @@ -131,7 +131,8 @@ static int do_tpm_extend(struct cmd_tbl *cmdtp, int flag, int argc, 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) { puts("PCR value after execution of the command:\n"); print_byte_string(out_digest, sizeof(out_digest)); diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c index 4ea5f9f..d93b83a 100644 --- a/cmd/tpm-v2.c +++ b/cmd/tpm-v2.c @@ -359,6 +359,7 @@ static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, static struct cmd_tbl tpm2_commands[] = { U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""), 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(startup, 0, 1, do_tpm2_startup, "", ""), 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" "info\n" " Show information about the TPM.\n" +"state\n" +" Show internal state from the TPM (if available)\n" "init\n" " Initialize the software stack. Always the first command to issue.\n" "startup <mode>\n" diff --git a/cmd/tpm_test.c b/cmd/tpm_test.c index a3ccb12..b35eae8 100644 --- a/cmd/tpm_test.c +++ b/cmd/tpm_test.c @@ -91,7 +91,8 @@ static int test_early_extend(struct udevice *dev) tpm_init(dev); TPM_CHECK(tpm_startup(dev, TPM_ST_CLEAR)); 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"); return 0; } @@ -438,7 +439,7 @@ static int test_timing(struct udevice *dev) 100); TTPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x)), 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_tsc_physical_presence(dev, PHYS_PRESENCE), 100); printf("done\n"); diff --git a/drivers/mtd/renesas_rpc_hf.c b/drivers/mtd/renesas_rpc_hf.c index 2c61ce7..aca7a6c 100644 --- a/drivers/mtd/renesas_rpc_hf.c +++ b/drivers/mtd/renesas_rpc_hf.c @@ -388,7 +388,8 @@ static int rpc_hf_probe(struct udevice *dev) } static const struct udevice_id rpc_hf_ids[] = { - { .compatible = "renesas,rpc" }, + { .compatible = "renesas,r7s72100-rpc-if" }, + { .compatible = "renesas,rcar-gen3-rpc-if" }, {} }; diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c index 26b6aa8..cb2b8fb 100644 --- a/drivers/spi/renesas_rpc_spi.c +++ b/drivers/spi/renesas_rpc_spi.c @@ -449,13 +449,8 @@ static const struct dm_spi_ops rpc_spi_ops = { }; static const struct udevice_id rpc_spi_ids[] = { - { .compatible = "renesas,rpc-r7s72100" }, - { .compatible = "renesas,rpc-r8a7795" }, - { .compatible = "renesas,rpc-r8a7796" }, - { .compatible = "renesas,rpc-r8a77965" }, - { .compatible = "renesas,rpc-r8a77970" }, - { .compatible = "renesas,rpc-r8a77995" }, - { .compatible = "renesas,rcar-gen3-rpc" }, + { .compatible = "renesas,r7s72100-rpc-if" }, + { .compatible = "renesas,rcar-gen3-rpc-if" }, { } }; diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c index f8c3087..acf4c78 100644 --- a/drivers/tpm/cr50_i2c.c +++ b/drivers/tpm/cr50_i2c.c @@ -13,11 +13,13 @@ #include <irq.h> #include <log.h> #include <spl.h> +#include <tpm-common.h> #include <tpm-v2.h> #include <acpi/acpigen.h> #include <acpi/acpi_device.h> #include <asm/gpio.h> #include <asm/io.h> +#include <asm/unaligned.h> #include <linux/delay.h> #include <dm/acpi.h> @@ -37,6 +39,50 @@ enum { 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 * @@ -54,6 +100,41 @@ struct cr50_priv { 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 */ 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; } +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) { char buf[80]; @@ -730,6 +892,7 @@ struct acpi_ops cr50_acpi_ops = { static const struct tpm_ops cr50_i2c_ops = { .open = cr50_i2c_open, .get_desc = cr50_i2c_get_desc, + .report_state = cr50_i2c_report_state, .send = cr50_i2c_send, .recv = cr50_i2c_recv, .cleanup = cr50_i2c_cleanup, diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c index 0eb35f5..5ff0cd3 100644 --- a/drivers/tpm/tpm-uclass.c +++ b/drivers/tpm/tpm-uclass.c @@ -49,6 +49,16 @@ int tpm_get_desc(struct udevice *dev, char *buf, int 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 */ static ulong tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip_priv *priv, u32 ordinal) diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c index ac6eb14..dd94bdc 100644 --- a/drivers/tpm/tpm2_tis_sandbox.c +++ b/drivers/tpm/tpm2_tis_sandbox.c @@ -366,8 +366,10 @@ static int sandbox_tpm2_check_readyness(struct udevice *dev, int command) break; default: - if (!tpm->tests_done) - return TPM2_RC_NEEDS_TEST; + /* Skip this, since the startup may have happened in SPL + * if (!tpm->tests_done) + * return TPM2_RC_NEEDS_TEST; + */ 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"); } +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) { struct sandbox_tpm2 *tpm = dev_get_priv(dev); @@ -832,6 +844,7 @@ static const struct tpm_ops sandbox_tpm2_ops = { .open = sandbox_tpm2_open, .close = sandbox_tpm2_close, .get_desc = sandbox_tpm2_get_desc, + .report_state = sandbox_tpm2_report_state, .xfer = sandbox_tpm2_xfer, }; diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 8ba55aa..d0e92c7 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -119,6 +119,7 @@ static struct usb_descriptor_header *fb_fs_function[] = { (struct usb_descriptor_header *)&interface_desc, (struct usb_descriptor_header *)&fs_ep_in, (struct usb_descriptor_header *)&fs_ep_out, + NULL, }; static struct usb_descriptor_header *fb_hs_function[] = { diff --git a/include/tpm-common.h b/include/tpm-common.h index a28629e..b2c5404 100644 --- a/include/tpm-common.h +++ b/include/tpm-common.h @@ -120,6 +120,16 @@ struct tpm_ops { 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 * * @dev: Device to talk to @@ -235,6 +245,16 @@ u32 tpm_clear_and_reenable(struct udevice *dev); 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 * * This first uses the device's send() method to send the bytes. Then it calls diff --git a/include/tpm-v2.h b/include/tpm-v2.h index e79c90b..737e575 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -658,4 +658,34 @@ u32 tpm2_disable_platform_hierarchy(struct udevice *dev); u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf, 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 */ diff --git a/include/tpm_api.h b/include/tpm_api.h index 11aa14e..8979d9d 100644 --- a/include/tpm_api.h +++ b/include/tpm_api.h @@ -81,14 +81,16 @@ u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data, * * @param dev TPM device * @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 - * @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 + * @param name digest source, used for log output * Return: return code of the operation */ 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. diff --git a/lib/tpm-v1.c b/lib/tpm-v1.c index 22a769c..d0e3ab1 100644 --- a/lib/tpm-v1.c +++ b/lib/tpm-v1.c @@ -456,12 +456,13 @@ u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm) 0x0, 0x0, 0x0, 0x4, }; 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]; size_t response_length = sizeof(response); 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)) return TPM_LIB_ERROR; err = tpm_sendrecv_command(dev, buf, response, &response_length); diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 1bf6278..697b982 100644 --- a/lib/tpm-v2.c +++ b/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 * 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] = { /* header 10 bytes */ 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 */ - /* handles 8 bytes */ + /* handles 4 bytes */ tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ /* session header 13 bytes */ @@ -107,12 +111,15 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index, tpm_u16(0), /* auth_size */ /* message 14 bytes + policy */ - tpm_u16(12 + nv_policy_size), /* size */ + tpm_u16(message_len + nv_policy_size), /* size */ tpm_u32(space_index), tpm_u16(TPM2_ALG_SHA256), tpm_u32(nv_attributes), tpm_u16(nv_policy_size), - /* nv_policy */ + /* + * nv_policy + * space_size + */ }; 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: * - the password (if any) */ - ret = pack_byte_string(command_v2, sizeof(command_v2), "s", - offset, nv_policy, nv_policy_size); + ret = pack_byte_string(command_v2, sizeof(command_v2), "sw", + offset, nv_policy, nv_policy_size, + offset + nv_policy_size, space_size); if (ret) return TPM_LIB_ERROR; @@ -157,6 +165,8 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm, }; int ret; + if (!digest) + return -EINVAL; /* * Fill the command structure starting from the first buffer: * - 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); } + +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; +} diff --git a/lib/tpm_api.c b/lib/tpm_api.c index 032f383..7e8df87 100644 --- a/lib/tpm_api.c +++ b/lib/tpm_api.c @@ -140,15 +140,17 @@ u32 tpm_write_lock(struct udevice *dev, u32 index) } 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); - else if (tpm_is_v2(dev)) + } else if (tpm_is_v2(dev)) { return tpm2_pcr_extend(dev, index, TPM2_ALG_SHA256, in_digest, TPM2_DIGEST_LEN); - else + /* @name is ignored as we do not support the TPM log here */ + } else { return -ENOSYS; + } } u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count) diff --git a/test/dm/Makefile b/test/dm/Makefile index 52fe178..7543df8 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -107,6 +107,7 @@ obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o obj-$(CONFIG_UT_DM) += tag.o obj-$(CONFIG_TEE) += tee.o obj-$(CONFIG_TIMER) += timer.o +obj-$(CONFIG_TPM_V2) += tpm.o obj-$(CONFIG_DM_USB) += usb.o obj-$(CONFIG_DM_VIDEO) += video.o ifeq ($(CONFIG_VIRTIO_SANDBOX),y) diff --git a/test/dm/tpm.c b/test/dm/tpm.c new file mode 100644 index 0000000..0b46f79 --- /dev/null +++ b/test/dm/tpm.c @@ -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); |