aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-11-26 00:04:38 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-26 03:29:22 -0500
commit2c31b7958fd21df9fa04e5c36cda0f063ac70b27 (patch)
treeeb6b7468b04cbe9fb13eb88aba94e0f28b3f4234
parent605bfaee9078cd0b01d83402315389839ee4bb5c (diff)
x86/hw-breakpoints: Don't lose GE flag while disabling a breakpoint
When we schedule out a breakpoint from the cpu, we also incidentally remove the "Global exact breakpoint" flag from the breakpoint control register. It makes us losing the fine grained precision about the origin of the instructions that may trigger breakpoint exceptions for the other breakpoints running in this cpu. Reported-by: Prasad <prasad@linux.vnet.ibm.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <1259211878-6013-1-git-send-regression-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/kernel/hw_breakpoint.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c
index 92ea5aad0b5c..d42f65ac4927 100644
--- a/arch/x86/kernel/hw_breakpoint.c
+++ b/arch/x86/kernel/hw_breakpoint.c
@@ -59,22 +59,28 @@ static DEFINE_PER_CPU(unsigned long, cpu_debugreg[HBP_NUM]);
59static DEFINE_PER_CPU(struct perf_event *, bp_per_reg[HBP_NUM]); 59static DEFINE_PER_CPU(struct perf_event *, bp_per_reg[HBP_NUM]);
60 60
61 61
62/* 62static inline unsigned long
63 * Encode the length, type, Exact, and Enable bits for a particular breakpoint 63__encode_dr7(int drnum, unsigned int len, unsigned int type)
64 * as stored in debug register 7.
65 */
66unsigned long encode_dr7(int drnum, unsigned int len, unsigned int type)
67{ 64{
68 unsigned long bp_info; 65 unsigned long bp_info;
69 66
70 bp_info = (len | type) & 0xf; 67 bp_info = (len | type) & 0xf;
71 bp_info <<= (DR_CONTROL_SHIFT + drnum * DR_CONTROL_SIZE); 68 bp_info <<= (DR_CONTROL_SHIFT + drnum * DR_CONTROL_SIZE);
72 bp_info |= (DR_GLOBAL_ENABLE << (drnum * DR_ENABLE_SIZE)) | 69 bp_info |= (DR_GLOBAL_ENABLE << (drnum * DR_ENABLE_SIZE));
73 DR_GLOBAL_SLOWDOWN; 70
74 return bp_info; 71 return bp_info;
75} 72}
76 73
77/* 74/*
75 * Encode the length, type, Exact, and Enable bits for a particular breakpoint
76 * as stored in debug register 7.
77 */
78unsigned long encode_dr7(int drnum, unsigned int len, unsigned int type)
79{
80 return __encode_dr7(drnum, len, type) | DR_GLOBAL_SLOWDOWN;
81}
82
83/*
78 * Decode the length and type bits for a particular breakpoint as 84 * Decode the length and type bits for a particular breakpoint as
79 * stored in debug register 7. Return the "enabled" status. 85 * stored in debug register 7. Return the "enabled" status.
80 */ 86 */
@@ -154,7 +160,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
154 return; 160 return;
155 161
156 dr7 = &__get_cpu_var(cpu_dr7); 162 dr7 = &__get_cpu_var(cpu_dr7);
157 *dr7 &= ~encode_dr7(i, info->len, info->type); 163 *dr7 &= ~__encode_dr7(i, info->len, info->type);
158 164
159 set_debugreg(*dr7, 7); 165 set_debugreg(*dr7, 7);
160} 166}