summaryrefslogtreecommitdiffstats
path: root/arch/arm/cpu/armv7/mx6
diff options
context:
space:
mode:
authorNitin Garg <nitin.garg@freescale.com>2014-09-16 13:33:25 -0500
committerStefano Babic <sbabic@denx.de>2014-09-22 16:21:04 +0200
commit36c1ca4d46ef11ac7b3c0afb5c42dadb4e8773f3 (patch)
treeb5dbaad08e0c4cc6a5ac7143784c6b22d97e82c5 /arch/arm/cpu/armv7/mx6
parent4f797c4c1c93b508928786f539cd6a4a98a68f22 (diff)
downloadblackbird-obmc-uboot-36c1ca4d46ef11ac7b3c0afb5c42dadb4e8773f3.tar.gz
blackbird-obmc-uboot-36c1ca4d46ef11ac7b3c0afb5c42dadb4e8773f3.zip
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>
Diffstat (limited to 'arch/arm/cpu/armv7/mx6')
-rw-r--r--arch/arm/cpu/armv7/mx6/clock.c27
-rw-r--r--arch/arm/cpu/armv7/mx6/hab.c169
-rw-r--r--arch/arm/cpu/armv7/mx6/soc.c15
3 files changed, 210 insertions, 1 deletions
diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c
index 336e557a27..d200531030 100644
--- a/arch/arm/cpu/armv7/mx6/clock.c
+++ b/arch/arm/cpu/armv7/mx6/clock.c
@@ -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) {
diff --git a/arch/arm/cpu/armv7/mx6/hab.c b/arch/arm/cpu/armv7/mx6/hab.c
index f6810a680d..8dee595eaf 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 ba21cfe580..05683a3400 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
OpenPOWER on IntegriCloud