
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