[U-Boot] HAB synchronous error loop i.MX8M

Hello, * * I'm using an i.MX8M based Boundary Devices Nitrogen8M board with U-Boot / U-Boot SPL as the bootloader. I want to use HAB (arch/arm/mach-imx/hab.c) in order to authenticate the bootloader and kernel images before running them. The problem is my board goes into a synchronous error loop when authenticating the bootloader image from U-Boot SPL level. I don't get any return code, nothing. It happens on the `hab_rvt_authenticate_image` call. The board is open, so it should just fail if the image is badly constructed/signed and let me continue.
Any ideas as to why is it happening and what could possibly be done to fix this?
Best regards, Bartlomiej Nowak

On Thu, Oct 03, 2019 at 12:06:24PM +0200, Bartlomiej wrote:
Hello,
I'm using an i.MX8M based Boundary Devices Nitrogen8M board with U-Boot / U-Boot SPL as the bootloader. I want to use HAB (arch/arm/mach-imx/hab.c) in order to authenticate the bootloader and kernel images before running them. The problem is my board goes into a synchronous error loop when authenticating the bootloader image from U-Boot SPL level. I don't get any return code, nothing. It happens on the `hab_rvt_authenticate_image` call. The board is open, so it should just fail if the image is badly constructed/signed and let me continue.
Any ideas as to why is it happening and what could possibly be done to fix this?
Best regards, Bartlomiej Nowak
Boundary Devices U-Boot is about a year old, and I haven't checked how they implemented it. I have a diff for i.MX8M HAB support which works for me.
Best regards, Patrick
diff --git a/arch/arm/include/asm/arch-imx8m/clock.h b/arch/arm/include/asm/arch-imx8m/clock.h index e7c1670f6b..5cebe10c6f 100644 --- a/arch/arm/include/asm/arch-imx8m/clock.h +++ b/arch/arm/include/asm/arch-imx8m/clock.h @@ -675,4 +675,5 @@ int set_clk_qspi(void); void enable_ocotp_clk(unsigned char enable); int enable_i2c_clk(unsigned char enable, unsigned int i2c_num); int set_clk_enet(enum enet_freq type); +void hab_caam_clock_enable(unsigned char enable); #endif diff --git a/arch/arm/include/asm/mach-imx/hab.h b/arch/arm/include/asm/mach-imx/hab.h index 95df88423c..f3bbad36de 100644 --- a/arch/arm/include/asm/mach-imx/hab.h +++ b/arch/arm/include/asm/mach-imx/hab.h @@ -10,6 +10,8 @@ #include <linux/types.h> #include <linux/compiler.h>
+DECLARE_GLOBAL_DATA_PTR; + /* * IVT header definitions * Security Reference Manual for i.MX 7Dual and 7Solo Applications Processors, @@ -165,6 +167,15 @@ typedef void hapi_clock_init_t(void); #define HAB_ENG_RTL 0x77 /* RTL simulation engine */ #define HAB_ENG_SW 0xff /* Software engine */
+#ifdef CONFIG_ARM64 +#define HAB_RVT_BASE 0x00000880 + +#define HAB_RVT_ENTRY ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x08)) +#define HAB_RVT_EXIT ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x10)) +#define HAB_RVT_AUTHENTICATE_IMAGE ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x20)) +#define HAB_RVT_REPORT_EVENT ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x40)) +#define HAB_RVT_REPORT_STATUS ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x48)) +#else #ifdef CONFIG_ROM_UNIFIED_SECTIONS #define HAB_RVT_BASE 0x00000100 #else @@ -178,13 +189,14 @@ typedef void hapi_clock_init_t(void); HAB_RVT_BASE_NEW : HAB_RVT_BASE_OLD) #endif
-#define HAB_RVT_ENTRY (*(uint32_t *)(HAB_RVT_BASE + 0x04)) -#define HAB_RVT_EXIT (*(uint32_t *)(HAB_RVT_BASE + 0x08)) -#define HAB_RVT_CHECK_TARGET (*(uint32_t *)(HAB_RVT_BASE + 0x0C)) -#define HAB_RVT_AUTHENTICATE_IMAGE (*(uint32_t *)(HAB_RVT_BASE + 0x10)) -#define HAB_RVT_REPORT_EVENT (*(uint32_t *)(HAB_RVT_BASE + 0x20)) -#define HAB_RVT_REPORT_STATUS (*(uint32_t *)(HAB_RVT_BASE + 0x24)) -#define HAB_RVT_FAILSAFE (*(uint32_t *)(HAB_RVT_BASE + 0x28)) +#define HAB_RVT_ENTRY ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x04)) +#define HAB_RVT_EXIT ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x08)) +#define HAB_RVT_CHECK_TARGET ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x0C)) +#define HAB_RVT_AUTHENTICATE_IMAGE ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x10)) +#define HAB_RVT_REPORT_EVENT ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x20)) +#define HAB_RVT_REPORT_STATUS ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x24)) +#define HAB_RVT_FAILSAFE ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x28)) +#endif
#define HAB_CID_ROM 0 /**< ROM Caller ID */ #define HAB_CID_UBOOT 1 /**< UBOOT Caller ID*/ diff --git a/arch/arm/include/asm/mach-imx/sys_proto.h b/arch/arm/include/asm/mach-imx/sys_proto.h index 4925dd7894..65791cb1b2 100644 --- a/arch/arm/include/asm/mach-imx/sys_proto.h +++ b/arch/arm/include/asm/mach-imx/sys_proto.h @@ -133,7 +133,8 @@ int mxs_wait_mask_set(struct mxs_register_32 *reg, u32 mask, u32 timeout); int mxs_wait_mask_clr(struct mxs_register_32 *reg, u32 mask, u32 timeout);
unsigned long call_imx_sip(unsigned long id, unsigned long reg0, - unsigned long reg1, unsigned long reg2); + unsigned long reg1, unsigned long reg2, + unsigned long reg3); unsigned long call_imx_sip_ret2(unsigned long id, unsigned long reg0, unsigned long *reg1, unsigned long reg2, unsigned long reg3); diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index aeb5493488..1efc1ed8fa 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -36,9 +36,9 @@ config USE_IMXIMG_PLUGIN
config SECURE_BOOT bool "Support i.MX HAB features" - depends on ARCH_MX7 || ARCH_MX6 || ARCH_MX5 + depends on ARCH_IMX8M || ARCH_MX7 || ARCH_MX6 || ARCH_MX5 select FSL_CAAM if HAS_CAAM - imply CMD_DEKBLOB + imply CMD_DEKBLOB if !ARCH_IMX8M help This option enables the support for secure boot (HAB). See doc/README.mxc_hab for more details. diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 08ee52edbf..61d6bf176e 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -16,6 +16,7 @@ endif obj-$(CONFIG_ENV_IS_IN_MMC) += mmc_env.o obj-$(CONFIG_FEC_MXC) += mac.o obj-$(CONFIG_SYS_I2C_MXC) += i2c-mxv7.o +obj-$(CONFIG_SECURE_BOOT) += hab.o obj-y += cpu.o endif
diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c index ce50dbe907..6b3f7928dd 100644 --- a/arch/arm/mach-imx/hab.c +++ b/arch/arm/mach-imx/hab.c @@ -20,7 +20,18 @@ #define MX6SL_PU_IROM_MMU_EN_VAR 0x00901c60 #define IS_HAB_ENABLED_BIT \ (is_soc_type(MXC_SOC_MX7ULP) ? 0x80000000 : \ - (is_soc_type(MXC_SOC_MX7) ? 0x2000000 : 0x2)) + ((is_soc_type(MXC_SOC_MX7) || is_soc_type(MXC_SOC_IMX8M)) ? 0x2000000 : 0x2)) + +#ifdef CONFIG_ARM64 +#define FSL_SIP_HAB 0xC2000007 +#define FSL_SIP_HAB_AUTHENTICATE 0x00 +#define FSL_SIP_HAB_ENTRY 0x01 +#define FSL_SIP_HAB_EXIT 0x02 +#define FSL_SIP_HAB_REPORT_EVENT 0x03 +#define FSL_SIP_HAB_REPORT_STATUS 0x04 + +static volatile gd_t *gd_save; +#endif
static int ivt_header_error(const char *err_str, struct ivt_header *ivt_hdr) { @@ -47,6 +58,97 @@ static int verify_ivt_header(struct ivt_header *ivt_hdr) return result; }
+static inline void save_gd(void) +{ +#ifdef CONFIG_ARM64 + gd_save = gd; +#endif +} + +static inline void restore_gd(void) +{ +#ifdef CONFIG_ARM64 + /* + * Make will already error that reserving x18 is not supported at the + * time of writing, clang: error: unknown argument: '-ffixed-x18' + */ + __asm__ volatile("mov x18, %0\n" : : "r" (gd_save)); +#endif +} + +static enum hab_status hab_rvt_entry(void) +{ + enum hab_status ret; + hab_rvt_entry_t *hab_rvt_entry_func; + + hab_rvt_entry_func = (hab_rvt_entry_t *)HAB_RVT_ENTRY; + +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + ret = (enum hab_status)call_imx_sip(FSL_SIP_HAB, + FSL_SIP_HAB_ENTRY, 0, 0, 0); + return ret; + } +#endif + + save_gd(); + ret = hab_rvt_entry_func(); + restore_gd(); + + return ret; +} + +static enum hab_status hab_rvt_exit(void) +{ + enum hab_status ret; + hab_rvt_exit_t *hab_rvt_exit_func; + + hab_rvt_exit_func = (hab_rvt_exit_t *)HAB_RVT_EXIT; + +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + ret = (enum hab_status)call_imx_sip(FSL_SIP_HAB, + FSL_SIP_HAB_EXIT, 0, 0, 0); + return ret; + } +#endif + + save_gd(); + ret = hab_rvt_exit_func(); + restore_gd(); + + return ret; +} + +static void *hab_rvt_authenticate_image(uint8_t cid, ptrdiff_t ivt_offset, + void **start, size_t *bytes, hab_loader_callback_f_t loader) +{ + void *ret; + hab_rvt_authenticate_image_t *hab_rvt_authenticate_image_func; + + hab_rvt_authenticate_image_func = + (hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE; + +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + ret = (void *)call_imx_sip(FSL_SIP_HAB, + FSL_SIP_HAB_AUTHENTICATE, (unsigned long)ivt_offset, + (unsigned long)start, (unsigned long)bytes); + return ret; + } +#endif + + save_gd(); + ret = hab_rvt_authenticate_image_func(cid, ivt_offset, start, + bytes, loader); + restore_gd(); + + return ret; +} + #if !defined(CONFIG_SPL_BUILD)
#define MAX_RECORD_BYTES (8*1024) /* 4 kbytes */ @@ -245,6 +347,57 @@ static void display_event(uint8_t *event_data, size_t bytes) process_event_record(event_data, bytes); }
+static enum hab_status hab_rvt_report_event(enum hab_status status, + uint32_t index, uint8_t *event, size_t *bytes) +{ + enum hab_status ret; + hab_rvt_report_event_t *hab_rvt_report_event; + + hab_rvt_report_event = (hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT; + +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + ret = (enum hab_status)call_imx_sip(FSL_SIP_HAB, + FSL_SIP_HAB_REPORT_EVENT, (unsigned long)index, + (unsigned long)event, (unsigned long)bytes); + return ret; + } +#endif + + save_gd(); + ret = hab_rvt_report_event(status, index, event, bytes); + restore_gd(); + + return ret; +} + +static enum hab_status hab_rvt_report_status(enum hab_config *config, + enum hab_state *state) +{ + enum hab_status ret; + hab_rvt_report_status_t *hab_rvt_report_status_func; + + hab_rvt_report_status_func = + (hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS; + +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + ret = (enum hab_status)call_imx_sip(FSL_SIP_HAB, + FSL_SIP_HAB_REPORT_STATUS, (unsigned long)config, + (unsigned long)state, 0); + return ret; + } +#endif + + save_gd(); + ret = hab_rvt_report_status_func(config, state); + restore_gd(); + + return ret; +} + static int get_hab_status(void) { uint32_t index = 0; /* Loop index */ @@ -252,12 +405,6 @@ static int get_hab_status(void) size_t bytes = sizeof(event_data); /* Event size in bytes */ enum hab_config config = 0; enum hab_state state = 0; - hab_rvt_report_event_t *hab_rvt_report_event; - hab_rvt_report_status_t *hab_rvt_report_status; - - hab_rvt_report_event = (hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT; - hab_rvt_report_status = - (hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS;
if (imx_hab_is_enabled()) puts("\nSecure boot enabled\n"); @@ -349,6 +496,7 @@ static int do_authenticate_image(cmd_tbl_t *cmdtp, int flag, int argc, return rcode; }
+#ifdef HAB_RVT_FAILSAFE static int do_hab_failsafe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -389,6 +537,7 @@ static int do_authenticate_image_or_failover(cmd_tbl_t *cmdtp, int flag, error: return ret; } +#endif
U_BOOT_CMD( hab_status, CONFIG_SYS_MAXARGS, 1, do_hab_status, @@ -405,6 +554,7 @@ U_BOOT_CMD( "ivt_offset - hex offset of IVT in the image" );
+#ifdef HAB_RVT_FAILSAFE U_BOOT_CMD( hab_failsafe, CONFIG_SYS_MAXARGS, 1, do_hab_failsafe, "run BootROM failsafe routine", @@ -420,6 +570,7 @@ U_BOOT_CMD( "length - image hex length\n" "ivt_offset - hex offset of IVT in the image" ); +#endif
#endif /* !defined(CONFIG_SPL_BUILD) */
@@ -471,7 +622,7 @@ static bool csf_is_valid(struct ivt *ivt, ulong start_addr, size_t bytes) return false; }
- csf_hdr = (u8 *)ivt->csf; + csf_hdr = (u8 *)(ulong)ivt->csf;
/* Verify if CSF Header exist */ if (*csf_hdr != HAB_CMD_HDR) { @@ -539,24 +690,19 @@ bool imx_hab_is_enabled(void) int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, uint32_t ivt_offset) { - uint32_t load_addr = 0; + ulong load_addr = 0; size_t bytes; - uint32_t ivt_addr = 0; + ulong ivt_addr = 0; int result = 1; ulong start; - hab_rvt_authenticate_image_t *hab_rvt_authenticate_image; - hab_rvt_entry_t *hab_rvt_entry; - hab_rvt_exit_t *hab_rvt_exit; - hab_rvt_check_target_t *hab_rvt_check_target; struct ivt *ivt; struct ivt_header *ivt_hdr; +#ifdef HAB_RVT_CHECK_TARGET + hab_rvt_check_target_t *hab_rvt_check_target; enum hab_status status;
- hab_rvt_authenticate_image = - (hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE; - hab_rvt_entry = (hab_rvt_entry_t *)HAB_RVT_ENTRY; - hab_rvt_exit = (hab_rvt_exit_t *)HAB_RVT_EXIT; hab_rvt_check_target = (hab_rvt_check_target_t *)HAB_RVT_CHECK_TARGET; +#endif
if (!imx_hab_is_enabled()) { puts("hab fuse not enabled\n"); @@ -579,8 +725,8 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size,
/* Verify IVT body */ if (ivt->self != ivt_addr) { - printf("ivt->self 0x%08x pointer is 0x%08x\n", - ivt->self, ivt_addr); + printf("ivt->self 0x%08x pointer is 0x%08lx\n", + ivt->self, (ulong)ivt_addr); goto hab_authentication_exit; }
@@ -602,12 +748,14 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, goto hab_exit_failure_print_status; }
+#ifdef HAB_RVT_CHECK_TARGET status = hab_rvt_check_target(HAB_TGT_MEMORY, (void *)ddr_start, bytes); if (status != HAB_SUCCESS) { printf("HAB check target 0x%08x-0x%08x fail\n", ddr_start, ddr_start + bytes); goto hab_exit_failure_print_status; } +#endif #ifdef DEBUG printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n", ivt_offset, ivt_addr); printf("ivt entry = 0x%08x, dcd = 0x%08x, csf = 0x%08x\n", ivt->entry, @@ -627,6 +775,8 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, printf("\tstart = 0x%08lx\n", start); printf("\tbytes = 0x%x\n", bytes); #endif + +#ifndef CONFIG_ARM64 /* * If the MMU is enabled, we have to notify the ROM * code, or it won't flush the caches when needed. @@ -654,8 +804,9 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, writel(1, MX6SL_PU_IROM_MMU_EN_VAR); } } +#endif
- load_addr = (uint32_t)hab_rvt_authenticate_image( + load_addr = (ulong)hab_rvt_authenticate_image( HAB_CID_UBOOT, ivt_offset, (void **)&start, (size_t *)&bytes, NULL); diff --git a/arch/arm/mach-imx/imx8m/clock.c b/arch/arm/mach-imx/imx8m/clock.c index 289b9417aa..232219f2f6 100644 --- a/arch/arm/mach-imx/imx8m/clock.c +++ b/arch/arm/mach-imx/imx8m/clock.c @@ -304,6 +304,13 @@ static u32 get_root_clk(enum clk_root_index clock_id) return root_src_clk / (post_podf + 1) / (pre_podf + 1); }
+#ifdef CONFIG_SECURE_BOOT +void hab_caam_clock_enable(unsigned char enable) +{ + /* The CAAM clock is always on for iMX8M */ +} +#endif + #ifdef CONFIG_MXC_OCOTP void enable_ocotp_clk(unsigned char enable) { diff --git a/arch/arm/mach-imx/imx_bootaux.c b/arch/arm/mach-imx/imx_bootaux.c index 18d7e6819c..3d9422d5a2 100644 --- a/arch/arm/mach-imx/imx_bootaux.c +++ b/arch/arm/mach-imx/imx_bootaux.c @@ -26,7 +26,7 @@ int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data)
/* Enable M4 */ #ifdef CONFIG_IMX8M - call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_START, 0, 0); + call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_START, 0, 0, 0); #else clrsetbits_le32(SRC_BASE_ADDR + SRC_M4_REG_OFFSET, SRC_M4C_NON_SCLR_RST_MASK, SRC_M4_ENABLE_MASK); @@ -38,7 +38,7 @@ int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data) int arch_auxiliary_core_check_up(u32 core_id) { #ifdef CONFIG_IMX8M - return call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_STARTED, 0, 0); + return call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_STARTED, 0, 0, 0); #else unsigned int val;
diff --git a/arch/arm/mach-imx/sip.c b/arch/arm/mach-imx/sip.c index 968e7cf309..fca520c671 100644 --- a/arch/arm/mach-imx/sip.c +++ b/arch/arm/mach-imx/sip.c @@ -7,7 +7,8 @@ #include <asm/arch/sys_proto.h>
unsigned long call_imx_sip(unsigned long id, unsigned long reg0, - unsigned long reg1, unsigned long reg2) + unsigned long reg1, unsigned long reg2, + unsigned long reg3) { struct pt_regs regs;
@@ -15,6 +16,7 @@ unsigned long call_imx_sip(unsigned long id, unsigned long reg0, regs.regs[1] = reg0; regs.regs[2] = reg1; regs.regs[3] = reg2; + regs.regs[4] = reg3;
smc_call(®s);
diff --git a/configs/imx8mq_evk_defconfig b/configs/imx8mq_evk_defconfig index e45731edda..d5f6cdf1ca 100644 --- a/configs/imx8mq_evk_defconfig +++ b/configs/imx8mq_evk_defconfig @@ -1,4 +1,5 @@ CONFIG_ARM=y +CONFIG_SECURE_BOOT=y CONFIG_SPL_SYS_ICACHE_OFF=y CONFIG_SPL_SYS_DCACHE_OFF=y CONFIG_ARCH_IMX8M=y

Hi Patrick,
On Thu, Oct 3, 2019 at 10:01 AM Patrick Wildt patrick@blueri.se wrote:
Boundary Devices U-Boot is about a year old, and I haven't checked how they implemented it. I have a diff for i.MX8M HAB support which works for me.
Please submit the i.MX8M HAB support as a formal patch.
Thanks
Best regards, Patrick
diff --git a/arch/arm/include/asm/arch-imx8m/clock.h b/arch/arm/include/asm/arch-imx8m/clock.h index e7c1670f6b..5cebe10c6f 100644 --- a/arch/arm/include/asm/arch-imx8m/clock.h +++ b/arch/arm/include/asm/arch-imx8m/clock.h @@ -675,4 +675,5 @@ int set_clk_qspi(void); void enable_ocotp_clk(unsigned char enable); int enable_i2c_clk(unsigned char enable, unsigned int i2c_num); int set_clk_enet(enum enet_freq type); +void hab_caam_clock_enable(unsigned char enable); #endif diff --git a/arch/arm/include/asm/mach-imx/hab.h b/arch/arm/include/asm/mach-imx/hab.h index 95df88423c..f3bbad36de 100644 --- a/arch/arm/include/asm/mach-imx/hab.h +++ b/arch/arm/include/asm/mach-imx/hab.h @@ -10,6 +10,8 @@ #include <linux/types.h> #include <linux/compiler.h>
+DECLARE_GLOBAL_DATA_PTR;
/*
- IVT header definitions
- Security Reference Manual for i.MX 7Dual and 7Solo Applications Processors,
@@ -165,6 +167,15 @@ typedef void hapi_clock_init_t(void); #define HAB_ENG_RTL 0x77 /* RTL simulation engine */ #define HAB_ENG_SW 0xff /* Software engine */
+#ifdef CONFIG_ARM64 +#define HAB_RVT_BASE 0x00000880
+#define HAB_RVT_ENTRY ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x08)) +#define HAB_RVT_EXIT ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x10)) +#define HAB_RVT_AUTHENTICATE_IMAGE ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x20)) +#define HAB_RVT_REPORT_EVENT ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x40)) +#define HAB_RVT_REPORT_STATUS ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x48)) +#else #ifdef CONFIG_ROM_UNIFIED_SECTIONS #define HAB_RVT_BASE 0x00000100 #else @@ -178,13 +189,14 @@ typedef void hapi_clock_init_t(void); HAB_RVT_BASE_NEW : HAB_RVT_BASE_OLD) #endif
-#define HAB_RVT_ENTRY (*(uint32_t *)(HAB_RVT_BASE + 0x04)) -#define HAB_RVT_EXIT (*(uint32_t *)(HAB_RVT_BASE + 0x08)) -#define HAB_RVT_CHECK_TARGET (*(uint32_t *)(HAB_RVT_BASE + 0x0C)) -#define HAB_RVT_AUTHENTICATE_IMAGE (*(uint32_t *)(HAB_RVT_BASE + 0x10)) -#define HAB_RVT_REPORT_EVENT (*(uint32_t *)(HAB_RVT_BASE + 0x20)) -#define HAB_RVT_REPORT_STATUS (*(uint32_t *)(HAB_RVT_BASE + 0x24)) -#define HAB_RVT_FAILSAFE (*(uint32_t *)(HAB_RVT_BASE + 0x28)) +#define HAB_RVT_ENTRY ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x04)) +#define HAB_RVT_EXIT ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x08)) +#define HAB_RVT_CHECK_TARGET ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x0C)) +#define HAB_RVT_AUTHENTICATE_IMAGE ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x10)) +#define HAB_RVT_REPORT_EVENT ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x20)) +#define HAB_RVT_REPORT_STATUS ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x24)) +#define HAB_RVT_FAILSAFE ((ulong)*(uint32_t *)(HAB_RVT_BASE + 0x28)) +#endif
#define HAB_CID_ROM 0 /**< ROM Caller ID */ #define HAB_CID_UBOOT 1 /**< UBOOT Caller ID*/ diff --git a/arch/arm/include/asm/mach-imx/sys_proto.h b/arch/arm/include/asm/mach-imx/sys_proto.h index 4925dd7894..65791cb1b2 100644 --- a/arch/arm/include/asm/mach-imx/sys_proto.h +++ b/arch/arm/include/asm/mach-imx/sys_proto.h @@ -133,7 +133,8 @@ int mxs_wait_mask_set(struct mxs_register_32 *reg, u32 mask, u32 timeout); int mxs_wait_mask_clr(struct mxs_register_32 *reg, u32 mask, u32 timeout);
unsigned long call_imx_sip(unsigned long id, unsigned long reg0,
unsigned long reg1, unsigned long reg2);
unsigned long reg1, unsigned long reg2,
unsigned long reg3);
unsigned long call_imx_sip_ret2(unsigned long id, unsigned long reg0, unsigned long *reg1, unsigned long reg2, unsigned long reg3); diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index aeb5493488..1efc1ed8fa 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -36,9 +36,9 @@ config USE_IMXIMG_PLUGIN
config SECURE_BOOT bool "Support i.MX HAB features"
depends on ARCH_MX7 || ARCH_MX6 || ARCH_MX5
depends on ARCH_IMX8M || ARCH_MX7 || ARCH_MX6 || ARCH_MX5 select FSL_CAAM if HAS_CAAM
imply CMD_DEKBLOB
imply CMD_DEKBLOB if !ARCH_IMX8M help This option enables the support for secure boot (HAB). See doc/README.mxc_hab for more details.
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 08ee52edbf..61d6bf176e 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -16,6 +16,7 @@ endif obj-$(CONFIG_ENV_IS_IN_MMC) += mmc_env.o obj-$(CONFIG_FEC_MXC) += mac.o obj-$(CONFIG_SYS_I2C_MXC) += i2c-mxv7.o +obj-$(CONFIG_SECURE_BOOT) += hab.o obj-y += cpu.o endif
diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c index ce50dbe907..6b3f7928dd 100644 --- a/arch/arm/mach-imx/hab.c +++ b/arch/arm/mach-imx/hab.c @@ -20,7 +20,18 @@ #define MX6SL_PU_IROM_MMU_EN_VAR 0x00901c60 #define IS_HAB_ENABLED_BIT \ (is_soc_type(MXC_SOC_MX7ULP) ? 0x80000000 : \
(is_soc_type(MXC_SOC_MX7) ? 0x2000000 : 0x2))
((is_soc_type(MXC_SOC_MX7) || is_soc_type(MXC_SOC_IMX8M)) ? 0x2000000 : 0x2))
+#ifdef CONFIG_ARM64 +#define FSL_SIP_HAB 0xC2000007 +#define FSL_SIP_HAB_AUTHENTICATE 0x00 +#define FSL_SIP_HAB_ENTRY 0x01 +#define FSL_SIP_HAB_EXIT 0x02 +#define FSL_SIP_HAB_REPORT_EVENT 0x03 +#define FSL_SIP_HAB_REPORT_STATUS 0x04
+static volatile gd_t *gd_save; +#endif
static int ivt_header_error(const char *err_str, struct ivt_header *ivt_hdr) { @@ -47,6 +58,97 @@ static int verify_ivt_header(struct ivt_header *ivt_hdr) return result; }
+static inline void save_gd(void) +{ +#ifdef CONFIG_ARM64
gd_save = gd;
+#endif +}
+static inline void restore_gd(void) +{ +#ifdef CONFIG_ARM64
/*
* Make will already error that reserving x18 is not supported at the
* time of writing, clang: error: unknown argument: '-ffixed-x18'
*/
__asm__ volatile("mov x18, %0\n" : : "r" (gd_save));
+#endif +}
+static enum hab_status hab_rvt_entry(void) +{
enum hab_status ret;
hab_rvt_entry_t *hab_rvt_entry_func;
hab_rvt_entry_func = (hab_rvt_entry_t *)HAB_RVT_ENTRY;
+#if defined(CONFIG_ARM64)
if (current_el() != 3) {
/* call sip */
ret = (enum hab_status)call_imx_sip(FSL_SIP_HAB,
FSL_SIP_HAB_ENTRY, 0, 0, 0);
return ret;
}
+#endif
save_gd();
ret = hab_rvt_entry_func();
restore_gd();
return ret;
+}
+static enum hab_status hab_rvt_exit(void) +{
enum hab_status ret;
hab_rvt_exit_t *hab_rvt_exit_func;
hab_rvt_exit_func = (hab_rvt_exit_t *)HAB_RVT_EXIT;
+#if defined(CONFIG_ARM64)
if (current_el() != 3) {
/* call sip */
ret = (enum hab_status)call_imx_sip(FSL_SIP_HAB,
FSL_SIP_HAB_EXIT, 0, 0, 0);
return ret;
}
+#endif
save_gd();
ret = hab_rvt_exit_func();
restore_gd();
return ret;
+}
+static void *hab_rvt_authenticate_image(uint8_t cid, ptrdiff_t ivt_offset,
- void **start, size_t *bytes, hab_loader_callback_f_t loader)
+{
void *ret;
hab_rvt_authenticate_image_t *hab_rvt_authenticate_image_func;
hab_rvt_authenticate_image_func =
(hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE;
+#if defined(CONFIG_ARM64)
if (current_el() != 3) {
/* call sip */
ret = (void *)call_imx_sip(FSL_SIP_HAB,
FSL_SIP_HAB_AUTHENTICATE, (unsigned long)ivt_offset,
(unsigned long)start, (unsigned long)bytes);
return ret;
}
+#endif
save_gd();
ret = hab_rvt_authenticate_image_func(cid, ivt_offset, start,
bytes, loader);
restore_gd();
return ret;
+}
#if !defined(CONFIG_SPL_BUILD)
#define MAX_RECORD_BYTES (8*1024) /* 4 kbytes */ @@ -245,6 +347,57 @@ static void display_event(uint8_t *event_data, size_t bytes) process_event_record(event_data, bytes); }
+static enum hab_status hab_rvt_report_event(enum hab_status status,
- uint32_t index, uint8_t *event, size_t *bytes)
+{
enum hab_status ret;
hab_rvt_report_event_t *hab_rvt_report_event;
hab_rvt_report_event = (hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT;
+#if defined(CONFIG_ARM64)
if (current_el() != 3) {
/* call sip */
ret = (enum hab_status)call_imx_sip(FSL_SIP_HAB,
FSL_SIP_HAB_REPORT_EVENT, (unsigned long)index,
(unsigned long)event, (unsigned long)bytes);
return ret;
}
+#endif
save_gd();
ret = hab_rvt_report_event(status, index, event, bytes);
restore_gd();
return ret;
+}
+static enum hab_status hab_rvt_report_status(enum hab_config *config,
- enum hab_state *state)
+{
enum hab_status ret;
hab_rvt_report_status_t *hab_rvt_report_status_func;
hab_rvt_report_status_func =
(hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS;
+#if defined(CONFIG_ARM64)
if (current_el() != 3) {
/* call sip */
ret = (enum hab_status)call_imx_sip(FSL_SIP_HAB,
FSL_SIP_HAB_REPORT_STATUS, (unsigned long)config,
(unsigned long)state, 0);
return ret;
}
+#endif
save_gd();
ret = hab_rvt_report_status_func(config, state);
restore_gd();
return ret;
+}
static int get_hab_status(void) { uint32_t index = 0; /* Loop index */ @@ -252,12 +405,6 @@ static int get_hab_status(void) size_t bytes = sizeof(event_data); /* Event size in bytes */ enum hab_config config = 0; enum hab_state state = 0;
hab_rvt_report_event_t *hab_rvt_report_event;
hab_rvt_report_status_t *hab_rvt_report_status;
hab_rvt_report_event = (hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT;
hab_rvt_report_status =
(hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS; if (imx_hab_is_enabled()) puts("\nSecure boot enabled\n");
@@ -349,6 +496,7 @@ static int do_authenticate_image(cmd_tbl_t *cmdtp, int flag, int argc, return rcode; }
+#ifdef HAB_RVT_FAILSAFE static int do_hab_failsafe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -389,6 +537,7 @@ static int do_authenticate_image_or_failover(cmd_tbl_t *cmdtp, int flag, error: return ret; } +#endif
U_BOOT_CMD( hab_status, CONFIG_SYS_MAXARGS, 1, do_hab_status, @@ -405,6 +554,7 @@ U_BOOT_CMD( "ivt_offset - hex offset of IVT in the image" );
+#ifdef HAB_RVT_FAILSAFE U_BOOT_CMD( hab_failsafe, CONFIG_SYS_MAXARGS, 1, do_hab_failsafe, "run BootROM failsafe routine", @@ -420,6 +570,7 @@ U_BOOT_CMD( "length - image hex length\n" "ivt_offset - hex offset of IVT in the image" ); +#endif
#endif /* !defined(CONFIG_SPL_BUILD) */
@@ -471,7 +622,7 @@ static bool csf_is_valid(struct ivt *ivt, ulong start_addr, size_t bytes) return false; }
csf_hdr = (u8 *)ivt->csf;
csf_hdr = (u8 *)(ulong)ivt->csf; /* Verify if CSF Header exist */ if (*csf_hdr != HAB_CMD_HDR) {
@@ -539,24 +690,19 @@ bool imx_hab_is_enabled(void) int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, uint32_t ivt_offset) {
uint32_t load_addr = 0;
ulong load_addr = 0; size_t bytes;
uint32_t ivt_addr = 0;
ulong ivt_addr = 0; int result = 1; ulong start;
hab_rvt_authenticate_image_t *hab_rvt_authenticate_image;
hab_rvt_entry_t *hab_rvt_entry;
hab_rvt_exit_t *hab_rvt_exit;
hab_rvt_check_target_t *hab_rvt_check_target; struct ivt *ivt; struct ivt_header *ivt_hdr;
+#ifdef HAB_RVT_CHECK_TARGET
hab_rvt_check_target_t *hab_rvt_check_target; enum hab_status status;
hab_rvt_authenticate_image =
(hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE;
hab_rvt_entry = (hab_rvt_entry_t *)HAB_RVT_ENTRY;
hab_rvt_exit = (hab_rvt_exit_t *)HAB_RVT_EXIT; hab_rvt_check_target = (hab_rvt_check_target_t *)HAB_RVT_CHECK_TARGET;
+#endif
if (!imx_hab_is_enabled()) { puts("hab fuse not enabled\n");
@@ -579,8 +725,8 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size,
/* Verify IVT body */ if (ivt->self != ivt_addr) {
printf("ivt->self 0x%08x pointer is 0x%08x\n",
ivt->self, ivt_addr);
printf("ivt->self 0x%08x pointer is 0x%08lx\n",
ivt->self, (ulong)ivt_addr); goto hab_authentication_exit; }
@@ -602,12 +748,14 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, goto hab_exit_failure_print_status; }
+#ifdef HAB_RVT_CHECK_TARGET status = hab_rvt_check_target(HAB_TGT_MEMORY, (void *)ddr_start, bytes); if (status != HAB_SUCCESS) { printf("HAB check target 0x%08x-0x%08x fail\n", ddr_start, ddr_start + bytes); goto hab_exit_failure_print_status; } +#endif #ifdef DEBUG printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n", ivt_offset, ivt_addr); printf("ivt entry = 0x%08x, dcd = 0x%08x, csf = 0x%08x\n", ivt->entry, @@ -627,6 +775,8 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, printf("\tstart = 0x%08lx\n", start); printf("\tbytes = 0x%x\n", bytes); #endif
+#ifndef CONFIG_ARM64 /* * If the MMU is enabled, we have to notify the ROM * code, or it won't flush the caches when needed. @@ -654,8 +804,9 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, writel(1, MX6SL_PU_IROM_MMU_EN_VAR); } } +#endif
load_addr = (uint32_t)hab_rvt_authenticate_image(
load_addr = (ulong)hab_rvt_authenticate_image( HAB_CID_UBOOT, ivt_offset, (void **)&start, (size_t *)&bytes, NULL);
diff --git a/arch/arm/mach-imx/imx8m/clock.c b/arch/arm/mach-imx/imx8m/clock.c index 289b9417aa..232219f2f6 100644 --- a/arch/arm/mach-imx/imx8m/clock.c +++ b/arch/arm/mach-imx/imx8m/clock.c @@ -304,6 +304,13 @@ static u32 get_root_clk(enum clk_root_index clock_id) return root_src_clk / (post_podf + 1) / (pre_podf + 1); }
+#ifdef CONFIG_SECURE_BOOT +void hab_caam_clock_enable(unsigned char enable) +{
/* The CAAM clock is always on for iMX8M */
+} +#endif
#ifdef CONFIG_MXC_OCOTP void enable_ocotp_clk(unsigned char enable) { diff --git a/arch/arm/mach-imx/imx_bootaux.c b/arch/arm/mach-imx/imx_bootaux.c index 18d7e6819c..3d9422d5a2 100644 --- a/arch/arm/mach-imx/imx_bootaux.c +++ b/arch/arm/mach-imx/imx_bootaux.c @@ -26,7 +26,7 @@ int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data)
/* Enable M4 */
#ifdef CONFIG_IMX8M
call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_START, 0, 0);
call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_START, 0, 0, 0);
#else clrsetbits_le32(SRC_BASE_ADDR + SRC_M4_REG_OFFSET, SRC_M4C_NON_SCLR_RST_MASK, SRC_M4_ENABLE_MASK); @@ -38,7 +38,7 @@ int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data) int arch_auxiliary_core_check_up(u32 core_id) { #ifdef CONFIG_IMX8M
return call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_STARTED, 0, 0);
return call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_STARTED, 0, 0, 0);
#else unsigned int val;
diff --git a/arch/arm/mach-imx/sip.c b/arch/arm/mach-imx/sip.c index 968e7cf309..fca520c671 100644 --- a/arch/arm/mach-imx/sip.c +++ b/arch/arm/mach-imx/sip.c @@ -7,7 +7,8 @@ #include <asm/arch/sys_proto.h>
unsigned long call_imx_sip(unsigned long id, unsigned long reg0,
unsigned long reg1, unsigned long reg2)
unsigned long reg1, unsigned long reg2,
unsigned long reg3)
{ struct pt_regs regs;
@@ -15,6 +16,7 @@ unsigned long call_imx_sip(unsigned long id, unsigned long reg0, regs.regs[1] = reg0; regs.regs[2] = reg1; regs.regs[3] = reg2;
regs.regs[4] = reg3; smc_call(®s);
diff --git a/configs/imx8mq_evk_defconfig b/configs/imx8mq_evk_defconfig index e45731edda..d5f6cdf1ca 100644 --- a/configs/imx8mq_evk_defconfig +++ b/configs/imx8mq_evk_defconfig @@ -1,4 +1,5 @@ CONFIG_ARM=y +CONFIG_SECURE_BOOT=y CONFIG_SPL_SYS_ICACHE_OFF=y CONFIG_SPL_SYS_DCACHE_OFF=y CONFIG_ARCH_IMX8M=y _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot

On Thu, Oct 03, 2019 at 10:13:19AM -0300, Fabio Estevam wrote:
Hi Patrick,
On Thu, Oct 3, 2019 at 10:01 AM Patrick Wildt patrick@blueri.se wrote:
Boundary Devices U-Boot is about a year old, and I haven't checked how they implemented it. I have a diff for i.MX8M HAB support which works for me.
Please submit the i.MX8M HAB support as a formal patch.
Thanks
It was only meant for him to test, but sure, I will do that. First I need to take care of all the other diffs I have in progress first. It's nearly a full-time job replying and fixing all the tiny nits mail by mail. :)
Patrick

Hello Patrick,
On a first glance it looks very similar to the Variscite's implementation for i.MX8M HAB, which actually seems to work for authenticating the bootloader image, but on the other hand fails on the kernel image on `hab_rvt_check_target` with the check target SMC returning -1 ("unknown function" according to SMC Calling Convention). I'll apply the diff, check out how it works and get back to you. Thank you very much!
Best regards, Bartlomiej Nowak
On 03.10.2019 15:27, Patrick Wildt wrote:
On Thu, Oct 03, 2019 at 10:13:19AM -0300, Fabio Estevam wrote:
Hi Patrick,
On Thu, Oct 3, 2019 at 10:01 AM Patrick Wildt patrick@blueri.se wrote:
Boundary Devices U-Boot is about a year old, and I haven't checked how they implemented it. I have a diff for i.MX8M HAB support which works for me.
Please submit the i.MX8M HAB support as a formal patch.
Thanks
It was only meant for him to test, but sure, I will do that. First I need to take care of all the other diffs I have in progress first. It's nearly a full-time job replying and fixing all the tiny nits mail by mail. :)
Patrick

Since I'm not booting Linux I don't know if it will help you. :(
Best regards, Patrick
On Thu, Oct 03, 2019 at 03:39:34PM +0200, Bartlomiej wrote:
Hello Patrick,
On a first glance it looks very similar to the Variscite's implementation for i.MX8M HAB, which actually seems to work for authenticating the bootloader image, but on the other hand fails on the kernel image on `hab_rvt_check_target` with the check target SMC returning -1 ("unknown function" according to SMC Calling Convention). I'll apply the diff, check out how it works and get back to you. Thank you very much!
Best regards, Bartlomiej Nowak
On 03.10.2019 15:27, Patrick Wildt wrote:
On Thu, Oct 03, 2019 at 10:13:19AM -0300, Fabio Estevam wrote:
Hi Patrick,
On Thu, Oct 3, 2019 at 10:01 AM Patrick Wildt patrick@blueri.se wrote:
Boundary Devices U-Boot is about a year old, and I haven't checked how they implemented it. I have a diff for i.MX8M HAB support which works for me.
Please submit the i.MX8M HAB support as a formal patch.
Thanks
It was only meant for him to test, but sure, I will do that. First I need to take care of all the other diffs I have in progress first. It's nearly a full-time job replying and fixing all the tiny nits mail by mail. :)
Patrick
participants (3)
-
Bartlomiej
-
Fabio Estevam
-
Patrick Wildt