powerpc: Refactor verification of MSR_RI

40x and BOOKE don't have MSR_RI therefore all tests involving
MSR_RI may be problematic on those plateforms.

Create helpers to check or set MSR_RI in regs, and use them
in common code.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/c2fb93708196734f4176dda334aaa3055f213b89.1629707037.git.christophe.leroy@csgroup.eu
This commit is contained in:
Christophe Leroy 2021-08-23 08:24:21 +00:00 committed by Michael Ellerman
parent 133c17a178
commit 806c0e6e7e
11 changed files with 40 additions and 30 deletions

View File

@ -22,6 +22,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <uapi/asm/ptrace.h> #include <uapi/asm/ptrace.h>
#include <asm/asm-const.h> #include <asm/asm-const.h>
#include <asm/reg.h>
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
struct pt_regs struct pt_regs
@ -272,6 +273,28 @@ static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
regs->gpr[3] = rc; regs->gpr[3] = rc;
} }
static inline bool cpu_has_msr_ri(void)
{
return !IS_ENABLED(CONFIG_BOOKE) && !IS_ENABLED(CONFIG_40x);
}
static inline bool regs_is_unrecoverable(struct pt_regs *regs)
{
return unlikely(cpu_has_msr_ri() && !(regs->msr & MSR_RI));
}
static inline void regs_set_recoverable(struct pt_regs *regs)
{
if (cpu_has_msr_ri())
regs_set_return_msr(regs, regs->msr | MSR_RI);
}
static inline void regs_set_unrecoverable(struct pt_regs *regs)
{
if (cpu_has_msr_ri())
regs_set_return_msr(regs, regs->msr & ~MSR_RI);
}
#define arch_has_single_step() (1) #define arch_has_single_step() (1)
#define arch_has_block_step() (true) #define arch_has_block_step() (true)
#define ARCH_HAS_USER_SINGLE_STEP_REPORT #define ARCH_HAS_USER_SINGLE_STEP_REPORT

View File

@ -92,8 +92,7 @@ notrace long system_call_exception(long r3, long r4, long r5,
CT_WARN_ON(ct_state() == CONTEXT_KERNEL); CT_WARN_ON(ct_state() == CONTEXT_KERNEL);
user_exit_irqoff(); user_exit_irqoff();
if (!IS_ENABLED(CONFIG_BOOKE) && !IS_ENABLED(CONFIG_40x)) BUG_ON(regs_is_unrecoverable(regs));
BUG_ON(!(regs->msr & MSR_RI));
BUG_ON(!(regs->msr & MSR_PR)); BUG_ON(!(regs->msr & MSR_PR));
BUG_ON(arch_irq_disabled_regs(regs)); BUG_ON(arch_irq_disabled_regs(regs));
@ -462,8 +461,7 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs)
{ {
unsigned long ret; unsigned long ret;
if (!IS_ENABLED(CONFIG_BOOKE) && !IS_ENABLED(CONFIG_40x)) BUG_ON(regs_is_unrecoverable(regs));
BUG_ON(!(regs->msr & MSR_RI));
BUG_ON(arch_irq_disabled_regs(regs)); BUG_ON(arch_irq_disabled_regs(regs));
CT_WARN_ON(ct_state() == CONTEXT_USER); CT_WARN_ON(ct_state() == CONTEXT_USER);
@ -494,8 +492,7 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs)
bool stack_store = current_thread_info()->flags & bool stack_store = current_thread_info()->flags &
_TIF_EMULATE_STACK_STORE; _TIF_EMULATE_STACK_STORE;
if (!IS_ENABLED(CONFIG_BOOKE) && !IS_ENABLED(CONFIG_40x) && if (regs_is_unrecoverable(regs))
unlikely(!(regs->msr & MSR_RI)))
unrecoverable_exception(regs); unrecoverable_exception(regs);
/* /*
* CT_WARN_ON comes here via program_check_exception, * CT_WARN_ON comes here via program_check_exception,

View File

@ -428,7 +428,7 @@ void hv_nmi_check_nonrecoverable(struct pt_regs *regs)
return; return;
nonrecoverable: nonrecoverable:
regs_set_return_msr(regs, regs->msr & ~MSR_RI); regs_set_unrecoverable(regs);
#endif #endif
} }
DEFINE_INTERRUPT_HANDLER_NMI(system_reset_exception) DEFINE_INTERRUPT_HANDLER_NMI(system_reset_exception)
@ -498,7 +498,7 @@ out:
die("Unrecoverable nested System Reset", regs, SIGABRT); die("Unrecoverable nested System Reset", regs, SIGABRT);
#endif #endif
/* Must die if the interrupt is not recoverable */ /* Must die if the interrupt is not recoverable */
if (!(regs->msr & MSR_RI)) { if (regs_is_unrecoverable(regs)) {
/* For the reason explained in die_mce, nmi_exit before die */ /* For the reason explained in die_mce, nmi_exit before die */
nmi_exit(); nmi_exit();
die("Unrecoverable System Reset", regs, SIGABRT); die("Unrecoverable System Reset", regs, SIGABRT);
@ -550,7 +550,7 @@ static inline int check_io_access(struct pt_regs *regs)
printk(KERN_DEBUG "%s bad port %lx at %p\n", printk(KERN_DEBUG "%s bad port %lx at %p\n",
(*nip & 0x100)? "OUT to": "IN from", (*nip & 0x100)? "OUT to": "IN from",
regs->gpr[rb] - _IO_BASE, nip); regs->gpr[rb] - _IO_BASE, nip);
regs_set_return_msr(regs, regs->msr | MSR_RI); regs_set_recoverable(regs);
regs_set_return_ip(regs, extable_fixup(entry)); regs_set_return_ip(regs, extable_fixup(entry));
return 1; return 1;
} }
@ -840,7 +840,7 @@ DEFINE_INTERRUPT_HANDLER_NMI(machine_check_exception)
bail: bail:
/* Must die if the interrupt is not recoverable */ /* Must die if the interrupt is not recoverable */
if (!(regs->msr & MSR_RI)) if (regs_is_unrecoverable(regs))
die_mce("Unrecoverable Machine check", regs, SIGBUS); die_mce("Unrecoverable Machine check", regs, SIGBUS);
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64

View File

@ -822,7 +822,7 @@ DEFINE_INTERRUPT_HANDLER_RAW(do_slb_fault)
/* IRQs are not reconciled here, so can't check irqs_disabled */ /* IRQs are not reconciled here, so can't check irqs_disabled */
VM_WARN_ON(mfmsr() & MSR_EE); VM_WARN_ON(mfmsr() & MSR_EE);
if (unlikely(!(regs->msr & MSR_RI))) if (regs_is_unrecoverable(regs))
return -EINVAL; return -EINVAL;
/* /*

View File

@ -251,7 +251,7 @@ static int ppc750_machine_check_exception(struct pt_regs *regs)
/* Are we prepared to handle this fault */ /* Are we prepared to handle this fault */
if ((entry = search_exception_tables(regs->nip)) != NULL) { if ((entry = search_exception_tables(regs->nip)) != NULL) {
tsi108_clear_pci_cfg_error(); tsi108_clear_pci_cfg_error();
regs_set_return_msr(regs, regs->msr | MSR_RI); regs_set_recoverable(regs);
regs_set_return_ip(regs, extable_fixup(entry)); regs_set_return_ip(regs, extable_fixup(entry));
return 1; return 1;
} }

View File

@ -173,7 +173,7 @@ static int mpc7448_machine_check_exception(struct pt_regs *regs)
/* Are we prepared to handle this fault */ /* Are we prepared to handle this fault */
if ((entry = search_exception_tables(regs->nip)) != NULL) { if ((entry = search_exception_tables(regs->nip)) != NULL) {
tsi108_clear_pci_cfg_error(); tsi108_clear_pci_cfg_error();
regs_set_return_msr(regs, regs->msr | MSR_RI); regs_set_recoverable(regs);
regs_set_return_ip(regs, extable_fixup(entry)); regs_set_return_ip(regs, extable_fixup(entry));
return 1; return 1;
} }

View File

@ -58,7 +58,7 @@ static int pasemi_system_reset_exception(struct pt_regs *regs)
restore_astate(hard_smp_processor_id()); restore_astate(hard_smp_processor_id());
/* everything handled */ /* everything handled */
regs_set_return_msr(regs, regs->msr | MSR_RI); regs_set_recoverable(regs);
return 1; return 1;
} }

View File

@ -588,7 +588,7 @@ static int opal_recover_mce(struct pt_regs *regs,
{ {
int recovered = 0; int recovered = 0;
if (!(regs->msr & MSR_RI)) { if (regs_is_unrecoverable(regs)) {
/* If MSR_RI isn't set, we cannot recover */ /* If MSR_RI isn't set, we cannot recover */
pr_err("Machine check interrupt unrecoverable: MSR(RI=0)\n"); pr_err("Machine check interrupt unrecoverable: MSR(RI=0)\n");
recovered = 0; recovered = 0;

View File

@ -783,7 +783,7 @@ static int recover_mce(struct pt_regs *regs, struct machine_check_event *evt)
{ {
int recovered = 0; int recovered = 0;
if (!(regs->msr & MSR_RI)) { if (regs_is_unrecoverable(regs)) {
/* If MSR_RI isn't set, we cannot recover */ /* If MSR_RI isn't set, we cannot recover */
pr_err("Machine check interrupt unrecoverable: MSR(RI=0)\n"); pr_err("Machine check interrupt unrecoverable: MSR(RI=0)\n");
recovered = 0; recovered = 0;

View File

@ -108,7 +108,7 @@ int fsl_rio_mcheck_exception(struct pt_regs *regs)
__func__); __func__);
out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR),
0); 0);
regs_set_return_msr(regs, regs->msr | MSR_RI); regs_set_recoverable(regs);
regs_set_return_ip(regs, extable_fixup(entry)); regs_set_return_ip(regs, extable_fixup(entry));
return 1; return 1;
} }

View File

@ -482,16 +482,6 @@ static inline void get_output_lock(void) {}
static inline void release_output_lock(void) {} static inline void release_output_lock(void) {}
#endif #endif
static inline int unrecoverable_excp(struct pt_regs *regs)
{
#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
/* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
return 0;
#else
return ((regs->msr & MSR_RI) == 0);
#endif
}
static void xmon_touch_watchdogs(void) static void xmon_touch_watchdogs(void)
{ {
touch_softlockup_watchdog_sync(); touch_softlockup_watchdog_sync();
@ -565,7 +555,7 @@ static int xmon_core(struct pt_regs *regs, volatile int fromipi)
bp = NULL; bp = NULL;
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
bp = at_breakpoint(regs->nip); bp = at_breakpoint(regs->nip);
if (bp || unrecoverable_excp(regs)) if (bp || regs_is_unrecoverable(regs))
fromipi = 0; fromipi = 0;
if (!fromipi) { if (!fromipi) {
@ -577,7 +567,7 @@ static int xmon_core(struct pt_regs *regs, volatile int fromipi)
cpu, BP_NUM(bp)); cpu, BP_NUM(bp));
xmon_print_symbol(regs->nip, " ", ")\n"); xmon_print_symbol(regs->nip, " ", ")\n");
} }
if (unrecoverable_excp(regs)) if (regs_is_unrecoverable(regs))
printf("WARNING: exception is not recoverable, " printf("WARNING: exception is not recoverable, "
"can't continue\n"); "can't continue\n");
release_output_lock(); release_output_lock();
@ -693,7 +683,7 @@ static int xmon_core(struct pt_regs *regs, volatile int fromipi)
printf("Stopped at breakpoint %tx (", BP_NUM(bp)); printf("Stopped at breakpoint %tx (", BP_NUM(bp));
xmon_print_symbol(regs->nip, " ", ")\n"); xmon_print_symbol(regs->nip, " ", ")\n");
} }
if (unrecoverable_excp(regs)) if (regs_is_unrecoverable(regs))
printf("WARNING: exception is not recoverable, " printf("WARNING: exception is not recoverable, "
"can't continue\n"); "can't continue\n");
remove_bpts(); remove_bpts();