diff options
author | Mark Rutland <mark.rutland@arm.com> | 2022-10-19 17:41:23 +0300 |
---|---|---|
committer | Will Deacon <will@kernel.org> | 2022-11-15 16:46:19 +0300 |
commit | 124c49b1b5d947b7180c5d6cbb09ddf76ea45ea2 (patch) | |
tree | 6951862857951bbbc5888bc61ab7dc5131987246 /arch/arm64/kernel/traps.c | |
parent | 0c5f416219da3795dc8b33e5bb7865a6b3c4e55c (diff) | |
download | linux-124c49b1b5d947b7180c5d6cbb09ddf76ea45ea2.tar.xz |
arm64: armv8_deprecated: rework deprected instruction handling
Support for deprecated instructions can be enabled or disabled at
runtime. To handle this, the code in armv8_deprecated.c registers and
unregisters undef_hooks, and makes cross CPU calls to configure HW
support. This is rather complicated, and the synchronization required to
make this safe ends up serializing the handling of instructions which
have been trapped.
This patch simplifies the deprecated instruction handling by removing
the dynamic registration and unregistration, and changing the trap
handling code to determine whether a handler should be invoked. This
removes the need for dynamic list management, and simplifies the locking
requirements, making it possible to handle trapped instructions entirely
in parallel.
Where changing the emulation state requires a cross-call, this is
serialized by locally disabling interrupts, ensuring that the CPU is not
left in an inconsistent state.
To simplify sysctl management, each insn_emulation is given a separate
sysctl table, permitting these to be registered separately. The core
sysctl code will iterate over all of these when walking sysfs.
I've tested this with userspace programs which use each of the
deprecated instructions, and I've concurrently modified the support
level for each of the features back-and-forth between HW and emulated to
check that there are no spurious SIGILLs sent to userspace when the
support level is changed.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: James Morse <james.morse@arm.com>
Cc: Joey Gouly <joey.gouly@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20221019144123.612388-10-mark.rutland@arm.com
Signed-off-by: Will Deacon <will@kernel.org>
Diffstat (limited to 'arch/arm64/kernel/traps.c')
-rw-r--r-- | arch/arm64/kernel/traps.c | 40 |
1 files changed, 1 insertions, 39 deletions
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 96eaf1aaec12..4c0caa589e12 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -373,27 +373,6 @@ void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size) regs->pstate &= ~PSR_BTYPE_MASK; } -static LIST_HEAD(undef_hook); -static DEFINE_RAW_SPINLOCK(undef_lock); - -void register_undef_hook(struct undef_hook *hook) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&undef_lock, flags); - list_add(&hook->node, &undef_hook); - raw_spin_unlock_irqrestore(&undef_lock, flags); -} - -void unregister_undef_hook(struct undef_hook *hook) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&undef_lock, flags); - list_del(&hook->node); - raw_spin_unlock_irqrestore(&undef_lock, flags); -} - static int user_insn_read(struct pt_regs *regs, u32 *insnp) { u32 instr; @@ -425,23 +404,6 @@ static int user_insn_read(struct pt_regs *regs, u32 *insnp) return 0; } -static int call_undef_hook(struct pt_regs *regs, u32 instr) -{ - struct undef_hook *hook; - unsigned long flags; - int (*fn)(struct pt_regs *regs, u32 instr) = NULL; - - raw_spin_lock_irqsave(&undef_lock, flags); - list_for_each_entry(hook, &undef_hook, node) - if ((instr & hook->instr_mask) == hook->instr_val && - (regs->pstate & hook->pstate_mask) == hook->pstate_val) - fn = hook->fn; - - raw_spin_unlock_irqrestore(&undef_lock, flags); - - return fn ? fn(regs, instr) : 1; -} - void force_signal_inject(int signal, int code, unsigned long address, unsigned long err) { const char *desc; @@ -502,7 +464,7 @@ void do_el0_undef(struct pt_regs *regs, unsigned long esr) if (try_emulate_mrs(regs, insn)) return; - if (call_undef_hook(regs, insn) == 0) + if (try_emulate_armv8_deprecated(regs, insn)) return; out_err: |