From dc526e4eb966cc0311f6ad8dd69d94ffcf56c25f Mon Sep 17 00:00:00 2001 From: Jason Liu Date: Wed, 14 Aug 2013 15:08:39 +0800 Subject: ENGR00275348-7 imx6: add secureboot support This patch add the secureboot support Signed-off-by: Jason Liu --- arch/arm/cpu/armv7/mx6/soc.c | 229 +++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mx6/imx-regs.h | 69 +++++++++ arch/arm/include/asm/arch-mx6/mx6_secure.h | 80 ++++++++++ arch/arm/include/asm/arch-mx6/sys_proto.h | 1 + common/cmd_bootm.c | 10 ++ tools/imximage.c | 38 ++++- tools/imximage.h | 4 + 7 files changed, 426 insertions(+), 5 deletions(-) create mode 100644 arch/arm/include/asm/arch-mx6/mx6_secure.h diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index f4bac7a..c803b5c 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -56,6 +56,10 @@ struct scu_regs { static unsigned int fuse = ~0; +#if defined(CONFIG_SECURE_BOOT) +#include +#endif + u32 get_cpu_rev(void) { struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; @@ -459,3 +463,228 @@ void v7_outer_cache_disable(void) writel(0, &pl310->pl310_ctrl); } #endif /* !CONFIG_SYS_L2CACHE_OFF */ + +#ifdef CONFIG_ARCH_MISC_INIT +int arch_misc_init(void) +{ +#ifdef CONFIG_SECURE_BOOT + get_hab_status(); +#endif + return 0; +} +#endif /* !CONFIG_ARCH_MISC_INIT */ + +#ifdef CONFIG_SECURE_BOOT +/* -------- start of HAB API updates ------------*/ +#define hab_rvt_report_event ((hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT) +#define hab_rvt_report_status ((hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS) +#define hab_rvt_authenticate_image \ + ((hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE) +#define hab_rvt_entry ((hab_rvt_entry_t *) HAB_RVT_ENTRY) +#define hab_rvt_exit ((hab_rvt_exit_t *) HAB_RVT_EXIT) +#define hab_rvt_clock_init HAB_RVT_CLOCK_INIT + +#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 + */ + +int check_hab_enable(void) +{ + u32 reg; + int result = 0; + struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; + struct fuse_bank *bank = &iim->bank[0]; + struct fuse_bank0_regs *fuse_bank0 = + (struct fuse_bank0_regs *)bank->fuse_regs; + + reg = readl(&fuse_bank0->cfg5); + if (reg & 0x2) + result = 1; + + return result; +} + +void display_event(uint8_t *event_data, size_t bytes) +{ + uint32_t i; + if ((event_data) && (bytes > 0)) { + for (i = 0; i < bytes; i++) { + if (i == 0) + printf("\t0x%02x", event_data[i]); + else if ((i % 8) == 0) + printf("\n\t0x%02x", event_data[i]); + else + printf(" 0x%02x", event_data[i]); + } + } +} + +int get_hab_status(void) +{ + uint32_t index = 0; /* Loop index */ + uint8_t event_data[128]; /* Event data buffer */ + size_t bytes = sizeof(event_data); /* Event size in bytes */ + hab_config_t config = 0; + hab_state_t state = 0; + + /* Check HAB status */ + if (hab_rvt_report_status(&config, &state) != HAB_SUCCESS) { + 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, + &bytes) == HAB_SUCCESS) { + printf("\n"); + printf("--------- HAB Event %d -----------------\n", + index + 1); + printf("event data:\n"); + display_event(event_data, bytes); + printf("\n"); + bytes = sizeof(event_data); + index++; + } + } + /* Display message if no HAB events are found */ + else { + printf("\nHAB Configuration: 0x%02x, HAB State: 0x%02x\n", + config, state); + printf("No HAB Events Found!\n\n"); + } + return 0; +} + +void hab_caam_clock_enable(void) +{ + u32 reg = 0; + + reg = readl(CCM_BASE_ADDR + CLKCTL_CCGR0); /* CCGR0 */ + reg |= 0x3F00; /*CG4 ~ CG6, enable CAAM clocks*/ + writel(reg, CCM_BASE_ADDR + CLKCTL_CCGR0); +} + + +void hab_caam_clock_disable(void) +{ + u32 reg = 0; + + reg = readl(CCM_BASE_ADDR + CLKCTL_CCGR0); /* CCGR0 */ + reg &= ~0x3F00; /*CG4 ~ CG6, disable CAAM clocks*/ + writel(reg, CCM_BASE_ADDR + CLKCTL_CCGR0); +} + +#ifdef DEBUG_AUTHENTICATE_IMAGE +void dump_mem(uint32_t addr, int size) +{ + int i; + + for (i = 0; i < size; i += 4) { + if (i != 0) { + if (i % 16 == 0) + printf("\n"); + else + printf(" "); + } + + printf("0x%08x", *(uint32_t *)addr); + addr += 4; + } + + printf("\n"); + + return; +} +#endif + +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; + + if (check_hab_enable() == 1) { + printf("\nAuthenticate uImage 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 + printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n", + ivt_offset, ddr_start + ivt_offset); + printf("Dumping IVT\n"); + dump_mem(ddr_start + ivt_offset, 0x20); + + printf("Dumping CSF Header\n"); + dump_mem(ddr_start + ivt_offset + 0x20, 0x40); + + get_hab_status(); + + printf("\nCalling authenticate_image in ROM\n"); + printf("\tivt_offset = 0x%x\n\tstart = 0x%08x" + "\n\tbytes = 0x%x\n", ivt_offset, start, bytes); +#endif + + 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"); + + hab_caam_clock_disable(); + + get_hab_status(); + } + + if ((!check_hab_enable()) || (load_addr != 0)) + result = 1; + + return result; +} +/* ----------- end of HAB API updates ------------*/ +#endif diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h index 933d9a2..4d97065 100644 --- a/arch/arm/include/asm/arch-mx6/imx-regs.h +++ b/arch/arm/include/asm/arch-mx6/imx-regs.h @@ -438,6 +438,56 @@ struct cspi_regs { ECSPI5_BASE_ADDR #endif +/* gpio and gpio based interrupt handling */ +#define GPIO_DR 0x00 +#define GPIO_GDIR 0x04 +#define GPIO_PSR 0x08 +#define GPIO_ICR1 0x0C +#define GPIO_ICR2 0x10 +#define GPIO_IMR 0x14 +#define GPIO_ISR 0x18 +#define GPIO_INT_LOW_LEV 0x0 +#define GPIO_INT_HIGH_LEV 0x1 +#define GPIO_INT_RISE_EDGE 0x2 +#define GPIO_INT_FALL_EDGE 0x3 +#define GPIO_INT_NONE 0x4 + +#define CLKCTL_CCR 0x00 +#define CLKCTL_CCDR 0x04 +#define CLKCTL_CSR 0x08 +#define CLKCTL_CCSR 0x0C +#define CLKCTL_CACRR 0x10 +#define CLKCTL_CBCDR 0x14 +#define CLKCTL_CBCMR 0x18 +#define CLKCTL_CSCMR1 0x1C +#define CLKCTL_CSCMR2 0x20 +#define CLKCTL_CSCDR1 0x24 +#define CLKCTL_CS1CDR 0x28 +#define CLKCTL_CS2CDR 0x2C +#define CLKCTL_CDCDR 0x30 +#define CLKCTL_CHSCCDR 0x34 +#define CLKCTL_CSCDR2 0x38 +#define CLKCTL_CSCDR3 0x3C +#define CLKCTL_CSCDR4 0x40 +#define CLKCTL_CWDR 0x44 +#define CLKCTL_CDHIPR 0x48 +#define CLKCTL_CDCR 0x4C +#define CLKCTL_CTOR 0x50 +#define CLKCTL_CLPCR 0x54 +#define CLKCTL_CISR 0x58 +#define CLKCTL_CIMR 0x5C +#define CLKCTL_CCOSR 0x60 +#define CLKCTL_CGPR 0x64 +#define CLKCTL_CCGR0 0x68 +#define CLKCTL_CCGR1 0x6C +#define CLKCTL_CCGR2 0x70 +#define CLKCTL_CCGR3 0x74 +#define CLKCTL_CCGR4 0x78 +#define CLKCTL_CCGR5 0x7C +#define CLKCTL_CCGR6 0x80 +#define CLKCTL_CCGR7 0x84 +#define CLKCTL_CMEOR 0x88 + struct iim_regs { u32 ctrl; u32 ctrl_set; @@ -469,6 +519,25 @@ struct iim_regs { } bank[15]; }; +struct fuse_bank0_regs { + u32 lock; + u32 rsvd0[3]; + u32 cfg0; + u32 rsvd1[3]; + u32 cfg1; + u32 rsvd2[3]; + u32 cfg2; + u32 rsvd3[3]; + u32 cfg3; + u32 rsvd4[3]; + u32 cfg4; + u32 rsvd5[3]; + u32 cfg5; + u32 rsvd6[3]; + u32 cfg6; + u32 rsvd7[3]; +}; + struct fuse_bank1_regs { u32 mem[0x18]; u32 ana1; diff --git a/arch/arm/include/asm/arch-mx6/mx6_secure.h b/arch/arm/include/asm/arch-mx6/mx6_secure.h new file mode 100644 index 0000000..84616c4 --- /dev/null +++ b/arch/arm/include/asm/arch-mx6/mx6_secure.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Auto Generate file, please don't edit it + * + */ + +#ifndef __SECURE_MX6Q_H__ +#define __SECURE_MX6Q_H__ + +#include + +/* -------- start of HAB API updates ------------*/ +/* The following are taken from HAB4 SIS */ + +/* Status definitions */ +typedef enum hab_status { + HAB_STS_ANY = 0x00, + HAB_FAILURE = 0x33, + HAB_WARNING = 0x69, + HAB_SUCCESS = 0xf0 +} hab_status_t; + +/* Security Configuration definitions */ +typedef enum hab_config { + HAB_CFG_RETURN = 0x33, /**< Field Return IC */ + HAB_CFG_OPEN = 0xf0, /**< Non-secure IC */ + HAB_CFG_CLOSED = 0xcc /**< Secure IC */ +} hab_config_t; + +/* State definitions */ +typedef enum hab_state { + HAB_STATE_INITIAL = 0x33, /**< Initialising state (transitory) */ + HAB_STATE_CHECK = 0x55, /**< Check state (non-secure) */ + HAB_STATE_NONSECURE = 0x66, /**< Non-secure state */ + HAB_STATE_TRUSTED = 0x99, /**< Trusted state */ + HAB_STATE_SECURE = 0xaa, /**< Secure state */ + HAB_STATE_FAIL_SOFT = 0xcc, /**< Soft fail state */ + HAB_STATE_FAIL_HARD = 0xff, /**< Hard fail state (terminal) */ + HAB_STATE_NONE = 0xf0, /**< No security state machine */ + HAB_STATE_MAX +} hab_state_t; + +/*Function prototype description*/ +typedef hab_status_t hab_rvt_report_event_t(hab_status_t, uint32_t, \ + uint8_t* , size_t*); +typedef hab_status_t hab_rvt_report_status_t(hab_config_t *, hab_state_t *); +typedef hab_status_t hab_loader_callback_f_t(void**, size_t*, const void*); +typedef hab_status_t hab_rvt_entry_t(void); +typedef hab_status_t hab_rvt_exit_t(void); +typedef void *hab_rvt_authenticate_image_t(uint8_t, ptrdiff_t, \ + void **, size_t *, hab_loader_callback_f_t); +typedef void hapi_clock_init_t(void); + +#define HAB_RVT_REPORT_EVENT (*(uint32_t *) 0x000000B4) +#define HAB_RVT_REPORT_STATUS (*(uint32_t *) 0x000000B8) +#define HAB_RVT_AUTHENTICATE_IMAGE (*(uint32_t *) 0x000000A4) +#define HAB_RVT_ENTRY (*(uint32_t *) 0x00000098) +#define HAB_RVT_EXIT (*(uint32_t *) 0x0000009C) +#define HAB_RVT_CLOCK_INIT ((hapi_clock_init_t *) 0x0000024D) + +#define HAB_CID_ROM 0 /**< ROM Caller ID */ +#define HAB_CID_UBOOT 1 /**< UBOOT Caller ID*/ +/* ----------- end of HAB API updates ------------*/ + +#endif diff --git a/arch/arm/include/asm/arch-mx6/sys_proto.h b/arch/arm/include/asm/arch-mx6/sys_proto.h index 38e4e51..d1b1bc9 100644 --- a/arch/arm/include/asm/arch-mx6/sys_proto.h +++ b/arch/arm/include/asm/arch-mx6/sys_proto.h @@ -48,6 +48,7 @@ void set_vddsoc(u32 mv); int fecmxc_initialize(bd_t *bis); u32 get_ahb_clk(void); u32 get_periph_clk(void); +int get_hab_status(void); int mxs_reset_block(struct mxs_register_32 *reg); int mxs_wait_mask_set(struct mxs_register_32 *reg, diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 7438469..e27cd8c 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -632,6 +632,16 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return do_bootm_subcommand(cmdtp, flag, argc, argv); } +#ifdef CONFIG_SECURE_BOOT + extern uint32_t authenticate_image( + uint32_t ddr_start, uint32_t image_size); + if (authenticate_image(load_addr, + image_get_image_size((image_header_t *)load_addr)) == 0) { + printf("Authenticate UImage Fail, Please check\n"); + return 1; + } +#endif + if (bootm_start(cmdtp, flag, argc, argv)) return 1; diff --git a/tools/imximage.c b/tools/imximage.c index b10beba..1e7c0f6 100644 --- a/tools/imximage.c +++ b/tools/imximage.c @@ -40,6 +40,7 @@ static table_entry_t imximage_cmds[] = { {CMD_DATA, "DATA", "Reg Write Data", }, {CMD_IMAGE_VERSION, "IMAGE_VERSION", "image version", }, {CMD_PLUGIN, "PLUGIN", "file plugin_addr", }, + {CMD_SECURE_BOOT, "SECURE_BOOT", "secure boot enable", }, {-1, "", "", }, }; @@ -74,6 +75,7 @@ static set_dcd_rst_t set_dcd_rst; static set_imx_hdr_t set_imx_hdr; static uint32_t max_dcd_entries; static uint32_t *header_size_ptr; +static struct stat *sbuf_ptr; static uint32_t get_cfg_value(char *token, char *name, int linenr) { @@ -250,13 +252,28 @@ static void set_imx_hdr_v2(struct imx_header *imxhdr, uint32_t dcd_len, + offsetof(imx_header_v2_t, boot_data); hdr_v2->boot_data.start = hdr_base - flash_offset; - /* Security feature are not supported */ - fhdr_v2->csf = 0; - header_size_ptr = &hdr_v2->boot_data.size; + if (imxhdr->secure_enable) { + uint32_t round_size; + round_size = ROUND(sbuf_ptr->st_size, CSF_ALIGN_SIZE); + + hdr_v2->boot_data.size = ROUND(round_size + CSF_DATA_SIZE + + flash_offset, 512); + fhdr_v2->csf = fhdr_v2->self + round_size; + } else { + /* Security feature are not supported */ + fhdr_v2->csf = 0; + header_size_ptr = &hdr_v2->boot_data.size; + } } else { imx_header_v2_t *next_hdr_v2; flash_header_v2_t *next_fhdr_v2; + if (imxhdr->secure_enable) { + fprintf(stderr, "Error: Header v2: SECURE_BOOT" + "is only supported in DCD mode!"); + exit(EXIT_FAILURE); + } + fhdr_v2->entry = imxhdr->iram_free_start + flash_offset + sizeof(flash_header_v2_t) + sizeof(boot_data_t); @@ -369,8 +386,9 @@ static void print_hdr_v2(struct imx_header *imx_hdr) imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2; flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; dcd_v2_t *dcd_v2 = &hdr_v2->data.dcd_table; - uint32_t size, version, plugin; + uint32_t size, version, plugin, secure_enable; + secure_enable = imx_hdr->secure_enable; plugin = hdr_v2->boot_data.plugin; if (!plugin) { size = be16_to_cpu(dcd_v2->header.length) - 8; @@ -389,6 +407,10 @@ static void print_hdr_v2(struct imx_header *imx_hdr) printf("Image Ver: %x", version); printf("%s\n", get_table_entry_name(imximage_versions, NULL, version)); printf("Mode: %s\n", plugin ? "PLUGIN" : "DCD"); + printf("Secure Boot Mode: %s\n", secure_enable ? "ON" : "OFF"); + if (secure_enable) { + printf("CSF Data Address: %08x\n", fhdr_v2->csf); + } if (!plugin) { printf("U-Boot Data Size: "); genimg_print_size(hdr_v2->boot_data.size); @@ -510,7 +532,10 @@ static void parse_cfg_fld(struct imx_header *imxhdr, int32_t *cmd, fprintf(stderr, "Error: %s[%d] - Invalid command" "(%s)\n", name, lineno, token); exit(EXIT_FAILURE); + } + if (*cmd == CMD_SECURE_BOOT) + imxhdr->secure_enable = 1; break; case CFG_REG_SIZE: parse_cfg_cmd(imxhdr, *cmd, token, name, lineno, fld, *dcd_len); @@ -643,6 +668,7 @@ static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd, { struct imx_header *imxhdr = (struct imx_header *)ptr; uint32_t dcd_len; + sbuf_ptr = sbuf; /* * In order to not change the old imx cfg file @@ -666,7 +692,9 @@ static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd, * The remaining fraction of a block bytes would * not be loaded. */ - *header_size_ptr = ROUND(sbuf->st_size + imxhdr->flash_offset, 512); + if (!imxhdr->secure_enable) + *header_size_ptr = ROUND(sbuf->st_size + + imxhdr->flash_offset, 512); } int imximage_check_params(struct mkimage_params *params) diff --git a/tools/imximage.h b/tools/imximage.h index 0871b79..0c46c70 100644 --- a/tools/imximage.h +++ b/tools/imximage.h @@ -36,6 +36,8 @@ */ #define MAX_PLUGIN_CODE_SIZE (16*1024) #define PLUGIN_IRAM_COPY_SIZE (16*1024) +#define CSF_ALIGN_SIZE 0x1000 +#define CSF_DATA_SIZE 0x2000 #define MAX_HW_CFG_SIZE_V1 60 /* Max number of registers imx can set for v1 */ #define APP_CODE_BARKER 0xB1 #define DCD_BARKER 0xB17219E9 @@ -65,6 +67,7 @@ enum imximage_cmd { CMD_BOOT_FROM, CMD_DATA, CMD_PLUGIN, + CMD_SECURE_BOOT }; enum imximage_fld_types { @@ -174,6 +177,7 @@ struct imx_header { uint32_t flash_offset; uint32_t iram_free_start; uint32_t plugin_size; + uint32_t secure_enable; } __attribute__((aligned(0x1000))); typedef void (*set_dcd_val_t)(struct imx_header *imxhdr, -- cgit v1.1