arm64: entry: split SDEI entry
authorMark Rutland <mark.rutland@arm.com>
Mon, 7 Jun 2021 09:46:21 +0000 (10:46 +0100)
committerWill Deacon <will@kernel.org>
Mon, 7 Jun 2021 10:35:56 +0000 (11:35 +0100)
We'd like to keep all the entry sequencing in entry-common.c, as this
will allow us to ensure this is consistent, and free from any unsound
instrumentation.

Currently __sdei_handler() performs the NMI entry/exit sequences in
sdei.c. Let's split the low-level entry sequence from the event
handling, moving the former to entry-common.c and keeping the latter in
sdei.c. The event handling function is renamed to do_sdei_event(),
matching the do_${FOO}() pattern used for other exception handlers.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Cc: James Morse <james.morse@arm.com>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20210607094624.34689-18-mark.rutland@arm.com
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/include/asm/sdei.h
arch/arm64/kernel/entry-common.c
arch/arm64/kernel/sdei.c

index 63e0b92a5fbb069bc232a93e32e17a39d6df9bd1..03d619a49d4a49c6ca7a5a75d37bdf38108405c0 100644 (file)
@@ -37,6 +37,9 @@ struct sdei_registered_event;
 asmlinkage unsigned long __sdei_handler(struct pt_regs *regs,
                                        struct sdei_registered_event *arg);
 
+unsigned long do_sdei_event(struct pt_regs *regs,
+                           struct sdei_registered_event *arg);
+
 unsigned long sdei_arch_get_entry_point(int conduit);
 #define sdei_arch_get_entry_point(x)   sdei_arch_get_entry_point(x)
 
index efe95edf10c0ceded3b572f71d7d4b50ef8208e2..1b32ca3848f53519619c9acde59580185ca73bbc 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/kprobes.h>
 #include <asm/mmu.h>
 #include <asm/processor.h>
+#include <asm/sdei.h>
 #include <asm/stacktrace.h>
 #include <asm/sysreg.h>
 #include <asm/system_misc.h>
@@ -710,3 +711,39 @@ asmlinkage void noinstr handle_bad_stack(struct pt_regs *regs)
        panic_bad_stack(regs, esr, far);
 }
 #endif /* CONFIG_VMAP_STACK */
+
+#ifdef CONFIG_ARM_SDE_INTERFACE
+asmlinkage noinstr unsigned long
+__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
+{
+       unsigned long ret;
+
+       /*
+        * We didn't take an exception to get here, so the HW hasn't
+        * set/cleared bits in PSTATE that we may rely on.
+        *
+        * The original SDEI spec (ARM DEN 0054A) can be read ambiguously as to
+        * whether PSTATE bits are inherited unchanged or generated from
+        * scratch, and the TF-A implementation always clears PAN and always
+        * clears UAO. There are no other known implementations.
+        *
+        * Subsequent revisions (ARM DEN 0054B) follow the usual rules for how
+        * PSTATE is modified upon architectural exceptions, and so PAN is
+        * either inherited or set per SCTLR_ELx.SPAN, and UAO is always
+        * cleared.
+        *
+        * We must explicitly reset PAN to the expected state, including
+        * clearing it when the host isn't using it, in case a VM had it set.
+        */
+       if (system_uses_hw_pan())
+               set_pstate_pan(1);
+       else if (cpu_has_pan())
+               set_pstate_pan(0);
+
+       arm64_enter_nmi(regs);
+       ret = do_sdei_event(regs, arg);
+       arm64_exit_nmi(regs);
+
+       return ret;
+}
+#endif /* CONFIG_ARM_SDE_INTERFACE */
index 2c7ca449dd5111206fa8559065fd95ce2858dcf9..e72953992743333fdfe1dc0bbc59c57561fabc89 100644 (file)
@@ -231,13 +231,13 @@ out_err:
 }
 
 /*
- * __sdei_handler() returns one of:
+ * do_sdei_event() returns one of:
  *  SDEI_EV_HANDLED -  success, return to the interrupted context.
  *  SDEI_EV_FAILED  -  failure, return this error code to firmare.
  *  virtual-address -  success, return to this address.
  */
-static __kprobes unsigned long _sdei_handler(struct pt_regs *regs,
-                                            struct sdei_registered_event *arg)
+unsigned long __kprobes do_sdei_event(struct pt_regs *regs,
+                                     struct sdei_registered_event *arg)
 {
        u32 mode;
        int i, err = 0;
@@ -292,45 +292,3 @@ static __kprobes unsigned long _sdei_handler(struct pt_regs *regs,
 
        return vbar + 0x480;
 }
-
-static void __kprobes notrace __sdei_pstate_entry(void)
-{
-       /*
-        * The original SDEI spec (ARM DEN 0054A) can be read ambiguously as to
-        * whether PSTATE bits are inherited unchanged or generated from
-        * scratch, and the TF-A implementation always clears PAN and always
-        * clears UAO. There are no other known implementations.
-        *
-        * Subsequent revisions (ARM DEN 0054B) follow the usual rules for how
-        * PSTATE is modified upon architectural exceptions, and so PAN is
-        * either inherited or set per SCTLR_ELx.SPAN, and UAO is always
-        * cleared.
-        *
-        * We must explicitly reset PAN to the expected state, including
-        * clearing it when the host isn't using it, in case a VM had it set.
-        */
-       if (system_uses_hw_pan())
-               set_pstate_pan(1);
-       else if (cpu_has_pan())
-               set_pstate_pan(0);
-}
-
-asmlinkage noinstr unsigned long
-__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
-{
-       unsigned long ret;
-
-       /*
-        * We didn't take an exception to get here, so the HW hasn't
-        * set/cleared bits in PSTATE that we may rely on. Initialize PAN.
-        */
-       __sdei_pstate_entry();
-
-       arm64_enter_nmi(regs);
-
-       ret = _sdei_handler(regs, arg);
-
-       arm64_exit_nmi(regs);
-
-       return ret;
-}