Commit 806c0e6e authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman
Browse files

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: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/c2fb93708196734f4176dda334aaa3055f213b89.1629707037.git.christophe.leroy@csgroup.eu
parent 133c17a1
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/err.h>
#include <uapi/asm/ptrace.h>
#include <asm/asm-const.h>
#include <asm/reg.h>

#ifndef __ASSEMBLY__
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;
}

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_block_step()	(true)
#define ARCH_HAS_USER_SINGLE_STEP_REPORT
+3 −6
Original line number Diff line number Diff line
@@ -92,8 +92,7 @@ notrace long system_call_exception(long r3, long r4, long r5,
	CT_WARN_ON(ct_state() == CONTEXT_KERNEL);
	user_exit_irqoff();

	if (!IS_ENABLED(CONFIG_BOOKE) && !IS_ENABLED(CONFIG_40x))
		BUG_ON(!(regs->msr & MSR_RI));
	BUG_ON(regs_is_unrecoverable(regs));
	BUG_ON(!(regs->msr & MSR_PR));
	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;

	if (!IS_ENABLED(CONFIG_BOOKE) && !IS_ENABLED(CONFIG_40x))
		BUG_ON(!(regs->msr & MSR_RI));
	BUG_ON(regs_is_unrecoverable(regs));
	BUG_ON(arch_irq_disabled_regs(regs));
	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 &
						_TIF_EMULATE_STACK_STORE;

	if (!IS_ENABLED(CONFIG_BOOKE) && !IS_ENABLED(CONFIG_40x) &&
	    unlikely(!(regs->msr & MSR_RI)))
	if (regs_is_unrecoverable(regs))
		unrecoverable_exception(regs);
	/*
	 * CT_WARN_ON comes here via program_check_exception,
+4 −4
Original line number Diff line number Diff line
@@ -428,7 +428,7 @@ void hv_nmi_check_nonrecoverable(struct pt_regs *regs)
	return;

nonrecoverable:
	regs_set_return_msr(regs, regs->msr & ~MSR_RI);
	regs_set_unrecoverable(regs);
#endif
}
DEFINE_INTERRUPT_HANDLER_NMI(system_reset_exception)
@@ -498,7 +498,7 @@ DEFINE_INTERRUPT_HANDLER_NMI(system_reset_exception)
		die("Unrecoverable nested System Reset", regs, SIGABRT);
#endif
	/* 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 */
		nmi_exit();
		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",
			       (*nip & 0x100)? "OUT to": "IN from",
			       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));
			return 1;
		}
@@ -840,7 +840,7 @@ DEFINE_INTERRUPT_HANDLER_NMI(machine_check_exception)

bail:
	/* 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);

#ifdef CONFIG_PPC_BOOK3S_64
+1 −1
Original line number Diff line number Diff line
@@ -822,7 +822,7 @@ DEFINE_INTERRUPT_HANDLER_RAW(do_slb_fault)
	/* IRQs are not reconciled here, so can't check irqs_disabled */
	VM_WARN_ON(mfmsr() & MSR_EE);

	if (unlikely(!(regs->msr & MSR_RI)))
	if (regs_is_unrecoverable(regs))
		return -EINVAL;

	/*
+1 −1
Original line number Diff line number Diff line
@@ -251,7 +251,7 @@ static int ppc750_machine_check_exception(struct pt_regs *regs)
	/* Are we prepared to handle this fault */
	if ((entry = search_exception_tables(regs->nip)) != NULL) {
		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));
		return 1;
	}
Loading