diff options
author | Benjamin Gray <bgray@linux.ibm.com> | 2023-06-19 10:36:25 +0300 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2023-06-19 10:36:26 +0300 |
commit | 5bcba4e6c13f0c889da1f9e67ee10accd9ca4c19 (patch) | |
tree | da6844eb74b2f2a374adf652893f3b6b56f5e952 | |
parent | 0ffd60b782ed79349baf28dd3259c872f39274e9 (diff) | |
download | linux-5bcba4e6c13f0c889da1f9e67ee10accd9ca4c19.tar.xz |
powerpc/dexcr: Handle hashchk exception
Recognise and pass the appropriate signal to the user program when a
hashchk instruction triggers. This is independent of allowing
configuration of DEXCR[NPHIE], as a hypervisor can enforce this aspect
regardless of the kernel.
The signal mirrors how ARM reports their similar check failure. For
example, their FPAC handler in arch/arm64/kernel/traps.c do_el0_fpac()
does this. When we fail to read the instruction that caused the fault
we send a segfault, similar to how emulate_math() does it.
Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230616034846.311705-5-bgray@linux.ibm.com
-rw-r--r-- | arch/powerpc/include/asm/ppc-opcode.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/traps.c | 16 |
2 files changed, 17 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index ca5a0da7df4e..ef6972aa33b9 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -222,6 +222,7 @@ #define OP_31_XOP_STFSX 663 #define OP_31_XOP_STFSUX 695 #define OP_31_XOP_STFDX 727 +#define OP_31_XOP_HASHCHK 754 #define OP_31_XOP_STFDUX 759 #define OP_31_XOP_LHBRX 790 #define OP_31_XOP_LFIWAX 855 diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 9bdd79aa51cf..e59ec6d32d37 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1516,6 +1516,22 @@ static void do_program_check(struct pt_regs *regs) return; } } + + if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE) && user_mode(regs)) { + ppc_inst_t insn; + + if (get_user_instr(insn, (void __user *)regs->nip)) { + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); + return; + } + + if (ppc_inst_primary_opcode(insn) == 31 && + get_xop(ppc_inst_val(insn)) == OP_31_XOP_HASHCHK) { + _exception(SIGILL, regs, ILL_ILLOPN, regs->nip); + return; + } + } + _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); return; } |