imx: Support i.MX6 High Assurance Boot authentication
authorNitin Garg <nitin.garg@freescale.com>
Tue, 16 Sep 2014 18:33:25 +0000 (13:33 -0500)
committerStefano Babic <sbabic@denx.de>
Mon, 22 Sep 2014 14:21:04 +0000 (16:21 +0200)
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>
arch/arm/cpu/armv7/mx6/clock.c
arch/arm/cpu/armv7/mx6/hab.c
arch/arm/cpu/armv7/mx6/soc.c
arch/arm/include/asm/arch-mx6/clock.h

index 336e557a27d68ddfb2c52875aeb9b7c0a4c0091f..d200531030e730301574f27943757ec50ab4f763 100644 (file)
@@ -642,6 +642,33 @@ int enable_pcie_clock(void)
                               BM_ANADIG_PLL_ENET_ENABLE_PCIE);
 }
 
+#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) {
index f6810a680d9f59493bb041ca79c3050fc5a59f9d..8dee595eaf85359bcf6a128fba2b088cc77cbbee 100644 (file)
@@ -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 ------------*/
        ((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"
+         );
index ba21cfe5807eee2d26b350f176e40f3f655f22a1..05683a3400cbcb55d436c6128d8d6262bc5db64f 100644 (file)
@@ -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
 
index c11674ff8a893c1b665a9a539363817553ed13fb..3c58a0ab6041897794d28ac514dd7ab2fe256949 100644 (file)
@@ -53,6 +53,7 @@ u32 imx_get_uartclk(void);
 u32 imx_get_fecclk(void);
 unsigned int mxc_get_clock(enum mxc_clock clk);
 void setup_gpmi_io_clk(u32 cfg);
+void hab_caam_clock_enable(unsigned char enable);
 void enable_ocotp_clk(unsigned char enable);
 void enable_usboh3_clk(unsigned char enable);
 void enable_uart_clk(unsigned char enable);