powerpc: Dynamically calculate the dabrx based on kernel/user/hypervisor
Currently we mark the DABRX to interrupt on all matches (hypervisor/kernel/user and then filter in software. We can be a lot smarter now that we can set the DABRX dynamically. This sets the DABRX based on the flags passed by the user. Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
4474ef055c
commit
cd14457304
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
struct arch_hw_breakpoint {
|
struct arch_hw_breakpoint {
|
||||||
unsigned long address;
|
unsigned long address;
|
||||||
|
unsigned long dabrx;
|
||||||
int type;
|
int type;
|
||||||
u8 len; /* length of the target data symbol */
|
u8 len; /* length of the target data symbol */
|
||||||
bool extraneous_interrupt;
|
bool extraneous_interrupt;
|
||||||
|
@ -73,7 +73,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
|
|||||||
* If so, DABR will be populated in single_step_dabr_instruction().
|
* If so, DABR will be populated in single_step_dabr_instruction().
|
||||||
*/
|
*/
|
||||||
if (current->thread.last_hit_ubp != bp)
|
if (current->thread.last_hit_ubp != bp)
|
||||||
set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
|
set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -170,6 +170,13 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
|||||||
|
|
||||||
info->address = bp->attr.bp_addr;
|
info->address = bp->attr.bp_addr;
|
||||||
info->len = bp->attr.bp_len;
|
info->len = bp->attr.bp_len;
|
||||||
|
info->dabrx = DABRX_ALL;
|
||||||
|
if (bp->attr.exclude_user)
|
||||||
|
info->dabrx &= ~DABRX_USER;
|
||||||
|
if (bp->attr.exclude_kernel)
|
||||||
|
info->dabrx &= ~DABRX_KERNEL;
|
||||||
|
if (bp->attr.exclude_hv)
|
||||||
|
info->dabrx &= ~DABRX_HYP;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8)
|
* Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8)
|
||||||
@ -197,7 +204,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
|
|||||||
|
|
||||||
info = counter_arch_bp(tsk->thread.last_hit_ubp);
|
info = counter_arch_bp(tsk->thread.last_hit_ubp);
|
||||||
regs->msr &= ~MSR_SE;
|
regs->msr &= ~MSR_SE;
|
||||||
set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
|
set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
|
||||||
tsk->thread.last_hit_ubp = NULL;
|
tsk->thread.last_hit_ubp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +288,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
|
|||||||
if (!info->extraneous_interrupt)
|
if (!info->extraneous_interrupt)
|
||||||
perf_bp_event(bp, regs);
|
perf_bp_event(bp, regs);
|
||||||
|
|
||||||
set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
|
set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
|
||||||
out:
|
out:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return rc;
|
return rc;
|
||||||
@ -313,7 +320,7 @@ int __kprobes single_step_dabr_instruction(struct die_args *args)
|
|||||||
if (!info->extraneous_interrupt)
|
if (!info->extraneous_interrupt)
|
||||||
perf_bp_event(bp, regs);
|
perf_bp_event(bp, regs);
|
||||||
|
|
||||||
set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
|
set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
|
||||||
current->thread.last_hit_ubp = NULL;
|
current->thread.last_hit_ubp = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -425,7 +425,7 @@ static int pseries_set_xdabr(unsigned long dabr, unsigned long dabrx)
|
|||||||
if (dabrx == 0 && dabr == 0)
|
if (dabrx == 0 && dabr == 0)
|
||||||
dabrx = DABRX_USER;
|
dabrx = DABRX_USER;
|
||||||
/* PAPR says we can only set kernel and user bits */
|
/* PAPR says we can only set kernel and user bits */
|
||||||
dabrx &= H_DABRX_KERNEL | H_DABRX_USER;
|
dabrx &= DABRX_KERNEL | DABRX_USER;
|
||||||
|
|
||||||
return plpar_hcall_norets(H_SET_XDABR, dabr, dabrx);
|
return plpar_hcall_norets(H_SET_XDABR, dabr, dabrx);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user