[U-Boot] [PATCH v3] imx: Support i.MX6 High Assurance Boot authentication
Stefano Babic
sbabic at denx.de
Fri Sep 12 10:46:31 CEST 2014
Hi Nitin,
On 04/09/2014 03:18, 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 at freescale.com>
>
> ---
>
> 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 | 32 ++++++-
> arch/arm/cpu/armv7/mx6/hab.c | 165 ++++++++++++++++++++++++++++++++-
> arch/arm/cpu/armv7/mx6/soc.c | 15 +++
> arch/arm/include/asm/arch-mx6/clock.h | 4 +
> 4 files changed, 214 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c
> index 820b8d5..db6a8fc 100644
> --- a/arch/arm/cpu/armv7/mx6/clock.c
> +++ b/arch/arm/cpu/armv7/mx6/clock.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
> + * Copyright (C) 2010-2014 Freescale Semiconductor, Inc.
> *
> * SPDX-License-Identifier: GPL-2.0+
> */
> @@ -543,6 +543,36 @@ int enable_pcie_clock(void)
> BM_ANADIG_PLL_ENET_ENABLE_PCIE);
> }
>
> +#ifdef CONFIG_SECURE_BOOT
> +void hab_caam_clock_enable(void)
> +{
> + struct mxc_ccm_reg *const imx_ccm =
> + (struct mxc_ccm_reg *)CCM_BASE_ADDR;
> +
> + /*CG4 ~ CG6, enable CAAM clocks*/
> + setbits_le32(&imx_ccm->CCGR0, MXC_CCM_CCGR0_CAAM_WRAPPER_IPG_MASK |
> + MXC_CCM_CCGR0_CAAM_WRAPPER_ACLK_MASK |
> + MXC_CCM_CCGR0_CAAM_SECURE_MEM_MASK);
> +
> + /* Enable EMI slow clk */
> + setbits_le32(&imx_ccm->CCGR6, MXC_CCM_CCGR6_EMI_SLOW_MASK);
> +}
> +
> +void hab_caam_clock_disable(void)
> +{
> + struct mxc_ccm_reg *const imx_ccm =
> + (struct mxc_ccm_reg *)CCM_BASE_ADDR;
> +
> + /*CG4 ~ CG6, disable CAAM clocks*/
> + clrbits_le32(&imx_ccm->CCGR0, MXC_CCM_CCGR0_CAAM_WRAPPER_IPG_MASK |
> + MXC_CCM_CCGR0_CAAM_WRAPPER_ACLK_MASK |
> + MXC_CCM_CCGR0_CAAM_SECURE_MEM_MASK);
> +
> + /* Disable EMI slow clk */
> + clrbits_le32(&imx_ccm->CCGR6, MXC_CCM_CCGR6_EMI_SLOW_MASK);
> +}
> +#endif
Generally, we have in clock.c one function per clock, getting as
enable_uart_clkparameter a boolean for enabling/disabling (i.e.
enable_ocotp_clk(), enable_uart_clk(),...)
Please stick with the same rule.
> +
> 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..61a94a1 100644
> --- a/arch/arm/cpu/armv7/mx6/hab.c
> +++ b/arch/arm/cpu/armv7/mx6/hab.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (C) 2010-2013 Freescale Semiconductor, Inc.
> + * Copyright (C) 2010-2014 Freescale Semiconductor, Inc.
> *
> * SPDX-License-Identifier: GPL-2.0+
> */
> @@ -7,8 +7,12 @@
> #include <common.h>
> #include <asm/io.h>
> #include <asm/arch/hab.h>
> +#include <asm/arch/clock.h>
> #include <asm/arch/sys_proto.h>
>
> +/* HAB (High Assurance Boot) debug */
> +#undef DEBUG_AUTHENTICATE_IMAGE
This is never defined, you do not need to undefine it.
> +
> /* -------- start of HAB API updates ------------*/
>
> #define hab_rvt_report_event_p \
> @@ -71,6 +75,41 @@
> ((hab_rvt_exit_t *)HAB_RVT_EXIT) \
> )
>
> +#define IVT_SIZE 0x20
> +#define ALIGN_SIZE 0x1000
> +#define CSF_PAD_SIZE 0x2000
> +
> +/*
> + * +------------+ 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 +183,105 @@ 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();
> +
> + 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_AUTHENTICATE_IMAGE
We have already a way for adding debugging. Use debug() instead of
printf(), and you can simply use #ifdef DEBUG for conditional branches.
We decided some times ago to avoid adding any flavour of specific DEBUG_
switches.
> + printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n",
> + ivt_offset, ddr_start + ivt_offset);
> + printf("Dumping IVT\n");
> + print_buffer(ddr_start + ivt_offset,
> + (void *)(ddr_start + ivt_offset),
> + 4, 0x8, 0);
> +
> + printf("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();
> +
> + printf("\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 but, authentication will fail and may
> + * crash.
> + */
> + 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.
> + * I don't think any exist, so we ignore them.
> + */
> + writel(1, 0x009024a8);
Can you add defines or (better) structures for this ? Writing in this
way into the hardware is generally not allowed in u-boot.
In the comments you say that it must be checked if MMU is on (generally
on when cache is enabled), but there is no check afterward, only a
different behavior depending on CPU. Does it mean that
pu_irom_mmu_enabled is set independently from MMU status ?
> + } else if (is_cpu_type(MXC_CPU_MX6DL) ||
> + is_cpu_type(MXC_CPU_MX6SOLO)) {
> + writel(1, 0x00901dd0);
> + } else if (is_cpu_type(MXC_CPU_MX6SL)) {
> + writel(1, 0x00900a18);
> + }
> +
> + 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) {
> + printf("hab exit function fail\n");
> + load_addr = 0;
> + }
> + } else {
> + printf("hab entry function fail\n");
Use puts() instead of printf() when you want to output a constant string.
> + }
> +
> + hab_caam_clock_disable();
> +
> + get_hab_status();
> + } else {
> + printf("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 +294,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, 1, 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 b0c1306..9842efb 100644
> --- a/arch/arm/cpu/armv7/mx6/soc.c
> +++ b/arch/arm/cpu/armv7/mx6/soc.c
> @@ -409,10 +409,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 339c789..2482e1a 100644
> --- a/arch/arm/include/asm/arch-mx6/clock.h
> +++ b/arch/arm/include/asm/arch-mx6/clock.h
> @@ -2,6 +2,8 @@
> * (C) Copyright 2009
> * Stefano Babic, DENX Software Engineering, sbabic at denx.de.
> *
> + * (C) Copyright 2014 Freescale Semiconductor, Inc.
> + *
> * SPDX-License-Identifier: GPL-2.0+
> */
>
> @@ -60,4 +62,6 @@ int enable_i2c_clk(unsigned char enable, unsigned i2c_num);
> 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 hab_caam_clock_enable(void);
> +void hab_caam_clock_disable(void);
> #endif /* __ASM_ARCH_CLOCK_H */
>
I have not found enough documentation to verify this: is this code
suitable for MX53, too ? I can see in MX53 manual that a "CAAM" is
available, but nothing more as that.
Best regards,
Stefano Babic
--
=====================================================================
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic at denx.de
=====================================================================
More information about the U-Boot
mailing list