diff options
Diffstat (limited to 'drivers/hab/habv4.c')
-rw-r--r-- | drivers/hab/habv4.c | 315 |
1 files changed, 176 insertions, 139 deletions
diff --git a/drivers/hab/habv4.c b/drivers/hab/habv4.c index f0a087d1a8..a1d823ed25 100644 --- a/drivers/hab/habv4.c +++ b/drivers/hab/habv4.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2014, 2015 Marc Kleine-Budde <mkl@pengutronix.de> * Copyright (C) 2010 Freescale Semiconductor, Inc. * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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. */ #define pr_fmt(fmt) "HABv4: " fmt @@ -22,13 +11,17 @@ #include <hab.h> #include <init.h> #include <types.h> +#include <mmu.h> +#include <zero_page.h> +#include <linux/sizes.h> #include <linux/arm-smccc.h> #include <asm/cache.h> -#include <mach/generic.h> -#include <mach/imx8mq.h> +#include <mach/imx/generic.h> +#include <mach/imx/imx8mq.h> + +#include "hab.h" -#define HABV4_RVT_IMX28 0xffff8af8 #define HABV4_RVT_IMX6_OLD 0x00000094 #define HABV4_RVT_IMX6_NEW 0x00000098 #define HABV4_RVT_IMX6UL 0x00000100 @@ -76,18 +69,6 @@ enum hab_config { HAB_CONFIG_CLOSED = 0xcc, /* Secure IC */ }; -/* State definitions */ -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 */ -}; - enum hab_reason { HAB_REASON_RSN_ANY = 0x00, /* Match any reason */ HAB_REASON_UNS_COMMAND = 0x03, /* Unsupported command */ @@ -164,33 +145,79 @@ struct hab_header { uint8_t par; } __packed; -typedef enum hab_status hab_loader_callback_fn(void **start, uint32_t *bytes, const void *boot_data); +typedef enum hab_status hab_loader_callback_fn(void **start, size_t *bytes, const void *boot_data); +typedef void hab_image_entry_fn(void); +/* + * This table is constructed from the NXP manual "High Assurance Boot + * Version 4 Application Programming Interface Reference Manual", + * section 4.5 ROM vector table. Revision 1.4 + */ struct habv4_rvt { struct hab_header header; enum hab_status (*entry)(void); enum hab_status (*exit)(void); - enum hab_status (*check_target)(enum hab_target target, const void *start, uint32_t bytes); - void *(*authenticate_image)(uint8_t cid, uint32_t ivt_offset, void **start, uint32_t *bytes, hab_loader_callback_fn *loader); - enum hab_status (*run_dcd)(const void *dcd); - enum hab_status (*run_csf)(const void *csf, uint8_t cid); + enum hab_status (*check_target)(enum hab_target target, const void *start, size_t bytes); + void *(*authenticate_image)(uint8_t cid, ptrdiff_t ivt_offset, void **start, size_t *bytes, hab_loader_callback_fn *loader); + enum hab_status (*run_dcd)(const uint8_t *dcd); + enum hab_status (*run_csf)(const uint8_t *csf, uint8_t cid, uint32_t srkmask); enum hab_status (*assert)(enum hab_assertion assertion, const void *data, uint32_t count); - enum hab_status (*report_event)(enum hab_status status, uint32_t index, void *event, uint32_t *bytes); - enum hab_status (*report_status)(enum hab_config *config, enum hab_state *state); + enum hab_status (*report_event)(enum hab_status status, uint32_t index, uint8_t *event, size_t *bytes); + enum hab_status (*report_status)(enum hab_config *config, enum habv4_state *state); void (*failsafe)(void); + hab_image_entry_fn* (* authenticate_image_no_dcd)(uint8_t cid, ptrdiff_t ivt_offset, void **start, size_t *bytes, hab_loader_callback_fn *loader); + uint32_t (*get_version)(void); + enum hab_status (*authenticate_container)(uint8_t cid, ptrdiff_t ivt_offset, void **start, size_t *bytes, hab_loader_callback_fn *loader, uint32_t srkmask, int skip_dcd); } __packed; -#define FSL_SIP_HAB 0xC2000007 -#define FSL_SIP_HAB_AUTHENTICATE 0x00 -#define FSL_SIP_HAB_ENTRY 0x01 -#define FSL_SIP_HAB_EXIT 0x02 -#define FSL_SIP_HAB_REPORT_EVENT 0x03 -#define FSL_SIP_HAB_REPORT_STATUS 0x04 -#define FSL_SIP_HAB_FAILSAFE 0x05 -#define FSL_SIP_HAB_CHECK_TARGET 0x06 +#define FSL_SIP_HAB 0xC2000007 + +/* + * These values correspondent to the jump table found in the upstream + * TF-A version 2.10 `imx_hab_handler`, not all HAB rom functions are + * supported yet. + */ +enum hab_sip_cmd { + FSL_SIP_HAB_AUTHENTICATE = 0x00, + FSL_SIP_HAB_ENTRY = 0x01, + FSL_SIP_HAB_EXIT = 0x02, + FSL_SIP_HAB_REPORT_EVENT = 0x03, + FSL_SIP_HAB_REPORT_STATUS = 0x04, + FSL_SIP_HAB_FAILSAFE = 0x05, + FSL_SIP_HAB_CHECK_TARGET = 0x06, + FSL_SIP_HAB_GET_VERSION = 0x07, + FSL_SIP_HAB_AUTH_IMG_NO_DCD = 0x08, +}; + +static enum hab_status hab_sip_report_event(enum hab_status status, + uint32_t index, uint8_t *event, + size_t *bytes) +{ + struct arm_smccc_res res; + + v8_flush_dcache_range((unsigned long)bytes, + (unsigned long)bytes + sizeof(*bytes)); + + if (event) + v8_flush_dcache_range((unsigned long)event, + (unsigned long)event + *bytes); + + arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_REPORT_EVENT, + (unsigned long)index, (unsigned long)event, + (unsigned long)bytes, 0, 0, 0, &res); + + v8_inv_dcache_range((unsigned long)bytes, + (unsigned long)bytes + sizeof(*bytes)); + + if (event) + v8_inv_dcache_range((unsigned long)event, + (unsigned long)event + *bytes); + + return (enum hab_status)res.a0; +} static enum hab_status hab_sip_report_status(enum hab_config *config, - enum hab_state *state) + enum habv4_state *state) { struct arm_smccc_res res; @@ -213,30 +240,62 @@ static enum hab_status hab_sip_report_status(enum hab_config *config, return (enum hab_status)res.a0; } +static uint32_t hab_sip_get_version(void) +{ + struct arm_smccc_res res; + + arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_GET_VERSION, 0, 0, 0, 0, 0, 0, &res); + + return (uint32_t)res.a0; +} + +#define HABV4_EVENT_MAX_LEN 0x80 + +#define IMX8MQ_ROM_OCRAM_ADDRESS 0x9061C0 + static enum hab_status imx8m_read_sram_events(enum hab_status status, - uint32_t index, void *event, - uint32_t *bytes) + uint32_t index, uint8_t *event, + size_t *bytes) { struct hab_event_record *events[10]; int num_events = 0; - char *sram = (char *)0x9061c0; + u8 *sram; int i = 0; int internal_index = 0; - char *end = 0; + uint16_t ev_len; + u8 *end = 0; struct hab_event_record *search; + if (cpu_is_mx8mq()) + sram = (char *)IMX8MQ_ROM_OCRAM_ADDRESS; + else + return HAB_STATUS_FAILURE; + /* * AN12263 HABv4 Guidelines and Recommendations * recommends the address and size, however errors are usually contained * within the first bytes. Scan only the first few bytes to rule out * lots of false positives. + * The max event length is just a sanity check. */ - end = sram + 0x1a0; + end = sram + 0x1a0; while (sram < end) { if (*sram == 0xdb) { search = (void *)sram; - sram = sram + be16_to_cpu(search->hdr.len); + ev_len = be16_to_cpu(search->hdr.len); + if (ev_len > HABV4_EVENT_MAX_LEN) + break; + + sram += ev_len; + if (sram > end) + break; + + if (num_events == ARRAY_SIZE(events)) { + pr_warn("Discarding excess event\n"); + continue; + } + events[num_events] = search; num_events++; } else { @@ -244,7 +303,7 @@ static enum hab_status imx8m_read_sram_events(enum hab_status status, } } while (i < num_events) { - if (events[i]->status == status) { + if (events[i]->status >= status) { if (internal_index == index) { *bytes = sizeof(struct hab_event_record) + be16_to_cpu(events[i]->hdr.len); @@ -260,9 +319,19 @@ static enum hab_status imx8m_read_sram_events(enum hab_status status, return HAB_STATUS_FAILURE; } +static enum hab_status imx8m_report_event(enum hab_status status, + uint32_t index, uint8_t *event, + size_t *bytes) +{ + if (cpu_is_mx8mq()) + return imx8m_read_sram_events(status, index, event, bytes); + else + return hab_sip_report_event(status, index, event, bytes); +} + struct habv4_rvt hab_smc_ops = { .header = { .tag = 0xdd }, - .report_event = imx8m_read_sram_events, + .report_event = imx8m_report_event, .report_status = hab_sip_report_status, }; @@ -298,7 +367,7 @@ static const char *habv4_get_config_str(enum hab_config config) return "<unknown>"; } -static const char *habv4_get_state_str(enum hab_state state) +static const char *habv4_get_state_str(enum habv4_state state) { switch (state) { case HAB_STATE_INITIAL: @@ -456,7 +525,7 @@ static void habv4_display_event_record(struct hab_event_record *record) pr_err("Engine: %s (0x%02x)\n", habv4_get_engine_str(record->engine), record->engine); } -static void habv4_display_event(uint8_t *data, uint32_t len) +static void habv4_display_event(uint8_t *data, size_t len) { unsigned int i; @@ -503,14 +572,44 @@ static bool is_known_rng_fail_event(const uint8_t *data, size_t len) return false; } +static uint8_t *hab_get_event(const struct habv4_rvt *rvt, int index, size_t *len) +{ + enum hab_status err; + uint8_t *buf; + + err = rvt->report_event(HAB_STATUS_ANY, index, NULL, len); + if (err != HAB_STATUS_SUCCESS) + return NULL; + + buf = malloc(*len); + if (!buf) + return NULL; + + err = rvt->report_event(HAB_STATUS_ANY, index, buf, len); + if (err != HAB_STATUS_SUCCESS) { + pr_err("Unexpected HAB return code\n"); + free(buf); + return NULL; + } + + return buf; +} + +static int habv4_state = -EPROBE_DEFER; + +int habv4_get_state(void) +{ + return habv4_state; +} + static int habv4_get_status(const struct habv4_rvt *rvt) { - uint8_t data[256]; - uint32_t len; - uint32_t index = 0; + uint8_t *data; + size_t len; + int i; enum hab_status status; enum hab_config config = 0x0; - enum hab_state state = 0x0; + enum habv4_state state = 0x0; if (rvt->header.tag != HAB_TAG_RVT) { pr_err("ERROR - RVT not found!\n"); @@ -518,6 +617,8 @@ static int habv4_get_status(const struct habv4_rvt *rvt) } status = rvt->report_status(&config, &state); + habv4_state = state; + pr_info("Status: %s (0x%02x)\n", habv4_get_status_str(status), status); pr_info("Config: %s (0x%02x)\n", habv4_get_config_str(config), config); pr_info("State: %s (0x%02x)\n", habv4_get_state_str(state), state); @@ -527,56 +628,42 @@ static int habv4_get_status(const struct habv4_rvt *rvt) return 0; } - len = sizeof(data); - while (rvt->report_event(HAB_STATUS_WARNING, index, data, &len) == HAB_STATUS_SUCCESS) { + for (i = 0;; i++) { + data = hab_get_event(rvt, i, &len); + if (!data) + break; /* suppress RNG self-test fail events if they can be handled in software */ - if (IS_ENABLED(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_SELF_TEST) && - is_known_rng_fail_event(data, len)) { + if (is_known_rng_fail_event(data, len)) { pr_debug("RNG self-test failure detected, will run software self-test\n"); } else { - pr_err("-------- HAB warning Event %d --------\n", index); + pr_err("-------- HAB Event %d --------\n", i); pr_err("event data:\n"); habv4_display_event(data, len); } - len = sizeof(data); - index++; - } - - len = sizeof(data); - index = 0; - while (rvt->report_event(HAB_STATUS_FAILURE, index, data, &len) == HAB_STATUS_SUCCESS) { - pr_err("-------- HAB failure Event %d --------\n", index); - pr_err("event data:\n"); - - habv4_display_event(data, len); - len = sizeof(data); - index++; + free(data); } - /* Check reason for stopping */ - len = sizeof(data); - index = 0; - if (rvt->report_event(HAB_STATUS_ANY, index, NULL, &len) == HAB_STATUS_SUCCESS) - pr_err("ERROR: Recompile with larger event data buffer (at least %d bytes)\n\n", len); - return -EPERM; } -int imx6_hab_get_status(void) +static int imx6_hab_get_status(void) { const struct habv4_rvt *rvt; rvt = (void *)HABV4_RVT_IMX6_OLD; + OPTIMIZER_HIDE_VAR(rvt); if (rvt->header.tag == HAB_TAG_RVT) return habv4_get_status(rvt); rvt = (void *)HABV4_RVT_IMX6_NEW; + OPTIMIZER_HIDE_VAR(rvt); if (rvt->header.tag == HAB_TAG_RVT) return habv4_get_status(rvt); rvt = (void *)HABV4_RVT_IMX6UL; + OPTIMIZER_HIDE_VAR(rvt); if (rvt->header.tag == HAB_TAG_RVT) return habv4_get_status(rvt); @@ -585,73 +672,23 @@ int imx6_hab_get_status(void) return -EINVAL; } -static int imx8m_hab_get_status(void) -{ - return habv4_get_status(&hab_smc_ops); -} - -static int init_imx8m_hab_get_status(void) +int imx8m_hab_print_status(void) { - if (!cpu_is_mx8mq()) - /* can happen in multi-image builds and is not an error */ - return 0; + pr_info("ROM version: 0x%x\n", hab_sip_get_version()); - /* - * Nobody will check the return value if there were HAB errors, but the - * initcall will fail spectaculously with a strange error message. - */ - imx8m_hab_get_status(); + habv4_get_status(&hab_smc_ops); return 0; } -/* - * - * - * - */ -postmmu_initcall(init_imx8m_hab_get_status); - -static int init_imx6_hab_get_status(void) +int imx6_hab_print_status(void) { - if (!cpu_is_mx6()) - /* can happen in multi-image builds and is not an error */ - return 0; + remap_range(0x0, SZ_1M, MAP_CACHED); - /* - * Nobody will check the return value if there were HAB errors, but the - * initcall will fail spectaculously with a strange error message. - */ imx6_hab_get_status(); - return 0; -} - -/* - * Need to run before MMU setup because i.MX6 ROM code is mapped near 0x0, - * which will no longer be accessible when the MMU sets the zero page to - * faulting. - */ -postconsole_initcall(init_imx6_hab_get_status); - -int imx28_hab_get_status(void) -{ - const struct habv4_rvt *rvt = (void *)HABV4_RVT_IMX28; - - return habv4_get_status(rvt); -} - -static int init_imx28_hab_get_status(void) -{ - if (!cpu_is_mx28()) - /* can happen in multi-image builds and is not an error */ - return 0; - + zero_page_faulting(); + remap_range((void *)PAGE_SIZE, SZ_1M - PAGE_SIZE, MAP_UNCACHED); - /* nobody will check the return value if there were HAB errors, but the - * initcall will fail spectaculously with a strange error message. */ - imx28_hab_get_status(); return 0; } -/* i.MX28 ROM code can be run after MMU setup to make use of caching */ -postmmu_initcall(init_imx28_hab_get_status); |