]>
Commit | Line | Data |
---|---|---|
7e2db742 PF |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright 2018-2019 NXP | |
4 | */ | |
5 | ||
6 | #include <common.h> | |
7 | #include <errno.h> | |
8 | #include <asm/io.h> | |
9 | #include <asm/arch/sci/sci.h> | |
10 | #include <asm/mach-imx/sys_proto.h> | |
11 | #include <asm/arch-imx/cpu.h> | |
12 | #include <asm/arch/sys_proto.h> | |
13 | #include <asm/arch/image.h> | |
14 | #include <console.h> | |
15 | ||
16 | DECLARE_GLOBAL_DATA_PTR; | |
17 | ||
18 | #define SEC_SECURE_RAM_BASE (0x31800000UL) | |
19 | #define SEC_SECURE_RAM_END_BASE (SEC_SECURE_RAM_BASE + 0xFFFFUL) | |
20 | #define SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE (0x60000000UL) | |
21 | ||
22 | #define SECO_PT 2U | |
23 | ||
24 | static inline bool check_in_dram(ulong addr) | |
25 | { | |
26 | int i; | |
27 | bd_t *bd = gd->bd; | |
28 | ||
29 | for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) { | |
30 | if (bd->bi_dram[i].size) { | |
31 | if (addr >= bd->bi_dram[i].start && | |
32 | addr < (bd->bi_dram[i].start + bd->bi_dram[i].size)) | |
33 | return true; | |
34 | } | |
35 | } | |
36 | ||
37 | return false; | |
38 | } | |
39 | ||
40 | int authenticate_os_container(ulong addr) | |
41 | { | |
42 | struct container_hdr *phdr; | |
43 | int i, ret = 0; | |
44 | int err; | |
45 | sc_rm_mr_t mr; | |
46 | sc_faddr_t start, end; | |
47 | u16 length; | |
48 | struct boot_img_t *img; | |
49 | unsigned long s, e; | |
50 | ||
51 | if (addr % 4) { | |
52 | puts("Error: Image's address is not 4 byte aligned\n"); | |
53 | return -EINVAL; | |
54 | } | |
55 | ||
56 | if (!check_in_dram(addr)) { | |
57 | puts("Error: Image's address is invalid\n"); | |
58 | return -EINVAL; | |
59 | } | |
60 | ||
61 | phdr = (struct container_hdr *)addr; | |
62 | if (phdr->tag != 0x87 && phdr->version != 0x0) { | |
63 | printf("Error: Wrong container header\n"); | |
64 | return -EFAULT; | |
65 | } | |
66 | ||
67 | if (!phdr->num_images) { | |
68 | printf("Error: Wrong container, no image found\n"); | |
69 | return -EFAULT; | |
70 | } | |
71 | ||
72 | length = phdr->length_lsb + (phdr->length_msb << 8); | |
73 | ||
74 | debug("container length %u\n", length); | |
75 | memcpy((void *)SEC_SECURE_RAM_BASE, (const void *)addr, | |
76 | ALIGN(length, CONFIG_SYS_CACHELINE_SIZE)); | |
77 | ||
a903e13f | 78 | err = sc_seco_authenticate(-1, SC_SECO_AUTH_CONTAINER, |
7e2db742 PF |
79 | SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE); |
80 | if (err) { | |
81 | printf("Authenticate container hdr failed, return %d\n", | |
82 | err); | |
83 | ret = -EIO; | |
84 | goto exit; | |
85 | } | |
86 | ||
87 | /* Copy images to dest address */ | |
88 | for (i = 0; i < phdr->num_images; i++) { | |
89 | img = (struct boot_img_t *)(addr + | |
90 | sizeof(struct container_hdr) + | |
91 | i * sizeof(struct boot_img_t)); | |
92 | ||
0e248b5f SF |
93 | debug("img %d, dst 0x%x, src 0x%x, size 0x%x\n", |
94 | i, (uint32_t) img->dst, img->offset + addr, img->size); | |
7e2db742 PF |
95 | |
96 | memcpy((void *)img->dst, (const void *)(img->offset + addr), | |
97 | img->size); | |
98 | ||
99 | s = img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1); | |
abf7752c | 100 | e = ALIGN(img->dst + img->size, CONFIG_SYS_CACHELINE_SIZE) - 1; |
7e2db742 PF |
101 | |
102 | flush_dcache_range(s, e); | |
103 | ||
104 | /* Find the memreg and set permission for seco pt */ | |
105 | err = sc_rm_find_memreg(-1, &mr, s, e); | |
106 | if (err) { | |
0e248b5f | 107 | printf("Error: can't find memreg for image load address 0x%x, error %d\n", img->dst, err); |
7e2db742 PF |
108 | ret = -ENOMEM; |
109 | goto exit; | |
110 | } | |
111 | ||
112 | err = sc_rm_get_memreg_info(-1, mr, &start, &end); | |
113 | if (!err) | |
114 | debug("memreg %u 0x%llx -- 0x%llx\n", mr, start, end); | |
115 | ||
116 | err = sc_rm_set_memreg_permissions(-1, mr, SECO_PT, | |
117 | SC_RM_PERM_FULL); | |
118 | if (err) { | |
119 | printf("Set permission failed for img %d, error %d\n", | |
120 | i, err); | |
121 | ret = -EPERM; | |
122 | goto exit; | |
123 | } | |
124 | ||
a903e13f | 125 | err = sc_seco_authenticate(-1, SC_SECO_VERIFY_IMAGE, |
7e2db742 PF |
126 | (1 << i)); |
127 | if (err) { | |
128 | printf("Authenticate img %d failed, return %d\n", | |
129 | i, err); | |
130 | ret = -EIO; | |
131 | } | |
132 | ||
133 | err = sc_rm_set_memreg_permissions(-1, mr, SECO_PT, | |
134 | SC_RM_PERM_NONE); | |
135 | if (err) { | |
136 | printf("Remove permission failed for img %d, err %d\n", | |
137 | i, err); | |
138 | ret = -EPERM; | |
139 | } | |
140 | ||
141 | if (ret) | |
142 | goto exit; | |
143 | } | |
144 | ||
145 | exit: | |
a903e13f | 146 | if (sc_seco_authenticate(-1, SC_SECO_REL_CONTAINER, 0) != SC_ERR_NONE) |
7e2db742 PF |
147 | printf("Error: release container failed!\n"); |
148 | ||
149 | return ret; | |
150 | } | |
151 | ||
152 | static int do_authenticate(cmd_tbl_t *cmdtp, int flag, int argc, | |
153 | char * const argv[]) | |
154 | { | |
155 | ulong addr; | |
156 | ||
157 | if (argc < 2) | |
158 | return CMD_RET_USAGE; | |
159 | ||
160 | addr = simple_strtoul(argv[1], NULL, 16); | |
161 | ||
162 | printf("Authenticate OS container at 0x%lx\n", addr); | |
163 | ||
164 | if (authenticate_os_container(addr)) | |
165 | return CMD_RET_FAILURE; | |
166 | ||
167 | return CMD_RET_SUCCESS; | |
168 | } | |
169 | ||
170 | static void display_life_cycle(u16 lc) | |
171 | { | |
172 | printf("Lifecycle: 0x%04X, ", lc); | |
173 | switch (lc) { | |
174 | case 0x1: | |
175 | printf("Pristine\n\n"); | |
176 | break; | |
177 | case 0x2: | |
178 | printf("Fab\n\n"); | |
179 | break; | |
180 | case 0x8: | |
181 | printf("Open\n\n"); | |
182 | break; | |
183 | case 0x20: | |
184 | printf("NXP closed\n\n"); | |
185 | break; | |
186 | case 0x80: | |
187 | printf("OEM closed\n\n"); | |
188 | break; | |
189 | case 0x100: | |
190 | printf("Partial field return\n\n"); | |
191 | break; | |
192 | case 0x200: | |
193 | printf("Full field return\n\n"); | |
194 | break; | |
195 | case 0x400: | |
196 | printf("No return\n\n"); | |
197 | break; | |
198 | default: | |
199 | printf("Unknown\n\n"); | |
200 | break; | |
201 | } | |
202 | } | |
203 | ||
204 | #define AHAB_AUTH_CONTAINER_REQ 0x87 | |
205 | #define AHAB_VERIFY_IMAGE_REQ 0x88 | |
206 | ||
207 | #define AHAB_NO_AUTHENTICATION_IND 0xee | |
208 | #define AHAB_BAD_KEY_HASH_IND 0xfa | |
209 | #define AHAB_INVALID_KEY_IND 0xf9 | |
210 | #define AHAB_BAD_SIGNATURE_IND 0xf0 | |
211 | #define AHAB_BAD_HASH_IND 0xf1 | |
212 | ||
213 | static void display_ahab_auth_event(u32 event) | |
214 | { | |
215 | u8 cmd = (event >> 16) & 0xff; | |
216 | u8 resp_ind = (event >> 8) & 0xff; | |
217 | ||
218 | switch (cmd) { | |
219 | case AHAB_AUTH_CONTAINER_REQ: | |
220 | printf("\tCMD = AHAB_AUTH_CONTAINER_REQ (0x%02X)\n", cmd); | |
221 | printf("\tIND = "); | |
222 | break; | |
223 | case AHAB_VERIFY_IMAGE_REQ: | |
224 | printf("\tCMD = AHAB_VERIFY_IMAGE_REQ (0x%02X)\n", cmd); | |
225 | printf("\tIND = "); | |
226 | break; | |
227 | default: | |
228 | return; | |
229 | } | |
230 | ||
231 | switch (resp_ind) { | |
232 | case AHAB_NO_AUTHENTICATION_IND: | |
233 | printf("AHAB_NO_AUTHENTICATION_IND (0x%02X)\n\n", resp_ind); | |
234 | break; | |
235 | case AHAB_BAD_KEY_HASH_IND: | |
236 | printf("AHAB_BAD_KEY_HASH_IND (0x%02X)\n\n", resp_ind); | |
237 | break; | |
238 | case AHAB_INVALID_KEY_IND: | |
239 | printf("AHAB_INVALID_KEY_IND (0x%02X)\n\n", resp_ind); | |
240 | break; | |
241 | case AHAB_BAD_SIGNATURE_IND: | |
242 | printf("AHAB_BAD_SIGNATURE_IND (0x%02X)\n\n", resp_ind); | |
243 | break; | |
244 | case AHAB_BAD_HASH_IND: | |
245 | printf("AHAB_BAD_HASH_IND (0x%02X)\n\n", resp_ind); | |
246 | break; | |
247 | default: | |
248 | printf("Unknown Indicator (0x%02X)\n\n", resp_ind); | |
249 | break; | |
250 | } | |
251 | } | |
252 | ||
253 | static int do_ahab_status(cmd_tbl_t *cmdtp, int flag, int argc, | |
254 | char * const argv[]) | |
255 | { | |
256 | int err; | |
257 | u8 idx = 0U; | |
258 | u32 event; | |
259 | u16 lc; | |
260 | ||
261 | err = sc_seco_chip_info(-1, &lc, NULL, NULL, NULL); | |
262 | if (err != SC_ERR_NONE) { | |
263 | printf("Error in get lifecycle\n"); | |
264 | return -EIO; | |
265 | } | |
266 | ||
267 | display_life_cycle(lc); | |
268 | ||
269 | err = sc_seco_get_event(-1, idx, &event); | |
270 | while (err == SC_ERR_NONE) { | |
271 | printf("SECO Event[%u] = 0x%08X\n", idx, event); | |
272 | display_ahab_auth_event(event); | |
273 | ||
274 | idx++; | |
275 | err = sc_seco_get_event(-1, idx, &event); | |
276 | } | |
277 | ||
278 | if (idx == 0) | |
279 | printf("No SECO Events Found!\n\n"); | |
280 | ||
281 | return 0; | |
282 | } | |
283 | ||
284 | static int confirm_close(void) | |
285 | { | |
286 | puts("Warning: Please ensure your sample is in NXP closed state, " | |
287 | "OEM SRK hash has been fused, \n" | |
288 | " and you are able to boot a signed image successfully " | |
289 | "without any SECO events reported.\n" | |
290 | " If not, your sample will be unrecoverable.\n" | |
291 | "\nReally perform this operation? <y/N>\n"); | |
292 | ||
293 | if (confirm_yesno()) | |
294 | return 1; | |
295 | ||
296 | puts("Ahab close aborted\n"); | |
297 | return 0; | |
298 | } | |
299 | ||
300 | static int do_ahab_close(cmd_tbl_t *cmdtp, int flag, int argc, | |
301 | char * const argv[]) | |
302 | { | |
303 | int err; | |
304 | u16 lc; | |
305 | ||
306 | if (!confirm_close()) | |
307 | return -EACCES; | |
308 | ||
309 | err = sc_seco_chip_info(-1, &lc, NULL, NULL, NULL); | |
310 | if (err != SC_ERR_NONE) { | |
311 | printf("Error in get lifecycle\n"); | |
312 | return -EIO; | |
313 | } | |
314 | ||
315 | if (lc != 0x20) { | |
316 | puts("Current lifecycle is NOT NXP closed, can't move to OEM closed\n"); | |
317 | display_life_cycle(lc); | |
318 | return -EPERM; | |
319 | } | |
320 | ||
321 | err = sc_seco_forward_lifecycle(-1, 16); | |
322 | if (err != SC_ERR_NONE) { | |
323 | printf("Error in forward lifecycle to OEM closed\n"); | |
324 | return -EIO; | |
325 | } | |
326 | ||
327 | printf("Change to OEM closed successfully\n"); | |
328 | ||
329 | return 0; | |
330 | } | |
331 | ||
332 | U_BOOT_CMD(auth_cntr, CONFIG_SYS_MAXARGS, 1, do_authenticate, | |
333 | "autenticate OS container via AHAB", | |
334 | "addr\n" | |
335 | "addr - OS container hex address\n" | |
336 | ); | |
337 | ||
338 | U_BOOT_CMD(ahab_status, CONFIG_SYS_MAXARGS, 1, do_ahab_status, | |
339 | "display AHAB lifecycle and events from seco", | |
340 | "" | |
341 | ); | |
342 | ||
343 | U_BOOT_CMD(ahab_close, CONFIG_SYS_MAXARGS, 1, do_ahab_close, | |
344 | "Change AHAB lifecycle to OEM closed", | |
345 | "" | |
346 | ); |