[coreboot-gerrit] New patch to review for coreboot: 90881e5 arm64: add smc layer to secmon

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Fri Mar 27 10:10:51 CET 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/9092

-gerrit

commit 90881e52341a03355dd6de0c3381d259d93d3869
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Wed Sep 17 01:16:20 2014 -0500

    arm64: add smc layer to secmon
    
    In order to process PSCI commands SMC instructions need to be
    serviced. Provide a simple way for users of SMC to register their
    handlers by function.
    
    The SMC layer hooks into the exception processing, however it only
    processes AARCH64 SMC calls. All others are ignored.
    
    BUG=chrome-os-partner:32112
    BRANCH=None
    TEST=Added nop smc call to depthcharge. SMC handled and continue booting
         to kernel.
    
    Change-Id: I378f13c29220ff9f37040f094bf9cfb69259af0c
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: 76d2febc50397348b68d38532b8f37e2b3cf6a30
    Original-Change-Id: Ieaa29fa883b9f9d55fc62ba92a1d45452296efa4
    Original-Signed-off-by: Aaron Durbin <adurbin at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/218846
    Original-Reviewed-by: Furquan Shaikh <furquan at chromium.org>
    Original-Commit-Queue: Furquan Shaikh <furquan at chromium.org>
    Original-Tested-by: Furquan Shaikh <furquan at chromium.org>
---
 src/arch/arm64/armv8/secmon/Makefile.inc  |   3 +-
 src/arch/arm64/armv8/secmon/secmon_init.c |  17 +---
 src/arch/arm64/armv8/secmon/smc.c         | 159 ++++++++++++++++++++++++++++++
 src/arch/arm64/include/arch/smc.h         | 122 +++++++++++++++++++++++
 4 files changed, 285 insertions(+), 16 deletions(-)

diff --git a/src/arch/arm64/armv8/secmon/Makefile.inc b/src/arch/arm64/armv8/secmon/Makefile.inc
index 5dadfa9..040f568 100644
--- a/src/arch/arm64/armv8/secmon/Makefile.inc
+++ b/src/arch/arm64/armv8/secmon/Makefile.inc
@@ -32,6 +32,7 @@ secmon-c-ccopts += -I$(src)/arch/arm64/include/armv8/ -include $(src)/include/kc
 secmon-S-ccopts += -I$(src)/arch/arm64/include/armv8/ -include $(src)/include/kconfig.h -D__SECMON__
 
 secmon-y += secmon_init.c
+secmon-y += smc.c
 secmon-y += ../exception.c
 secmon-y += ../../cpu.c
 secmon-y += ../../transition_asm.S ../../transition.c
@@ -48,4 +49,4 @@ $(SECMON_SRC): $(SECMON_RMOD)
 
 $(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
+		    cd $(dir $@); $(OBJCOPY_secmon) -I binary $(notdir $<) -O elf64-littleaarch64 -B aarch64 $(notdir $@)
diff --git a/src/arch/arm64/armv8/secmon/secmon_init.c b/src/arch/arm64/armv8/secmon/secmon_init.c
index 660d6d4..de433bb 100644
--- a/src/arch/arm64/armv8/secmon/secmon_init.c
+++ b/src/arch/arm64/armv8/secmon/secmon_init.c
@@ -24,6 +24,7 @@
 #include <arch/exception.h>
 #include <arch/lib_helpers.h>
 #include <arch/secmon.h>
+#include <arch/smc.h>
 #include <arch/transition.h>
 #include <console/console.h>
 #include <rmodule.h>
@@ -40,20 +41,6 @@ static void cpu_init(int bsp)
 		cpu_set_bsp();
 }
 
-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(struct secmon_params *params, int bsp)
 {
 	struct exc_state exc_state;
@@ -61,7 +48,7 @@ static void secmon_init(struct secmon_params *params, int bsp)
 	exception_hwinit();
 	cpu_init(bsp);
 
-	secmon_el3_init();
+	smc_init();
 
 	/*
 	 * Check if the arg is non-NULL
diff --git a/src/arch/arm64/armv8/secmon/smc.c b/src/arch/arm64/armv8/secmon/smc.c
new file mode 100644
index 0000000..3bb52f0
--- /dev/null
+++ b/src/arch/arm64/armv8/secmon/smc.c
@@ -0,0 +1,159 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 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 <string.h>
+#include <stdlib.h>
+#include <arch/cpu.h>
+#include <arch/smc.h>
+#include <arch/exception.h>
+#include <arch/lib_helpers.h>
+#include <console/console.h>
+
+enum {
+	EC_SMC32 = 0x13,
+	EC_SMC64 = 0x17,
+
+	SMC_NUM_RANGES = 8,
+};
+
+struct smc_range {
+	uint32_t func_begin;
+	uint32_t func_end;
+	int (*handler)(struct smc_call *);
+};
+
+struct smc_ranges {
+	size_t used;
+	struct smc_range handlers[SMC_NUM_RANGES];
+};
+
+static struct smc_ranges smc_functions;
+
+static struct smc_range *smc_handler_by_function(uint32_t fid)
+{
+	int i;
+
+	for (i = 0; i < smc_functions.used; i++) {
+		struct smc_range *r = &smc_functions.handlers[i];
+
+		if (fid >= r->func_begin && fid <= r->func_end)
+			return r;
+	}
+
+	return NULL;
+}
+
+int smc_register_range(uint32_t min, uint32_t max, int (*h)(struct smc_call *))
+{
+	struct smc_range *r;
+
+	if (smc_functions.used == SMC_NUM_RANGES)
+		return -1;
+
+	if (min > max)
+		return -1;
+
+	/* This check isn't exhaustive but it's fairly quick. */
+	if (smc_handler_by_function(min) || smc_handler_by_function(max))
+		return -1;
+
+	r = &smc_functions.handlers[smc_functions.used];
+	r->func_begin = min;
+	r->func_end = max;
+	r->handler = h;
+	smc_functions.used++;
+
+	return 0;
+}
+
+static int smc_cleanup(struct exc_state *state, struct smc_call *smc, int ret)
+{
+	memcpy(&state->regs.x, &smc->results, ARRAY_SIZE(smc->results));
+
+	return ret;
+}
+
+static int smc_return_with_error(struct exc_state *state, struct smc_call *smc)
+{
+	smc32_return(smc, SMC_UNKNOWN_FUNC);
+	return smc_cleanup(state, smc, EXC_RET_HANDLED);
+}
+
+static int smc_handler(struct exc_state *state, uint64_t vector_id)
+{
+	struct smc_call smc_storage;
+	struct smc_call *smc = &smc_storage;
+	uint32_t exception_class;
+	uint32_t esr;
+	struct smc_range *r;
+
+	memcpy(&smc->args, &state->regs.x, ARRAY_SIZE(smc->args));
+	memcpy(&smc->results, &state->regs.x, ARRAY_SIZE(smc->results));
+
+	esr = raw_read_esr_el3();
+	exception_class = (esr >> 26) & 0x3f;
+
+	/* No support for 32-bit SMC calls. */
+	if (exception_class == EC_SMC32)
+		smc_return_with_error(state, smc);
+
+	/* Check to ensure this is an SMC from aarch64. */
+	if (exception_class != EC_SMC64)
+		return EXC_RET_IGNORED;
+
+	/* Ensure immediate value is 0. */
+	if ((esr & 0xffff) != 0)
+		smc_return_with_error(state, smc);
+
+	r = smc_handler_by_function(smc_function_id(smc));
+
+	if (r != NULL) {
+		if (!r->handler(smc))
+			return smc_cleanup(state, smc, EXC_RET_HANDLED);
+	}
+
+	return smc_return_with_error(state, smc);
+}
+
+/* SMC calls can be generated by 32-bit or 64-bit code. */
+static struct exception_handler smc_handler64 = {
+	.handler = &smc_handler,
+};
+
+static struct exception_handler smc_handler32 = {
+	.handler = &smc_handler,
+};
+
+void smc_init(void)
+{
+	uint32_t scr;
+
+	/* Enable SMC */
+	scr = raw_read_scr_el3();
+	scr &= ~(SCR_SMC_MASK);
+	scr |= SCR_SMC_ENABLE;
+	raw_write_scr_el3(scr);
+
+	if (!cpu_is_bsp())
+		return;
+
+	/* Register SMC handlers. */
+	exception_handler_register(EXC_VID_LOW64_SYNC, &smc_handler64);
+	exception_handler_register(EXC_VID_LOW32_SYNC, &smc_handler32);
+}
diff --git a/src/arch/arm64/include/arch/smc.h b/src/arch/arm64/include/arch/smc.h
new file mode 100644
index 0000000..288459e
--- /dev/null
+++ b/src/arch/arm64/include/arch/smc.h
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 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
+ */
+
+#ifndef __ARCH_SMC_H__
+#define __ARCH_SMC_H__
+
+#include <stdint.h>
+
+enum {
+	FUNC_ID_CALL_TYPE_SHIFT = 31,
+	FUNC_ID_CALL_TYPE_MASK = (1 << FUNC_ID_CALL_TYPE_SHIFT),
+	FUNC_ID_FASTCALL = (1 << FUNC_ID_CALL_TYPE_SHIFT),
+	FUNC_ID_STDCALL = (0 << FUNC_ID_CALL_TYPE_SHIFT),
+
+	FUNC_ID_CALL_CONVENTION_SHIFT = 30,
+	FUNC_ID_CALL_CONVENTION_MASK = (1 << FUNC_ID_CALL_CONVENTION_SHIFT),
+	FUNC_ID_SMC32 = (0 << FUNC_ID_CALL_CONVENTION_SHIFT),
+	FUNC_ID_SMC64 = (1 << FUNC_ID_CALL_CONVENTION_SHIFT),
+
+	FUNC_ID_ENTITY_SHIFT = 24,
+	FUNC_ID_ENTITY_MASK = (0x3f << FUNC_ID_ENTITY_SHIFT),
+
+	FUNC_ID_FUNC_NUMBER_SHIFT = 0,
+	FUNC_ID_FUNC_NUMBER_MASK = (0xffff << FUNC_ID_FUNC_NUMBER_SHIFT),
+
+	FUNC_ID_MASK = FUNC_ID_CALL_TYPE_MASK | FUNC_ID_CALL_CONVENTION_MASK |
+	               FUNC_ID_ENTITY_MASK | FUNC_ID_FUNC_NUMBER_MASK,
+
+	SMC_NUM_ARGS = 8, /* The last is optional hypervisor id. */
+	SMC_NUM_RESULTS = 4,
+
+	SMC_UNKNOWN_FUNC = 0xffffffff,
+};
+
+#define SMC_FUNC(entity, number, call_convention, call_type) \
+	((call_type) | (call_convention) | \
+		((entity) << FUNC_ID_ENTITY_SHIFT) | (number))
+
+#define SMC_FUNC_FAST(entity, number, call_convention) \
+	SMC_FUNC((entity), (number), (call_convention), FUNC_ID_FASTCALL)
+
+#define SMC_FUNC_FAST32(entity, number) \
+	SMC_FUNC_FAST((entity), (number), FUNC_ID_SMC32)
+
+#define SMC_FUNC_FAST64(entity, number) \
+	SMC_FUNC_FAST((entity), (number), FUNC_ID_SMC64)
+
+struct smc_call {
+	uint64_t args[SMC_NUM_ARGS];
+	uint64_t results[SMC_NUM_RESULTS];
+};
+
+/* SMC immediate value needs to be 0. */
+/* Check mod AARCHx mode against calling convention. */
+
+static inline uint64_t smc64_arg(const struct smc_call *smc, unsigned i)
+{
+	return smc->args[i];
+}
+
+static inline uint32_t smc32_arg(const struct smc_call *smc, unsigned i)
+{
+	return smc64_arg(smc, i);
+}
+
+static inline void smc64_result(struct smc_call *smc, unsigned i, uint64_t v)
+{
+	smc->results[i] = v;
+}
+
+static inline void smc32_result(struct smc_call *smc, unsigned i, uint32_t v)
+{
+	uint64_t v64 = v;
+	smc64_result(smc, i, v64);
+}
+
+static inline void smc32_return(struct smc_call *smc, int32_t v)
+{
+	smc32_result(smc, 0, v);
+}
+
+static inline uint32_t smc_hypervisor_id(const struct smc_call *smc)
+{
+	/* Set in W7 */
+	return smc32_arg(smc, 7);
+}
+
+static inline uint32_t smc_session_id(const struct smc_call *smc)
+{
+	/* Set in W6 */
+	return smc32_arg(smc, 6);
+}
+
+static inline uint32_t smc_function_id(const struct smc_call *smc)
+{
+	/* Function ID in W0. */
+	return smc32_arg(smc, 0)  & FUNC_ID_MASK;
+}
+
+/* Initialize the SMC layer. */
+void smc_init(void);
+
+/* Register a handler for a given function range, inclusive. */
+int smc_register_range(uint32_t min, uint32_t max, int (*)(struct smc_call *));
+
+#endif /* __ARCH_SMC_H__ */



More information about the coreboot-gerrit mailing list