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