1 /* 2 * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved. 3 * Copyright (c) 2022, Linaro. 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 */ 7 8 #include <assert.h> 9 10 #include <arch_helpers.h> 11 #if MEASURED_BOOT 12 #include <common/desc_image_load.h> 13 #endif 14 #include <common/fdt_wrappers.h> 15 #include <libfdt.h> 16 #include <platform_def.h> 17 18 #define DTB_PROP_HW_LOG_ADDR "tpm_event_log_addr" 19 #define DTB_PROP_HW_LOG_SIZE "tpm_event_log_size" 20 21 #if MEASURED_BOOT 22 23 static int imx8m_event_log_fdt_init_overlay(uintptr_t dt_base, int dt_size) 24 { 25 int ret; 26 int offset; 27 void *dtb = (void *)dt_base; 28 29 ret = fdt_create_empty_tree(dtb, dt_size); 30 if (ret < 0) { 31 ERROR("cannot create empty dtb tree: %s\n", 32 fdt_strerror(ret)); 33 return ret; 34 } 35 36 offset = fdt_path_offset(dtb, "/"); 37 if (offset < 0) { 38 ERROR("cannot find root of the tree: %s\n", 39 fdt_strerror(offset)); 40 return offset; 41 } 42 43 offset = fdt_add_subnode(dtb, offset, "fragment@0"); 44 if (offset < 0) { 45 ERROR("cannot add fragment node: %s\n", 46 fdt_strerror(offset)); 47 return offset; 48 } 49 50 ret = fdt_setprop_string(dtb, offset, "target-path", "/"); 51 if (ret < 0) { 52 ERROR("cannot set target-path property: %s\n", 53 fdt_strerror(ret)); 54 return ret; 55 } 56 57 offset = fdt_add_subnode(dtb, offset, "__overlay__"); 58 if (offset < 0) { 59 ERROR("cannot add __overlay__ node: %s\n", 60 fdt_strerror(offset)); 61 return ret; 62 } 63 64 offset = fdt_add_subnode(dtb, offset, "tpm_event_log"); 65 if (offset < 0) { 66 ERROR("cannot add tpm_event_log node: %s\n", 67 fdt_strerror(offset)); 68 return offset; 69 } 70 71 ret = fdt_setprop_string(dtb, offset, "compatible", 72 "arm,tpm_event_log"); 73 if (ret < 0) { 74 ERROR("cannot set compatible property: %s\n", 75 fdt_strerror(ret)); 76 return ret; 77 } 78 79 ret = fdt_setprop_u64(dtb, offset, "tpm_event_log_addr", 0); 80 if (ret < 0) { 81 ERROR("cannot set tpm_event_log_addr property: %s\n", 82 fdt_strerror(ret)); 83 return ret; 84 } 85 86 ret = fdt_setprop_u32(dtb, offset, "tpm_event_log_size", 0); 87 if (ret < 0) { 88 ERROR("cannot set tpm_event_log_size property: %s\n", 89 fdt_strerror(ret)); 90 return ret; 91 } 92 93 return ret; 94 } 95 96 /* 97 * Write the Event Log address and its size in the DTB. 98 * 99 * This function is supposed to be called only by BL2. 100 * 101 * Returns: 102 * 0 = success 103 * < 0 = error 104 */ 105 static int imx8m_set_event_log_info(uintptr_t config_base, 106 uintptr_t log_addr, size_t log_size) 107 { 108 /* As libfdt uses void *, we can't avoid this cast */ 109 void *dtb = (void *)config_base; 110 const char *compatible_tpm = "arm,tpm_event_log"; 111 uint64_t base = cpu_to_fdt64(log_addr); 112 uint32_t sz = cpu_to_fdt32(log_size); 113 int err, node; 114 115 err = fdt_open_into(dtb, dtb, PLAT_IMX8M_DTO_MAX_SIZE); 116 if (err < 0) { 117 ERROR("Invalid Device Tree at %p: error %d\n", dtb, err); 118 return err; 119 } 120 121 /* 122 * Verify that the DTB is valid, before attempting to write to it, 123 * and get the DTB root node. 124 */ 125 126 /* Check if the pointer to DT is correct */ 127 err = fdt_check_header(dtb); 128 if (err < 0) { 129 WARN("Invalid DTB file passed\n"); 130 return err; 131 } 132 133 /* 134 * Find the TPM node in device tree. 135 */ 136 node = fdt_node_offset_by_compatible(dtb, -1, compatible_tpm); 137 if (node < 0) { 138 ERROR("The compatible property '%s' not%s", compatible_tpm, 139 " found in the config\n"); 140 return node; 141 } 142 143 err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_ADDR, &base, 8); 144 if (err < 0) { 145 ERROR("Failed to add log addr err %d\n", err); 146 return err; 147 } 148 149 err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_SIZE, &sz, 4); 150 if (err < 0) { 151 ERROR("Failed to add log addr err %d\n", err); 152 return err; 153 } 154 155 err = fdt_pack(dtb); 156 if (err < 0) { 157 ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, err); 158 return err; 159 } 160 161 /* 162 * Ensure that the info written to the DTB is visible 163 * to other images. 164 */ 165 flush_dcache_range(config_base, fdt_totalsize(dtb)); 166 167 return err; 168 } 169 170 /* 171 * This function writes the Event Log address and its size 172 * in the QEMU DTB. 173 * 174 * This function is supposed to be called only by BL2. 175 * 176 * Returns: 177 * 0 = success 178 * < 0 = error 179 */ 180 int imx8m_set_nt_fw_info(size_t log_size, uintptr_t *ns_log_addr) 181 { 182 uintptr_t ns_addr; 183 int err; 184 185 assert(ns_log_addr != NULL); 186 187 ns_addr = PLAT_IMX8M_DTO_BASE + PLAT_IMX8M_DTO_MAX_SIZE; 188 189 imx8m_event_log_fdt_init_overlay(PLAT_IMX8M_DTO_BASE, 190 PLAT_IMX8M_DTO_MAX_SIZE); 191 192 /* Write the Event Log address and its size in the DTB */ 193 err = imx8m_set_event_log_info(PLAT_IMX8M_DTO_BASE, 194 ns_addr, log_size); 195 196 /* Return Event Log address in Non-secure memory */ 197 *ns_log_addr = (err < 0) ? 0UL : ns_addr; 198 return err; 199 } 200 201 #endif /* MEASURED_BOOT */ 202