From cb2c4f93c18b948fbfde9d50ab7d30362be0e00a Mon Sep 17 00:00:00 2001 From: "Ying-Chun Liu (PaulLiu)" Date: Wed, 6 Oct 2021 09:27:00 +0800 Subject: [PATCH] feat(plat/imx/imx8m/imx8mm): add support for measured boot Add helper functions to generate event log for imx8mm when MEASURED_BOOT=1. Signed-off-by: Ying-Chun Liu (PaulLiu) Change-Id: Ifc947d749055787fbda0b39170aa2eb8865b7802 --- plat/imx/imx8m/imx8m_dyn_cfg_helpers.c | 200 +++++++++++++++++++ plat/imx/imx8m/imx8m_measured_boot.c | 85 ++++++++ plat/imx/imx8m/imx8mm/include/platform_def.h | 4 + plat/imx/imx8m/imx8mm/platform.mk | 17 +- plat/imx/imx8m/include/imx8m_measured_boot.h | 16 ++ 5 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 plat/imx/imx8m/imx8m_dyn_cfg_helpers.c create mode 100644 plat/imx/imx8m/imx8m_measured_boot.c create mode 100644 plat/imx/imx8m/include/imx8m_measured_boot.h diff --git a/plat/imx/imx8m/imx8m_dyn_cfg_helpers.c b/plat/imx/imx8m/imx8m_dyn_cfg_helpers.c new file mode 100644 index 000000000..8b2fdd626 --- /dev/null +++ b/plat/imx/imx8m/imx8m_dyn_cfg_helpers.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2022, Linaro. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#if MEASURED_BOOT +#include +#endif +#include +#include + +#define DTB_PROP_HW_LOG_ADDR "tpm_event_log_addr" +#define DTB_PROP_HW_LOG_SIZE "tpm_event_log_size" + +#if MEASURED_BOOT + +static int imx8m_event_log_fdt_init_overlay(uintptr_t dt_base, int dt_size) +{ + int ret; + int offset; + void *dtb = (void *)dt_base; + + ret = fdt_create_empty_tree(dtb, dt_size); + if (ret < 0) { + ERROR("cannot create empty dtb tree: %s\n", + fdt_strerror(ret)); + return ret; + } + + offset = fdt_path_offset(dtb, "/"); + if (offset < 0) { + ERROR("cannot find root of the tree: %s\n", + fdt_strerror(offset)); + return offset; + } + + offset = fdt_add_subnode(dtb, offset, "fragment@0"); + if (offset < 0) { + ERROR("cannot add fragment node: %s\n", + fdt_strerror(offset)); + return offset; + } + + ret = fdt_setprop_string(dtb, offset, "target-path", "/"); + if (ret < 0) { + ERROR("cannot set target-path property: %s\n", + fdt_strerror(ret)); + return ret; + } + + offset = fdt_add_subnode(dtb, offset, "__overlay__"); + if (offset < 0) { + ERROR("cannot add __overlay__ node: %s\n", + fdt_strerror(offset)); + return ret; + } + + offset = fdt_add_subnode(dtb, offset, "tpm_event_log"); + if (offset < 0) { + ERROR("cannot add tpm_event_log node: %s\n", + fdt_strerror(offset)); + return offset; + } + + ret = fdt_setprop_string(dtb, offset, "compatible", + "arm,tpm_event_log"); + if (ret < 0) { + ERROR("cannot set compatible property: %s\n", + fdt_strerror(ret)); + return ret; + } + + ret = fdt_setprop_u64(dtb, offset, "tpm_event_log_addr", 0); + if (ret < 0) { + ERROR("cannot set tpm_event_log_addr property: %s\n", + fdt_strerror(ret)); + return ret; + } + + ret = fdt_setprop_u32(dtb, offset, "tpm_event_log_size", 0); + if (ret < 0) { + ERROR("cannot set tpm_event_log_size property: %s\n", + fdt_strerror(ret)); + return ret; + } + + return ret; +} + +/* + * Write the Event Log address and its size in the DTB. + * + * This function is supposed to be called only by BL2. + * + * Returns: + * 0 = success + * < 0 = error + */ +static int imx8m_set_event_log_info(uintptr_t config_base, + uintptr_t log_addr, size_t log_size) +{ + /* As libfdt uses void *, we can't avoid this cast */ + void *dtb = (void *)config_base; + const char *compatible_tpm = "arm,tpm_event_log"; + uint64_t base = cpu_to_fdt64(log_addr); + uint32_t sz = cpu_to_fdt32(log_size); + int err, node; + + err = fdt_open_into(dtb, dtb, PLAT_IMX8M_DTO_MAX_SIZE); + if (err < 0) { + ERROR("Invalid Device Tree at %p: error %d\n", dtb, err); + return err; + } + + /* + * Verify that the DTB is valid, before attempting to write to it, + * and get the DTB root node. + */ + + /* Check if the pointer to DT is correct */ + err = fdt_check_header(dtb); + if (err < 0) { + WARN("Invalid DTB file passed\n"); + return err; + } + + /* + * Find the TPM node in device tree. + */ + node = fdt_node_offset_by_compatible(dtb, -1, compatible_tpm); + if (node < 0) { + ERROR("The compatible property '%s' not%s", compatible_tpm, + " found in the config\n"); + return node; + } + + err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_ADDR, &base, 8); + if (err < 0) { + ERROR("Failed to add log addr err %d\n", err); + return err; + } + + err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_SIZE, &sz, 4); + if (err < 0) { + ERROR("Failed to add log addr err %d\n", err); + return err; + } + + err = fdt_pack(dtb); + if (err < 0) { + ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, err); + return err; + } + + /* + * Ensure that the info written to the DTB is visible + * to other images. + */ + flush_dcache_range(config_base, fdt_totalsize(dtb)); + + return err; +} + +/* + * This function writes the Event Log address and its size + * in the QEMU DTB. + * + * This function is supposed to be called only by BL2. + * + * Returns: + * 0 = success + * < 0 = error + */ +int imx8m_set_nt_fw_info(size_t log_size, uintptr_t *ns_log_addr) +{ + uintptr_t ns_addr; + int err; + + assert(ns_log_addr != NULL); + + ns_addr = PLAT_IMX8M_DTO_BASE + PLAT_IMX8M_DTO_MAX_SIZE; + + imx8m_event_log_fdt_init_overlay(PLAT_IMX8M_DTO_BASE, + PLAT_IMX8M_DTO_MAX_SIZE); + + /* Write the Event Log address and its size in the DTB */ + err = imx8m_set_event_log_info(PLAT_IMX8M_DTO_BASE, + ns_addr, log_size); + + /* Return Event Log address in Non-secure memory */ + *ns_log_addr = (err < 0) ? 0UL : ns_addr; + return err; +} + +#endif /* MEASURED_BOOT */ diff --git a/plat/imx/imx8m/imx8m_measured_boot.c b/plat/imx/imx8m/imx8m_measured_boot.c new file mode 100644 index 000000000..ec61606e5 --- /dev/null +++ b/plat/imx/imx8m/imx8m_measured_boot.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022, Arm Limited. All rights reserved. + * Copyright (c) 2022, Linaro. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include "./include/imx8m_measured_boot.h" +#include +#include + +/* Event Log data */ +static uint8_t event_log[PLAT_IMX_EVENT_LOG_MAX_SIZE]; + +/* FVP table with platform specific image IDs, names and PCRs */ +static const event_log_metadata_t imx8m_event_log_metadata[] = { + { BL31_IMAGE_ID, EVLOG_BL31_STRING, PCR_0 }, + { BL32_IMAGE_ID, EVLOG_BL32_STRING, PCR_0 }, + { BL32_EXTRA1_IMAGE_ID, EVLOG_BL32_EXTRA1_STRING, PCR_0 }, + { BL32_EXTRA2_IMAGE_ID, EVLOG_BL32_EXTRA2_STRING, PCR_0 }, + { BL33_IMAGE_ID, EVLOG_BL33_STRING, PCR_0 }, + { EVLOG_INVALID_ID, NULL, (unsigned int)(-1) } /* Terminator */ +}; + +const event_log_metadata_t *plat_event_log_get_metadata(void) +{ + return imx8m_event_log_metadata; +} + +int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data) +{ + /* Calculate image hash and record data in Event Log */ + int err = event_log_measure_and_record(image_data->image_base, + image_data->image_size, + image_id); + if (err != 0) { + ERROR("%s%s image id %u (%i)\n", + "Failed to ", "record", image_id, err); + return err; + } + + return 0; +} + +void bl2_plat_mboot_init(void) +{ + event_log_init(event_log, event_log + sizeof(event_log)); + event_log_write_header(); +} + +void bl2_plat_mboot_finish(void) +{ + int rc = 0; + + /* Event Log address in Non-Secure memory */ + uintptr_t ns_log_addr; + + /* Event Log filled size */ + size_t event_log_cur_size; + + event_log_cur_size = event_log_get_cur_size(event_log); + + rc = imx8m_set_nt_fw_info(event_log_cur_size, &ns_log_addr); + if (rc != 0) { + ERROR("%s(): Unable to update %s_FW_CONFIG\n", + __func__, "NT"); + /* + * It is a fatal error because on i.MX U-boot assumes that + * a valid event log exists and will use it to record the + * measurements into the fTPM. + */ + panic(); + } + + /* Copy Event Log to Non-secure memory */ + (void)memcpy((void *)ns_log_addr, (const void *)event_log, + event_log_cur_size); + + /* Ensure that the Event Log is visible in Non-secure memory */ + flush_dcache_range(ns_log_addr, event_log_cur_size); + + dump_event_log((uint8_t *)event_log, event_log_cur_size); +} diff --git a/plat/imx/imx8m/imx8mm/include/platform_def.h b/plat/imx/imx8m/imx8mm/include/platform_def.h index 6709678b2..300ef9e62 100644 --- a/plat/imx/imx8m/imx8mm/include/platform_def.h +++ b/plat/imx/imx8m/imx8mm/include/platform_def.h @@ -152,3 +152,7 @@ #define MAX_IO_HANDLES 3U #define MAX_IO_DEVICES 2U #define MAX_IO_BLOCK_DEVICES 1U + +#define PLAT_IMX8M_DTO_BASE 0x53000000 +#define PLAT_IMX8M_DTO_MAX_SIZE 0x1000 +#define PLAT_IMX_EVENT_LOG_MAX_SIZE UL(0x400) diff --git a/plat/imx/imx8m/imx8mm/platform.mk b/plat/imx/imx8m/imx8mm/platform.mk index ac5a80982..cd8de891b 100644 --- a/plat/imx/imx8m/imx8mm/platform.mk +++ b/plat/imx/imx8m/imx8mm/platform.mk @@ -8,11 +8,14 @@ PLAT_INCLUDES := -Iplat/imx/common/include \ -Iplat/imx/imx8m/include \ -Iplat/imx/imx8m/imx8mm/include \ -Idrivers/imx/usdhc \ - -Iinclude/common/tbbr + -Iinclude/common/tbbr \ + -Iinclude/lib/libfdt # Include GICv3 driver files include drivers/arm/gic/v3/gicv3.mk +include lib/libfdt/libfdt.mk + IMX_GIC_SOURCES := ${GICV3_SOURCES} \ plat/common/plat_gicv3.c \ plat/common/plat_psci_common.c \ @@ -43,6 +46,7 @@ BL31_SOURCES += plat/imx/common/imx8_helpers.S \ ifeq (${NEED_BL2},yes) BL2_SOURCES += common/desc_image_load.c \ + common/fdt_wrappers.c \ plat/imx/common/imx8_helpers.S \ plat/imx/common/imx_uart_console.S \ plat/imx/imx8m/imx8mm/imx8mm_bl2_el3_setup.c \ @@ -148,3 +152,14 @@ $(eval $(call add_define,IMX_BOOT_UART_BASE)) EL3_EXCEPTION_HANDLING := 1 SDEI_SUPPORT := 1 + +ifeq (${MEASURED_BOOT},1) + MEASURED_BOOT_MK := drivers/measured_boot/event_log/event_log.mk + $(info Including ${MEASURED_BOOT_MK}) + include ${MEASURED_BOOT_MK} + +BL2_SOURCES += plat/imx/imx8m/imx8m_measured_boot.c \ + plat/imx/imx8m/imx8m_dyn_cfg_helpers.c \ + ${EVENT_LOG_SOURCES} + +endif diff --git a/plat/imx/imx8m/include/imx8m_measured_boot.h b/plat/imx/imx8m/include/imx8m_measured_boot.h new file mode 100644 index 000000000..2ec0c4646 --- /dev/null +++ b/plat/imx/imx8m/include/imx8m_measured_boot.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022, Linaro + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef IMX8M_MEASURED_BOOT_H +#define IMX8M_MEASURED_BOOT_H + +#include + +#include + +int imx8m_set_nt_fw_info(size_t log_size, uintptr_t *ns_log_addr); + +#endif /* IMX8M_MEASURED_BOOT_H */