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