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 
imx8m_event_log_fdt_init_overlay(uintptr_t dt_base,int dt_size)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  */
imx8m_set_event_log_info(uintptr_t config_base,uintptr_t log_addr,size_t log_size)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  */
imx8m_set_nt_fw_info(size_t log_size,uintptr_t * ns_log_addr)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