From 80f0208e66ef6c7efe9f01e1870b561fbb7d87c6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Lothar=20Wa=C3=9Fmann?= Date: Mon, 15 Jun 2015 10:11:10 +0200 Subject: [PATCH] mx53: add HAB support --- arch/arm/cpu/armv7/mx5/Makefile | 2 + arch/arm/cpu/armv7/mx5/hab.c | 348 ++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mx5/hab.h | 176 ++++++++++++++ board/karo/tx53/config.mk | 3 +- board/karo/tx53/tx53.c | 5 + 5 files changed, 533 insertions(+), 1 deletion(-) create mode 100644 arch/arm/cpu/armv7/mx5/hab.c create mode 100644 arch/arm/include/asm/arch-mx5/hab.h diff --git a/arch/arm/cpu/armv7/mx5/Makefile b/arch/arm/cpu/armv7/mx5/Makefile index d021842f68..93b5378b6b 100644 --- a/arch/arm/cpu/armv7/mx5/Makefile +++ b/arch/arm/cpu/armv7/mx5/Makefile @@ -9,3 +9,5 @@ obj-y := soc.o clock.o obj-y += lowlevel_init.o + +obj-$(CONFIG_SECURE_BOOT) += hab.o diff --git a/arch/arm/cpu/armv7/mx5/hab.c b/arch/arm/cpu/armv7/mx5/hab.c new file mode 100644 index 0000000000..8d5949f24a --- /dev/null +++ b/arch/arm/cpu/armv7/mx5/hab.c @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +HAB_FUNC(entry, hab_status_t) +HAB_FUNC(exit, hab_status_t) +HAB_FUNC5(authenticate_image, void *, uint8_t, size_t, void **, size_t *, hab_loader_callback_f_t) +HAB_FUNC2(report_status, hab_status_t, hab_config_t *, hab_state_t *) +HAB_FUNC4(report_event, hab_status_t, hab_status_t, uint32_t, uint8_t *, size_t *) +HAB_FUNC3(check_target, hab_status_t, uint8_t, const void *, size_t) +HAB_FUNC3(assert, hab_status_t, uint8_t, const void *, size_t) + +struct mx53_ivt { + u32 header; + u32 app_start_addr; + u32 rsrvd1; + void *dcd_ptr; + struct mx53_boot_data *boot_data; + void *self; + void *csf; + u32 rsrvd2; +}; + +struct mx53_boot_data { + void *start; + u32 length; + u32 plugin; +}; + +#define IVT_SIZE 0x20 +#define ALIGN_SIZE 0x400 +#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 + */ + +static inline int read_fuse(unsigned bank, unsigned row) +{ + struct iim_regs *iim_regs = (void *)IMX_IIM_BASE; + u32 *fuses; + + if (bank > ARRAY_SIZE(iim_regs->bank)) + return -EINVAL; + fuses = iim_regs->bank[bank].fuse_regs; + + debug("Reading fuse bank %u row %u @ %p\n", bank, row, &fuses[row]); + return readl(&fuses[row]); +} + +static bool is_hab_enabled(void) +{ +#ifdef DEBUG + static int first = 1; + + if (first) { + debug("rvt_base=%p\n", hab_rvt_base()); + debug("hab_rvt_entry=%p\n", hab_rvt_entry_p); + debug("hab_rvt_exit=%p\n", hab_rvt_exit_p); + debug("hab_rvt_check_target=%p\n", hab_rvt_check_target_p); + debug("hab_rvt_authenticate_image=%p\n", hab_rvt_authenticate_image_p); + debug("hab_rvt_report_event=%p\n", hab_rvt_report_event_p); + debug("hab_rvt_report_status=%p\n", hab_rvt_report_status_p); + debug("hab_rvt_assert=%p\n", hab_rvt_assert_p); + first = 0; + } +#endif + return read_fuse(0, 4) & (1 << 1); +} + +static void mx53_hab_display_event(uint8_t *event_data, size_t bytes) +{ + uint32_t i; + + if (!(event_data && bytes > 0)) + return; + + 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]); + } +} + +static inline void mx53_hab_pr_fuse_val(unsigned bank, unsigned row) +{ + printf(" %02x", read_fuse(bank, row)); +} + +static inline void mx53_hab_dump_srk_hash(void) +{ + int i; + + printf("SRK hash:\n\t"); + mx53_hab_pr_fuse_val(1, 1); + for (i = 1; i <= 31; i++) { + if (i % 8 == 0) + printf("\n\t"); + mx53_hab_pr_fuse_val(3, i); + } + printf("\n"); +} + +int get_hab_status(void) +{ + static uint32_t last_hab_event __attribute__((section(".data"))); + uint32_t index = last_hab_event; /* Loop index */ + uint8_t event_data[128]; /* Event data buffer */ + size_t bytes = sizeof(event_data); /* Event size in bytes */ + enum hab_config config; + enum hab_state state; + int ret; + int hab_debug = getenv_yesno("hab_debug") == 1; + + if (hab_debug) { + if (is_hab_enabled()) { + printf("Secure boot enabled\n\t"); + } else { + printf("Secure boot disabled\n"); + } + mx53_hab_dump_srk_hash(); + } + + /* Check HAB status */ + config = state = 0; /* ROM code assumes short enums! */ + ret = hab_rvt_report_status(&config, &state); + if (hab_debug || ret != HAB_SUCCESS) + printf("HAB Configuration: 0x%02x, HAB State: 0x%02x\n", + config, state); + if (ret != HAB_SUCCESS) { + /* Display HAB Error events */ + while (hab_rvt_report_event(HAB_STS_ANY, index, event_data, + &bytes) == HAB_SUCCESS) { + puts("\n"); + printf("--------- HAB Event %d -----------------\n", + index + 1); + puts("event data:\n"); + mx53_hab_display_event(event_data, bytes); + puts("\n"); + bytes = sizeof(event_data); + index++; + } + ret = index - last_hab_event; + last_hab_event = index; + } else { + /* Display message if no HAB events are found */ + if (hab_debug) + puts("No HAB Events Found!\n"); + ret = 0; + } + return ret; +} + +static inline hab_status_t hab_init(void) +{ + hab_status_t ret; + + ret = hab_rvt_entry(); + debug("hab_rvt_entry() returned %02x\n", ret); + if (ret != HAB_SUCCESS) { + printf("hab entry function failed: %02x\n", ret); + } + + return ret; +} + +static inline hab_status_t hab_exit(void) +{ + hab_status_t ret; + + ret = hab_rvt_exit(); + if (ret != HAB_SUCCESS) + printf("hab exit function failed: %02x\n", ret); + + return ret; +} + +static hab_status_t hab_check_target(hab_target_t type, uint32_t addr, size_t len) +{ + hab_status_t ret; + + ret = hab_init(); + if (ret != HAB_SUCCESS) + return ret; + + ret = hab_rvt_check_target(type, (void *)addr, len); + if (ret != HAB_SUCCESS) { + printf("check_target(0x%08x, 0x%08x) failed: %d\n", + addr, len, ret); + return ret; + } + ret = hab_exit(); + + if (ret == HAB_SUCCESS && get_hab_status() > 0) { + return HAB_FAILURE; + } + return ret; +} + +static hab_status_t hab_assert(uint32_t type, uint32_t addr, size_t len) +{ + hab_status_t ret; + + ret = hab_init(); + if (ret != HAB_SUCCESS) + return ret; + + ret = hab_rvt_assert(type, (void *)addr, len); + if (ret != HAB_SUCCESS) { + printf("assert(0x%08x, 0x%08x) failed: %d\n", + addr, len, ret); + return ret; + } + ret = hab_exit(); + + if (ret == HAB_SUCCESS && get_hab_status() > 0) { + return HAB_FAILURE; + } + return ret; +} + +static int do_hab_status(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + if (argc != 1) + return CMD_RET_USAGE; + + get_hab_status(); + + return CMD_RET_SUCCESS; +} + +static int do_hab_check_target(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + hab_target_t type = HAB_TGT_MEMORY; + uint32_t addr; + size_t len; + + if (argc < 3) + return CMD_RET_USAGE; + + addr = simple_strtoul(argv[1], NULL, 16); + len = simple_strtoul(argv[2], NULL, 16); + if (argc > 3) { + switch (argv[3][0]) { + case 'p': + case 'P': + type = HAB_TGT_PERIPHERAL; + break; + case 'm': + case 'M': + type = HAB_TGT_MEMORY; + break; + default: + printf("Invalid type '%s'\n", argv[3]); + return CMD_RET_USAGE; + } + } + if (hab_check_target(type, addr, len) != HAB_SUCCESS) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +static int do_hab_assert(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + uint32_t type = 0; + uint32_t addr; + size_t len; + + if (argc < 3) + return CMD_RET_USAGE; + + addr = simple_strtoul(argv[1], NULL, 16); + len = simple_strtoul(argv[2], NULL, 16); + if (argc > 3) { + type = simple_strtoul(argv[3], NULL, 16); + } + + if (hab_assert(type, addr, len) != HAB_SUCCESS) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + hab_status, CONFIG_SYS_MAXARGS, 1, do_hab_status, + "display HAB status", + "" + ); + +U_BOOT_CMD( + hab_check_target, 4, 0, do_hab_check_target, + "verify an address range via HAB", + "addr len [type]\n" + "\t\taddr -\taddress to verify\n" + "\t\tlen -\tlength of addr range to verify\n" + ); + +U_BOOT_CMD( + hab_assert, 4, 0, do_hab_assert, + "Test an assertion against the HAB audit log", + "addr len [type]\n" + "\t\taddr -\taddress to verify\n" + "\t\tlen -\tlength of addr range to verify\n" + ); diff --git a/arch/arm/include/asm/arch-mx5/hab.h b/arch/arm/include/asm/arch-mx5/hab.h new file mode 100644 index 0000000000..c71f664114 --- /dev/null +++ b/arch/arm/include/asm/arch-mx5/hab.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + * +*/ + +#ifndef __ARCH_MX5_HAB_H +#define __ARCH_MX5_HAB_H + +#ifdef CONFIG_SECURE_BOOT + +#include + +int get_hab_status(void); + +/* -------- 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; + +typedef enum hab_target { + HAB_TGT_MEMORY = 0x0f, /* Check memory white list */ + HAB_TGT_PERIPHERAL = 0xf0, /* Check peripheral white list*/ +} hab_target_t; + +enum HAB_FUNC_OFFSETS { + HAB_RVT_HEADER, + HAB_RVT_ENTRY, + HAB_RVT_EXIT, + HAB_RVT_CHECK_TARGET, + HAB_RVT_AUTHENTICATE_IMAGE, + HAB_RVT_RUN_DCD, + HAB_RVT_RUN_CSF, + HAB_RVT_ASSERT, + HAB_RVT_REPORT_EVENT, + HAB_RVT_REPORT_STATUS, + HAB_RVT_FAILSAFE, +}; + +/* Function prototype description */ +typedef hab_status_t hab_rvt_entry_t(void); + +typedef hab_status_t hab_rvt_exit_t(void); + +typedef hab_status_t hab_rvt_check_target_t(hab_target_t, const void *, + size_t); + +typedef hab_status_t hab_loader_callback_f_t(void**, size_t*, const void*); +typedef void *hab_rvt_authenticate_image_t(uint8_t, ptrdiff_t, + void **, size_t *, hab_loader_callback_f_t); + +typedef hab_status_t hab_rvt_assert_t(uint32_t, const void *, + size_t); + +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(enum hab_config *, + enum hab_state *); + +typedef void hapi_clock_init_t(void); + +#define HAB_RVT_BASE 0x00000094 + +static inline void **hab_rvt_base(void) +{ + uint32_t *base = (void *)0x94; + + if ((*base & 0xff0000ff) != cpu_to_be32(0xdd000040)) { + printf("Invalid RVT @ %p\n", base); + hang(); + } + return (void **)base; +} + +#define HAB_CID_ROM 0 /**< ROM Caller ID */ +#define HAB_CID_UBOOT 1 /**< UBOOT Caller ID*/ +/* ----------- end of HAB API updates ------------*/ + +#define hab_rvt_entry_p \ + ((hab_rvt_entry_t *)hab_rvt_base()[HAB_RVT_ENTRY]) + +#define hab_rvt_exit_p \ + ((hab_rvt_exit_t *)hab_rvt_base()[HAB_RVT_EXIT]) + +#define hab_rvt_check_target_p \ + ((hab_rvt_check_target_t*)hab_rvt_base()[HAB_RVT_CHECK_TARGET]) + +#define hab_rvt_authenticate_image_p \ + ((hab_rvt_authenticate_image_t *)hab_rvt_base()[HAB_RVT_AUTHENTICATE_IMAGE]) + +#define hab_rvt_assert_p \ + ((hab_rvt_assert_t*)hab_rvt_base()[HAB_RVT_ASSERT]) + +#define hab_rvt_report_event_p \ + ((hab_rvt_report_event_t*)hab_rvt_base()[HAB_RVT_REPORT_EVENT]) + +#define hab_rvt_report_status_p \ + ((hab_rvt_report_status_t*)hab_rvt_base()[HAB_RVT_REPORT_STATUS]) + +#define HAB_FUNC(n, rt) \ +static inline rt hab_rvt_##n(void) \ +{ \ + if (hab_rvt_base() == NULL) \ + return (rt)-1; \ + return hab_rvt_##n##_p(); \ +} \ + +#define HAB_FUNC2(n, rt, t1, t2) \ +static inline rt hab_rvt_##n(t1 p1, t2 p2) \ +{ \ + if (hab_rvt_base() == NULL) \ + return (rt)-1; \ + return hab_rvt_##n##_p(p1, p2); \ +} + +#define HAB_FUNC3(n, rt, t1, t2, t3) \ +static inline rt hab_rvt_##n(t1 p1, t2 p2, t3 p3) \ +{ \ + if (hab_rvt_base() == NULL) \ + return (rt)-1; \ + return hab_rvt_##n##_p(p1, p2, p3); \ +} + +#define HAB_FUNC4(n, rt, t1, t2, t3, t4) \ +static inline rt hab_rvt_##n(t1 p1, t2 p2, t3 p3, t4 p4) \ +{ \ + if (hab_rvt_base() == NULL) \ + return (rt)-1; \ + return hab_rvt_##n##_p(p1, p2, p3, p4); \ +} + +#define HAB_FUNC5(n, rt, t1, t2, t3, t4, t5) \ +static inline rt hab_rvt_##n(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \ +{ \ + if (hab_rvt_base() == NULL) \ + return (rt)-1; \ + return hab_rvt_##n##_p(p1, p2, p3, p4, p5); \ +} + +#else /* CONFIG_SECURE_BOOT */ + +static inline int get_hab_status(void) +{ + return 0; +} + +#endif /* CONFIG_SECURE_BOOT */ +#endif /* __ARCH_MX5_HAB_H */ diff --git a/board/karo/tx53/config.mk b/board/karo/tx53/config.mk index 0ecbf32915..09d6709dfe 100644 --- a/board/karo/tx53/config.mk +++ b/board/karo/tx53/config.mk @@ -1,6 +1,7 @@ # stack is allocated below CONFIG_SYS_TEXT_BASE -CONFIG_SYS_TEXT_BASE := 0x70100000 +CONFIG_SYS_TEXT_BASE := 0x700ff000 __HAVE_ARCH_GENERIC_BOARD := y PLATFORM_CPPFLAGS += -Werror LOGO_BMP = logos/karo.bmp +OBJCOPYFLAGS += -j .pad diff --git a/board/karo/tx53/tx53.c b/board/karo/tx53/tx53.c index 6c0a302315..299a647b16 100644 --- a/board/karo/tx53/tx53.c +++ b/board/karo/tx53/tx53.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ DECLARE_GLOBAL_DATA_PTR; PAD_CTL_SRE_FAST | PAD_CTL_PUS_47K_UP) char __uboot_img_end[0] __attribute__((section(".__uboot_img_end"))); +char __csf_data[0] __attribute__((section(".__csf_data"))); static iomux_v3_cfg_t tx53_pads[] = { /* NAND flash pads are set up in lowlevel_init.S */ @@ -1378,6 +1380,9 @@ exit: gpio_set_value(TX53_RESET_OUT_GPIO, 1); clear_ctrlc(); + + get_hab_status(); + return ret; } -- 2.39.2