Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 270111
b: refs/heads/master
c: 6f26aa0
h: refs/heads/master
i:
  270109: 70078b4
  270107: a5d3cfb
  270103: 9c960c5
  270095: 3aa6417
  270079: 70f0da5
v: v3
  • Loading branch information
Will Deacon committed Aug 31, 2011
1 parent 443a6d3 commit 4b5fe2f
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 36 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c512de955f0982aafa49d3f00d5643052a6790e5
refs/heads/master: 6f26aa05c9edffff6a4c2cd71774bc659a5cceec
1 change: 1 addition & 0 deletions trunk/arch/arm/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ static inline void decode_ctrl_reg(u32 reg,
/* Watchpoints */
#define ARM_BREAKPOINT_LOAD 1
#define ARM_BREAKPOINT_STORE 2
#define ARM_FSR_ACCESS_MASK (1 << 11)

/* Privilege Levels */
#define ARM_BREAKPOINT_PRIV 1
Expand Down
100 changes: 65 additions & 35 deletions trunk/arch/arm/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,24 +339,10 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
val_base = ARM_BASE_BVR;
slots = (struct perf_event **)__get_cpu_var(bp_on_reg);
max_slots = core_num_brps;
if (info->step_ctrl.enabled) {
/* Override the breakpoint data with the step data. */
addr = info->trigger & ~0x3;
ctrl = encode_ctrl_reg(info->step_ctrl);
}
} else {
/* Watchpoint */
if (info->step_ctrl.enabled) {
/* Install into the reserved breakpoint region. */
ctrl_base = ARM_BASE_BCR + core_num_brps;
val_base = ARM_BASE_BVR + core_num_brps;
/* Override the watchpoint data with the step data. */
addr = info->trigger & ~0x3;
ctrl = encode_ctrl_reg(info->step_ctrl);
} else {
ctrl_base = ARM_BASE_WCR;
val_base = ARM_BASE_WVR;
}
ctrl_base = ARM_BASE_WCR;
val_base = ARM_BASE_WVR;
slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
max_slots = core_num_wrps;
}
Expand All @@ -375,6 +361,17 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
goto out;
}

/* Override the breakpoint data with the step data. */
if (info->step_ctrl.enabled) {
addr = info->trigger & ~0x3;
ctrl = encode_ctrl_reg(info->step_ctrl);
if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE) {
i = 0;
ctrl_base = ARM_BASE_BCR + core_num_brps;
val_base = ARM_BASE_BVR + core_num_brps;
}
}

/* Setup the address register. */
write_wb_reg(val_base + i, addr);

Expand All @@ -398,10 +395,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
max_slots = core_num_brps;
} else {
/* Watchpoint */
if (info->step_ctrl.enabled)
base = ARM_BASE_BCR + core_num_brps;
else
base = ARM_BASE_WCR;
base = ARM_BASE_WCR;
slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
max_slots = core_num_wrps;
}
Expand All @@ -419,6 +413,13 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n"))
return;

/* Ensure that we disable the mismatch breakpoint. */
if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE &&
info->step_ctrl.enabled) {
i = 0;
base = ARM_BASE_BCR + core_num_brps;
}

/* Reset the control register. */
write_wb_reg(base + i, 0);
}
Expand Down Expand Up @@ -659,34 +660,62 @@ static void disable_single_step(struct perf_event *bp)
arch_install_hw_breakpoint(bp);
}

static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs)
static void watchpoint_handler(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
int i;
int i, access;
u32 val, ctrl_reg, alignment_mask;
struct perf_event *wp, **slots;
struct arch_hw_breakpoint *info;
struct arch_hw_breakpoint_ctrl ctrl;

slots = (struct perf_event **)__get_cpu_var(wp_on_reg);

/* Without a disassembler, we can only handle 1 watchpoint. */
BUG_ON(core_num_wrps > 1);

for (i = 0; i < core_num_wrps; ++i) {
rcu_read_lock();

wp = slots[i];

if (wp == NULL) {
rcu_read_unlock();
continue;
}
if (wp == NULL)
goto unlock;

info = counter_arch_bp(wp);
/*
* The DFAR is an unknown value. Since we only allow a
* single watchpoint, we can set the trigger to the lowest
* possible faulting address.
* The DFAR is an unknown value on debug architectures prior
* to 7.1. Since we only allow a single watchpoint on these
* older CPUs, we can set the trigger to the lowest possible
* faulting address.
*/
info = counter_arch_bp(wp);
info->trigger = wp->attr.bp_addr;
if (debug_arch < ARM_DEBUG_ARCH_V7_1) {
BUG_ON(i > 0);
info->trigger = wp->attr.bp_addr;
} else {
if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
alignment_mask = 0x7;
else
alignment_mask = 0x3;

/* Check if the watchpoint value matches. */
val = read_wb_reg(ARM_BASE_WVR + i);
if (val != (addr & ~alignment_mask))
goto unlock;

/* Possible match, check the byte address select. */
ctrl_reg = read_wb_reg(ARM_BASE_WCR + i);
decode_ctrl_reg(ctrl_reg, &ctrl);
if (!((1 << (addr & alignment_mask)) & ctrl.len))
goto unlock;

/* Check that the access type matches. */
access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W :
HW_BREAKPOINT_R;
if (!(access & hw_breakpoint_type(wp)))
goto unlock;

/* We have a winner. */
info->trigger = addr;
}

pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
perf_bp_event(wp, regs);

Expand All @@ -698,6 +727,7 @@ static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs)
if (!wp->overflow_handler)
enable_single_step(wp, instruction_pointer(regs));

unlock:
rcu_read_unlock();
}
}
Expand Down Expand Up @@ -813,7 +843,7 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
case ARM_ENTRY_ASYNC_WATCHPOINT:
WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n");
case ARM_ENTRY_SYNC_WATCHPOINT:
watchpoint_handler(addr, regs);
watchpoint_handler(addr, fsr, regs);
break;
default:
ret = 1; /* Unhandled fault. */
Expand Down

0 comments on commit 4b5fe2f

Please sign in to comment.