Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6749ef0b authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt
Browse files

Revert "powerpc/hw-breakpoint: Use generic hw-breakpoint interfaces for new PPC ptrace flags"



This reverts commit 1b788400.

It causes oopses when passed incorrect arguments and has a
design fault using IPIs with interrupts disabled.

Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
---
parent 933b90a9
Loading
Loading
Loading
Loading
+0 −16
Original line number Diff line number Diff line
@@ -127,22 +127,6 @@ Some examples of using the structure to:
  p.addr2           = (uint64_t) end_range;
  p.condition_value = 0;

- set a watchpoint in server processors (BookS)

  p.version         = 1;
  p.trigger_type    = PPC_BREAKPOINT_TRIGGER_RW;
  p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
  or
  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;

  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
  p.addr            = (uint64_t) begin_range;
  /* For PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE addr2 needs to be specified, where
   * addr2 - addr <= 8 Bytes.
   */
  p.addr2           = (uint64_t) end_range;
  p.condition_value = 0;

3. PTRACE_DELHWDEBUG

Takes an integer which identifies an existing breakpoint or watchpoint
+6 −71
Original line number Diff line number Diff line
@@ -1336,12 +1336,6 @@ static int set_dac_range(struct task_struct *child,
static long ppc_set_hwdebug(struct task_struct *child,
		     struct ppc_hw_breakpoint *bp_info)
{
#ifdef CONFIG_HAVE_HW_BREAKPOINT
	int len = 0;
	struct thread_struct *thread = &(child->thread);
	struct perf_event *bp;
	struct perf_event_attr attr;
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#ifndef CONFIG_PPC_ADV_DEBUG_REGS
	unsigned long dabr;
#endif
@@ -1385,9 +1379,13 @@ static long ppc_set_hwdebug(struct task_struct *child,
	 */
	if ((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0 ||
	    (bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0 ||
	    bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT ||
	    bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
		return -EINVAL;

	if (child->thread.dabr)
		return -ENOSPC;

	if ((unsigned long)bp_info->addr >= TASK_SIZE)
		return -EIO;

@@ -1397,63 +1395,15 @@ static long ppc_set_hwdebug(struct task_struct *child,
		dabr |= DABR_DATA_READ;
	if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
		dabr |= DABR_DATA_WRITE;
#ifdef CONFIG_HAVE_HW_BREAKPOINT
	if (ptrace_get_breakpoints(child) < 0)
		return -ESRCH;

	/*
	 * Check if the request is for 'range' breakpoints. We can
	 * support it if range < 8 bytes.
	 */
	if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE) {
		len = bp_info->addr2 - bp_info->addr;
	} else if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) {
		ptrace_put_breakpoints(child);
		return -EINVAL;
	}
	bp = thread->ptrace_bps[0];
	if (bp) {
		ptrace_put_breakpoints(child);
		return -ENOSPC;
	}

	/* Create a new breakpoint request if one doesn't exist already */
	hw_breakpoint_init(&attr);
	attr.bp_addr = (unsigned long)bp_info->addr & ~HW_BREAKPOINT_ALIGN;
	attr.bp_len = len;
	arch_bp_generic_fields(dabr & (DABR_DATA_WRITE | DABR_DATA_READ),
								&attr.bp_type);

	thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
					       ptrace_triggered, NULL, child);
	if (IS_ERR(bp)) {
		thread->ptrace_bps[0] = NULL;
		ptrace_put_breakpoints(child);
		return PTR_ERR(bp);
	}

	ptrace_put_breakpoints(child);
	return 1;
#endif /* CONFIG_HAVE_HW_BREAKPOINT */

	if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
		return -EINVAL;

	if (child->thread.dabr)
		return -ENOSPC;

	child->thread.dabr = dabr;

	return 1;
#endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */
}

static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
{
#ifdef CONFIG_HAVE_HW_BREAKPOINT
	int ret = 0;
	struct thread_struct *thread = &(child->thread);
	struct perf_event *bp;
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
	int rc;

@@ -1473,25 +1423,10 @@ static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
#else
	if (data != 1)
		return -EINVAL;

#ifdef CONFIG_HAVE_HW_BREAKPOINT
	if (ptrace_get_breakpoints(child) < 0)
		return -ESRCH;

	bp = thread->ptrace_bps[0];
	if (bp) {
		unregister_hw_breakpoint(bp);
		thread->ptrace_bps[0] = NULL;
	} else
		ret = -ENOENT;
	ptrace_put_breakpoints(child);
	return ret;
#else /* CONFIG_HAVE_HW_BREAKPOINT */
	if (child->thread.dabr == 0)
		return -ENOENT;

	child->thread.dabr = 0;
#endif /* CONFIG_HAVE_HW_BREAKPOINT */

	return 0;
#endif
@@ -1598,7 +1533,7 @@ long arch_ptrace(struct task_struct *child, long request,
		dbginfo.data_bp_alignment = 4;
#endif
		dbginfo.sizeof_condition = 0;
		dbginfo.features = PPC_DEBUG_FEATURE_DATA_BP_RANGE;
		dbginfo.features = 0;
#endif /* CONFIG_PPC_ADV_DEBUG_REGS */

		if (!access_ok(VERIFY_WRITE, datavp,