[U-Boot] [PATCH v4] imx: Support i.MX6 High Assurance Boot authentication

When CONFIG_SECURE_BOOT is enabled, the signed images like kernel and dtb can be authenticated using iMX6 CAAM. The added command hab_auth_img can be used for HAB authentication of images. The command takes the image DDR location, IVT (Image Vector Table) offset inside image as parameters. Detailed info about signing images can be found in Freescale AppNote AN4581.
Signed-off-by: Nitin Garg nitin.garg@freescale.com
---
Changes in v4: - Use single hab_caam_clock_enable api for en/disable - Remove unused DEBUG_AUTHENTICATE_IMAGE - Use DEBUG instead of DEBUG_AUTHENTICATE_IMAGE - Add defined for pu_irom_mmu_enabled var location - Add MMU check before setting ROM variable - Replace printf with puts where applicable
Changes in v3: - Remove typecast of get_cpu_rev since its not required
Changes in v2: - Cleaned up clock code as per review comments - Removed dead code as per review comments - Re-written commit log as per review comments
arch/arm/cpu/armv7/mx6/clock.c | 27 ++++++ arch/arm/cpu/armv7/mx6/hab.c | 169 ++++++++++++++++++++++++++++++++- arch/arm/cpu/armv7/mx6/soc.c | 15 +++ arch/arm/include/asm/arch-mx6/clock.h | 1 + 4 files changed, 211 insertions(+), 1 deletion(-)
diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c index 8a33330..48f0bdd 100644 --- a/arch/arm/cpu/armv7/mx6/clock.c +++ b/arch/arm/cpu/armv7/mx6/clock.c @@ -568,6 +568,33 @@ void enable_pll3(void) } }
+#ifdef CONFIG_SECURE_BOOT +void hab_caam_clock_enable(unsigned char enable) +{ + u32 reg; + + /* CG4 ~ CG6, CAAM clocks */ + reg = __raw_readl(&imx_ccm->CCGR0); + if (enable) + reg |= (MXC_CCM_CCGR0_CAAM_WRAPPER_IPG_MASK | + MXC_CCM_CCGR0_CAAM_WRAPPER_ACLK_MASK | + MXC_CCM_CCGR0_CAAM_SECURE_MEM_MASK); + else + reg &= ~(MXC_CCM_CCGR0_CAAM_WRAPPER_IPG_MASK | + MXC_CCM_CCGR0_CAAM_WRAPPER_ACLK_MASK | + MXC_CCM_CCGR0_CAAM_SECURE_MEM_MASK); + __raw_writel(reg, &imx_ccm->CCGR0); + + /* EMI slow clk */ + reg = __raw_readl(&imx_ccm->CCGR6); + if (enable) + reg |= MXC_CCM_CCGR6_EMI_SLOW_MASK; + else + reg &= ~MXC_CCM_CCGR6_EMI_SLOW_MASK; + __raw_writel(reg, &imx_ccm->CCGR6); +} +#endif + unsigned int mxc_get_clock(enum mxc_clock clk) { switch (clk) { diff --git a/arch/arm/cpu/armv7/mx6/hab.c b/arch/arm/cpu/armv7/mx6/hab.c index f6810a6..8dee595 100644 --- a/arch/arm/cpu/armv7/mx6/hab.c +++ b/arch/arm/cpu/armv7/mx6/hab.c @@ -1,12 +1,14 @@ /* - * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. + * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. * * SPDX-License-Identifier: GPL-2.0+ */
#include <common.h> #include <asm/io.h> +#include <asm/system.h> #include <asm/arch/hab.h> +#include <asm/arch/clock.h> #include <asm/arch/sys_proto.h>
/* -------- start of HAB API updates ------------*/ @@ -71,6 +73,44 @@ ((hab_rvt_exit_t *)HAB_RVT_EXIT) \ )
+#define IVT_SIZE 0x20 +#define ALIGN_SIZE 0x1000 +#define CSF_PAD_SIZE 0x2000 +#define MX6DQ_PU_IROM_MMU_EN_VAR 0x009024a8 +#define MX6DLS_PU_IROM_MMU_EN_VAR 0x00901dd0 +#define MX6SL_PU_IROM_MMU_EN_VAR 0x00900a18 + +/* + * +------------+ 0x0 (DDR_UIMAGE_START) - + * | Header | | + * +------------+ 0x40 | + * | | | + * | | | + * | | | + * | | | + * | Image Data | | + * . | | + * . | > Stuff to be authenticated ----+ + * . | | | + * | | | | + * | | | | + * +------------+ | | + * | | | | + * | Fill Data | | | + * | | | | + * +------------+ Align to ALIGN_SIZE | | + * | IVT | | | + * +------------+ + IVT_SIZE - | + * | | | + * | CSF DATA | <---------------------------------------------------------+ + * | | + * +------------+ + * | | + * | Fill Data | + * | | + * +------------+ + CSF_PAD_SIZE + */ + bool is_hab_enabled(void) { struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; @@ -144,6 +184,108 @@ int get_hab_status(void) return 0; }
+uint32_t authenticate_image(uint32_t ddr_start, uint32_t image_size) +{ + uint32_t load_addr = 0; + size_t bytes; + ptrdiff_t ivt_offset = 0; + int result = 0; + 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_authenticate_image = hab_rvt_authenticate_image_p; + hab_rvt_entry = hab_rvt_entry_p; + hab_rvt_exit = hab_rvt_exit_p; + + if (is_hab_enabled()) { + printf("\nAuthenticate image from DDR location 0x%x...\n", + ddr_start); + + hab_caam_clock_enable(1); + + if (hab_rvt_entry() == HAB_SUCCESS) { + /* If not already aligned, Align to ALIGN_SIZE */ + ivt_offset = (image_size + ALIGN_SIZE - 1) & + ~(ALIGN_SIZE - 1); + + start = ddr_start; + bytes = ivt_offset + IVT_SIZE + CSF_PAD_SIZE; +#ifdef DEBUG + printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n", + ivt_offset, ddr_start + ivt_offset); + puts("Dumping IVT\n"); + print_buffer(ddr_start + ivt_offset, + (void *)(ddr_start + ivt_offset), + 4, 0x8, 0); + + puts("Dumping CSF Header\n"); + print_buffer(ddr_start + ivt_offset+IVT_SIZE, + (void *)(ddr_start + ivt_offset+IVT_SIZE), + 4, 0x10, 0); + + get_hab_status(); + + puts("\nCalling authenticate_image in ROM\n"); + printf("\tivt_offset = 0x%x\n", ivt_offset); + printf("\tstart = 0x%08lx\n", start); + printf("\tbytes = 0x%x\n", bytes); +#endif + /* + * If the MMU is enabled, we have to notify the ROM + * code, or it won't flush the caches when needed. + * This is done, by setting the "pu_irom_mmu_enabled" + * word to 1. You can find its address by looking in + * the ROM map. This is critical for + * authenticate_image(). If MMU is enabled, without + * setting this bit, authentication will fail and may + * crash. + */ + /* Check MMU enabled */ + if (get_cr() & CR_M) { + if (is_cpu_type(MXC_CPU_MX6Q) || + is_cpu_type(MXC_CPU_MX6D)) { + /* + * This won't work on Rev 1.0.0 of + * i.MX6Q/D, since their ROM doesn't + * do cache flushes. don't think any + * exist, so we ignore them. + */ + writel(1, MX6DQ_PU_IROM_MMU_EN_VAR); + } else if (is_cpu_type(MXC_CPU_MX6DL) || + is_cpu_type(MXC_CPU_MX6SOLO)) { + writel(1, MX6DLS_PU_IROM_MMU_EN_VAR); + } else if (is_cpu_type(MXC_CPU_MX6SL)) { + writel(1, MX6SL_PU_IROM_MMU_EN_VAR); + } + } + + load_addr = (uint32_t)hab_rvt_authenticate_image( + HAB_CID_UBOOT, + ivt_offset, (void **)&start, + (size_t *)&bytes, NULL); + if (hab_rvt_exit() != HAB_SUCCESS) { + puts("hab exit function fail\n"); + load_addr = 0; + } + } else { + puts("hab entry function fail\n"); + } + + hab_caam_clock_enable(0); + + get_hab_status(); + } else { + puts("hab fuse not enabled\n"); + } + + if ((!is_hab_enabled()) || (load_addr != 0)) + result = 1; + + return result; +} + int do_hab_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { if ((argc != 1)) { @@ -156,8 +298,33 @@ int do_hab_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 0; }
+static int do_authenticate_image(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + ulong addr, ivt_offset; + int rcode = 0; + + if (argc < 3) + return CMD_RET_USAGE; + + addr = simple_strtoul(argv[1], NULL, 16); + ivt_offset = simple_strtoul(argv[2], NULL, 16); + + rcode = authenticate_image(addr, ivt_offset); + + return rcode; +} + U_BOOT_CMD( hab_status, CONFIG_SYS_MAXARGS, 1, do_hab_status, "display HAB status", "" ); + +U_BOOT_CMD( + hab_auth_img, 3, 0, do_authenticate_image, + "authenticate image via HAB", + "addr ivt_offset\n" + "addr - image hex address\n" + "ivt_offset - hex offset of IVT in the image" + ); diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index ac84a1f..0d5fbf1 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -273,10 +273,25 @@ int board_postclk_init(void) #ifndef CONFIG_SYS_DCACHE_OFF void enable_caches(void) { +#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) + enum dcache_option option = DCACHE_WRITETHROUGH; +#else + enum dcache_option option = DCACHE_WRITEBACK; +#endif + /* Avoid random hang when download by usb */ invalidate_dcache_all(); + /* Enable D-cache. I-cache is already enabled in start.S */ dcache_enable(); + + /* Enable caching on OCRAM and ROM */ + mmu_set_region_dcache_behaviour(ROMCP_ARB_BASE_ADDR, + ROMCP_ARB_END_ADDR, + option); + mmu_set_region_dcache_behaviour(IRAM_BASE_ADDR, + IRAM_SIZE, + option); } #endif
diff --git a/arch/arm/include/asm/arch-mx6/clock.h b/arch/arm/include/asm/arch-mx6/clock.h index fd4b860..2953b36 100644 --- a/arch/arm/include/asm/arch-mx6/clock.h +++ b/arch/arm/include/asm/arch-mx6/clock.h @@ -61,4 +61,5 @@ int enable_spi_clk(unsigned char enable, unsigned spi_num); void enable_ipu_clock(void); int enable_fec_anatop_clock(enum enet_freq freq); void enable_pll3(void); +void hab_caam_clock_enable(unsigned char enable); #endif /* __ASM_ARCH_CLOCK_H */

Hi Nitin,
On 16/09/2014 20:33, Nitin Garg wrote:
When CONFIG_SECURE_BOOT is enabled, the signed images like kernel and dtb can be authenticated using iMX6 CAAM. The added command hab_auth_img can be used for HAB authentication of images. The command takes the image DDR location, IVT (Image Vector Table) offset inside image as parameters. Detailed info about signing images can be found in Freescale AppNote AN4581.
Signed-off-by: Nitin Garg nitin.garg@freescale.com
I wanted to apply it on current tree, but it seems it depends on "mx6: clock: Add api to enable pll3". Or better, it seems in your tree on top the the patch for pll3. It is not an issue and I solve it myself, but can you confim that or do you prefer that I apply this one only after the thermal series will be merged ?
Best regards, Stefano Babic

Hi Stefano,
On 09/22/2014 09:07 AM, Stefano Babic wrote:
Hi Nitin,
On 16/09/2014 20:33, Nitin Garg wrote:
When CONFIG_SECURE_BOOT is enabled, the signed images like kernel and dtb can be authenticated using iMX6 CAAM. The added command hab_auth_img can be used for HAB authentication of images. The command takes the image DDR location, IVT (Image Vector Table) offset inside image as parameters. Detailed info about signing images can be found in Freescale AppNote AN4581.
Signed-off-by: Nitin Garg nitin.garg@freescale.com
I wanted to apply it on current tree, but it seems it depends on "mx6: clock: Add api to enable pll3". Or better, it seems in your tree on top the the patch for pll3. It is not an issue and I solve it myself, but can you confim that or do you prefer that I apply this one only after the thermal series will be merged ?
Best regards, Stefano Babic
Yes you are correct, in my tree I did HAB patch on top of temperature sensor patch. Pls resolve it or I can help if needed. I do not have any preference with ordering of HAB and temperature patch.
Thanks, Nitin Garg

Hi Nitin,
On 16/09/2014 20:33, Nitin Garg wrote:
When CONFIG_SECURE_BOOT is enabled, the signed images like kernel and dtb can be authenticated using iMX6 CAAM. The added command hab_auth_img can be used for HAB authentication of images. The command takes the image DDR location, IVT (Image Vector Table) offset inside image as parameters. Detailed info about signing images can be found in Freescale AppNote AN4581.
Signed-off-by: Nitin Garg nitin.garg@freescale.com
Applied to u-boot-imx, thanks !
Best regards, Stefano Babic

Hi Nitin,
On Tue, Sep 16, 2014 at 3:33 PM, Nitin Garg nitin.garg@freescale.com wrote:
When CONFIG_SECURE_BOOT is enabled, the signed images like kernel and dtb can be authenticated using iMX6 CAAM. The added command hab_auth_img can be used for HAB authentication of images. The command takes the image DDR location, IVT (Image Vector Table) offset inside image as parameters. Detailed info about signing images can be found in Freescale AppNote AN4581.
Signed-off-by: Nitin Garg nitin.garg@freescale.com
I have just tested the 'hab_status' command and it hangs my mx6sxsabresd board:
U-Boot 2014.10-rc2-16959-g6eb2f0d-dirty (Sep 30 2014 - 10:28:19)
CPU: Freescale i.MX6SX rev1.0 at 792 MHz Reset cause: POR Board: MX6SX SABRE SDB I2C: ready DRAM: 1 GiB MMC: FSL_SDHC: 0 In: serial Out: serial Err: serial PMIC: PFUZE100 ID=0x10 Net: FEC [PRIME] Hit any key to stop autoboot: 0 => hab_status
Secure boot disabled
(hangs the system)
Could you please take a look at this issue?

Hi Fabio,
On 09/30/2014 08:44 AM, Fabio Estevam wrote:
Hi Nitin,
On Tue, Sep 16, 2014 at 3:33 PM, Nitin Garg nitin.garg@freescale.com wrote:
When CONFIG_SECURE_BOOT is enabled, the signed images like kernel and dtb can be authenticated using iMX6 CAAM. The added command hab_auth_img can be used for HAB authentication of images. The command takes the image DDR location, IVT (Image Vector Table) offset inside image as parameters. Detailed info about signing images can be found in Freescale AppNote AN4581.
Signed-off-by: Nitin Garg nitin.garg@freescale.com
I have just tested the 'hab_status' command and it hangs my mx6sxsabresd board:
U-Boot 2014.10-rc2-16959-g6eb2f0d-dirty (Sep 30 2014 - 10:28:19)
CPU: Freescale i.MX6SX rev1.0 at 792 MHz Reset cause: POR Board: MX6SX SABRE SDB I2C: ready DRAM: 1 GiB MMC: FSL_SDHC: 0 In: serial Out: serial Err: serial PMIC: PFUZE100 ID=0x10 Net: FEC [PRIME] Hit any key to stop autoboot: 0 => hab_status
Secure boot disabled
(hangs the system)
Could you please take a look at this issue?
I found the reason for the hang. The HAB api table was not updated for i.MX6SX. Since i.MX6SX ROM implements unified sections in ROM, the HAP function pointers needs to be updated. I have sent a patch for the same.
-Nitin
participants (3)
-
Fabio Estevam
-
Nitin Garg
-
Stefano Babic