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