Skip to content

Commit d60b228

Browse files
mrutland-armwilldeacon
authored andcommitted
arm64: entry: split SDEI entry
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>
1 parent 8168f09 commit d60b228

3 files changed

Lines changed: 43 additions & 45 deletions

File tree

arch/arm64/include/asm/sdei.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ struct sdei_registered_event;
3737
asmlinkage unsigned long __sdei_handler(struct pt_regs *regs,
3838
struct sdei_registered_event *arg);
3939

40+
unsigned long do_sdei_event(struct pt_regs *regs,
41+
struct sdei_registered_event *arg);
42+
4043
unsigned long sdei_arch_get_entry_point(int conduit);
4144
#define sdei_arch_get_entry_point(x) sdei_arch_get_entry_point(x)
4245

arch/arm64/kernel/entry-common.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <asm/kprobes.h>
2121
#include <asm/mmu.h>
2222
#include <asm/processor.h>
23+
#include <asm/sdei.h>
2324
#include <asm/stacktrace.h>
2425
#include <asm/sysreg.h>
2526
#include <asm/system_misc.h>
@@ -710,3 +711,39 @@ asmlinkage void noinstr handle_bad_stack(struct pt_regs *regs)
710711
panic_bad_stack(regs, esr, far);
711712
}
712713
#endif /* CONFIG_VMAP_STACK */
714+
715+
#ifdef CONFIG_ARM_SDE_INTERFACE
716+
asmlinkage noinstr unsigned long
717+
__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
718+
{
719+
unsigned long ret;
720+
721+
/*
722+
* We didn't take an exception to get here, so the HW hasn't
723+
* set/cleared bits in PSTATE that we may rely on.
724+
*
725+
* The original SDEI spec (ARM DEN 0054A) can be read ambiguously as to
726+
* whether PSTATE bits are inherited unchanged or generated from
727+
* scratch, and the TF-A implementation always clears PAN and always
728+
* clears UAO. There are no other known implementations.
729+
*
730+
* Subsequent revisions (ARM DEN 0054B) follow the usual rules for how
731+
* PSTATE is modified upon architectural exceptions, and so PAN is
732+
* either inherited or set per SCTLR_ELx.SPAN, and UAO is always
733+
* cleared.
734+
*
735+
* We must explicitly reset PAN to the expected state, including
736+
* clearing it when the host isn't using it, in case a VM had it set.
737+
*/
738+
if (system_uses_hw_pan())
739+
set_pstate_pan(1);
740+
else if (cpu_has_pan())
741+
set_pstate_pan(0);
742+
743+
arm64_enter_nmi(regs);
744+
ret = do_sdei_event(regs, arg);
745+
arm64_exit_nmi(regs);
746+
747+
return ret;
748+
}
749+
#endif /* CONFIG_ARM_SDE_INTERFACE */

arch/arm64/kernel/sdei.c

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,13 @@ unsigned long sdei_arch_get_entry_point(int conduit)
231231
}
232232

233233
/*
234-
* __sdei_handler() returns one of:
234+
* do_sdei_event() returns one of:
235235
* SDEI_EV_HANDLED - success, return to the interrupted context.
236236
* SDEI_EV_FAILED - failure, return this error code to firmare.
237237
* virtual-address - success, return to this address.
238238
*/
239-
static __kprobes unsigned long _sdei_handler(struct pt_regs *regs,
240-
struct sdei_registered_event *arg)
239+
unsigned long __kprobes do_sdei_event(struct pt_regs *regs,
240+
struct sdei_registered_event *arg)
241241
{
242242
u32 mode;
243243
int i, err = 0;
@@ -292,45 +292,3 @@ static __kprobes unsigned long _sdei_handler(struct pt_regs *regs,
292292

293293
return vbar + 0x480;
294294
}
295-
296-
static void __kprobes notrace __sdei_pstate_entry(void)
297-
{
298-
/*
299-
* The original SDEI spec (ARM DEN 0054A) can be read ambiguously as to
300-
* whether PSTATE bits are inherited unchanged or generated from
301-
* scratch, and the TF-A implementation always clears PAN and always
302-
* clears UAO. There are no other known implementations.
303-
*
304-
* Subsequent revisions (ARM DEN 0054B) follow the usual rules for how
305-
* PSTATE is modified upon architectural exceptions, and so PAN is
306-
* either inherited or set per SCTLR_ELx.SPAN, and UAO is always
307-
* cleared.
308-
*
309-
* We must explicitly reset PAN to the expected state, including
310-
* clearing it when the host isn't using it, in case a VM had it set.
311-
*/
312-
if (system_uses_hw_pan())
313-
set_pstate_pan(1);
314-
else if (cpu_has_pan())
315-
set_pstate_pan(0);
316-
}
317-
318-
asmlinkage noinstr unsigned long
319-
__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
320-
{
321-
unsigned long ret;
322-
323-
/*
324-
* We didn't take an exception to get here, so the HW hasn't
325-
* set/cleared bits in PSTATE that we may rely on. Initialize PAN.
326-
*/
327-
__sdei_pstate_entry();
328-
329-
arm64_enter_nmi(regs);
330-
331-
ret = _sdei_handler(regs, arg);
332-
333-
arm64_exit_nmi(regs);
334-
335-
return ret;
336-
}

0 commit comments

Comments
 (0)