aboutsummaryrefslogtreecommitdiff
path: root/src/arch/arm64/armv8
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/arm64/armv8')
-rw-r--r--src/arch/arm64/armv8/Makefile.inc4
-rw-r--r--src/arch/arm64/armv8/lib/Makefile.inc5
-rw-r--r--src/arch/arm64/armv8/secmon/Makefile.inc49
-rw-r--r--src/arch/arm64/armv8/secmon/secmon_init.c83
-rw-r--r--src/arch/arm64/armv8/secmon_loader.c111
5 files changed, 252 insertions, 0 deletions
diff --git a/src/arch/arm64/armv8/Makefile.inc b/src/arch/arm64/armv8/Makefile.inc
index 52663b85c5..955ca67602 100644
--- a/src/arch/arm64/armv8/Makefile.inc
+++ b/src/arch/arm64/armv8/Makefile.inc
@@ -21,6 +21,8 @@
subdirs-y += lib/
+subdirs-$(CONFIG_ARCH_USE_SECURE_MONITOR) += secmon/
+
armv8_flags = -march=armv8-a -I$(src)/arch/arm64/include/armv8/ -D__COREBOOT_ARM_ARCH__=8
armv8_asm_flags = $(armv8_flags)
@@ -71,6 +73,8 @@ ramstage-y += cpu.S
ramstage-y += exception.c
ramstage-y += mmu.c
+ramstage-$(CONFIG_ARCH_USE_SECURE_MONITOR) += secmon_loader.c
+
ramstage-c-ccopts += $(armv8_flags)
ramstage-S-ccopts += $(armv8_asm_flags)
diff --git a/src/arch/arm64/armv8/lib/Makefile.inc b/src/arch/arm64/armv8/lib/Makefile.inc
index fe08662841..0622593e4f 100644
--- a/src/arch/arm64/armv8/lib/Makefile.inc
+++ b/src/arch/arm64/armv8/lib/Makefile.inc
@@ -32,4 +32,9 @@ endif
ifeq ($(CONFIG_ARCH_RAMSTAGE_ARMV8_64),y)
ramstage-y += $(lib_access)
+
+ifeq ($(CONFIG_ARCH_USE_SECURE_MONITOR),y)
+secmon-y += $(lib_access)
+endif
+
endif
diff --git a/src/arch/arm64/armv8/secmon/Makefile.inc b/src/arch/arm64/armv8/secmon/Makefile.inc
new file mode 100644
index 0000000000..b140941e8b
--- /dev/null
+++ b/src/arch/arm64/armv8/secmon/Makefile.inc
@@ -0,0 +1,49 @@
+################################################################################
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2014 Google 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; version 2 of the License.
+##
+## 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.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+##
+################################################################################
+
+$(eval $(call create_class_compiler,secmon,arm64))
+
+SECMON_DIR=$(obj)/arch/arm64/armv8/secmon
+SECMON_SRC=$(SECMON_DIR)/secmon
+SECMON_OBJ=$(SECMON_DIR)/secmon.o
+SECMON_ELF=$(SECMON_DIR)/secmon.elf
+SECMON_RMOD=$(SECMON_DIR)/secmon.elf.rmod
+SECMON_RAMSTAGE=$(SECMON_DIR)/secmon.ramstage.o
+
+secmon-c-ccopts += -I$(src)/arch/arm64/include/armv8/ -include $(src)/include/kconfig.h -D__SECMON__
+secmon-S-ccopts += -I$(src)/arch/arm64/include/armv8/ -include $(src)/include/kconfig.h -D__SECMON__
+
+secmon-y += secmon_init.c
+secmon-y += ../../transition_asm.S ../../transition.c
+
+ramstage-srcs += $(SECMON_SRC)
+
+$(SECMON_OBJ): $$(secmon-objs)
+ $(CC_secmon) $(LDFLAGS) -nostdlib -r -o $@ $^
+
+$(eval $(call rmodule_link,$(SECMON_ELF), $(SECMON_OBJ), 0,arm64))
+
+$(SECMON_SRC): $(SECMON_RMOD)
+ $(OBJCOPY_secmon) -O binary $< $@
+
+$(SECMON_RAMSTAGE): $(SECMON_SRC)
+ @printf " OBJCOPY $(subst $(obj)/,,$(@))\n"
+ cd $(dir $@); $(OBJCOPY_secmon) -I binary $(notdir $<) -O elf64-littleaarch64 -B aarch64 $(notdir $@) \ No newline at end of file
diff --git a/src/arch/arm64/armv8/secmon/secmon_init.c b/src/arch/arm64/armv8/secmon/secmon_init.c
new file mode 100644
index 0000000000..e8bdd82d29
--- /dev/null
+++ b/src/arch/arm64/armv8/secmon/secmon_init.c
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Google 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; version 2 of
+ * the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <arch/barrier.h>
+#include <arch/io.h>
+#include <arch/lib_helpers.h>
+#include <arch/secmon.h>
+#include <arch/transition.h>
+#include <console/console.h>
+#include <rmodule.h>
+#include <stddef.h>
+
+static void secmon_wait(void)
+{
+ /*
+ * TODO(furquan): This should be a point of no-return. Once we have PSCI
+ * support we need to respond to kernel calls
+ */
+ while (1)
+ wfe();
+}
+
+static void secmon_el3_init(void)
+{
+ uint32_t scr;
+
+ scr = raw_read_scr_el3();
+
+ /* Enable SMC */
+ scr &= ~(SCR_SMC_MASK);
+ scr |= SCR_SMC_ENABLE;
+
+ raw_write_scr_el3(scr);
+ isb();
+}
+
+static void secmon_init(void *arg)
+{
+ struct exc_state exc_state;
+ struct secmon_params *params = arg;
+
+ printk(BIOS_DEBUG, "ARM64: secmon in %s\n", __func__);
+
+ secmon_el3_init();
+
+ /*
+ * Check if the arg is non-NULL
+ * 1) If yes, we make an EL2 transition to that entry point
+ * 2) If no, we just wait
+ */
+ if (params == NULL) {
+ secmon_wait();
+ }
+
+ memset(&exc_state, 0, sizeof(exc_state));
+ exc_state.elx.spsr = get_eret_el(params->elx_el, params->elx_mode);
+
+ transition_with_entry(params->entry, params->arg, &exc_state);
+}
+
+/*
+ * This variable holds entry point for secmon init code. Once the stacks are
+ * setup by the stage_entry.S, it jumps to c_entry.
+ */
+void (*c_entry)(void*) = &secmon_init;
diff --git a/src/arch/arm64/armv8/secmon_loader.c b/src/arch/arm64/armv8/secmon_loader.c
new file mode 100644
index 0000000000..066f1c18a8
--- /dev/null
+++ b/src/arch/arm64/armv8/secmon_loader.c
@@ -0,0 +1,111 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Google 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; version 2 of
+ * the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * secmon_loader.c: Responsible for loading the rmodule, providing entry point
+ * and parameter location for the rmodule.
+ */
+
+#include <arch/lib_helpers.h>
+#include <arch/secmon.h>
+#include <console/console.h>
+#include <rmodule.h>
+#include <string.h>
+
+/* SECMON entry point encoded as an rmodule */
+extern unsigned char _binary_secmon_start[];
+
+typedef void (*secmon_entry_t)(struct secmon_params *);
+
+void __attribute__((weak)) soc_get_secmon_base_size(uint64_t *secmon_base, size_t *secmon_size)
+{
+ /* Default weak implementation initializes to 0 */
+ *secmon_base = 0;
+ *secmon_size = 0;
+}
+
+static secmon_entry_t secmon_load_rmodule(void)
+{
+ struct rmodule secmon_mod;
+ uint64_t secmon_base;
+ size_t secmon_size;
+
+ /* Get base address and size of the area available for secure monitor
+ * rmodule.
+ */
+ soc_get_secmon_base_size(&secmon_base, &secmon_size);
+
+ if ((secmon_base == 0) || (secmon_size == 0)) {
+ printk(BIOS_ERR, "ARM64: secmon_base / secmon_size invalid\n");
+ return NULL;
+ }
+
+ printk(BIOS_DEBUG,"secmon_base:%lx,secmon_size:%lx\n",
+ (unsigned long)secmon_base, (unsigned long)secmon_size);
+
+ /* Fail if can't parse secmon module */
+ if (rmodule_parse(&_binary_secmon_start, &secmon_mod)) {
+ printk(BIOS_ERR, "ARM64: secmon_mod not found\n");
+ return NULL;
+ }
+
+ /* Load rmodule at secmon_base */
+ if (rmodule_load((void *)secmon_base, &secmon_mod)) {
+ printk(BIOS_ERR, "ARM64:secmon_mod cannot load\n");
+ return NULL;
+ }
+
+ /* Identify the entry point for secure monitor */
+ return rmodule_entry(&secmon_mod);
+}
+
+void secmon_run(void (*entry)(void *), void *cb_tables)
+{
+ struct secmon_params params;
+ uint32_t scr;
+
+ printk(BIOS_SPEW, "payload jump @ %p\n", entry);
+
+ if (get_current_el() != EL3) {
+ printk(BIOS_DEBUG, "Secmon Error: Can only be loaded in EL3\n");
+ return;
+ }
+
+ secmon_entry_t doit = secmon_load_rmodule();
+
+ if (doit == NULL)
+ die("ARM64 Error: secmon load error");
+
+ printk(BIOS_DEBUG, "ARM64: Loaded the el3 monitor...jumping to %p\n",
+ doit);
+
+ params.entry = entry;
+ params.arg = cb_tables;
+ params.elx_el = EL2;
+ params.elx_mode = SPSR_USE_L;
+
+ /* We want to enforce the following policies:
+ * NS bit is set for lower EL
+ */
+ scr = raw_read_scr_el3();
+ scr |= SCR_NS;
+ raw_write_scr_el3(scr);
+
+ doit(&params);
+}