]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/mx5/hab.c
Merge branch 'karo-tx-uboot' into kc-merge
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / mx5 / hab.c
1 /*
2  * Copyright (C) 2010-2014 Freescale Semiconductor, Inc.
3  *
4  * SPDX-License-Identifier:    GPL-2.0+
5  */
6
7 #include <common.h>
8 #include <errno.h>
9 #include <asm/io.h>
10 #include <asm/system.h>
11 #include <asm/arch/clock.h>
12 #include <asm/arch/sys_proto.h>
13 #include <asm/arch/hab.h>
14
15 HAB_FUNC(entry, hab_status_t)
16 HAB_FUNC(exit, hab_status_t)
17 HAB_FUNC5(authenticate_image, void *, uint8_t, size_t, void **, size_t *, hab_loader_callback_f_t)
18 HAB_FUNC2(report_status, hab_status_t, hab_config_t *, hab_state_t *)
19 HAB_FUNC4(report_event, hab_status_t, hab_status_t, uint32_t, uint8_t *, size_t *)
20 HAB_FUNC3(check_target, hab_status_t, uint8_t, const void *, size_t)
21 HAB_FUNC3(assert, hab_status_t, uint8_t, const void *, size_t)
22
23 struct mx53_ivt {
24         u32 header;
25         u32 app_start_addr;
26         u32 rsrvd1;
27         void *dcd_ptr;
28         struct mx53_boot_data *boot_data;
29         void *self;
30         void *csf;
31         u32 rsrvd2;
32 };
33
34 struct mx53_boot_data {
35         void *start;
36         u32 length;
37         u32 plugin;
38 };
39
40 #define IVT_SIZE                0x20
41 #define ALIGN_SIZE              0x400
42 #define CSF_PAD_SIZE            0x2000
43
44 /*
45  * +------------+  0x0 (DDR_UIMAGE_START) -
46  * |   Header   |                          |
47  * +------------+  0x40                    |
48  * |            |                          |
49  * |            |                          |
50  * |            |                          |
51  * |            |                          |
52  * | Image Data |                          |
53  * .            |                          |
54  * .            |                           > Stuff to be authenticated ----+
55  * .            |                          |                                |
56  * |            |                          |                                |
57  * |            |                          |                                |
58  * +------------+                          |                                |
59  * |            |                          |                                |
60  * | Fill Data  |                          |                                |
61  * |            |                          |                                |
62  * +------------+ Align to ALIGN_SIZE      |                                |
63  * |    IVT     |                          |                                |
64  * +------------+ + IVT_SIZE              -                                 |
65  * |            |                                                           |
66  * |  CSF DATA  | <---------------------------------------------------------+
67  * |            |
68  * +------------+
69  * |            |
70  * | Fill Data  |
71  * |            |
72  * +------------+ + CSF_PAD_SIZE
73  */
74
75 static inline int read_fuse(unsigned bank, unsigned row)
76 {
77         struct iim_regs *iim_regs = (void *)IMX_IIM_BASE;
78         u32 *fuses;
79
80         if (bank > ARRAY_SIZE(iim_regs->bank))
81                 return -EINVAL;
82         fuses = iim_regs->bank[bank].fuse_regs;
83
84         debug("Reading fuse bank %u row %u @ %p\n", bank, row, &fuses[row]);
85         return readl(&fuses[row]);
86 }
87
88 static bool is_hab_enabled(void)
89 {
90 #ifdef DEBUG
91         static int first = 1;
92
93         if (first) {
94                 debug("rvt_base=%p\n", hab_rvt_base());
95                 debug("hab_rvt_entry=%p\n", hab_rvt_entry_p);
96                 debug("hab_rvt_exit=%p\n", hab_rvt_exit_p);
97                 debug("hab_rvt_check_target=%p\n", hab_rvt_check_target_p);
98                 debug("hab_rvt_authenticate_image=%p\n", hab_rvt_authenticate_image_p);
99                 debug("hab_rvt_report_event=%p\n", hab_rvt_report_event_p);
100                 debug("hab_rvt_report_status=%p\n", hab_rvt_report_status_p);
101                 debug("hab_rvt_assert=%p\n", hab_rvt_assert_p);
102                 first = 0;
103         }
104 #endif
105         return read_fuse(0, 4) & (1 << 1);
106 }
107
108 static void mx53_hab_display_event(uint8_t *event_data, size_t bytes)
109 {
110         uint32_t i;
111
112         if (!(event_data && bytes > 0))
113                 return;
114
115         for (i = 0; i < bytes; i++) {
116                 if (i == 0)
117                         printf("\t0x%02x", event_data[i]);
118                 else if ((i % 8) == 0)
119                         printf("\n\t0x%02x", event_data[i]);
120                 else
121                         printf(" 0x%02x", event_data[i]);
122         }
123 }
124
125 static inline void mx53_hab_pr_fuse_val(unsigned bank, unsigned row)
126 {
127         printf(" %02x", read_fuse(bank, row));
128 }
129
130 static inline void mx53_hab_dump_srk_hash(void)
131 {
132         int i;
133
134         printf("SRK hash:\n\t");
135         mx53_hab_pr_fuse_val(1, 1);
136         for (i = 1; i <= 31; i++) {
137                 if (i % 8 == 0)
138                         printf("\n\t");
139                 mx53_hab_pr_fuse_val(3, i);
140         }
141         printf("\n");
142 }
143
144 int get_hab_status(void)
145 {
146         static uint32_t last_hab_event __attribute__((section(".data")));
147         uint32_t index = last_hab_event; /* Loop index */
148         uint8_t event_data[128]; /* Event data buffer */
149         size_t bytes = sizeof(event_data); /* Event size in bytes */
150         enum hab_config config;
151         enum hab_state state;
152         int ret;
153         int hab_debug = getenv_yesno("hab_debug") == 1;
154
155         if (hab_debug) {
156                 if (is_hab_enabled()) {
157                         printf("Secure boot enabled\n\t");
158                 } else {
159                         printf("Secure boot disabled\n");
160                 }
161                 mx53_hab_dump_srk_hash();
162         }
163
164         /* Check HAB status */
165         config = state = 0; /* ROM code assumes short enums! */
166         ret = hab_rvt_report_status(&config, &state);
167         if (hab_debug || ret != HAB_SUCCESS)
168                 printf("HAB Configuration: 0x%02x, HAB State: 0x%02x\n",
169                         config, state);
170         if (ret != HAB_SUCCESS) {
171                 /* Display HAB Error events */
172                 while (hab_rvt_report_event(HAB_STS_ANY, index, event_data,
173                                         &bytes) == HAB_SUCCESS) {
174                         puts("\n");
175                         printf("--------- HAB Event %d -----------------\n",
176                                index + 1);
177                         puts("event data:\n");
178                         mx53_hab_display_event(event_data, bytes);
179                         puts("\n");
180                         bytes = sizeof(event_data);
181                         index++;
182                 }
183                 ret = index - last_hab_event;
184                 last_hab_event = index;
185         } else {
186                 /* Display message if no HAB events are found */
187                 if (hab_debug)
188                         puts("No HAB Events Found!\n");
189                 ret = 0;
190         }
191         return ret;
192 }
193
194 static inline hab_status_t hab_init(void)
195 {
196         hab_status_t ret;
197
198         ret = hab_rvt_entry();
199         debug("hab_rvt_entry() returned %02x\n", ret);
200         if (ret != HAB_SUCCESS) {
201                 printf("hab entry function failed: %02x\n", ret);
202         }
203
204         return ret;
205 }
206
207 static inline hab_status_t hab_exit(void)
208 {
209         hab_status_t ret;
210
211         ret = hab_rvt_exit();
212         if (ret != HAB_SUCCESS)
213                 printf("hab exit function failed: %02x\n", ret);
214
215         return ret;
216 }
217
218 static hab_status_t hab_check_target(hab_target_t type, uint32_t addr, size_t len)
219 {
220         hab_status_t ret;
221
222         ret = hab_init();
223         if (ret != HAB_SUCCESS)
224                 return ret;
225
226         ret = hab_rvt_check_target(type, (void *)addr, len);
227         if (ret != HAB_SUCCESS) {
228                 printf("check_target(0x%08x, 0x%08x) failed: %d\n",
229                         addr, len, ret);
230                 return ret;
231         }
232         ret = hab_exit();
233
234         if (ret == HAB_SUCCESS && get_hab_status() > 0) {
235                 return HAB_FAILURE;
236         }
237         return ret;
238 }
239
240 static hab_status_t hab_assert(uint32_t type, uint32_t addr, size_t len)
241 {
242         hab_status_t ret;
243
244         ret = hab_init();
245         if (ret != HAB_SUCCESS)
246                 return ret;
247
248         ret = hab_rvt_assert(type, (void *)addr, len);
249         if (ret != HAB_SUCCESS) {
250                 printf("assert(0x%08x, 0x%08x) failed: %d\n",
251                         addr, len, ret);
252                 return ret;
253         }
254         ret = hab_exit();
255
256         if (ret == HAB_SUCCESS && get_hab_status() > 0) {
257                 return HAB_FAILURE;
258         }
259         return ret;
260 }
261
262 static int do_hab_status(cmd_tbl_t *cmdtp, int flag, int argc,
263                         char *const argv[])
264 {
265         if (argc != 1)
266                 return CMD_RET_USAGE;
267
268         get_hab_status();
269
270         return CMD_RET_SUCCESS;
271 }
272
273 static int do_hab_check_target(cmd_tbl_t *cmdtp, int flag, int argc,
274                         char *const argv[])
275 {
276         hab_target_t type = HAB_TGT_MEMORY;
277         uint32_t addr;
278         size_t len;
279
280         if (argc < 3)
281                 return CMD_RET_USAGE;
282
283         addr = simple_strtoul(argv[1], NULL, 16);
284         len = simple_strtoul(argv[2], NULL, 16);
285         if (argc > 3) {
286                 switch (argv[3][0]) {
287                 case 'p':
288                 case 'P':
289                         type = HAB_TGT_PERIPHERAL;
290                         break;
291                 case 'm':
292                 case 'M':
293                         type = HAB_TGT_MEMORY;
294                         break;
295                 default:
296                         printf("Invalid type '%s'\n", argv[3]);
297                         return CMD_RET_USAGE;
298                 }
299         }
300         if (hab_check_target(type, addr, len) != HAB_SUCCESS)
301                 return CMD_RET_FAILURE;
302
303         return CMD_RET_SUCCESS;
304 }
305
306 static int do_hab_assert(cmd_tbl_t *cmdtp, int flag, int argc,
307                         char *const argv[])
308 {
309         uint32_t type = 0;
310         uint32_t addr;
311         size_t len;
312
313         if (argc < 3)
314                 return CMD_RET_USAGE;
315
316         addr = simple_strtoul(argv[1], NULL, 16);
317         len = simple_strtoul(argv[2], NULL, 16);
318         if (argc > 3) {
319                 type = simple_strtoul(argv[3], NULL, 16);
320         }
321
322         if (hab_assert(type, addr, len) != HAB_SUCCESS)
323                 return CMD_RET_FAILURE;
324
325         return CMD_RET_SUCCESS;
326 }
327
328 U_BOOT_CMD(
329                 hab_status, CONFIG_SYS_MAXARGS, 1, do_hab_status,
330                 "display HAB status",
331                 ""
332           );
333
334 U_BOOT_CMD(
335                 hab_check_target, 4, 0, do_hab_check_target,
336                 "verify an address range via HAB",
337                 "addr len [type]\n"
338                 "\t\taddr -\taddress to verify\n"
339                 "\t\tlen -\tlength of addr range to verify\n"
340           );
341
342 U_BOOT_CMD(
343                 hab_assert, 4, 0, do_hab_assert,
344                 "Test an assertion against the HAB audit log",
345                 "addr len [type]\n"
346                 "\t\taddr -\taddress to verify\n"
347                 "\t\tlen -\tlength of addr range to verify\n"
348           );