From c428ca80c298df55db242571d868dae7b475ccb5 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Thu, 25 Mar 2021 17:30:06 +0800 Subject: imx: hab: Add function to authenticate kernel image When loading kernel image, the image size is parsed from header, so it does not include the CSF and IVT. Add back the authenticate_image function to wrap the imx_hab_authenticate_image with calculating IVT offset and full image size. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/mach-imx/hab.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'arch/arm/mach-imx/hab.c') diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c index d0757d8b66..66ac440349 100644 --- a/arch/arm/mach-imx/hab.c +++ b/arch/arm/mach-imx/hab.c @@ -698,3 +698,15 @@ hab_authentication_exit: return result; } + +int authenticate_image(u32 ddr_start, u32 raw_image_size) +{ + u32 ivt_offset; + size_t bytes; + + ivt_offset = (raw_image_size + ALIGN_SIZE - 1) & + ~(ALIGN_SIZE - 1); + bytes = ivt_offset + IVT_SIZE + CSF_PAD_SIZE; + + return imx_hab_authenticate_image(ddr_start, bytes, ivt_offset); +} -- cgit v1.2.3 From 507da978fa0a09874b5b154bec5521688d9660d8 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 25 Mar 2021 17:30:07 +0800 Subject: imx: HAB: Update hab codes to support ARM64 and i.MX8M There are some changes to support ARM64 i.MX8M platform in this patches: 1. The hab_rvt base and function vectors are different as i.MX6/7 2. Need to bypass an workaround for i.MX6 to fix problem in MMU. 3. The x18 register needed save & restore before calling any HAB API. According to ARM procedure call spec, the x18 is caller saved when it is used as temporary register. So calling HAB API may scratch this register, and cause crash once accessing the gd pointer. On ARMv7, the r9 is callee saved when it is used as variable register. So no need to save & restore it. 4. Add SEC_CONFIG fuse for iMX8M When current EL is not EL3, the direct calling to HAB will fail because CAAM/SNVS can't initialize at non-secure mode. In this case, we use SIP call to run the HAB in ATF. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/include/asm/mach-imx/hab.h | 14 +++ arch/arm/mach-imx/hab.c | 229 ++++++++++++++++++++++++++++++++---- 2 files changed, 218 insertions(+), 25 deletions(-) (limited to 'arch/arm/mach-imx/hab.c') diff --git a/arch/arm/include/asm/mach-imx/hab.h b/arch/arm/include/asm/mach-imx/hab.h index d8bd77075a..c4393ef443 100644 --- a/arch/arm/include/asm/mach-imx/hab.h +++ b/arch/arm/include/asm/mach-imx/hab.h @@ -165,6 +165,18 @@ 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 *)(HAB_RVT_BASE + 0x08)) +#define HAB_RVT_EXIT (*(ulong *)(HAB_RVT_BASE + 0x10)) +#define HAB_RVT_CHECK_TARGET (*(ulong *)(HAB_RVT_BASE + 0x18)) +#define HAB_RVT_AUTHENTICATE_IMAGE (*(ulong *)(HAB_RVT_BASE + 0x20)) +#define HAB_RVT_REPORT_EVENT (*(ulong *)(HAB_RVT_BASE + 0x40)) +#define HAB_RVT_REPORT_STATUS (*(ulong *)(HAB_RVT_BASE + 0x48)) +#define HAB_RVT_FAILSAFE (*(ulong *)(HAB_RVT_BASE + 0x50)) +#else + #ifdef CONFIG_ROM_UNIFIED_SECTIONS #define HAB_RVT_BASE 0x00000100 #else @@ -186,6 +198,8 @@ typedef void hapi_clock_init_t(void); #define HAB_RVT_REPORT_STATUS (*(uint32_t *)(HAB_RVT_BASE + 0x24)) #define HAB_RVT_FAILSAFE (*(uint32_t *)(HAB_RVT_BASE + 0x28)) +#endif /*CONFIG_ARM64*/ + #define HAB_CID_ROM 0 /**< ROM Caller ID */ #define HAB_CID_UBOOT 1 /**< UBOOT Caller ID*/ diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c index 66ac440349..9ebdbe6ac3 100644 --- a/arch/arm/mach-imx/hab.c +++ b/arch/arm/mach-imx/hab.c @@ -10,10 +10,14 @@ #include #include #include +#include #include #include #include #include +#include + +DECLARE_GLOBAL_DATA_PTR; #define ALIGN_SIZE 0x1000 #define MX6DQ_PU_IROM_MMU_EN_VAR 0x009024a8 @@ -21,7 +25,7 @@ #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)) static int ivt_header_error(const char *err_str, struct ivt_header *ivt_hdr) { @@ -48,6 +52,194 @@ static int verify_ivt_header(struct ivt_header *ivt_hdr) return result; } +#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 +#define FSL_SIP_HAB_FAILSAFE 0x05 +#define FSL_SIP_HAB_CHECK_TARGET 0x06 +static volatile gd_t *gd_save; +#endif + +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 +} + +enum hab_status hab_rvt_report_event(enum hab_status status, u32 index, + u8 *event, size_t *bytes) +{ + enum hab_status ret; + hab_rvt_report_event_t *hab_rvt_report_event_func; + struct arm_smccc_res res __maybe_unused; + + hab_rvt_report_event_func = (hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT; +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_REPORT_EVENT, (unsigned long)index, + (unsigned long)event, (unsigned long)bytes, 0, 0, 0, &res); + return (enum hab_status)res.a0; + } +#endif + + save_gd(); + ret = hab_rvt_report_event_func(status, index, event, bytes); + restore_gd(); + + return ret; + +} + +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; + struct arm_smccc_res res __maybe_unused; + + hab_rvt_report_status_func = (hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS; +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_REPORT_STATUS, (unsigned long)config, + (unsigned long)state, 0, 0, 0, 0, &res); + return (enum hab_status)res.a0; + } +#endif + + save_gd(); + ret = hab_rvt_report_status_func(config, state); + restore_gd(); + + return ret; +} + +enum hab_status hab_rvt_entry(void) +{ + enum hab_status ret; + hab_rvt_entry_t *hab_rvt_entry_func; + struct arm_smccc_res res __maybe_unused; + + hab_rvt_entry_func = (hab_rvt_entry_t *)HAB_RVT_ENTRY; +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_ENTRY, 0, 0, 0, 0, 0, 0, &res); + return (enum hab_status)res.a0; + } +#endif + + save_gd(); + ret = hab_rvt_entry_func(); + restore_gd(); + + return ret; +} + +enum hab_status hab_rvt_exit(void) +{ + enum hab_status ret; + hab_rvt_exit_t *hab_rvt_exit_func; + struct arm_smccc_res res __maybe_unused; + + hab_rvt_exit_func = (hab_rvt_exit_t *)HAB_RVT_EXIT; +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_EXIT, 0, 0, 0, 0, 0, 0, &res); + return (enum hab_status)res.a0; + } +#endif + + save_gd(); + ret = hab_rvt_exit_func(); + restore_gd(); + + return ret; +} + +void hab_rvt_failsafe(void) +{ + hab_rvt_failsafe_t *hab_rvt_failsafe_func; + + hab_rvt_failsafe_func = (hab_rvt_failsafe_t *)HAB_RVT_FAILSAFE; +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_FAILSAFE, 0, 0, 0, 0, 0, 0, NULL); + return; + } +#endif + + save_gd(); + hab_rvt_failsafe_func(); + restore_gd(); +} + +enum hab_status hab_rvt_check_target(enum hab_target type, const void *start, + size_t bytes) +{ + enum hab_status ret; + hab_rvt_check_target_t *hab_rvt_check_target_func; + struct arm_smccc_res res __maybe_unused; + + hab_rvt_check_target_func = (hab_rvt_check_target_t *)HAB_RVT_CHECK_TARGET; +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_CHECK_TARGET, (unsigned long)type, + (unsigned long)start, (unsigned long)bytes, 0, 0, 0, &res); + return (enum hab_status)res.a0; + } +#endif + + save_gd(); + ret = hab_rvt_check_target_func(type, start, bytes); + restore_gd(); + + return ret; +} + +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; + struct arm_smccc_res res __maybe_unused; + + hab_rvt_authenticate_image_func = (hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE; +#if defined(CONFIG_ARM64) + if (current_el() != 3) { + /* call sip */ + arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_AUTHENTICATE, (unsigned long)ivt_offset, + (unsigned long)start, (unsigned long)bytes, 0, 0, 0, &res); + return (void *)res.a0; + } +#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 */ @@ -253,12 +445,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"); @@ -493,7 +679,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) { @@ -561,25 +747,15 @@ 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; 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; - if (!imx_hab_is_enabled()) { puts("hab fuse not enabled\n"); return 0; @@ -591,7 +767,7 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, hab_caam_clock_enable(1); /* Calculate IVT address header */ - ivt_addr = ddr_start + ivt_offset; + ivt_addr = (ulong) (ddr_start + ivt_offset); ivt = (struct ivt *)ivt_addr; ivt_hdr = &ivt->hdr; @@ -601,7 +777,7 @@ 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", + printf("ivt->self 0x%08x pointer is 0x%08lx\n", ivt->self, ivt_addr); goto hab_authentication_exit; } @@ -624,9 +800,9 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, goto hab_exit_failure_print_status; } - status = hab_rvt_check_target(HAB_TGT_MEMORY, (void *)ddr_start, bytes); + status = hab_rvt_check_target(HAB_TGT_MEMORY, (void *)(ulong)ddr_start, bytes); if (status != HAB_SUCCESS) { - printf("HAB check target 0x%08x-0x%08x fail\n", + printf("HAB check target 0x%08x-0x%08lx fail\n", ddr_start, ddr_start + bytes); goto hab_exit_failure_print_status; } @@ -649,6 +825,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. @@ -676,8 +854,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); -- cgit v1.2.3 From fe8acf556c3f6e83efb0836c31371d1b78289464 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Thu, 25 Mar 2021 17:30:08 +0800 Subject: imx: HAB: Validate IVT before authenticating image Calling csf_is_valid() with an un-signed image may lead to data abort as the CSF pointer could be pointing to a garbage address when accessed in HAB_HDR_LEN(*(const struct hab_hdr *)(ulong)ivt_initial->csf). Authenticate image from DDR location 0x80800000... Check CSF for Write Data command before authenticating image data abort pc : [] lr : [] reloc pc : [<8780294c>] lr : [<87802910>] sp : fdf45dc8 ip : 00000214 fp : 00000000 r10: fffb6170 r9 : fdf4fec0 r8 : 00722020 r7 : 80f20000 r6 : 80800000 r5 : 80800000 r4 : 00720000 r3 : 17a5aca3 r2 : 00000000 r1 : 80f2201f r0 : 00000019 Flags: NzcV IRQs off FIQs off Mode SVC_32 Resetting CPU ... resetting ... To avoid such errors during authentication process, validate IVT structure by calling validate_ivt function which checks the following values in an IVT: IVT_HEADER = 0x4X2000D1 ENTRY != 0x0 RES1 = 0x0 DCD = 0x0 /* Recommended */ SELF != 0x0 /* Absoulute address of IVT */ CSF != 0x0 RES2 = 0x0 This commit also checks if Image's start address is 4 byte aligned. commit "0088d127 MLK-14945 HAB: Check if IVT valid before authenticating image" removed as this patch addresses the issue. Signed-off-by: Utkarsh Gupta Signed-off-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/mach-imx/hab.c | 59 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 16 deletions(-) (limited to 'arch/arm/mach-imx/hab.c') diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c index 9ebdbe6ac3..f2d5f744e8 100644 --- a/arch/arm/mach-imx/hab.c +++ b/arch/arm/mach-imx/hab.c @@ -728,6 +728,48 @@ static bool csf_is_valid(struct ivt *ivt, ulong start_addr, size_t bytes) return true; } +/* + * Validate IVT structure of the image being authenticated + */ +static int validate_ivt(struct ivt *ivt_initial) +{ + struct ivt_header *ivt_hdr = &ivt_initial->hdr; + + if ((ulong)ivt_initial & 0x3) { + puts("Error: Image's start address is not 4 byte aligned\n"); + return 0; + } + + /* Check IVT fields before allowing authentication */ + if ((!verify_ivt_header(ivt_hdr)) && \ + (ivt_initial->entry != 0x0) && \ + (ivt_initial->reserved1 == 0x0) && \ + (ivt_initial->self == \ + (uint32_t)((ulong)ivt_initial & 0xffffffff)) && \ + (ivt_initial->csf != 0x0) && \ + (ivt_initial->reserved2 == 0x0)) { + /* Report boot failure if DCD pointer is found in IVT */ + if (ivt_initial->dcd != 0x0) + puts("Error: DCD pointer must be 0\n"); + else + return 1; + } + + puts("Error: Invalid IVT structure\n"); + debug("\nAllowed IVT structure:\n"); + debug("IVT HDR = 0x4X2000D1\n"); + debug("IVT ENTRY = 0xXXXXXXXX\n"); + debug("IVT RSV1 = 0x0\n"); + debug("IVT DCD = 0x0\n"); /* Recommended */ + debug("IVT BOOT_DATA = 0xXXXXXXXX\n"); /* Commonly 0x0 */ + debug("IVT SELF = 0xXXXXXXXX\n"); /* = ddr_start + ivt_offset */ + debug("IVT CSF = 0xXXXXXXXX\n"); + debug("IVT RSV2 = 0x0\n"); + + /* Invalid IVT structure */ + return 0; +} + bool imx_hab_is_enabled(void) { struct imx_sec_config_fuse_t *fuse = @@ -753,7 +795,6 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, int result = 1; ulong start; struct ivt *ivt; - struct ivt_header *ivt_hdr; enum hab_status status; if (!imx_hab_is_enabled()) { @@ -769,24 +810,10 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, /* Calculate IVT address header */ ivt_addr = (ulong) (ddr_start + ivt_offset); ivt = (struct ivt *)ivt_addr; - ivt_hdr = &ivt->hdr; /* Verify IVT header bugging out on error */ - if (verify_ivt_header(ivt_hdr)) - goto hab_authentication_exit; - - /* Verify IVT body */ - if (ivt->self != ivt_addr) { - printf("ivt->self 0x%08x pointer is 0x%08lx\n", - ivt->self, ivt_addr); + if (!validate_ivt(ivt)) goto hab_authentication_exit; - } - - /* Verify if IVT DCD pointer is NULL */ - if (ivt->dcd) { - puts("Error: DCD pointer must be NULL\n"); - goto hab_authentication_exit; - } start = ddr_start; bytes = image_size; -- cgit v1.2.3 From 1dc295148a93bc5b856b8b964079b54ea7f29514 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Thu, 25 Mar 2021 17:30:09 +0800 Subject: hab: Change calling to ROM API failsafe Modify to use hab_rvt_failsafe function for failsafe ROM API, not directly call its ROM address. This function will wrap the sip call for iMX8M platforms. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/mach-imx/hab.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'arch/arm/mach-imx/hab.c') diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c index f2d5f744e8..bd00d4a458 100644 --- a/arch/arm/mach-imx/hab.c +++ b/arch/arm/mach-imx/hab.c @@ -539,14 +539,11 @@ static int do_authenticate_image(struct cmd_tbl *cmdtp, int flag, int argc, static int do_hab_failsafe(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - hab_rvt_failsafe_t *hab_rvt_failsafe; - if (argc != 1) { cmd_usage(cmdtp); return 1; } - hab_rvt_failsafe = (hab_rvt_failsafe_t *)HAB_RVT_FAILSAFE; hab_rvt_failsafe(); return 0; -- cgit v1.2.3 From 1d756add3c478f3fe79ed36aa86b2447949879b3 Mon Sep 17 00:00:00 2001 From: Breno Lima Date: Thu, 25 Mar 2021 17:30:10 +0800 Subject: imx: hab: Enable hab.c to authenticate additional images in open configuration Currently it's not possible to authenticate additional boot images in HAB open configuration. The hab.c code is checking if the SEC_CONFIG[1] fuse is programmed prior to calling the hab_authenticate_image() API function. Users cannot check if their additional boot images has been correctly signed prior to closing their device. Enable hab.c to authenticate additional boot images in open mode so HAB events can be retrieved through get_hab_status() function. Signed-off-by: Breno Lima Reviewed-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/mach-imx/hab.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'arch/arm/mach-imx/hab.c') diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c index bd00d4a458..01ddfab699 100644 --- a/arch/arm/mach-imx/hab.c +++ b/arch/arm/mach-imx/hab.c @@ -794,10 +794,8 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, struct ivt *ivt; enum hab_status status; - if (!imx_hab_is_enabled()) { + if (!imx_hab_is_enabled()) puts("hab fuse not enabled\n"); - return 0; - } printf("\nAuthenticate image from DDR location 0x%x...\n", ddr_start); @@ -896,7 +894,7 @@ hab_exit_failure_print_status: hab_authentication_exit: - if (load_addr != 0) + if (load_addr != 0 || !imx_hab_is_enabled()) result = 0; return result; -- cgit v1.2.3 From cd8355664db363768b672f9a362044e2db9bd86c Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Thu, 25 Mar 2021 17:30:11 +0800 Subject: imx: hab: Display All HAB events via hab_status command Add ability for hab_status command to show All HAB events and not just HAB failure events Signed-off-by: Utkarsh Gupta Reviewed-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/mach-imx/hab.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-imx/hab.c') diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c index 01ddfab699..264e148ba6 100644 --- a/arch/arm/mach-imx/hab.c +++ b/arch/arm/mach-imx/hab.c @@ -456,8 +456,8 @@ static int get_hab_status(void) printf("\nHAB Configuration: 0x%02x, HAB State: 0x%02x\n", config, state); - /* Display HAB Error events */ - while (hab_rvt_report_event(HAB_FAILURE, index, event_data, + /* Display HAB events */ + while (hab_rvt_report_event(HAB_STS_ANY, index, event_data, &bytes) == HAB_SUCCESS) { puts("\n"); printf("--------- HAB Event %d -----------------\n", -- cgit v1.2.3 From f217470b392806be340e9c03d46e98bb29d7caec Mon Sep 17 00:00:00 2001 From: Breno Lima Date: Thu, 25 Mar 2021 17:30:12 +0800 Subject: imx: hab: Check if IVT header is HABv4 The HABv4 implementation in ROM checks if HAB major version in IVT header is 4.x. The current implementation in hab.c code is only validating HAB v4.0 and HAB v4.1 and may be incompatible with newer HABv4 versions. Modify verify_ivt_header() function to align with HABv4 implementation in ROM code. Signed-off-by: Breno Lima Reviewed-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/include/asm/mach-imx/hab.h | 2 -- arch/arm/mach-imx/hab.c | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'arch/arm/mach-imx/hab.c') diff --git a/arch/arm/include/asm/mach-imx/hab.h b/arch/arm/include/asm/mach-imx/hab.h index c4393ef443..62218818f9 100644 --- a/arch/arm/include/asm/mach-imx/hab.h +++ b/arch/arm/include/asm/mach-imx/hab.h @@ -18,8 +18,6 @@ */ #define IVT_HEADER_MAGIC 0xD1 #define IVT_TOTAL_LENGTH 0x20 -#define IVT_HEADER_V1 0x40 -#define IVT_HEADER_V2 0x41 struct __packed ivt_header { uint8_t magic; diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c index 264e148ba6..5f46df0f8b 100644 --- a/arch/arm/mach-imx/hab.c +++ b/arch/arm/mach-imx/hab.c @@ -45,8 +45,7 @@ static int verify_ivt_header(struct ivt_header *ivt_hdr) if (be16_to_cpu(ivt_hdr->length) != IVT_TOTAL_LENGTH) result = ivt_header_error("bad length", ivt_hdr); - if (ivt_hdr->version != IVT_HEADER_V1 && - ivt_hdr->version != IVT_HEADER_V2) + if ((ivt_hdr->version & HAB_MAJ_MASK) != HAB_MAJ_VER) result = ivt_header_error("bad version", ivt_hdr); return result; -- cgit v1.2.3 From 58f75efeaf30c786c26fade79d127c988b813751 Mon Sep 17 00:00:00 2001 From: Breno Lima Date: Thu, 25 Mar 2021 17:30:13 +0800 Subject: mx7ulp: hab: Add hab_status command for HABv4 M4 boot When booting in low power or dual boot modes the M4 binary is authenticated by the M4 ROM code. Add an option in hab_status command so users can retrieve M4 HAB failure and warning events. => hab_status m4 Secure boot disabled HAB Configuration: 0xf0, HAB State: 0x66 No HAB Events Found! Add command documentation in mx6_mx7_secure_boot.txt guide. As HAB M4 API cannot be called from A7 core the code is parsing the M4 HAB persistent memory region. The HAB persistent memory stores HAB events, public keys and others HAB related information. The HAB persistent memory region addresses and sizes can be found in AN12263 "HABv4 RVT Guidelines and Recommendations". Reviewed-by: Utkarsh Gupta Reviewed-by: Ye Li Signed-off-by: Breno Lima Signed-off-by: Peng Fan --- arch/arm/include/asm/mach-imx/hab.h | 15 +++++ arch/arm/mach-imx/hab.c | 99 ++++++++++++++++++++++++++++ doc/imx/habv4/guides/mx6_mx7_secure_boot.txt | 25 +++++++ 3 files changed, 139 insertions(+) (limited to 'arch/arm/mach-imx/hab.c') diff --git a/arch/arm/include/asm/mach-imx/hab.h b/arch/arm/include/asm/mach-imx/hab.h index 62218818f9..1085c37828 100644 --- a/arch/arm/include/asm/mach-imx/hab.h +++ b/arch/arm/include/asm/mach-imx/hab.h @@ -42,6 +42,15 @@ struct __packed hab_hdr { u8 par; /* Parameters field */ }; +/* Default event structure */ +struct __packed evt_def { + struct hab_hdr hdr; /* Header */ + uint32_t sts; /* Status */ + uint32_t ctx; /* Default context */ + uint8_t *data; /* Default data location */ + size_t bytes; /* Size of default data */ +}; + /* -------- start of HAB API updates ------------*/ /* The following are taken from HAB4 SIS */ @@ -211,6 +220,12 @@ typedef void hapi_clock_init_t(void); #define IVT_SIZE 0x20 #define CSF_PAD_SIZE 0x2000 +#define HAB_TAG_EVT 0xDB +#define HAB_TAG_EVT_DEF 0x0C + +#define HAB_MAJ_VER 0x40 +#define HAB_MAJ_MASK 0xF0 + /* ----------- end of HAB API updates ------------*/ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c index 5f46df0f8b..469ef0fd1c 100644 --- a/arch/arm/mach-imx/hab.c +++ b/arch/arm/mach-imx/hab.c @@ -27,6 +27,12 @@ DECLARE_GLOBAL_DATA_PTR; (is_soc_type(MXC_SOC_MX7ULP) ? 0x80000000 : \ ((is_soc_type(MXC_SOC_MX7) || is_soc_type(MXC_SOC_IMX8M)) ? 0x2000000 : 0x2)) +#ifdef CONFIG_MX7ULP +#define HAB_M4_PERSISTENT_START ((soc_rev() >= CHIP_REV_2_0) ? 0x20008040 : \ + 0x20008180) +#define HAB_M4_PERSISTENT_BYTES 0xB80 +#endif + static int ivt_header_error(const char *err_str, struct ivt_header *ivt_hdr) { printf("%s magic=0x%x length=0x%02x version=0x%x\n", err_str, @@ -477,15 +483,99 @@ static int get_hab_status(void) return 0; } +#ifdef CONFIG_MX7ULP + +static int get_record_len(struct record *rec) +{ + return (size_t)((rec->len[0] << 8) + (rec->len[1])); +} + +static int get_hab_status_m4(void) +{ + unsigned int index = 0; + uint8_t event_data[128]; + size_t record_len, offset = 0; + enum hab_config config = 0; + enum hab_state state = 0; + + if (imx_hab_is_enabled()) + puts("\nSecure boot enabled\n"); + else + puts("\nSecure boot disabled\n"); + + /* + * HAB in both A7 and M4 gather the security state + * and configuration of the chip from + * shared SNVS module + */ + hab_rvt_report_status(&config, &state); + printf("\nHAB Configuration: 0x%02x, HAB State: 0x%02x\n", + config, state); + + struct record *rec = (struct record *)(HAB_M4_PERSISTENT_START); + + record_len = get_record_len(rec); + + /* Check if HAB persistent memory is valid */ + if (rec->tag != HAB_TAG_EVT_DEF || + record_len != sizeof(struct evt_def) || + (rec->par & HAB_MAJ_MASK) != HAB_MAJ_VER) { + puts("\nERROR: Invalid HAB persistent memory\n"); + return 1; + } + + /* Parse events in HAB M4 persistent memory region */ + while (offset < HAB_M4_PERSISTENT_BYTES) { + rec = (struct record *)(HAB_M4_PERSISTENT_START + offset); + + record_len = get_record_len(rec); + + if (rec->tag == HAB_TAG_EVT) { + memcpy(&event_data, rec, record_len); + puts("\n"); + printf("--------- HAB Event %d -----------------\n", + index + 1); + puts("event data:\n"); + display_event(event_data, record_len); + puts("\n"); + index++; + } + + offset += record_len; + + /* Ensure all records start on a word boundary */ + if ((offset % 4) != 0) + offset = offset + (4 - (offset % 4)); + } + + if (!index) + puts("No HAB Events Found!\n\n"); + + return 0; +} +#endif + static int do_hab_status(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { +#ifdef CONFIG_MX7ULP + if ((argc > 2)) { + cmd_usage(cmdtp); + return 1; + } + + if (strcmp("m4", argv[1]) == 0) + get_hab_status_m4(); + else + get_hab_status(); +#else if ((argc != 1)) { cmd_usage(cmdtp); return 1; } get_hab_status(); +#endif return 0; } @@ -588,11 +678,20 @@ error: return ret; } +#ifdef CONFIG_MX7ULP +U_BOOT_CMD( + hab_status, CONFIG_SYS_MAXARGS, 2, do_hab_status, + "display HAB status and events", + "hab_status - A7 HAB event and status\n" + "hab_status m4 - M4 HAB event and status" + ); +#else U_BOOT_CMD( hab_status, CONFIG_SYS_MAXARGS, 1, do_hab_status, "display HAB status", "" ); +#endif U_BOOT_CMD( hab_auth_img, 4, 0, do_authenticate_image, diff --git a/doc/imx/habv4/guides/mx6_mx7_secure_boot.txt b/doc/imx/habv4/guides/mx6_mx7_secure_boot.txt index 20fff937b6..53f71fbc3e 100644 --- a/doc/imx/habv4/guides/mx6_mx7_secure_boot.txt +++ b/doc/imx/habv4/guides/mx6_mx7_secure_boot.txt @@ -213,6 +213,30 @@ the example below: HAB Configuration: 0xf0, HAB State: 0x66 No HAB Events Found! +1.6.1 Verifying HAB events in i.MX7ULP +--------------------------------------- + +When booting i.MX7ULP in low power or dual boot modes the M4 binary is +authenticated by an independent HAB in M4 ROM code using a +different SRK key set. + +The U-Boot provides a M4 option in hab_status command so users can retrieve +M4 HAB failure and warning events. + +- Verify HAB M4 events: + + => hab_status m4 + + Secure boot disabled + + HAB Configuration: 0xf0, HAB State: 0x66 + No HAB Events Found! + +As HAB M4 API cannot be called from A7 core the command is parsing the M4 HAB +persistent memory region, M4 software should not modify this reserved region. + +Details about HAB persistent memory region can be found in AN12263[2]. + 1.7 Closing the device ----------------------- @@ -400,3 +424,4 @@ If no HAB events were found the zImage is successfully signed. References: [1] AN4581: "Secure Boot on i.MX 50, i.MX 53, i.MX 6 and i.MX 7 Series using HABv4" - Rev 2. +[2] AN12263: "HABv4 RVT Guidelines and Recommendations" - Rev 0. -- cgit v1.2.3 From e449e2d405eb74e1e6615ea8f49a780d00a07952 Mon Sep 17 00:00:00 2001 From: Breno Lima Date: Thu, 25 Mar 2021 17:30:14 +0800 Subject: imx: hab: Fix build warnings in 32-bit targets When building 32-bit targets with CONFIG_SECURE_BOOT and DEBUG enabled the following warnings are displayed: arch/arm/mach-imx/hab.c:840:41: warning: format '%lx' expects argument \ of type 'long unsigned int', but argument 3 has type 'uint32_t \ {aka unsigned int}' [-Wformat=] printf("HAB check target 0x%08x-0x%08lx fail\n", ~~~~^ %08x ddr_start, ddr_start + bytes); arch/arm/mach-imx/hab.c:845:45: warning: format '%x' expects argument \ of type 'unsigned int', but argument 3 has type 'ulong \ {aka long unsigned int}' [-Wformat=] printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n", ivt_offset, ivt_addr); ~^ %lx Fix warnings by providing the correct data type. Reviewed-by: Ye Li Signed-off-by: Breno Lima Signed-off-by: Peng Fan --- arch/arm/mach-imx/hab.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-imx/hab.c') diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c index 469ef0fd1c..00bd157d0e 100644 --- a/arch/arm/mach-imx/hab.c +++ b/arch/arm/mach-imx/hab.c @@ -923,11 +923,11 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size, status = hab_rvt_check_target(HAB_TGT_MEMORY, (void *)(ulong)ddr_start, bytes); if (status != HAB_SUCCESS) { printf("HAB check target 0x%08x-0x%08lx fail\n", - ddr_start, ddr_start + bytes); + ddr_start, ddr_start + (ulong)bytes); goto hab_exit_failure_print_status; } #ifdef DEBUG - printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n", ivt_offset, ivt_addr); + printf("\nivt_offset = 0x%x, ivt addr = 0x%lx\n", ivt_offset, ivt_addr); printf("ivt entry = 0x%08x, dcd = 0x%08x, csf = 0x%08x\n", ivt->entry, ivt->dcd, ivt->csf); puts("Dumping IVT\n"); -- cgit v1.2.3