Skip to content

Commit

Permalink
powerpc/perf: Fix setting of "to" addresses for BHRB
Browse files Browse the repository at this point in the history
Currently we only set the "to" address in the branch stack when the CPU
explicitly gives us a value.  Unfortunately it only does this for XL form
branches (eg blr, bctr, bctar) and not I and B form branches (eg b, bc).

Fortunately if we read the instruction from memory we can extract the offset of
a branch and calculate the target address.

This adds a function power_pmu_bhrb_to() to calculate the target/to address of
the corresponding I and B form branches.  It handles branches in both user and
kernel spaces.  It also plumbs this into the perf brhb reading code.

Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
  • Loading branch information
Michael Neuling authored and Benjamin Herrenschmidt committed May 14, 2013
1 parent 506e70d commit 6912318
Showing 1 changed file with 30 additions and 1 deletion.
31 changes: 30 additions & 1 deletion arch/powerpc/perf/core-book3s.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
#include <linux/perf_event.h>
#include <linux/percpu.h>
#include <linux/hardirq.h>
#include <linux/uaccess.h>
#include <asm/reg.h>
#include <asm/pmc.h>
#include <asm/machdep.h>
#include <asm/firmware.h>
#include <asm/ptrace.h>
#include <asm/code-patching.h>

#define BHRB_MAX_ENTRIES 32
#define BHRB_TARGET 0x0000000000000002
Expand Down Expand Up @@ -362,6 +364,32 @@ void power_pmu_flush_branch_stack(void)
if (ppmu->bhrb_nr)
power_pmu_bhrb_reset();
}
/* Calculate the to address for a branch */
static __u64 power_pmu_bhrb_to(u64 addr)
{
unsigned int instr;
int ret;
__u64 target;

if (is_kernel_addr(addr))
return branch_target((unsigned int *)addr);

/* Userspace: need copy instruction here then translate it */
pagefault_disable();
ret = __get_user_inatomic(instr, (unsigned int __user *)addr);
if (ret) {
pagefault_enable();
return 0;
}
pagefault_enable();

target = branch_target(&instr);
if ((!target) || (instr & BRANCH_ABSOLUTE))
return target;

/* Translate relative branch target from kernel to user address */
return target - (unsigned long)&instr + addr;
}

/* Processing BHRB entries */
void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
Expand Down Expand Up @@ -426,7 +454,8 @@ void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
/* Branches to immediate field
(ie I or B form) */
cpuhw->bhrb_entries[u_index].from = addr;
cpuhw->bhrb_entries[u_index].to = 0;
cpuhw->bhrb_entries[u_index].to =
power_pmu_bhrb_to(addr);
cpuhw->bhrb_entries[u_index].mispred = pred;
cpuhw->bhrb_entries[u_index].predicted = ~pred;
}
Expand Down

0 comments on commit 6912318

Please sign in to comment.