diff options
-rw-r--r-- | arch/arm/cpu/armv7/mx6/Kconfig | 6 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/mx6/Makefile | 5 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/mx6/bee.c | 453 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-mx6/mx6_bee.h | 50 |
4 files changed, 513 insertions, 1 deletions
diff --git a/arch/arm/cpu/armv7/mx6/Kconfig b/arch/arm/cpu/armv7/mx6/Kconfig index 744d67a..2757451 100644 --- a/arch/arm/cpu/armv7/mx6/Kconfig +++ b/arch/arm/cpu/armv7/mx6/Kconfig @@ -58,6 +58,12 @@ config MX6_DDRCAL Say "Y" if your board uses dynamic (per-boot) DDR calibration. If unsure, say N. +config CMD_BEE + bool "Enable commands for Bus Encryption Engine(BEE)" + depends on MX6UL + help + Set "Y" to enable the bee commands + choice prompt "MX6 board select" optional diff --git a/arch/arm/cpu/armv7/mx6/Makefile b/arch/arm/cpu/armv7/mx6/Makefile index 024f703..d240f3a 100644 --- a/arch/arm/cpu/armv7/mx6/Makefile +++ b/arch/arm/cpu/armv7/mx6/Makefile @@ -2,7 +2,7 @@ # (C) Copyright 2000-2006 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. # -# (C) Copyright 2011 Freescale Semiconductor, Inc. +# (C) Copyright 2011-2015 Freescale Semiconductor, Inc. # # SPDX-License-Identifier: GPL-2.0+ # @@ -11,3 +11,6 @@ obj-y := soc.o clock.o obj-$(CONFIG_SPL_BUILD) += ddr.o obj-$(CONFIG_MP) += mp.o obj-$(CONFIG_MX6UL_LITESOM) += litesom.o +ifdef CONFIG_MX6UL +obj-$(CONFIG_CMD_BEE) += bee.o +endif diff --git a/arch/arm/cpu/armv7/mx6/bee.c b/arch/arm/cpu/armv7/mx6/bee.c new file mode 100644 index 0000000..a4bd76d --- /dev/null +++ b/arch/arm/cpu/armv7/mx6/bee.c @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm/io.h> +#include <asm/arch/mx6_bee.h> +#include <linux/errno.h> +#include <asm/system.h> +#include <common.h> +#include <command.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if (defined(CONFIG_SYS_DCACHE_OFF) || defined(CONFIG_SYS_ICACHE_OFF)) +#error "Bee needs Cache Open" +#endif + +struct bee_parameters { + int key_method; + int mode; + u32 start1; + u32 size1; + u32 start2; + u32 size2; +}; + +#define SOFT_KEY 0 +#define SNVS_KEY 1 + +#define ECB_MODE 0 +#define CTR_MODE 1 + +#define AES_REGION0_ADDR 0x10000000 +#define AES_REGION1_ADDR 0x30000000 + +static struct bee_parameters para; +static int bee_inited; + +union key_soft { + u8 s_key[16]; + u32 b_key[4]; +}; + +union key_soft key_bad; + +/* software version */ +u8 hw_get_random_byte(void) +{ + static u32 lcg_state; + static u32 nb_soft = 9876543; +#define MAX_SOFT_RNG 1024 + static const u32 a = 1664525; + static const u32 c = 1013904223; + nb_soft = (nb_soft + 1) % MAX_SOFT_RNG; + lcg_state = (a * lcg_state + c); + return (u8) (lcg_state >> 24); +} + +/* + * Lock bee GPR0 bits + * Only reset can release these bits. + */ +static int bee_lock(void) +{ + int val; + + val = readl(BEE_BASE_ADDR + GPR0); + val |= (GPR0_CTRL_CLK_EN_LOCK | GPR0_CTRL_SFTRST_N_LOCK | + GPR0_CTRL_AES_MODE_LOCK | GPR0_SEC_LEVEL_LOCK | + GPR0_AES_KEY_SEL_LOCK | GPR0_BEE_ENABLE_LOCK); + writel(val, BEE_BASE_ADDR + GPR0); + + return 0; +} + +/* Only check bee enable lock is enough */ +static int bee_locked(void) +{ + int val; + + val = readl(BEE_BASE_ADDR + GPR0); + + return val & GPR0_BEE_ENABLE_LOCK ? 1 : 0; +} + +int bee_init(struct bee_parameters *p) +{ + int i; + union key_soft *key = &key_bad; + u32 value; + + if (bee_locked()) { + printf("BEE already enabled and locked.\n"); + return CMD_RET_FAILURE; + } + + /* CLKGATE, SFTRST */ + writel(GPR0_CTRL_CLK_EN | GPR0_CTRL_SFTRST_N, BEE_BASE_ADDR + GPR0); + /* OFFSET_ADDR0 */ + writel(p->start1 >> 16, BEE_BASE_ADDR + GPR1); + /* + * OFFSET_ADDR1 + * Default protect IRAM region, if what you want to protect + * bigger that 512M which is the max size that one AES region + * can protect, we need AES region 1 to cover. + */ + writel(p->start2 >> 16, BEE_BASE_ADDR + GPR2); + + if (p->key_method == SOFT_KEY) { + for (i = 0; i < 16; i++) + key->s_key[i] = hw_get_random_byte(); + /* AES 128 key from software */ + /* aes0_key0_w0 */ + writel(key->b_key[0], BEE_BASE_ADDR + GPR3); + /* aes0_key0_w1 */ + writel(key->b_key[1], BEE_BASE_ADDR + GPR4); + /* aes0_key0_w2 */ + writel(key->b_key[2], BEE_BASE_ADDR + GPR5); + /* aes0_key0_w3 */ + writel(key->b_key[3], BEE_BASE_ADDR + GPR6); + } + + if (p->mode == ECB_MODE) { + value = GPR0_CTRL_CLK_EN | GPR0_CTRL_SFTRST_N | + GPR0_SEC_LEVEL_3 | GPR0_AES_KEY_SEL_SNVS | + GPR0_BEE_ENABLE | GPR0_CTRL_AES_MODE_ECB; + if (p->key_method == SOFT_KEY) + value = GPR0_CTRL_CLK_EN | GPR0_CTRL_SFTRST_N | + GPR0_SEC_LEVEL_3 | GPR0_AES_KEY_SEL_SOFT | + GPR0_BEE_ENABLE | GPR0_CTRL_AES_MODE_ECB; + writel(value, BEE_BASE_ADDR + GPR0); + } else { + for (i = 0; i < 16; i++) + key->s_key[i] = hw_get_random_byte(); + /* aes_key1_w0 */ + writel(key->b_key[0], BEE_BASE_ADDR + GPR8); + /* aes_key1_w1 */ + writel(key->b_key[1], BEE_BASE_ADDR + GPR9); + /* aes_key1_w2 */ + writel(key->b_key[2], BEE_BASE_ADDR + GPR10); + /* aes_key1_w3 */ + writel(key->b_key[3], BEE_BASE_ADDR + GPR11); + + value = GPR0_CTRL_CLK_EN | GPR0_CTRL_SFTRST_N | + GPR0_SEC_LEVEL_3 | GPR0_AES_KEY_SEL_SNVS | + GPR0_BEE_ENABLE | GPR0_CTRL_AES_MODE_CTR; + if (p->key_method == SOFT_KEY) + value = GPR0_CTRL_CLK_EN | GPR0_CTRL_SFTRST_N | + GPR0_SEC_LEVEL_3 | GPR0_AES_KEY_SEL_SOFT | + GPR0_BEE_ENABLE | GPR0_CTRL_AES_MODE_CTR; + writel(value, BEE_BASE_ADDR + GPR0); + } + + bee_lock(); + + printf("BEE is settings as: %s mode, %s %d key\n", + (p->mode == ECB_MODE) ? "ECB" : "CTR", + (p->key_method == SOFT_KEY) ? "SOFT" : "SNVS HW", + (p->mode == ECB_MODE) ? 128 : 256); + + return CMD_RET_SUCCESS; +} + +int bee_test(struct bee_parameters *p, int region) +{ + u32 result = 0, range, address; + int i, val; + /* + * Test instruction running in AES Region: + * int test(void) + * { + * return 0x55aa55aa; + * } + * Assemble: + * 0xe59f0000: ldr r0, [pc] + * 0xe12fff1e: bx lr + * 0x55aa55aa: 0x55aa55aa + */ + u32 inst[3] = {0xe59f0000, 0xe12fff1e, 0x55aa55aa}; + + /* Cache enabled? */ + if ((get_cr() & (CR_I | CR_C)) != (CR_I | CR_C)) { + printf("Enable dcache and icache first!\n"); + return CMD_RET_FAILURE; + } + + printf("Test Region %d\nBegin Data test: Writing... ", region); + + range = (region == 0) ? p->size1 : p->size2; + address = (region == 0) ? AES_REGION0_ADDR : AES_REGION1_ADDR; + for (i = 0; i < range; i = i + 4) + writel(i, address + i); + + printf("Finshed Write!\n"); + + flush_dcache_range(address, address + range); + + printf("Reading... "); + for (i = 0; i < range; i = i + 4) { + val = readl(address + i); + if (val != i) + result++; + } + printf("Finshed Read!\n"); + + if (result > 0) + printf("BEE Data Test check Failed!\n"); + else + printf("BEE Data Test Check Passed!\n"); + + for (i = 0; i < ARRAY_SIZE(inst); i++) + writel(inst[i], address + (i * 4)); + + flush_dcache_range(address, address + sizeof(inst)); + + val = ((int (*)(void))address)(); + + printf("\nBee Instruction test, Program:\n" + "int test(void)\n" + "{\n" + " return 0x55aa55aa;\n" + "}\n" + "Assemble:\n" + "0xe59f0000: ldr r0, [pc]\n" + "0xe12fff1e: bx lr\n" + "0x55aa55aa: 0x55aa55aa\n" + "Runnint at 0x%x\n", address); + if (val == 0x55aa55aa) + printf("Bee Instruction Test Passed!\n"); + else + printf("Bee Instruction Test Failed!\n"); + + return CMD_RET_SUCCESS; +} + +static int region_valid(u32 start, u32 size) +{ + if ((start < PHYS_SDRAM) || (start >= (start + size - 1)) || + (start >= (PHYS_SDRAM + PHYS_SDRAM_SIZE - 1))) { + printf("Invalid start 0x%x, size 0x%x\n", start, size); + return -EINVAL; + } + + if (size > SZ_512M) { + printf("The region size exceeds SZ_512M\n"); + return -EINVAL; + } + + if ((start & 0xFFFF) && (size & 0xFFFF)) { + printf("start or size not 64KB aligned!\n"); + return -EINVAL; + } + + if ((start + size - 1) >= (gd->start_addr_sp - CONFIG_STACKSIZE)) { + printf("Overlap with uboot execution environment!\n" + "Decrease size or start\n"); + return -EINVAL; + } + + return 0; +} + +static int do_bee_init(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 start, size; + int ret; + struct bee_parameters *p = ¶ + +#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) + enum dcache_option option = DCACHE_WRITETHROUGH; +#else + enum dcache_option option = DCACHE_WRITEBACK; +#endif + + if (argc > 5) + return CMD_RET_USAGE; + + /* Cache enabled? */ + if ((get_cr() & (CR_I | CR_C)) != (CR_I | CR_C)) { + /* + * Here we need icache and dcache both enabled, because + * we may take the protected region for instruction and + * data usage. And icache and dcache both enabled are + * better for performance. + */ + printf("Please enable dcache and icache first!\n"); + return CMD_RET_FAILURE; + } + + p->key_method = SOFT_KEY; + p->mode = ECB_MODE; + p->start1 = PHYS_SDRAM; + p->size1 = SZ_512M; + p->start2 = IRAM_BASE_ADDR; + p->size2 = IRAM_SIZE; + + if (argc == 2) { + p->key_method = (int)simple_strtoul(argv[1], NULL, 16); + p->mode = ECB_MODE; + p->start1 = PHYS_SDRAM; + p->size1 = SZ_512M; + } else if (argc == 3) { + p->key_method = (int)simple_strtoul(argv[1], NULL, 16); + p->mode = (int)simple_strtoul(argv[2], NULL, 10); + p->start1 = PHYS_SDRAM; + p->size1 = SZ_512M; + } else if ((argc == 4) || (argc == 5)) { + p->key_method = (int)simple_strtoul(argv[1], NULL, 16); + p->mode = (int)simple_strtoul(argv[2], NULL, 10); + start = (u32)simple_strtoul(argv[3], NULL, 16); + /* Default size that AES Region0 can protected */ + size = SZ_512M; + if (argc == 5) + size = (u32)simple_strtoul(argv[4], NULL, 16); + p->start1 = start; + p->size1 = size; + } + + if ((p->key_method != SOFT_KEY) && (p->key_method != SNVS_KEY)) + return CMD_RET_USAGE; + + if ((p->mode != ECB_MODE) && (p->mode != CTR_MODE)) + return CMD_RET_USAGE; + + /* + * No need to check region valid for IRAM, since it is fixed. + * Only check DRAM region here. + */ + if (region_valid(p->start1, p->size1)) + return CMD_RET_FAILURE; + + ret = bee_init(p); + if (ret) + return CMD_RET_FAILURE; + + /* + * Set DCACHE OFF to AES REGION0 and AES REGION1 first + * to avoid possible unexcepted cache settings. + */ + mmu_set_region_dcache_behaviour(AES_REGION0_ADDR, SZ_1G, DCACHE_OFF); + + mmu_set_region_dcache_behaviour(AES_REGION0_ADDR, p->size1, option); + + mmu_set_region_dcache_behaviour(AES_REGION1_ADDR, p->size2, option); + + printf("Access Region 0x%x - 0x%x to protect 0x%x - 0x%x\n" + "Do not directly access 0x%x - 0x%x\n" + "Access Region 0x%x - 0x%x to protect 0x%x - 0x%x\n" + "Do not directly access 0x%x - 0x%x\n", + AES_REGION0_ADDR, AES_REGION0_ADDR + p->size1 - 1, + p->start1, p->start1 + p->size1 - 1, + p->start1, p->start1 + p->size1 - 1, + AES_REGION1_ADDR, AES_REGION1_ADDR + p->size2 - 1, + p->start2, p->start2 + p->size2 - 1, + p->start2, p->start2 + p->size2 - 1); + + bee_inited = 1; + + return CMD_RET_SUCCESS; +} + +static int do_bee_test(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + int ret; + int region; + + if (bee_inited == 0) { + printf("Bee not initialized, run bee init first!\n"); + return CMD_RET_FAILURE; + } + if (argc > 2) + return CMD_RET_USAGE; + + region = 0; + if (argc == 2) + region = (int)simple_strtoul(argv[1], NULL, 16); + /* Only two regions are supported, 0 and 1 */ + if (region >= 2) + return CMD_RET_USAGE; + + ret = bee_test(¶, region); + if (ret) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +static cmd_tbl_t cmd_bmp_sub[] = { + U_BOOT_CMD_MKENT(init, 5, 0, do_bee_init, "", ""), + U_BOOT_CMD_MKENT(test, 2, 0, do_bee_test, "", ""), +}; + +static int do_bee_ops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + cmd_tbl_t *c; + + c = find_cmd_tbl(argv[1], &cmd_bmp_sub[0], ARRAY_SIZE(cmd_bmp_sub)); + + /* Drop off the 'bee' command argument */ + argc--; + argv++; + + if (c) + return c->cmd(cmdtp, flag, argc, argv); + else + return CMD_RET_USAGE; +} + +U_BOOT_CMD( + bee, CONFIG_SYS_MAXARGS, 1, do_bee_ops, + "BEE function test", + "init [key] [mode] [start] [size] - BEE block initial\n" + " key: 0 | 1, 0 means software key, 1 means SNVS random key\n" + " mode: 0 | 1, 0 means ECB mode, 1 means CTR mode\n" + " start: start address that you want to protect\n" + " size: The size of the area that you want to protect\n" + " start and end(start + size) addr both should be 64KB aligned.\n" + "\n" + " After initialization, the mapping:\n" + " 1. [0x10000000 - (0x10000000 + size - 1)] <--->\n" + " [start - (start + size - 1)]\n" + " Here [start - (start + size -1)] is fixed mapping to\n" + " [0x10000000 - (0x10000000 + size - 1)], whatever start is.\n" + " 2. [0x30000000 - (0x30000000 + IRAM_SIZE - 1)] <--->\n" + " [IRAM_BASE_ADDR - (IRAM_BASE_ADDR + IRAM_SIZE - 1)]\n" + "\n" + " Note: Here we only use AES region 0 to protect the DRAM\n" + " area that you specified, max size SZ_512M.\n" + " AES region 1 is used to protect IRAM area.\n" + " Example:\n" + " 1. bee init 1 1 0xa0000000 0x10000\n" + " Access 0x10000000 - 0x10010000 to protect 0xa0000000 - 0xa0010000\n" + " 2. bee init 1 1 0x80000000 0x20000\n" + " Access 0x10000000 - 0x10020000 to protect 0x80000000 - 0x80020000\n" + "\n" + " Default configuration if only `bee init` without any args:\n" + " 1. software key\n" + " 2. ECB mode\n" + " 3. Address protected:\n" + " Remapped Region0: PHYS_SDRAM - PHYS_SDRAM + SZ_512M\n" + " Remapped Region1: IRAM_BASE_ADDR - IRAM_BASE_ADDR + IRAM_SIZE\n" + " 4. Default Mapping for 6UL:\n" + " [0x10000000 - 0x2FFFFFFF] <-> [0x80000000 - 0x9FFFFFFF]\n" + " [0x30000000 - 0x3001FFFF] <-> [0x00900000 - 0x0091FFFF]\n" + "\n" + "bee test [region] - BEE function test\n" + " region: 0 | 1, 0 means region0, 1 means regions1\n" +); + diff --git a/arch/arm/include/asm/arch-mx6/mx6_bee.h b/arch/arm/include/asm/arch-mx6/mx6_bee.h new file mode 100644 index 0000000..eb51dfe --- /dev/null +++ b/arch/arm/include/asm/arch-mx6/mx6_bee.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#define GPR0 0x0 +#define GPR1 0x4 +#define GPR2 0x8 +#define GPR3 0xC +#define GPR4 0x10 +#define GPR5 0x14 +#define GPR6 0x18 +#define GPR7 0x1C +#define GPR8 0x20 +#define GPR9 0x24 +#define GPR10 0x28 +#define GPR11 0x2C + +#define GPR0_CTRL_CLK_EN_LOCK (1 << 31) +#define GPR0_CTRL_CLK_EN (1 << 15) +#define GPR0_CTRL_SFTRST_N_LOCK (1 << 30) +#define GPR0_CTRL_SFTRST (0 << 14) +#define GPR0_CTRL_SFTRST_N (1 << 14) +#define GPR0_CTRL_AES_MODE_LOCK (1 << 29) +#define GPR0_CTRL_AES_MODE_ECB (0 << 13) +#define GPR0_CTRL_AES_MODE_CTR (1 << 13) +#define GPR0_SEC_LEVEL_LOCK (3 << 24) +#define GPR0_SEC_LEVEL (3 << 8) +#define GPR0_AES_KEY_SEL_LOCK (1 << 20) +#define GPR0_AES_KEY_SEL_SNVS (0 << 4) +#define GPR0_AES_KEY_SEL_SOFT (1 << 4) +#define GPR0_BEE_ENABLE_LOCK (1 << 16) +#define GPR0_BEE_ENABLE (1 << 0) + +/* + * SECURITY LEVEL + * Non-Secure User | Non-Secure Spvr | Secure User | Secure Spvr + * Level + * (0)00 RD + WR RD + WR RD + WR RD + WR + * (1)01 None RD + WR RD + WR RD + WR + * (2)10 None None RD + WR RD + WR + * (3)11 None None None RD + WR + */ +#define GPR0_SEC_LEVEL_0 (0 << 8) +#define GPR0_SEC_LEVEL_1 (1 << 8) +#define GPR0_SEC_LEVEL_2 (2 << 8) +#define GPR0_SEC_LEVEL_3 (3 << 8) |