
U-Boot might be the first component to start the event log. So allocate and attach it to the device if not initialized. The address is copied into the device tree for the kernel so the event log is accessible from Linux userspace too. TODO: Is devm_kzalloc() the right way to allocate the event log here? Do we need to use lmb instead and mark the area in a specific way so the Linux kernel won't accidentally overwrite the memory before the tpm module reads it? Signed-off-by: Ludwig Nussel <ludwig.nussel@siemens.com> --- boot/image-fdt.c | 65 +++++++++++++++++++++++++++++ include/tpm-common.h | 1 + include/tpm_tcg2.h | 4 ++ lib/tpm_tcg2.c | 97 +++++++++++++++++++++++++++++++++++--------- 4 files changed, 148 insertions(+), 19 deletions(-) diff --git a/boot/image-fdt.c b/boot/image-fdt.c index 3f0ac54f76f..30684decc34 100644 --- a/boot/image-fdt.c +++ b/boot/image-fdt.c @@ -24,6 +24,10 @@ #include <asm/io.h> #include <dm/ofnode.h> #include <tee/optee.h> +#if defined(CONFIG_MEASURED_BOOT) +#include <tpm_tcg2.h> +#include <dm/device.h> +#endif DECLARE_GLOBAL_DATA_PTR; @@ -583,6 +587,65 @@ __weak int arch_fixup_fdt(void *blob) return 0; } +static int copy_tpm_event_log(void *blob) +{ +#if defined(CONFIG_MEASURED_BOOT) + int rc; + struct udevice *dev; + ofnode node; + char path[256]; + + rc = tcg2_platform_get_tpm2(&dev); + if (rc) + return rc; + + struct tcg2_event_log *log = tcg2_platform_get_dev_log(dev); + + if (!log || !log->allocated) { + log_debug("tpm event log not allocated\n"); + return -ENOENT; + } + + node = dev_ofnode(dev); + if (!ofnode_valid(node)) { + log_err("tpm %p has no device tree representation\n", dev); + return -ENOENT; + } + + rc = ofnode_get_path(node, path, sizeof(path)); + if (rc) + return rc; + + if (fdt_path_offset(blob, path) < 0) { + log_warning("kernel device tree lacks %s\n", path); + return 0; + } + + strlcat(path, "/linux,sml-base", sizeof(path)); + if (fdt_path_offset(blob, path) >= 0) { + log_warning("kernel dt already defines an event log address at %s\n", path); + return 0; + } + char *end = strrchr(path, '/'); + *end = 0; + + fdt64_t a = cpu_to_fdt64((u64)virt_to_phys(log->log)); + fdt32_t s = cpu_to_fdt32((u32)log->log_position); + + rc = fdt_find_and_setprop(blob, path, "linux,sml-base", &a, sizeof(a), 1); + if (rc) { + log_err("failed to set sml-base: %d\n", rc); + return rc; + } + rc = fdt_find_and_setprop(blob, path, "linux,sml-size", &s, sizeof(s), 1); + if (rc) { + log_err("failed to set sml-size: %d\n", rc); + return rc; + } +#endif + return 0; +} + int image_setup_libfdt(struct bootm_headers *images, void *blob, bool lmb) { ulong *initrd_start = &images->initrd_start; @@ -625,6 +688,8 @@ int image_setup_libfdt(struct bootm_headers *images, void *blob, bool lmb) goto err; } + copy_tpm_event_log(blob); + /* Store name of configuration node as u-boot,bootconf in /chosen node */ if (images->fit_uname_cfg) fdt_find_and_setprop(blob, "/chosen", "u-boot,bootconf", diff --git a/include/tpm-common.h b/include/tpm-common.h index bfb84a931d1..f02dae679bd 100644 --- a/include/tpm-common.h +++ b/include/tpm-common.h @@ -83,6 +83,7 @@ struct tpm_chip_priv { u32 active_banks[TPM2_NUM_PCR_BANKS]; #endif bool plat_hier_disabled; + void *log; /* struct tcg2_event_log */ }; /** diff --git a/include/tpm_tcg2.h b/include/tpm_tcg2.h index eb6afe49e77..1b40abc4d7b 100644 --- a/include/tpm_tcg2.h +++ b/include/tpm_tcg2.h @@ -162,12 +162,14 @@ struct tcg_efi_spec_id_event { * @log_position: Current entry position * @log_size: Log space available * @found: Boolean indicating if an existing log was discovered + * @allocated: Boolean indicating that the log was allocated by u-boot */ struct tcg2_event_log { u8 *log; u32 log_position; u32 log_size; bool found; + bool allocated; }; /** @@ -345,4 +347,6 @@ void tcg2_platform_startup_error(struct udevice *dev, int rc); */ u32 tcg2_algorithm_to_mask(enum tpm2_algorithms); +struct tcg2_event_log *tcg2_platform_get_dev_log(struct udevice *dev); + #endif /* __TPM_TCG_V2_H */ diff --git a/lib/tpm_tcg2.c b/lib/tpm_tcg2.c index c314b401d0b..0d994120255 100644 --- a/lib/tpm_tcg2.c +++ b/lib/tpm_tcg2.c @@ -20,6 +20,8 @@ #include <linux/unaligned/le_byteshift.h> #include "tpm-utils.h" #include <bloblist.h> +#include <dm/devres.h> +#include <lmb.h> int tcg2_get_pcr_info(struct udevice *dev, u32 *supported_bank, u32 *active_bank, u32 *bank_num) @@ -205,6 +207,9 @@ static int tcg2_log_append_check(struct tcg2_event_log *elog, u32 pcr_index, u32 event_size; u8 *log; + if (!elog->log_size) + return 0; + event_size = size + tcg2_event_get_size(digest_list); if (elog->log_position + event_size > elog->log_size) { printf("%s: log too large: %u + %u > %u\n", __func__, @@ -533,6 +538,14 @@ int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog, struct tpml_digest_values digest_list; int rc; + if (!elog) + elog = tcg2_platform_get_dev_log(dev); + + if (!elog) { + log_err("no event log allocated"); + return -ENOENT; + } + if (data) rc = tcg2_create_digest(dev, data, size, &digest_list); else @@ -555,11 +568,29 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, int rc; u32 log_active = 0; - elog->log_position = 0; - elog->found = false; + if (elog) { + elog->log_position = 0; + elog->found = false; + elog->allocated = false; + } else if (tcg2_platform_get_dev_log(dev)) { + return -EEXIST; + } rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size); - if (!rc) { + /* no existing event log found and none allocated yet */ + if (rc && !elog) { + /* magic size value. Same as in acpi_table.c */ + log.log_size = 0x10000; + log.log = devm_kzalloc(dev, log.log_size, 0); + if (log.log) { + log.allocated = true; + ignore_existing_log = true; + } else { + log_err("Failed to allocate %u bytes event log\n", log.log_size); + } + } + + if (log.log) { log.log_position = 0; log.found = false; @@ -571,26 +602,40 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, return rc; } - if (elog->log_size) { - if (log.found) { - if (elog->log_size < log.log_position) - return -ENOBUFS; - - /* - * Copy the discovered log into the user buffer - * if there's enough space. - */ - memcpy(elog->log, log.log, log.log_position); + if (elog) { + if (elog->log_size) { + if (log.found) { + if (elog->log_size < log.log_position) + return -ENOBUFS; + + /* + * Copy the discovered log into the user buffer + * if there's enough space. + */ + memcpy(elog->log, log.log, log.log_position); + } + + unmap_physmem(log.log, MAP_NOCACHE); + } else { + elog->log = log.log; + elog->log_size = log.log_size; } - unmap_physmem(log.log, MAP_NOCACHE); + elog->log_position = log.log_position; + elog->found = log.found; } else { + struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); + + elog = devm_kzalloc(dev, sizeof(struct tcg2_event_log), 0); + elog->log = log.log; elog->log_size = log.log_size; - } + elog->log_position = log.log_position; + elog->found = log.found; + elog->allocated = log.allocated; - elog->log_position = log.log_position; - elog->found = log.found; + priv->log = elog; + } } pcr_allocate: @@ -603,8 +648,10 @@ pcr_allocate: * valid. User's can pass in their own buffer as a fallback if no * memory region is found. */ - if (!elog->found && elog->log_size) - rc = tcg2_log_init(dev, elog); + if (elog) { + if (!elog->found && elog->log_size) + rc = tcg2_log_init(dev, elog); + } return rc; } @@ -618,6 +665,9 @@ int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog, if (rc) return rc; + if (!elog && tcg2_platform_get_dev_log(*dev)) + return -EEXIST; + rc = tpm_auto_start(*dev); if (rc) return rc; @@ -653,6 +703,15 @@ void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog, unmap_physmem(elog->log, MAP_NOCACHE); } +struct tcg2_event_log *tcg2_platform_get_dev_log(struct udevice *dev) +{ + struct tpm_chip_priv *priv; + + priv = dev_get_uclass_priv(dev); + + return priv->log; +} + __weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size) { const __be32 *addr_prop = NULL; -- 2.34.1