blob: 01ddfab6996a41417e35a56a63ab9e52562828a0 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stefano Babicb83c7092013-06-28 00:20:21 +02002/*
Ulises Cardenas29067ab2015-07-02 21:26:30 -05003 * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
Stefano Babicb83c7092013-06-28 00:20:21 +02004 */
5
6#include <common.h>
Simon Glass09140112020-05-10 11:40:03 -06007#include <command.h>
Adrian Alonsofba6f9e2015-10-12 13:48:14 -05008#include <config.h>
9#include <fuse.h>
Parthiban Nallathambiea910312018-11-21 14:50:40 +010010#include <mapmem.h>
11#include <image.h>
Stefano Babicb83c7092013-06-28 00:20:21 +020012#include <asm/io.h>
Peng Fan507da972021-03-25 17:30:07 +080013#include <asm/global_data.h>
Nitin Garg36c1ca42014-09-16 13:33:25 -050014#include <asm/system.h>
Nitin Garg36c1ca42014-09-16 13:33:25 -050015#include <asm/arch/clock.h>
Stefano Babicf2f07e82014-06-10 10:26:22 +020016#include <asm/arch/sys_proto.h>
Stefano Babic552a8482017-06-29 10:16:06 +020017#include <asm/mach-imx/hab.h>
Peng Fan507da972021-03-25 17:30:07 +080018#include <linux/arm-smccc.h>
19
20DECLARE_GLOBAL_DATA_PTR;
Stefano Babicb83c7092013-06-28 00:20:21 +020021
Nitin Garg36c1ca42014-09-16 13:33:25 -050022#define ALIGN_SIZE 0x1000
Nitin Garg36c1ca42014-09-16 13:33:25 -050023#define MX6DQ_PU_IROM_MMU_EN_VAR 0x009024a8
24#define MX6DLS_PU_IROM_MMU_EN_VAR 0x00901dd0
Breno Matheus Lima57600692019-05-07 20:19:17 +000025#define MX6SL_PU_IROM_MMU_EN_VAR 0x00901c60
Adrian Alonsoee3899a2015-10-12 13:48:15 -050026#define IS_HAB_ENABLED_BIT \
Peng Fan27117b22017-02-22 16:21:53 +080027 (is_soc_type(MXC_SOC_MX7ULP) ? 0x80000000 : \
Peng Fan507da972021-03-25 17:30:07 +080028 ((is_soc_type(MXC_SOC_MX7) || is_soc_type(MXC_SOC_IMX8M)) ? 0x2000000 : 0x2))
Nitin Garg36c1ca42014-09-16 13:33:25 -050029
Bryan O'Donoghue49b6d052018-01-12 12:40:03 +000030static int ivt_header_error(const char *err_str, struct ivt_header *ivt_hdr)
31{
32 printf("%s magic=0x%x length=0x%02x version=0x%x\n", err_str,
33 ivt_hdr->magic, ivt_hdr->length, ivt_hdr->version);
34
35 return 1;
36}
37
38static int verify_ivt_header(struct ivt_header *ivt_hdr)
39{
40 int result = 0;
41
42 if (ivt_hdr->magic != IVT_HEADER_MAGIC)
43 result = ivt_header_error("bad magic", ivt_hdr);
44
45 if (be16_to_cpu(ivt_hdr->length) != IVT_TOTAL_LENGTH)
46 result = ivt_header_error("bad length", ivt_hdr);
47
48 if (ivt_hdr->version != IVT_HEADER_V1 &&
49 ivt_hdr->version != IVT_HEADER_V2)
50 result = ivt_header_error("bad version", ivt_hdr);
51
52 return result;
53}
54
Peng Fan507da972021-03-25 17:30:07 +080055#ifdef CONFIG_ARM64
56#define FSL_SIP_HAB 0xC2000007
57#define FSL_SIP_HAB_AUTHENTICATE 0x00
58#define FSL_SIP_HAB_ENTRY 0x01
59#define FSL_SIP_HAB_EXIT 0x02
60#define FSL_SIP_HAB_REPORT_EVENT 0x03
61#define FSL_SIP_HAB_REPORT_STATUS 0x04
62#define FSL_SIP_HAB_FAILSAFE 0x05
63#define FSL_SIP_HAB_CHECK_TARGET 0x06
64static volatile gd_t *gd_save;
65#endif
66
67static inline void save_gd(void)
68{
69#ifdef CONFIG_ARM64
70 gd_save = gd;
71#endif
72}
73
74static inline void restore_gd(void)
75{
76#ifdef CONFIG_ARM64
77 /*
78 * Make will already error that reserving x18 is not supported at the
79 * time of writing, clang: error: unknown argument: '-ffixed-x18'
80 */
81 __asm__ volatile("mov x18, %0\n" : : "r" (gd_save));
82#endif
83}
84
85enum hab_status hab_rvt_report_event(enum hab_status status, u32 index,
86 u8 *event, size_t *bytes)
87{
88 enum hab_status ret;
89 hab_rvt_report_event_t *hab_rvt_report_event_func;
90 struct arm_smccc_res res __maybe_unused;
91
92 hab_rvt_report_event_func = (hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT;
93#if defined(CONFIG_ARM64)
94 if (current_el() != 3) {
95 /* call sip */
96 arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_REPORT_EVENT, (unsigned long)index,
97 (unsigned long)event, (unsigned long)bytes, 0, 0, 0, &res);
98 return (enum hab_status)res.a0;
99 }
100#endif
101
102 save_gd();
103 ret = hab_rvt_report_event_func(status, index, event, bytes);
104 restore_gd();
105
106 return ret;
107
108}
109
110enum hab_status hab_rvt_report_status(enum hab_config *config, enum hab_state *state)
111{
112 enum hab_status ret;
113 hab_rvt_report_status_t *hab_rvt_report_status_func;
114 struct arm_smccc_res res __maybe_unused;
115
116 hab_rvt_report_status_func = (hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS;
117#if defined(CONFIG_ARM64)
118 if (current_el() != 3) {
119 /* call sip */
120 arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_REPORT_STATUS, (unsigned long)config,
121 (unsigned long)state, 0, 0, 0, 0, &res);
122 return (enum hab_status)res.a0;
123 }
124#endif
125
126 save_gd();
127 ret = hab_rvt_report_status_func(config, state);
128 restore_gd();
129
130 return ret;
131}
132
133enum hab_status hab_rvt_entry(void)
134{
135 enum hab_status ret;
136 hab_rvt_entry_t *hab_rvt_entry_func;
137 struct arm_smccc_res res __maybe_unused;
138
139 hab_rvt_entry_func = (hab_rvt_entry_t *)HAB_RVT_ENTRY;
140#if defined(CONFIG_ARM64)
141 if (current_el() != 3) {
142 /* call sip */
143 arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_ENTRY, 0, 0, 0, 0, 0, 0, &res);
144 return (enum hab_status)res.a0;
145 }
146#endif
147
148 save_gd();
149 ret = hab_rvt_entry_func();
150 restore_gd();
151
152 return ret;
153}
154
155enum hab_status hab_rvt_exit(void)
156{
157 enum hab_status ret;
158 hab_rvt_exit_t *hab_rvt_exit_func;
159 struct arm_smccc_res res __maybe_unused;
160
161 hab_rvt_exit_func = (hab_rvt_exit_t *)HAB_RVT_EXIT;
162#if defined(CONFIG_ARM64)
163 if (current_el() != 3) {
164 /* call sip */
165 arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_EXIT, 0, 0, 0, 0, 0, 0, &res);
166 return (enum hab_status)res.a0;
167 }
168#endif
169
170 save_gd();
171 ret = hab_rvt_exit_func();
172 restore_gd();
173
174 return ret;
175}
176
177void hab_rvt_failsafe(void)
178{
179 hab_rvt_failsafe_t *hab_rvt_failsafe_func;
180
181 hab_rvt_failsafe_func = (hab_rvt_failsafe_t *)HAB_RVT_FAILSAFE;
182#if defined(CONFIG_ARM64)
183 if (current_el() != 3) {
184 /* call sip */
185 arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_FAILSAFE, 0, 0, 0, 0, 0, 0, NULL);
186 return;
187 }
188#endif
189
190 save_gd();
191 hab_rvt_failsafe_func();
192 restore_gd();
193}
194
195enum hab_status hab_rvt_check_target(enum hab_target type, const void *start,
196 size_t bytes)
197{
198 enum hab_status ret;
199 hab_rvt_check_target_t *hab_rvt_check_target_func;
200 struct arm_smccc_res res __maybe_unused;
201
202 hab_rvt_check_target_func = (hab_rvt_check_target_t *)HAB_RVT_CHECK_TARGET;
203#if defined(CONFIG_ARM64)
204 if (current_el() != 3) {
205 /* call sip */
206 arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_CHECK_TARGET, (unsigned long)type,
207 (unsigned long)start, (unsigned long)bytes, 0, 0, 0, &res);
208 return (enum hab_status)res.a0;
209 }
210#endif
211
212 save_gd();
213 ret = hab_rvt_check_target_func(type, start, bytes);
214 restore_gd();
215
216 return ret;
217}
218
219void *hab_rvt_authenticate_image(uint8_t cid, ptrdiff_t ivt_offset,
220 void **start, size_t *bytes, hab_loader_callback_f_t loader)
221{
222 void *ret;
223 hab_rvt_authenticate_image_t *hab_rvt_authenticate_image_func;
224 struct arm_smccc_res res __maybe_unused;
225
226 hab_rvt_authenticate_image_func = (hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE;
227#if defined(CONFIG_ARM64)
228 if (current_el() != 3) {
229 /* call sip */
230 arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_AUTHENTICATE, (unsigned long)ivt_offset,
231 (unsigned long)start, (unsigned long)bytes, 0, 0, 0, &res);
232 return (void *)res.a0;
233 }
234#endif
235
236 save_gd();
237 ret = hab_rvt_authenticate_image_func(cid, ivt_offset, start, bytes, loader);
238 restore_gd();
239
240 return ret;
241}
242
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100243#if !defined(CONFIG_SPL_BUILD)
244
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500245#define MAX_RECORD_BYTES (8*1024) /* 4 kbytes */
246
247struct record {
248 uint8_t tag; /* Tag */
249 uint8_t len[2]; /* Length */
250 uint8_t par; /* Version */
251 uint8_t contents[MAX_RECORD_BYTES];/* Record Data */
252 bool any_rec_flag;
253};
254
Bryan O'Donoghue58bebfb2018-01-12 12:40:12 +0000255static char *rsn_str[] = {
256 "RSN = HAB_RSN_ANY (0x00)\n",
257 "RSN = HAB_ENG_FAIL (0x30)\n",
258 "RSN = HAB_INV_ADDRESS (0x22)\n",
259 "RSN = HAB_INV_ASSERTION (0x0C)\n",
260 "RSN = HAB_INV_CALL (0x28)\n",
261 "RSN = HAB_INV_CERTIFICATE (0x21)\n",
262 "RSN = HAB_INV_COMMAND (0x06)\n",
263 "RSN = HAB_INV_CSF (0x11)\n",
264 "RSN = HAB_INV_DCD (0x27)\n",
265 "RSN = HAB_INV_INDEX (0x0F)\n",
266 "RSN = HAB_INV_IVT (0x05)\n",
267 "RSN = HAB_INV_KEY (0x1D)\n",
268 "RSN = HAB_INV_RETURN (0x1E)\n",
269 "RSN = HAB_INV_SIGNATURE (0x18)\n",
270 "RSN = HAB_INV_SIZE (0x17)\n",
271 "RSN = HAB_MEM_FAIL (0x2E)\n",
272 "RSN = HAB_OVR_COUNT (0x2B)\n",
273 "RSN = HAB_OVR_STORAGE (0x2D)\n",
274 "RSN = HAB_UNS_ALGORITHM (0x12)\n",
275 "RSN = HAB_UNS_COMMAND (0x03)\n",
276 "RSN = HAB_UNS_ENGINE (0x0A)\n",
277 "RSN = HAB_UNS_ITEM (0x24)\n",
278 "RSN = HAB_UNS_KEY (0x1B)\n",
279 "RSN = HAB_UNS_PROTOCOL (0x14)\n",
280 "RSN = HAB_UNS_STATE (0x09)\n",
281 "RSN = INVALID\n",
282 NULL
283};
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500284
Bryan O'Donoghue58bebfb2018-01-12 12:40:12 +0000285static char *sts_str[] = {
286 "STS = HAB_SUCCESS (0xF0)\n",
287 "STS = HAB_FAILURE (0x33)\n",
288 "STS = HAB_WARNING (0x69)\n",
289 "STS = INVALID\n",
290 NULL
291};
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500292
Bryan O'Donoghue58bebfb2018-01-12 12:40:12 +0000293static char *eng_str[] = {
294 "ENG = HAB_ENG_ANY (0x00)\n",
295 "ENG = HAB_ENG_SCC (0x03)\n",
296 "ENG = HAB_ENG_RTIC (0x05)\n",
297 "ENG = HAB_ENG_SAHARA (0x06)\n",
298 "ENG = HAB_ENG_CSU (0x0A)\n",
299 "ENG = HAB_ENG_SRTC (0x0C)\n",
300 "ENG = HAB_ENG_DCP (0x1B)\n",
301 "ENG = HAB_ENG_CAAM (0x1D)\n",
302 "ENG = HAB_ENG_SNVS (0x1E)\n",
303 "ENG = HAB_ENG_OCOTP (0x21)\n",
304 "ENG = HAB_ENG_DTCP (0x22)\n",
305 "ENG = HAB_ENG_ROM (0x36)\n",
306 "ENG = HAB_ENG_HDCP (0x24)\n",
307 "ENG = HAB_ENG_RTL (0x77)\n",
308 "ENG = HAB_ENG_SW (0xFF)\n",
309 "ENG = INVALID\n",
310 NULL
311};
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500312
Bryan O'Donoghue58bebfb2018-01-12 12:40:12 +0000313static char *ctx_str[] = {
314 "CTX = HAB_CTX_ANY(0x00)\n",
315 "CTX = HAB_CTX_FAB (0xFF)\n",
316 "CTX = HAB_CTX_ENTRY (0xE1)\n",
317 "CTX = HAB_CTX_TARGET (0x33)\n",
318 "CTX = HAB_CTX_AUTHENTICATE (0x0A)\n",
319 "CTX = HAB_CTX_DCD (0xDD)\n",
320 "CTX = HAB_CTX_CSF (0xCF)\n",
321 "CTX = HAB_CTX_COMMAND (0xC0)\n",
322 "CTX = HAB_CTX_AUT_DAT (0xDB)\n",
323 "CTX = HAB_CTX_ASSERT (0xA0)\n",
324 "CTX = HAB_CTX_EXIT (0xEE)\n",
325 "CTX = INVALID\n",
326 NULL
327};
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500328
Bryan O'Donoghue58bebfb2018-01-12 12:40:12 +0000329static uint8_t hab_statuses[5] = {
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500330 HAB_STS_ANY,
331 HAB_FAILURE,
332 HAB_WARNING,
333 HAB_SUCCESS,
334 -1
335};
336
Bryan O'Donoghue58bebfb2018-01-12 12:40:12 +0000337static uint8_t hab_reasons[26] = {
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500338 HAB_RSN_ANY,
339 HAB_ENG_FAIL,
340 HAB_INV_ADDRESS,
341 HAB_INV_ASSERTION,
342 HAB_INV_CALL,
343 HAB_INV_CERTIFICATE,
344 HAB_INV_COMMAND,
345 HAB_INV_CSF,
346 HAB_INV_DCD,
347 HAB_INV_INDEX,
348 HAB_INV_IVT,
349 HAB_INV_KEY,
350 HAB_INV_RETURN,
351 HAB_INV_SIGNATURE,
352 HAB_INV_SIZE,
353 HAB_MEM_FAIL,
354 HAB_OVR_COUNT,
355 HAB_OVR_STORAGE,
356 HAB_UNS_ALGORITHM,
357 HAB_UNS_COMMAND,
358 HAB_UNS_ENGINE,
359 HAB_UNS_ITEM,
360 HAB_UNS_KEY,
361 HAB_UNS_PROTOCOL,
362 HAB_UNS_STATE,
363 -1
364};
365
Bryan O'Donoghue58bebfb2018-01-12 12:40:12 +0000366static uint8_t hab_contexts[12] = {
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500367 HAB_CTX_ANY,
368 HAB_CTX_FAB,
369 HAB_CTX_ENTRY,
370 HAB_CTX_TARGET,
371 HAB_CTX_AUTHENTICATE,
372 HAB_CTX_DCD,
373 HAB_CTX_CSF,
374 HAB_CTX_COMMAND,
375 HAB_CTX_AUT_DAT,
376 HAB_CTX_ASSERT,
377 HAB_CTX_EXIT,
378 -1
379};
380
Bryan O'Donoghue58bebfb2018-01-12 12:40:12 +0000381static uint8_t hab_engines[16] = {
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500382 HAB_ENG_ANY,
383 HAB_ENG_SCC,
384 HAB_ENG_RTIC,
385 HAB_ENG_SAHARA,
386 HAB_ENG_CSU,
387 HAB_ENG_SRTC,
388 HAB_ENG_DCP,
389 HAB_ENG_CAAM,
390 HAB_ENG_SNVS,
391 HAB_ENG_OCOTP,
392 HAB_ENG_DTCP,
393 HAB_ENG_ROM,
394 HAB_ENG_HDCP,
395 HAB_ENG_RTL,
396 HAB_ENG_SW,
397 -1
398};
399
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500400static inline uint8_t get_idx(uint8_t *list, uint8_t tgt)
401{
402 uint8_t idx = 0;
403 uint8_t element = list[idx];
404 while (element != -1) {
405 if (element == tgt)
406 return idx;
407 element = list[++idx];
408 }
409 return -1;
410}
411
Bryan O'Donoghue58bebfb2018-01-12 12:40:12 +0000412static void process_event_record(uint8_t *event_data, size_t bytes)
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500413{
414 struct record *rec = (struct record *)event_data;
415
416 printf("\n\n%s", sts_str[get_idx(hab_statuses, rec->contents[0])]);
417 printf("%s", rsn_str[get_idx(hab_reasons, rec->contents[1])]);
418 printf("%s", ctx_str[get_idx(hab_contexts, rec->contents[2])]);
419 printf("%s", eng_str[get_idx(hab_engines, rec->contents[3])]);
420}
421
Bryan O'Donoghue58bebfb2018-01-12 12:40:12 +0000422static void display_event(uint8_t *event_data, size_t bytes)
Stefano Babicb83c7092013-06-28 00:20:21 +0200423{
424 uint32_t i;
425
426 if (!(event_data && bytes > 0))
427 return;
428
429 for (i = 0; i < bytes; i++) {
430 if (i == 0)
431 printf("\t0x%02x", event_data[i]);
432 else if ((i % 8) == 0)
433 printf("\n\t0x%02x", event_data[i]);
434 else
435 printf(" 0x%02x", event_data[i]);
436 }
Ulises Cardenas29067ab2015-07-02 21:26:30 -0500437
438 process_event_record(event_data, bytes);
Stefano Babicb83c7092013-06-28 00:20:21 +0200439}
440
Bryan O'Donoghue58bebfb2018-01-12 12:40:12 +0000441static int get_hab_status(void)
Stefano Babicb83c7092013-06-28 00:20:21 +0200442{
443 uint32_t index = 0; /* Loop index */
444 uint8_t event_data[128]; /* Event data buffer */
445 size_t bytes = sizeof(event_data); /* Event size in bytes */
446 enum hab_config config = 0;
447 enum hab_state state = 0;
Stefano Babicb83c7092013-06-28 00:20:21 +0200448
Bryan O'Donoghuee5b30e42018-01-12 12:40:14 +0000449 if (imx_hab_is_enabled())
Stefano Babicb83c7092013-06-28 00:20:21 +0200450 puts("\nSecure boot enabled\n");
451 else
452 puts("\nSecure boot disabled\n");
453
454 /* Check HAB status */
455 if (hab_rvt_report_status(&config, &state) != HAB_SUCCESS) {
456 printf("\nHAB Configuration: 0x%02x, HAB State: 0x%02x\n",
457 config, state);
458
459 /* Display HAB Error events */
460 while (hab_rvt_report_event(HAB_FAILURE, index, event_data,
461 &bytes) == HAB_SUCCESS) {
462 puts("\n");
463 printf("--------- HAB Event %d -----------------\n",
464 index + 1);
465 puts("event data:\n");
466 display_event(event_data, bytes);
467 puts("\n");
468 bytes = sizeof(event_data);
469 index++;
470 }
471 }
472 /* Display message if no HAB events are found */
473 else {
474 printf("\nHAB Configuration: 0x%02x, HAB State: 0x%02x\n",
475 config, state);
476 puts("No HAB Events Found!\n\n");
477 }
478 return 0;
479}
480
Simon Glass09140112020-05-10 11:40:03 -0600481static int do_hab_status(struct cmd_tbl *cmdtp, int flag, int argc,
482 char *const argv[])
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100483{
484 if ((argc != 1)) {
485 cmd_usage(cmdtp);
486 return 1;
487 }
488
489 get_hab_status();
490
491 return 0;
492}
493
Parthiban Nallathambiea910312018-11-21 14:50:40 +0100494static ulong get_image_ivt_offset(ulong img_addr)
495{
496 const void *buf;
497
498 buf = map_sysmem(img_addr, 0);
499 switch (genimg_get_format(buf)) {
Tom Rinic76c93a2019-05-23 07:14:07 -0400500#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
Parthiban Nallathambiea910312018-11-21 14:50:40 +0100501 case IMAGE_FORMAT_LEGACY:
502 return (image_get_image_size((image_header_t *)img_addr)
503 + 0x1000 - 1) & ~(0x1000 - 1);
504#endif
505#if IMAGE_ENABLE_FIT
506 case IMAGE_FORMAT_FIT:
507 return (fit_get_size(buf) + 0x1000 - 1) & ~(0x1000 - 1);
508#endif
509 default:
510 return 0;
511 }
512}
513
Simon Glass09140112020-05-10 11:40:03 -0600514static int do_authenticate_image(struct cmd_tbl *cmdtp, int flag, int argc,
515 char *const argv[])
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100516{
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000517 ulong addr, length, ivt_offset;
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100518 int rcode = 0;
519
Parthiban Nallathambiea910312018-11-21 14:50:40 +0100520 if (argc < 3)
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100521 return CMD_RET_USAGE;
522
523 addr = simple_strtoul(argv[1], NULL, 16);
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000524 length = simple_strtoul(argv[2], NULL, 16);
Parthiban Nallathambiea910312018-11-21 14:50:40 +0100525 if (argc == 3)
526 ivt_offset = get_image_ivt_offset(addr);
527 else
528 ivt_offset = simple_strtoul(argv[3], NULL, 16);
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100529
Bryan O'Donoghue57f65482018-01-12 12:40:13 +0000530 rcode = imx_hab_authenticate_image(addr, length, ivt_offset);
Bryan O'Donoghue9535b392018-01-12 12:39:56 +0000531 if (rcode == 0)
532 rcode = CMD_RET_SUCCESS;
533 else
534 rcode = CMD_RET_FAILURE;
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000535
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100536 return rcode;
537}
538
Simon Glass09140112020-05-10 11:40:03 -0600539static int do_hab_failsafe(struct cmd_tbl *cmdtp, int flag, int argc,
540 char *const argv[])
Bryan O'Donoghue9587b0d2018-01-12 12:40:19 +0000541{
Bryan O'Donoghue9587b0d2018-01-12 12:40:19 +0000542 if (argc != 1) {
543 cmd_usage(cmdtp);
544 return 1;
545 }
546
Bryan O'Donoghue9587b0d2018-01-12 12:40:19 +0000547 hab_rvt_failsafe();
548
549 return 0;
550}
551
Simon Glass09140112020-05-10 11:40:03 -0600552static int do_hab_version(struct cmd_tbl *cmdtp, int flag, int argc,
553 char *const argv[])
Sjoerd Simonsb4eca2d2019-06-18 23:08:59 +0200554{
555 struct hab_hdr *hdr = (struct hab_hdr *)HAB_RVT_BASE;
556
557 if (hdr->tag != HAB_TAG_RVT) {
558 printf("Unexpected header tag: %x\n", hdr->tag);
559 return CMD_RET_FAILURE;
560 }
561
562 printf("HAB version: %d.%d\n", hdr->par >> 4, hdr->par & 0xf);
563
564 return 0;
565}
566
Simon Glass09140112020-05-10 11:40:03 -0600567static int do_authenticate_image_or_failover(struct cmd_tbl *cmdtp, int flag,
568 int argc, char *const argv[])
Bryan O'Donoghue49e62422018-03-26 15:36:46 +0100569{
570 int ret = CMD_RET_FAILURE;
571
572 if (argc != 4) {
573 ret = CMD_RET_USAGE;
574 goto error;
575 }
576
577 if (!imx_hab_is_enabled()) {
578 printf("error: secure boot disabled\n");
579 goto error;
580 }
581
582 if (do_authenticate_image(NULL, flag, argc, argv) != CMD_RET_SUCCESS) {
583 fprintf(stderr, "authentication fail -> %s %s %s %s\n",
584 argv[0], argv[1], argv[2], argv[3]);
585 do_hab_failsafe(0, 0, 1, NULL);
586 };
587 ret = CMD_RET_SUCCESS;
588error:
589 return ret;
590}
591
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100592U_BOOT_CMD(
593 hab_status, CONFIG_SYS_MAXARGS, 1, do_hab_status,
594 "display HAB status",
595 ""
596 );
597
598U_BOOT_CMD(
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000599 hab_auth_img, 4, 0, do_authenticate_image,
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100600 "authenticate image via HAB",
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000601 "addr length ivt_offset\n"
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100602 "addr - image hex address\n"
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000603 "length - image hex length\n"
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100604 "ivt_offset - hex offset of IVT in the image"
605 );
606
Bryan O'Donoghue9587b0d2018-01-12 12:40:19 +0000607U_BOOT_CMD(
608 hab_failsafe, CONFIG_SYS_MAXARGS, 1, do_hab_failsafe,
609 "run BootROM failsafe routine",
610 ""
611 );
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100612
Bryan O'Donoghue49e62422018-03-26 15:36:46 +0100613U_BOOT_CMD(
614 hab_auth_img_or_fail, 4, 0,
615 do_authenticate_image_or_failover,
616 "authenticate image via HAB on failure drop to USB BootROM mode",
617 "addr length ivt_offset\n"
618 "addr - image hex address\n"
619 "length - image hex length\n"
620 "ivt_offset - hex offset of IVT in the image"
621 );
622
Sjoerd Simonsb4eca2d2019-06-18 23:08:59 +0200623U_BOOT_CMD(
624 hab_version, 1, 0, do_hab_version,
625 "print HAB major/minor version",
626 ""
627 );
628
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100629#endif /* !defined(CONFIG_SPL_BUILD) */
630
Utkarsh Guptaed286bc2018-02-20 01:19:24 +0000631/* Get CSF Header length */
632static int get_hab_hdr_len(struct hab_hdr *hdr)
633{
634 return (size_t)((hdr->len[0] << 8) + (hdr->len[1]));
635}
636
637/* Check whether addr lies between start and
638 * end and is within the length of the image
639 */
640static int chk_bounds(u8 *addr, size_t bytes, u8 *start, u8 *end)
641{
642 size_t csf_size = (size_t)((end + 1) - addr);
643
644 return (addr && (addr >= start) && (addr <= end) &&
645 (csf_size >= bytes));
646}
647
648/* Get Length of each command in CSF */
649static int get_csf_cmd_hdr_len(u8 *csf_hdr)
650{
651 if (*csf_hdr == HAB_CMD_HDR)
652 return sizeof(struct hab_hdr);
653
654 return get_hab_hdr_len((struct hab_hdr *)csf_hdr);
655}
656
657/* Check if CSF is valid */
658static bool csf_is_valid(struct ivt *ivt, ulong start_addr, size_t bytes)
659{
660 u8 *start = (u8 *)start_addr;
661 u8 *csf_hdr;
662 u8 *end;
663
664 size_t csf_hdr_len;
665 size_t cmd_hdr_len;
666 size_t offset = 0;
667
668 if (bytes != 0)
669 end = start + bytes - 1;
670 else
671 end = start;
672
673 /* Verify if CSF pointer content is zero */
674 if (!ivt->csf) {
675 puts("Error: CSF pointer is NULL\n");
676 return false;
677 }
678
Peng Fan507da972021-03-25 17:30:07 +0800679 csf_hdr = (u8 *)(ulong)ivt->csf;
Utkarsh Guptaed286bc2018-02-20 01:19:24 +0000680
681 /* Verify if CSF Header exist */
682 if (*csf_hdr != HAB_CMD_HDR) {
683 puts("Error: CSF header command not found\n");
684 return false;
685 }
686
687 csf_hdr_len = get_hab_hdr_len((struct hab_hdr *)csf_hdr);
688
689 /* Check if the CSF lies within the image bounds */
690 if (!chk_bounds(csf_hdr, csf_hdr_len, start, end)) {
691 puts("Error: CSF lies outside the image bounds\n");
692 return false;
693 }
694
695 do {
Utkarsh Gupta20fa1dd2018-02-20 01:19:25 +0000696 struct hab_hdr *cmd;
697
698 cmd = (struct hab_hdr *)&csf_hdr[offset];
699
700 switch (cmd->tag) {
701 case (HAB_CMD_WRT_DAT):
702 puts("Error: Deprecated write command found\n");
703 return false;
704 case (HAB_CMD_CHK_DAT):
705 puts("Error: Deprecated check command found\n");
706 return false;
707 case (HAB_CMD_SET):
708 if (cmd->par == HAB_PAR_MID) {
709 puts("Error: Deprecated Set MID command found\n");
710 return false;
711 }
712 default:
713 break;
714 }
715
Utkarsh Guptaed286bc2018-02-20 01:19:24 +0000716 cmd_hdr_len = get_csf_cmd_hdr_len(&csf_hdr[offset]);
717 if (!cmd_hdr_len) {
718 puts("Error: Invalid command length\n");
719 return false;
720 }
721 offset += cmd_hdr_len;
722
723 } while (offset < csf_hdr_len);
724
725 return true;
726}
727
Utkarsh Guptafe8acf52021-03-25 17:30:08 +0800728/*
729 * Validate IVT structure of the image being authenticated
730 */
731static int validate_ivt(struct ivt *ivt_initial)
732{
733 struct ivt_header *ivt_hdr = &ivt_initial->hdr;
734
735 if ((ulong)ivt_initial & 0x3) {
736 puts("Error: Image's start address is not 4 byte aligned\n");
737 return 0;
738 }
739
740 /* Check IVT fields before allowing authentication */
741 if ((!verify_ivt_header(ivt_hdr)) && \
742 (ivt_initial->entry != 0x0) && \
743 (ivt_initial->reserved1 == 0x0) && \
744 (ivt_initial->self == \
745 (uint32_t)((ulong)ivt_initial & 0xffffffff)) && \
746 (ivt_initial->csf != 0x0) && \
747 (ivt_initial->reserved2 == 0x0)) {
748 /* Report boot failure if DCD pointer is found in IVT */
749 if (ivt_initial->dcd != 0x0)
750 puts("Error: DCD pointer must be 0\n");
751 else
752 return 1;
753 }
754
755 puts("Error: Invalid IVT structure\n");
756 debug("\nAllowed IVT structure:\n");
757 debug("IVT HDR = 0x4X2000D1\n");
758 debug("IVT ENTRY = 0xXXXXXXXX\n");
759 debug("IVT RSV1 = 0x0\n");
760 debug("IVT DCD = 0x0\n"); /* Recommended */
761 debug("IVT BOOT_DATA = 0xXXXXXXXX\n"); /* Commonly 0x0 */
762 debug("IVT SELF = 0xXXXXXXXX\n"); /* = ddr_start + ivt_offset */
763 debug("IVT CSF = 0xXXXXXXXX\n");
764 debug("IVT RSV2 = 0x0\n");
765
766 /* Invalid IVT structure */
767 return 0;
768}
769
Bryan O'Donoghue07eefaf2018-01-12 12:40:16 +0000770bool imx_hab_is_enabled(void)
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100771{
772 struct imx_sec_config_fuse_t *fuse =
773 (struct imx_sec_config_fuse_t *)&imx_sec_config_fuse;
774 uint32_t reg;
775 int ret;
776
777 ret = fuse_read(fuse->bank, fuse->word, &reg);
778 if (ret) {
779 puts("\nSecure boot fuse read error\n");
780 return ret;
781 }
782
783 return (reg & IS_HAB_ENABLED_BIT) == IS_HAB_ENABLED_BIT;
784}
785
Bryan O'Donoghue57f65482018-01-12 12:40:13 +0000786int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size,
787 uint32_t ivt_offset)
Nitin Garg36c1ca42014-09-16 13:33:25 -0500788{
Peng Fan507da972021-03-25 17:30:07 +0800789 ulong load_addr = 0;
Nitin Garg36c1ca42014-09-16 13:33:25 -0500790 size_t bytes;
Peng Fan507da972021-03-25 17:30:07 +0800791 ulong ivt_addr = 0;
Bryan O'Donoghue9535b392018-01-12 12:39:56 +0000792 int result = 1;
Nitin Garg36c1ca42014-09-16 13:33:25 -0500793 ulong start;
Bryan O'Donoghue49b6d052018-01-12 12:40:03 +0000794 struct ivt *ivt;
Bryan O'Donoghueb7c3cae2018-01-12 12:40:10 +0000795 enum hab_status status;
Nitin Garg36c1ca42014-09-16 13:33:25 -0500796
Breno Lima1d756ad2021-03-25 17:30:10 +0800797 if (!imx_hab_is_enabled())
Nitin Garg36c1ca42014-09-16 13:33:25 -0500798 puts("hab fuse not enabled\n");
Nitin Garg36c1ca42014-09-16 13:33:25 -0500799
Bryan O'Donoghued2c61802018-01-12 12:39:57 +0000800 printf("\nAuthenticate image from DDR location 0x%x...\n",
801 ddr_start);
802
803 hab_caam_clock_enable(1);
804
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000805 /* Calculate IVT address header */
Peng Fan507da972021-03-25 17:30:07 +0800806 ivt_addr = (ulong) (ddr_start + ivt_offset);
Bryan O'Donoghue49b6d052018-01-12 12:40:03 +0000807 ivt = (struct ivt *)ivt_addr;
Bryan O'Donoghue49b6d052018-01-12 12:40:03 +0000808
809 /* Verify IVT header bugging out on error */
Utkarsh Guptafe8acf52021-03-25 17:30:08 +0800810 if (!validate_ivt(ivt))
Breno Lima669f2d12018-02-20 01:19:22 +0000811 goto hab_authentication_exit;
Bryan O'Donoghue49b6d052018-01-12 12:40:03 +0000812
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000813 start = ddr_start;
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000814 bytes = image_size;
Bryan O'Donoghue04099e92018-01-12 12:40:05 +0000815
Utkarsh Guptaed286bc2018-02-20 01:19:24 +0000816 /* Verify CSF */
817 if (!csf_is_valid(ivt, start, bytes))
818 goto hab_authentication_exit;
819
Bryan O'Donoghue04099e92018-01-12 12:40:05 +0000820 if (hab_rvt_entry() != HAB_SUCCESS) {
821 puts("hab entry function fail\n");
Bryan O'Donoghue2c6c68d22018-01-12 12:40:11 +0000822 goto hab_exit_failure_print_status;
Bryan O'Donoghue04099e92018-01-12 12:40:05 +0000823 }
824
Peng Fan507da972021-03-25 17:30:07 +0800825 status = hab_rvt_check_target(HAB_TGT_MEMORY, (void *)(ulong)ddr_start, bytes);
Bryan O'Donoghueb7c3cae2018-01-12 12:40:10 +0000826 if (status != HAB_SUCCESS) {
Peng Fan507da972021-03-25 17:30:07 +0800827 printf("HAB check target 0x%08x-0x%08lx fail\n",
Bryan O'Donoghueb7c3cae2018-01-12 12:40:10 +0000828 ddr_start, ddr_start + bytes);
Bryan O'Donoghue2c6c68d22018-01-12 12:40:11 +0000829 goto hab_exit_failure_print_status;
Bryan O'Donoghueb7c3cae2018-01-12 12:40:10 +0000830 }
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000831#ifdef DEBUG
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000832 printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n", ivt_offset, ivt_addr);
Bryan O'Donoghue824ef302018-01-12 12:40:07 +0000833 printf("ivt entry = 0x%08x, dcd = 0x%08x, csf = 0x%08x\n", ivt->entry,
834 ivt->dcd, ivt->csf);
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000835 puts("Dumping IVT\n");
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000836 print_buffer(ivt_addr, (void *)(ivt_addr), 4, 0x8, 0);
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000837
838 puts("Dumping CSF Header\n");
Bryan O'Donoghuefd15fe52018-01-12 12:40:06 +0000839 print_buffer(ivt->csf, (void *)(ivt->csf), 4, 0x10, 0);
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000840
841#if !defined(CONFIG_SPL_BUILD)
842 get_hab_status();
843#endif
844
845 puts("\nCalling authenticate_image in ROM\n");
846 printf("\tivt_offset = 0x%x\n", ivt_offset);
847 printf("\tstart = 0x%08lx\n", start);
848 printf("\tbytes = 0x%x\n", bytes);
849#endif
Peng Fan507da972021-03-25 17:30:07 +0800850
851#ifndef CONFIG_ARM64
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000852 /*
853 * If the MMU is enabled, we have to notify the ROM
854 * code, or it won't flush the caches when needed.
855 * This is done, by setting the "pu_irom_mmu_enabled"
856 * word to 1. You can find its address by looking in
857 * the ROM map. This is critical for
858 * authenticate_image(). If MMU is enabled, without
859 * setting this bit, authentication will fail and may
860 * crash.
861 */
862 /* Check MMU enabled */
863 if (is_soc_type(MXC_SOC_MX6) && get_cr() & CR_M) {
864 if (is_mx6dq()) {
865 /*
866 * This won't work on Rev 1.0.0 of
867 * i.MX6Q/D, since their ROM doesn't
868 * do cache flushes. don't think any
869 * exist, so we ignore them.
870 */
871 if (!is_mx6dqp())
872 writel(1, MX6DQ_PU_IROM_MMU_EN_VAR);
873 } else if (is_mx6sdl()) {
874 writel(1, MX6DLS_PU_IROM_MMU_EN_VAR);
875 } else if (is_mx6sl()) {
876 writel(1, MX6SL_PU_IROM_MMU_EN_VAR);
877 }
878 }
Peng Fan507da972021-03-25 17:30:07 +0800879#endif
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000880
Peng Fan507da972021-03-25 17:30:07 +0800881 load_addr = (ulong)hab_rvt_authenticate_image(
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000882 HAB_CID_UBOOT,
883 ivt_offset, (void **)&start,
884 (size_t *)&bytes, NULL);
885 if (hab_rvt_exit() != HAB_SUCCESS) {
886 puts("hab exit function fail\n");
887 load_addr = 0;
888 }
889
Bryan O'Donoghue2c6c68d22018-01-12 12:40:11 +0000890hab_exit_failure_print_status:
Bryan O'Donoghued2c61802018-01-12 12:39:57 +0000891#if !defined(CONFIG_SPL_BUILD)
892 get_hab_status();
893#endif
Bryan O'Donoghue2c6c68d22018-01-12 12:40:11 +0000894
Breno Lima669f2d12018-02-20 01:19:22 +0000895hab_authentication_exit:
Bryan O'Donoghue2c6c68d22018-01-12 12:40:11 +0000896
Breno Lima1d756ad2021-03-25 17:30:10 +0800897 if (load_addr != 0 || !imx_hab_is_enabled())
Bryan O'Donoghue9535b392018-01-12 12:39:56 +0000898 result = 0;
Nitin Garg36c1ca42014-09-16 13:33:25 -0500899
900 return result;
901}
Ye Lic428ca82021-03-25 17:30:06 +0800902
903int authenticate_image(u32 ddr_start, u32 raw_image_size)
904{
905 u32 ivt_offset;
906 size_t bytes;
907
908 ivt_offset = (raw_image_size + ALIGN_SIZE - 1) &
909 ~(ALIGN_SIZE - 1);
910 bytes = ivt_offset + IVT_SIZE + CSF_PAD_SIZE;
911
912 return imx_hab_authenticate_image(ddr_start, bytes, ivt_offset);
913}