361c578efc855b5c09389eee07a644286cd0a471
[oweals/u-boot.git] / arch / arm / mach-imx / imx8 / ahab.c
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
78         err = sc_seco_authenticate(-1, SC_SECO_AUTH_CONTAINER,
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
93                 debug("img %d, dst 0x%llx, src 0x%lx, size 0x%x\n",
94                       i, img->dst, img->offset + addr, img->size);
95
96                 memcpy((void *)img->dst, (const void *)(img->offset + addr),
97                        img->size);
98
99                 s = img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1);
100                 e = ALIGN(img->dst + img->size, CONFIG_SYS_CACHELINE_SIZE);
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) {
107                         printf("Not found memreg for image: %d, error %d\n",
108                                i, err);
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
126                 err = sc_seco_authenticate(-1, SC_SECO_VERIFY_IMAGE,
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:
147         if (sc_seco_authenticate(-1, SC_SECO_REL_CONTAINER, 0) != SC_ERR_NONE)
148                 printf("Error: release container failed!\n");
149
150         return ret;
151 }
152
153 static int do_authenticate(cmd_tbl_t *cmdtp, int flag, int argc,
154                            char * const argv[])
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
254 static int do_ahab_status(cmd_tbl_t *cmdtp, int flag, int argc,
255                           char * const argv[])
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
301 static int do_ahab_close(cmd_tbl_t *cmdtp, int flag, int argc,
302                          char * const argv[])
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 );