summaryrefslogtreecommitdiffstats
path: root/drivers/hab/habv4.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hab/habv4.c')
-rw-r--r--drivers/hab/habv4.c256
1 files changed, 145 insertions, 111 deletions
diff --git a/drivers/hab/habv4.c b/drivers/hab/habv4.c
index d58768fa54..a1d823ed25 100644
--- a/drivers/hab/habv4.c
+++ b/drivers/hab/habv4.c
@@ -1,16 +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.
*
- * 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
@@ -19,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
@@ -73,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 */
@@ -161,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;
@@ -210,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 {
@@ -241,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);
@@ -257,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,
};
@@ -295,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:
@@ -453,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;
@@ -500,7 +572,7 @@ 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, int *len)
+static uint8_t *hab_get_event(const struct habv4_rvt *rvt, int index, size_t *len)
{
enum hab_status err;
uint8_t *buf;
@@ -523,14 +595,21 @@ static uint8_t *hab_get_event(const struct habv4_rvt *rvt, int index, int *len)
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;
- uint32_t len;
+ 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");
@@ -538,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);
@@ -567,19 +648,22 @@ static int habv4_get_status(const struct habv4_rvt *rvt)
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);
@@ -588,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);