From: Peng Fan Date: Wed, 25 Sep 2019 08:11:14 +0000 (+0000) Subject: imx8: Add AHAB secure boot support X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=7e2db742319beacdb23445f214e02c4c55efa680;p=u-boot.git imx8: Add AHAB secure boot support Add function and new command "auth_cntr" for secure boot support. When booting with life cycle set to OEM closed, we need to use this function to authenticate the OS container and load kernel & FDT from OS container to their destination. Also add image authentication call when loading container images. Users can set CONFIG_AHAB_BOOT=y to enable the feature. It is not set at default. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- diff --git a/arch/arm/mach-imx/imx8/Kconfig b/arch/arm/mach-imx/imx8/Kconfig index d17760e333..36c2e5224c 100644 --- a/arch/arm/mach-imx/imx8/Kconfig +++ b/arch/arm/mach-imx/imx8/Kconfig @@ -1,5 +1,10 @@ if ARCH_IMX8 +config AHAB_BOOT + bool "Support i.MX8 AHAB features" + help + This option enables the support for AHAB secure boot. + config IMX8 bool diff --git a/arch/arm/mach-imx/imx8/ahab.c b/arch/arm/mach-imx/imx8/ahab.c new file mode 100644 index 0000000000..cf3c7d762a --- /dev/null +++ b/arch/arm/mach-imx/imx8/ahab.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2019 NXP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define SEC_SECURE_RAM_BASE (0x31800000UL) +#define SEC_SECURE_RAM_END_BASE (SEC_SECURE_RAM_BASE + 0xFFFFUL) +#define SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE (0x60000000UL) + +#define SECO_PT 2U + +static inline bool check_in_dram(ulong addr) +{ + int i; + bd_t *bd = gd->bd; + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) { + if (bd->bi_dram[i].size) { + if (addr >= bd->bi_dram[i].start && + addr < (bd->bi_dram[i].start + bd->bi_dram[i].size)) + return true; + } + } + + return false; +} + +int authenticate_os_container(ulong addr) +{ + struct container_hdr *phdr; + int i, ret = 0; + int err; + sc_rm_mr_t mr; + sc_faddr_t start, end; + u16 length; + struct boot_img_t *img; + unsigned long s, e; + + if (addr % 4) { + puts("Error: Image's address is not 4 byte aligned\n"); + return -EINVAL; + } + + if (!check_in_dram(addr)) { + puts("Error: Image's address is invalid\n"); + return -EINVAL; + } + + phdr = (struct container_hdr *)addr; + if (phdr->tag != 0x87 && phdr->version != 0x0) { + printf("Error: Wrong container header\n"); + return -EFAULT; + } + + if (!phdr->num_images) { + printf("Error: Wrong container, no image found\n"); + return -EFAULT; + } + + length = phdr->length_lsb + (phdr->length_msb << 8); + + debug("container length %u\n", length); + memcpy((void *)SEC_SECURE_RAM_BASE, (const void *)addr, + ALIGN(length, CONFIG_SYS_CACHELINE_SIZE)); + + err = sc_seco_authenticate(-1, SC_MISC_AUTH_CONTAINER, + SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE); + if (err) { + printf("Authenticate container hdr failed, return %d\n", + err); + ret = -EIO; + goto exit; + } + + /* Copy images to dest address */ + for (i = 0; i < phdr->num_images; i++) { + img = (struct boot_img_t *)(addr + + sizeof(struct container_hdr) + + i * sizeof(struct boot_img_t)); + + debug("img %d, dst 0x%llx, src 0x%lx, size 0x%x\n", + i, img->dst, img->offset + addr, img->size); + + memcpy((void *)img->dst, (const void *)(img->offset + addr), + img->size); + + s = img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1); + e = ALIGN(img->dst + img->size, CONFIG_SYS_CACHELINE_SIZE); + + flush_dcache_range(s, e); + + /* Find the memreg and set permission for seco pt */ + err = sc_rm_find_memreg(-1, &mr, s, e); + if (err) { + printf("Not found memreg for image: %d, error %d\n", + i, err); + ret = -ENOMEM; + goto exit; + } + + err = sc_rm_get_memreg_info(-1, mr, &start, &end); + if (!err) + debug("memreg %u 0x%llx -- 0x%llx\n", mr, start, end); + + err = sc_rm_set_memreg_permissions(-1, mr, SECO_PT, + SC_RM_PERM_FULL); + if (err) { + printf("Set permission failed for img %d, error %d\n", + i, err); + ret = -EPERM; + goto exit; + } + + err = sc_seco_authenticate(-1, SC_MISC_VERIFY_IMAGE, + (1 << i)); + if (err) { + printf("Authenticate img %d failed, return %d\n", + i, err); + ret = -EIO; + } + + err = sc_rm_set_memreg_permissions(-1, mr, SECO_PT, + SC_RM_PERM_NONE); + if (err) { + printf("Remove permission failed for img %d, err %d\n", + i, err); + ret = -EPERM; + } + + if (ret) + goto exit; + } + +exit: + if (sc_seco_authenticate(-1, SC_MISC_REL_CONTAINER, 0) != SC_ERR_NONE) + printf("Error: release container failed!\n"); + + return ret; +} + +static int do_authenticate(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + ulong addr; + + if (argc < 2) + return CMD_RET_USAGE; + + addr = simple_strtoul(argv[1], NULL, 16); + + printf("Authenticate OS container at 0x%lx\n", addr); + + if (authenticate_os_container(addr)) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +static void display_life_cycle(u16 lc) +{ + printf("Lifecycle: 0x%04X, ", lc); + switch (lc) { + case 0x1: + printf("Pristine\n\n"); + break; + case 0x2: + printf("Fab\n\n"); + break; + case 0x8: + printf("Open\n\n"); + break; + case 0x20: + printf("NXP closed\n\n"); + break; + case 0x80: + printf("OEM closed\n\n"); + break; + case 0x100: + printf("Partial field return\n\n"); + break; + case 0x200: + printf("Full field return\n\n"); + break; + case 0x400: + printf("No return\n\n"); + break; + default: + printf("Unknown\n\n"); + break; + } +} + +#define AHAB_AUTH_CONTAINER_REQ 0x87 +#define AHAB_VERIFY_IMAGE_REQ 0x88 + +#define AHAB_NO_AUTHENTICATION_IND 0xee +#define AHAB_BAD_KEY_HASH_IND 0xfa +#define AHAB_INVALID_KEY_IND 0xf9 +#define AHAB_BAD_SIGNATURE_IND 0xf0 +#define AHAB_BAD_HASH_IND 0xf1 + +static void display_ahab_auth_event(u32 event) +{ + u8 cmd = (event >> 16) & 0xff; + u8 resp_ind = (event >> 8) & 0xff; + + switch (cmd) { + case AHAB_AUTH_CONTAINER_REQ: + printf("\tCMD = AHAB_AUTH_CONTAINER_REQ (0x%02X)\n", cmd); + printf("\tIND = "); + break; + case AHAB_VERIFY_IMAGE_REQ: + printf("\tCMD = AHAB_VERIFY_IMAGE_REQ (0x%02X)\n", cmd); + printf("\tIND = "); + break; + default: + return; + } + + switch (resp_ind) { + case AHAB_NO_AUTHENTICATION_IND: + printf("AHAB_NO_AUTHENTICATION_IND (0x%02X)\n\n", resp_ind); + break; + case AHAB_BAD_KEY_HASH_IND: + printf("AHAB_BAD_KEY_HASH_IND (0x%02X)\n\n", resp_ind); + break; + case AHAB_INVALID_KEY_IND: + printf("AHAB_INVALID_KEY_IND (0x%02X)\n\n", resp_ind); + break; + case AHAB_BAD_SIGNATURE_IND: + printf("AHAB_BAD_SIGNATURE_IND (0x%02X)\n\n", resp_ind); + break; + case AHAB_BAD_HASH_IND: + printf("AHAB_BAD_HASH_IND (0x%02X)\n\n", resp_ind); + break; + default: + printf("Unknown Indicator (0x%02X)\n\n", resp_ind); + break; + } +} + +static int do_ahab_status(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + int err; + u8 idx = 0U; + u32 event; + u16 lc; + + err = sc_seco_chip_info(-1, &lc, NULL, NULL, NULL); + if (err != SC_ERR_NONE) { + printf("Error in get lifecycle\n"); + return -EIO; + } + + display_life_cycle(lc); + + err = sc_seco_get_event(-1, idx, &event); + while (err == SC_ERR_NONE) { + printf("SECO Event[%u] = 0x%08X\n", idx, event); + display_ahab_auth_event(event); + + idx++; + err = sc_seco_get_event(-1, idx, &event); + } + + if (idx == 0) + printf("No SECO Events Found!\n\n"); + + return 0; +} + +static int confirm_close(void) +{ + puts("Warning: Please ensure your sample is in NXP closed state, " + "OEM SRK hash has been fused, \n" + " and you are able to boot a signed image successfully " + "without any SECO events reported.\n" + " If not, your sample will be unrecoverable.\n" + "\nReally perform this operation? \n"); + + if (confirm_yesno()) + return 1; + + puts("Ahab close aborted\n"); + return 0; +} + +static int do_ahab_close(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + int err; + u16 lc; + + if (!confirm_close()) + return -EACCES; + + err = sc_seco_chip_info(-1, &lc, NULL, NULL, NULL); + if (err != SC_ERR_NONE) { + printf("Error in get lifecycle\n"); + return -EIO; + } + + if (lc != 0x20) { + puts("Current lifecycle is NOT NXP closed, can't move to OEM closed\n"); + display_life_cycle(lc); + return -EPERM; + } + + err = sc_seco_forward_lifecycle(-1, 16); + if (err != SC_ERR_NONE) { + printf("Error in forward lifecycle to OEM closed\n"); + return -EIO; + } + + printf("Change to OEM closed successfully\n"); + + return 0; +} + +U_BOOT_CMD(auth_cntr, CONFIG_SYS_MAXARGS, 1, do_authenticate, + "autenticate OS container via AHAB", + "addr\n" + "addr - OS container hex address\n" +); + +U_BOOT_CMD(ahab_status, CONFIG_SYS_MAXARGS, 1, do_ahab_status, + "display AHAB lifecycle and events from seco", + "" +); + +U_BOOT_CMD(ahab_close, CONFIG_SYS_MAXARGS, 1, do_ahab_close, + "Change AHAB lifecycle to OEM closed", + "" +); diff --git a/arch/arm/mach-imx/imx8/parse-container.c b/arch/arm/mach-imx/imx8/parse-container.c index 32f78bdddf..b57e68e412 100644 --- a/arch/arm/mach-imx/imx8/parse-container.c +++ b/arch/arm/mach-imx/imx8/parse-container.c @@ -7,6 +7,67 @@ #include #include #include +#include + +#define SEC_SECURE_RAM_BASE 0x31800000UL +#define SEC_SECURE_RAM_END_BASE (SEC_SECURE_RAM_BASE + 0xFFFFUL) +#define SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE 0x60000000UL + +#define SECO_PT 2U + +#ifdef CONFIG_AHAB_BOOT +static int authenticate_image(struct boot_img_t *img, int image_index) +{ + sc_faddr_t start, end; + sc_rm_mr_t mr; + int err; + int ret = 0; + + debug("img %d, dst 0x%llx, src 0x%x, size 0x%x\n", + image_index, img->dst, img->offset, img->size); + + /* Find the memreg and set permission for seco pt */ + err = sc_rm_find_memreg(-1, &mr, + img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1), + ALIGN(img->dst + img->size, CONFIG_SYS_CACHELINE_SIZE)); + + if (err) { + printf("can't find memreg for image: %d, err %d\n", + image_index, err); + return -ENOMEM; + } + + err = sc_rm_get_memreg_info(-1, mr, &start, &end); + if (!err) + debug("memreg %u 0x%llx -- 0x%llx\n", mr, start, end); + + err = sc_rm_set_memreg_permissions(-1, mr, + SECO_PT, SC_RM_PERM_FULL); + if (err) { + printf("set permission failed for img %d, error %d\n", + image_index, err); + return -EPERM; + } + + err = sc_seco_authenticate(-1, SC_MISC_VERIFY_IMAGE, + 1 << image_index); + if (err) { + printf("authenticate img %d failed, return %d\n", + image_index, err); + ret = -EIO; + } + + err = sc_rm_set_memreg_permissions(-1, mr, + SECO_PT, SC_RM_PERM_NONE); + if (err) { + printf("remove permission failed for img %d, error %d\n", + image_index, err); + ret = -EPERM; + } + + return ret; +} +#endif static struct boot_img_t *read_auth_image(struct spl_image_info *spl_image, struct spl_load_info *info, @@ -45,6 +106,13 @@ static struct boot_img_t *read_auth_image(struct spl_image_info *spl_image, return NULL; } +#ifdef CONFIG_AHAB_BOOT + if (authenticate_image(&images[image_index], image_index)) { + printf("Failed to authenticate image %d\n", image_index); + return NULL; + } +#endif + return &images[image_index]; } @@ -54,7 +122,7 @@ static int read_auth_container(struct spl_image_info *spl_image, struct container_hdr *container = NULL; u16 length; u32 sectors; - int i, size; + int i, size, ret = 0; size = roundup(CONTAINER_HDR_ALIGNMENT, info->bl_len); sectors = size / info->bl_len; @@ -96,13 +164,27 @@ static int read_auth_container(struct spl_image_info *spl_image, return -EIO; } +#ifdef CONFIG_AHAB_BOOT + memcpy((void *)SEC_SECURE_RAM_BASE, (const void *)container, + ALIGN(length, CONFIG_SYS_CACHELINE_SIZE)); + + ret = sc_seco_authenticate(-1, SC_MISC_AUTH_CONTAINER, + SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE); + if (ret) { + printf("authenticate container hdr failed, return %d\n", ret); + return ret; + } +#endif + for (i = 0; i < container->num_images; i++) { struct boot_img_t *image = read_auth_image(spl_image, info, container, i, sector); - if (!image) - return -EINVAL; + if (!image) { + ret = -EINVAL; + goto end_auth; + } if (i == 0) { spl_image->load_addr = image->dst; @@ -110,7 +192,12 @@ static int read_auth_container(struct spl_image_info *spl_image, } } - return 0; +end_auth: +#ifdef CONFIG_AHAB_BOOT + if (sc_seco_authenticate(-1, SC_MISC_REL_CONTAINER, 0)) + printf("Error: release container failed!\n"); +#endif + return ret; } int spl_load_imx_container(struct spl_image_info *spl_image,