Commit 7bdfc1af authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull powerpc fixes from Michael Ellerman:

 - A fix for breakpoint handling which was using get_user() while atomic

 - Fix the Power10 HASHCHK handler which was using get_user() while
   atomic

 - A few build fixes for issues caused by recent changes

Thanks to Benjamin Gray, Christophe Leroy, Kajol Jain, and Naveen N Rao.

* tag 'powerpc-6.6-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/dexcr: Move HASHCHK trap handler
  powerpc/82xx: Select FSL_SOC
  powerpc: Fix build issue with LD_DEAD_CODE_DATA_ELIMINATION and FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY
  powerpc/watchpoints: Annotate atomic context in more places
  powerpc/watchpoint: Disable pagefaults when getting user instruction
  powerpc/watchpoints: Disable preemption in thread_change_pc()
  powerpc/perf/hv-24x7: Update domain value check
parents 88a174a9 c3f43096
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -255,7 +255,7 @@ config PPC
	select HAVE_KPROBES
	select HAVE_KPROBES_ON_FTRACE
	select HAVE_KRETPROBES
	select HAVE_LD_DEAD_CODE_DATA_ELIMINATION if HAVE_OBJTOOL_MCOUNT
	select HAVE_LD_DEAD_CODE_DATA_ELIMINATION if HAVE_OBJTOOL_MCOUNT && (!ARCH_USING_PATCHABLE_FUNCTION_ENTRY || (!CC_IS_GCC || GCC_VERSION >= 110100))
	select HAVE_LIVEPATCH			if HAVE_DYNAMIC_FTRACE_WITH_REGS
	select HAVE_MOD_ARCH_SPECIFIC
	select HAVE_NMI				if PERF_EVENTS || (PPC64 && PPC_BOOK3S)
+15 −1
Original line number Diff line number Diff line
@@ -230,13 +230,15 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
	struct arch_hw_breakpoint *info;
	int i;

	preempt_disable();

	for (i = 0; i < nr_wp_slots(); i++) {
		struct perf_event *bp = __this_cpu_read(bp_per_reg[i]);

		if (unlikely(bp && counter_arch_bp(bp)->perf_single_step))
			goto reset;
	}
	return;
	goto out;

reset:
	regs_set_return_msr(regs, regs->msr & ~MSR_SE);
@@ -245,6 +247,9 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
		__set_breakpoint(i, info);
		info->perf_single_step = false;
	}

out:
	preempt_enable();
}

static bool is_larx_stcx_instr(int type)
@@ -363,6 +368,11 @@ static void handle_p10dd1_spurious_exception(struct perf_event **bp,
	}
}

/*
 * Handle a DABR or DAWR exception.
 *
 * Called in atomic context.
 */
int hw_breakpoint_handler(struct die_args *args)
{
	bool err = false;
@@ -490,6 +500,8 @@ NOKPROBE_SYMBOL(hw_breakpoint_handler);

/*
 * Handle single-step exceptions following a DABR hit.
 *
 * Called in atomic context.
 */
static int single_step_dabr_instruction(struct die_args *args)
{
@@ -541,6 +553,8 @@ NOKPROBE_SYMBOL(single_step_dabr_instruction);

/*
 * Handle debug exception notifications.
 *
 * Called in atomic context.
 */
int hw_breakpoint_exceptions_notify(
		struct notifier_block *unused, unsigned long val, void *data)
+6 −1
Original line number Diff line number Diff line
@@ -131,8 +131,13 @@ void wp_get_instr_detail(struct pt_regs *regs, ppc_inst_t *instr,
			 int *type, int *size, unsigned long *ea)
{
	struct instruction_op op;
	int err;

	if (__get_user_instr(*instr, (void __user *)regs->nip))
	pagefault_disable();
	err = __get_user_instr(*instr, (void __user *)regs->nip);
	pagefault_enable();

	if (err)
		return;

	analyse_instr(&op, regs, *instr);
+36 −20
Original line number Diff line number Diff line
@@ -1512,24 +1512,12 @@ 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;
			}
		}

		/* User mode considers other cases after enabling IRQs */
		if (!user_mode(regs)) {
			_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
			return;
		}
	}
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
	if (reason & REASON_TM) {
		/* This is a TM "Bad Thing Exception" program check.
@@ -1561,16 +1549,44 @@ static void do_program_check(struct pt_regs *regs)

	/*
	 * If we took the program check in the kernel skip down to sending a
	 * SIGILL. The subsequent cases all relate to emulating instructions
	 * which we should only do for userspace. We also do not want to enable
	 * interrupts for kernel faults because that might lead to further
	 * faults, and loose the context of the original exception.
	 * SIGILL. The subsequent cases all relate to user space, such as
	 * emulating instructions which we should only do for user space. We
	 * also do not want to enable interrupts for kernel faults because that
	 * might lead to further faults, and loose the context of the original
	 * exception.
	 */
	if (!user_mode(regs))
		goto sigill;

	interrupt_cond_local_irq_enable(regs);

	/*
	 * (reason & REASON_TRAP) is mostly handled before enabling IRQs,
	 * except get_user_instr() can sleep so we cannot reliably inspect the
	 * current instruction in that context. Now that we know we are
	 * handling a user space trap and can sleep, we can check if the trap
	 * was a hashchk failure.
	 */
	if (reason & REASON_TRAP) {
		if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE)) {
			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;
	}

	/* (reason & REASON_ILLEGAL) would be the obvious thing here,
	 * but there seems to be a hardware bug on the 405GP (RevD)
	 * that means ESR is sometimes set incorrectly - either to
+1 −1
Original line number Diff line number Diff line
@@ -1418,7 +1418,7 @@ static int h_24x7_event_init(struct perf_event *event)
	}

	domain = event_get_domain(event);
	if (domain >= HV_PERF_DOMAIN_MAX) {
	if (domain  == 0 || domain >= HV_PERF_DOMAIN_MAX) {
		pr_devel("invalid domain %d\n", domain);
		return -EINVAL;
	}
Loading