blob: 9ebdbe6ac32e983181b3df4fa151b0d15d38d239 [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{
542 hab_rvt_failsafe_t *hab_rvt_failsafe;
543
544 if (argc != 1) {
545 cmd_usage(cmdtp);
546 return 1;
547 }
548
Breno Lima7b889ba2018-02-20 01:19:26 +0000549 hab_rvt_failsafe = (hab_rvt_failsafe_t *)HAB_RVT_FAILSAFE;
Bryan O'Donoghue9587b0d2018-01-12 12:40:19 +0000550 hab_rvt_failsafe();
551
552 return 0;
553}
554
Simon Glass09140112020-05-10 11:40:03 -0600555static int do_hab_version(struct cmd_tbl *cmdtp, int flag, int argc,
556 char *const argv[])
Sjoerd Simonsb4eca2d2019-06-18 23:08:59 +0200557{
558 struct hab_hdr *hdr = (struct hab_hdr *)HAB_RVT_BASE;
559
560 if (hdr->tag != HAB_TAG_RVT) {
561 printf("Unexpected header tag: %x\n", hdr->tag);
562 return CMD_RET_FAILURE;
563 }
564
565 printf("HAB version: %d.%d\n", hdr->par >> 4, hdr->par & 0xf);
566
567 return 0;
568}
569
Simon Glass09140112020-05-10 11:40:03 -0600570static int do_authenticate_image_or_failover(struct cmd_tbl *cmdtp, int flag,
571 int argc, char *const argv[])
Bryan O'Donoghue49e62422018-03-26 15:36:46 +0100572{
573 int ret = CMD_RET_FAILURE;
574
575 if (argc != 4) {
576 ret = CMD_RET_USAGE;
577 goto error;
578 }
579
580 if (!imx_hab_is_enabled()) {
581 printf("error: secure boot disabled\n");
582 goto error;
583 }
584
585 if (do_authenticate_image(NULL, flag, argc, argv) != CMD_RET_SUCCESS) {
586 fprintf(stderr, "authentication fail -> %s %s %s %s\n",
587 argv[0], argv[1], argv[2], argv[3]);
588 do_hab_failsafe(0, 0, 1, NULL);
589 };
590 ret = CMD_RET_SUCCESS;
591error:
592 return ret;
593}
594
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100595U_BOOT_CMD(
596 hab_status, CONFIG_SYS_MAXARGS, 1, do_hab_status,
597 "display HAB status",
598 ""
599 );
600
601U_BOOT_CMD(
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000602 hab_auth_img, 4, 0, do_authenticate_image,
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100603 "authenticate image via HAB",
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000604 "addr length ivt_offset\n"
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100605 "addr - image hex address\n"
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000606 "length - image hex length\n"
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100607 "ivt_offset - hex offset of IVT in the image"
608 );
609
Bryan O'Donoghue9587b0d2018-01-12 12:40:19 +0000610U_BOOT_CMD(
611 hab_failsafe, CONFIG_SYS_MAXARGS, 1, do_hab_failsafe,
612 "run BootROM failsafe routine",
613 ""
614 );
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100615
Bryan O'Donoghue49e62422018-03-26 15:36:46 +0100616U_BOOT_CMD(
617 hab_auth_img_or_fail, 4, 0,
618 do_authenticate_image_or_failover,
619 "authenticate image via HAB on failure drop to USB BootROM mode",
620 "addr length ivt_offset\n"
621 "addr - image hex address\n"
622 "length - image hex length\n"
623 "ivt_offset - hex offset of IVT in the image"
624 );
625
Sjoerd Simonsb4eca2d2019-06-18 23:08:59 +0200626U_BOOT_CMD(
627 hab_version, 1, 0, do_hab_version,
628 "print HAB major/minor version",
629 ""
630 );
631
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100632#endif /* !defined(CONFIG_SPL_BUILD) */
633
Utkarsh Guptaed286bc2018-02-20 01:19:24 +0000634/* Get CSF Header length */
635static int get_hab_hdr_len(struct hab_hdr *hdr)
636{
637 return (size_t)((hdr->len[0] << 8) + (hdr->len[1]));
638}
639
640/* Check whether addr lies between start and
641 * end and is within the length of the image
642 */
643static int chk_bounds(u8 *addr, size_t bytes, u8 *start, u8 *end)
644{
645 size_t csf_size = (size_t)((end + 1) - addr);
646
647 return (addr && (addr >= start) && (addr <= end) &&
648 (csf_size >= bytes));
649}
650
651/* Get Length of each command in CSF */
652static int get_csf_cmd_hdr_len(u8 *csf_hdr)
653{
654 if (*csf_hdr == HAB_CMD_HDR)
655 return sizeof(struct hab_hdr);
656
657 return get_hab_hdr_len((struct hab_hdr *)csf_hdr);
658}
659
660/* Check if CSF is valid */
661static bool csf_is_valid(struct ivt *ivt, ulong start_addr, size_t bytes)
662{
663 u8 *start = (u8 *)start_addr;
664 u8 *csf_hdr;
665 u8 *end;
666
667 size_t csf_hdr_len;
668 size_t cmd_hdr_len;
669 size_t offset = 0;
670
671 if (bytes != 0)
672 end = start + bytes - 1;
673 else
674 end = start;
675
676 /* Verify if CSF pointer content is zero */
677 if (!ivt->csf) {
678 puts("Error: CSF pointer is NULL\n");
679 return false;
680 }
681
Peng Fan507da972021-03-25 17:30:07 +0800682 csf_hdr = (u8 *)(ulong)ivt->csf;
Utkarsh Guptaed286bc2018-02-20 01:19:24 +0000683
684 /* Verify if CSF Header exist */
685 if (*csf_hdr != HAB_CMD_HDR) {
686 puts("Error: CSF header command not found\n");
687 return false;
688 }
689
690 csf_hdr_len = get_hab_hdr_len((struct hab_hdr *)csf_hdr);
691
692 /* Check if the CSF lies within the image bounds */
693 if (!chk_bounds(csf_hdr, csf_hdr_len, start, end)) {
694 puts("Error: CSF lies outside the image bounds\n");
695 return false;
696 }
697
698 do {
Utkarsh Gupta20fa1dd2018-02-20 01:19:25 +0000699 struct hab_hdr *cmd;
700
701 cmd = (struct hab_hdr *)&csf_hdr[offset];
702
703 switch (cmd->tag) {
704 case (HAB_CMD_WRT_DAT):
705 puts("Error: Deprecated write command found\n");
706 return false;
707 case (HAB_CMD_CHK_DAT):
708 puts("Error: Deprecated check command found\n");
709 return false;
710 case (HAB_CMD_SET):
711 if (cmd->par == HAB_PAR_MID) {
712 puts("Error: Deprecated Set MID command found\n");
713 return false;
714 }
715 default:
716 break;
717 }
718
Utkarsh Guptaed286bc2018-02-20 01:19:24 +0000719 cmd_hdr_len = get_csf_cmd_hdr_len(&csf_hdr[offset]);
720 if (!cmd_hdr_len) {
721 puts("Error: Invalid command length\n");
722 return false;
723 }
724 offset += cmd_hdr_len;
725
726 } while (offset < csf_hdr_len);
727
728 return true;
729}
730
Bryan O'Donoghue07eefaf2018-01-12 12:40:16 +0000731bool imx_hab_is_enabled(void)
Sven Ebenfeld15b505b2016-11-06 16:37:55 +0100732{
733 struct imx_sec_config_fuse_t *fuse =
734 (struct imx_sec_config_fuse_t *)&imx_sec_config_fuse;
735 uint32_t reg;
736 int ret;
737
738 ret = fuse_read(fuse->bank, fuse->word, &reg);
739 if (ret) {
740 puts("\nSecure boot fuse read error\n");
741 return ret;
742 }
743
744 return (reg & IS_HAB_ENABLED_BIT) == IS_HAB_ENABLED_BIT;
745}
746
Bryan O'Donoghue57f65482018-01-12 12:40:13 +0000747int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size,
748 uint32_t ivt_offset)
Nitin Garg36c1ca42014-09-16 13:33:25 -0500749{
Peng Fan507da972021-03-25 17:30:07 +0800750 ulong load_addr = 0;
Nitin Garg36c1ca42014-09-16 13:33:25 -0500751 size_t bytes;
Peng Fan507da972021-03-25 17:30:07 +0800752 ulong ivt_addr = 0;
Bryan O'Donoghue9535b392018-01-12 12:39:56 +0000753 int result = 1;
Nitin Garg36c1ca42014-09-16 13:33:25 -0500754 ulong start;
Bryan O'Donoghue49b6d052018-01-12 12:40:03 +0000755 struct ivt *ivt;
756 struct ivt_header *ivt_hdr;
Bryan O'Donoghueb7c3cae2018-01-12 12:40:10 +0000757 enum hab_status status;
Nitin Garg36c1ca42014-09-16 13:33:25 -0500758
Bryan O'Donoghuee5b30e42018-01-12 12:40:14 +0000759 if (!imx_hab_is_enabled()) {
Nitin Garg36c1ca42014-09-16 13:33:25 -0500760 puts("hab fuse not enabled\n");
Bryan O'Donoghue4467ae62018-01-12 12:40:15 +0000761 return 0;
Nitin Garg36c1ca42014-09-16 13:33:25 -0500762 }
763
Bryan O'Donoghued2c61802018-01-12 12:39:57 +0000764 printf("\nAuthenticate image from DDR location 0x%x...\n",
765 ddr_start);
766
767 hab_caam_clock_enable(1);
768
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000769 /* Calculate IVT address header */
Peng Fan507da972021-03-25 17:30:07 +0800770 ivt_addr = (ulong) (ddr_start + ivt_offset);
Bryan O'Donoghue49b6d052018-01-12 12:40:03 +0000771 ivt = (struct ivt *)ivt_addr;
772 ivt_hdr = &ivt->hdr;
773
774 /* Verify IVT header bugging out on error */
775 if (verify_ivt_header(ivt_hdr))
Breno Lima669f2d12018-02-20 01:19:22 +0000776 goto hab_authentication_exit;
Bryan O'Donoghue49b6d052018-01-12 12:40:03 +0000777
Bryan O'Donoghuee59eb9e2018-01-12 12:40:04 +0000778 /* Verify IVT body */
779 if (ivt->self != ivt_addr) {
Peng Fan507da972021-03-25 17:30:07 +0800780 printf("ivt->self 0x%08x pointer is 0x%08lx\n",
Bryan O'Donoghuee59eb9e2018-01-12 12:40:04 +0000781 ivt->self, ivt_addr);
Breno Lima669f2d12018-02-20 01:19:22 +0000782 goto hab_authentication_exit;
Bryan O'Donoghuee59eb9e2018-01-12 12:40:04 +0000783 }
784
Utkarsh Gupta8c4037a2018-02-20 01:19:23 +0000785 /* Verify if IVT DCD pointer is NULL */
Breno Matheus Limab2ca8902018-12-07 22:31:49 +0000786 if (ivt->dcd) {
787 puts("Error: DCD pointer must be NULL\n");
788 goto hab_authentication_exit;
789 }
Utkarsh Gupta8c4037a2018-02-20 01:19:23 +0000790
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000791 start = ddr_start;
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000792 bytes = image_size;
Bryan O'Donoghue04099e92018-01-12 12:40:05 +0000793
Utkarsh Guptaed286bc2018-02-20 01:19:24 +0000794 /* Verify CSF */
795 if (!csf_is_valid(ivt, start, bytes))
796 goto hab_authentication_exit;
797
Bryan O'Donoghue04099e92018-01-12 12:40:05 +0000798 if (hab_rvt_entry() != HAB_SUCCESS) {
799 puts("hab entry function fail\n");
Bryan O'Donoghue2c6c68d22018-01-12 12:40:11 +0000800 goto hab_exit_failure_print_status;
Bryan O'Donoghue04099e92018-01-12 12:40:05 +0000801 }
802
Peng Fan507da972021-03-25 17:30:07 +0800803 status = hab_rvt_check_target(HAB_TGT_MEMORY, (void *)(ulong)ddr_start, bytes);
Bryan O'Donoghueb7c3cae2018-01-12 12:40:10 +0000804 if (status != HAB_SUCCESS) {
Peng Fan507da972021-03-25 17:30:07 +0800805 printf("HAB check target 0x%08x-0x%08lx fail\n",
Bryan O'Donoghueb7c3cae2018-01-12 12:40:10 +0000806 ddr_start, ddr_start + bytes);
Bryan O'Donoghue2c6c68d22018-01-12 12:40:11 +0000807 goto hab_exit_failure_print_status;
Bryan O'Donoghueb7c3cae2018-01-12 12:40:10 +0000808 }
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000809#ifdef DEBUG
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000810 printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n", ivt_offset, ivt_addr);
Bryan O'Donoghue824ef302018-01-12 12:40:07 +0000811 printf("ivt entry = 0x%08x, dcd = 0x%08x, csf = 0x%08x\n", ivt->entry,
812 ivt->dcd, ivt->csf);
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000813 puts("Dumping IVT\n");
Bryan O'Donoghuec5800b22018-01-12 12:40:01 +0000814 print_buffer(ivt_addr, (void *)(ivt_addr), 4, 0x8, 0);
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000815
816 puts("Dumping CSF Header\n");
Bryan O'Donoghuefd15fe52018-01-12 12:40:06 +0000817 print_buffer(ivt->csf, (void *)(ivt->csf), 4, 0x10, 0);
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000818
819#if !defined(CONFIG_SPL_BUILD)
820 get_hab_status();
821#endif
822
823 puts("\nCalling authenticate_image in ROM\n");
824 printf("\tivt_offset = 0x%x\n", ivt_offset);
825 printf("\tstart = 0x%08lx\n", start);
826 printf("\tbytes = 0x%x\n", bytes);
827#endif
Peng Fan507da972021-03-25 17:30:07 +0800828
829#ifndef CONFIG_ARM64
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000830 /*
831 * If the MMU is enabled, we have to notify the ROM
832 * code, or it won't flush the caches when needed.
833 * This is done, by setting the "pu_irom_mmu_enabled"
834 * word to 1. You can find its address by looking in
835 * the ROM map. This is critical for
836 * authenticate_image(). If MMU is enabled, without
837 * setting this bit, authentication will fail and may
838 * crash.
839 */
840 /* Check MMU enabled */
841 if (is_soc_type(MXC_SOC_MX6) && get_cr() & CR_M) {
842 if (is_mx6dq()) {
843 /*
844 * This won't work on Rev 1.0.0 of
845 * i.MX6Q/D, since their ROM doesn't
846 * do cache flushes. don't think any
847 * exist, so we ignore them.
848 */
849 if (!is_mx6dqp())
850 writel(1, MX6DQ_PU_IROM_MMU_EN_VAR);
851 } else if (is_mx6sdl()) {
852 writel(1, MX6DLS_PU_IROM_MMU_EN_VAR);
853 } else if (is_mx6sl()) {
854 writel(1, MX6SL_PU_IROM_MMU_EN_VAR);
855 }
856 }
Peng Fan507da972021-03-25 17:30:07 +0800857#endif
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000858
Peng Fan507da972021-03-25 17:30:07 +0800859 load_addr = (ulong)hab_rvt_authenticate_image(
Bryan O'Donoghue53c8a512018-01-12 12:39:58 +0000860 HAB_CID_UBOOT,
861 ivt_offset, (void **)&start,
862 (size_t *)&bytes, NULL);
863 if (hab_rvt_exit() != HAB_SUCCESS) {
864 puts("hab exit function fail\n");
865 load_addr = 0;
866 }
867
Bryan O'Donoghue2c6c68d22018-01-12 12:40:11 +0000868hab_exit_failure_print_status:
Bryan O'Donoghued2c61802018-01-12 12:39:57 +0000869#if !defined(CONFIG_SPL_BUILD)
870 get_hab_status();
871#endif
Bryan O'Donoghue2c6c68d22018-01-12 12:40:11 +0000872
Breno Lima669f2d12018-02-20 01:19:22 +0000873hab_authentication_exit:
Bryan O'Donoghue2c6c68d22018-01-12 12:40:11 +0000874
Bryan O'Donoghued2c61802018-01-12 12:39:57 +0000875 if (load_addr != 0)
Bryan O'Donoghue9535b392018-01-12 12:39:56 +0000876 result = 0;
Nitin Garg36c1ca42014-09-16 13:33:25 -0500877
878 return result;
879}
Ye Lic428ca82021-03-25 17:30:06 +0800880
881int authenticate_image(u32 ddr_start, u32 raw_image_size)
882{
883 u32 ivt_offset;
884 size_t bytes;
885
886 ivt_offset = (raw_image_size + ALIGN_SIZE - 1) &
887 ~(ALIGN_SIZE - 1);
888 bytes = ivt_offset + IVT_SIZE + CSF_PAD_SIZE;
889
890 return imx_hab_authenticate_image(ddr_start, bytes, ivt_offset);
891}