aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2012-09-06 17:24:56 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-09-09 19:59:10 -0400
commit4474ef055c5d8cb8eaf002d69e49af71e3aa3a88 (patch)
treee57b99bfa78d7c3faf4125ab4a08f17fed2c41d8
parent3ab96a02e829131c19db8ed99239289acdb4e3dc (diff)
powerpc: Rework set_dabr so it can take a DABRX value as well
Rework set_dabr to take a DABRX value as well. Both the pseries and PS3 hypervisors do some checks on the DABRX values that are passed in the hcall. This patch stops bogus values from being passed to hypervisor. Also, in the case where we are clearing the breakpoint, where DABR and DABRX are zero, we modify the DABRX value to make it valid so that the hcall won't fail. Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/include/asm/debug.h2
-rw-r--r--arch/powerpc/include/asm/hw_breakpoint.h2
-rw-r--r--arch/powerpc/include/asm/machdep.h3
-rw-r--r--arch/powerpc/include/asm/processor.h1
-rw-r--r--arch/powerpc/include/asm/reg.h3
-rw-r--r--arch/powerpc/kernel/hw_breakpoint.c12
-rw-r--r--arch/powerpc/kernel/process.c14
-rw-r--r--arch/powerpc/kernel/ptrace.c3
-rw-r--r--arch/powerpc/kernel/signal.c2
-rw-r--r--arch/powerpc/platforms/cell/beat.c4
-rw-r--r--arch/powerpc/platforms/cell/beat.h2
-rw-r--r--arch/powerpc/platforms/ps3/setup.c10
-rw-r--r--arch/powerpc/platforms/pseries/setup.c14
-rw-r--r--arch/powerpc/xmon/xmon.c4
14 files changed, 46 insertions, 30 deletions
diff --git a/arch/powerpc/include/asm/debug.h b/arch/powerpc/include/asm/debug.h
index 716d2f089eb6..32de2577bb6d 100644
--- a/arch/powerpc/include/asm/debug.h
+++ b/arch/powerpc/include/asm/debug.h
@@ -44,7 +44,7 @@ static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; }
44static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } 44static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
45#endif 45#endif
46 46
47extern int set_dabr(unsigned long dabr); 47extern int set_dabr(unsigned long dabr, unsigned long dabrx);
48#ifdef CONFIG_PPC_ADV_DEBUG_REGS 48#ifdef CONFIG_PPC_ADV_DEBUG_REGS
49extern void do_send_trap(struct pt_regs *regs, unsigned long address, 49extern void do_send_trap(struct pt_regs *regs, unsigned long address,
50 unsigned long error_code, int signal_code, int brkpt); 50 unsigned long error_code, int signal_code, int brkpt);
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index 39b323e80c30..c6f48eb5299c 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -61,7 +61,7 @@ extern void ptrace_triggered(struct perf_event *bp,
61 struct perf_sample_data *data, struct pt_regs *regs); 61 struct perf_sample_data *data, struct pt_regs *regs);
62static inline void hw_breakpoint_disable(void) 62static inline void hw_breakpoint_disable(void)
63{ 63{
64 set_dabr(0); 64 set_dabr(0, 0);
65} 65}
66extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs); 66extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs);
67 67
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 42ce570812c1..236b4779ec4f 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -180,7 +180,8 @@ struct machdep_calls {
180 void (*enable_pmcs)(void); 180 void (*enable_pmcs)(void);
181 181
182 /* Set DABR for this platform, leave empty for default implemenation */ 182 /* Set DABR for this platform, leave empty for default implemenation */
183 int (*set_dabr)(unsigned long dabr); 183 int (*set_dabr)(unsigned long dabr,
184 unsigned long dabrx);
184 185
185#ifdef CONFIG_PPC32 /* XXX for now */ 186#ifdef CONFIG_PPC32 /* XXX for now */
186 /* A general init function, called by ppc_init in init/main.c. 187 /* A general init function, called by ppc_init in init/main.c.
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 7e7fa13e4667..83efc6e81543 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -219,6 +219,7 @@ struct thread_struct {
219#endif /* CONFIG_HAVE_HW_BREAKPOINT */ 219#endif /* CONFIG_HAVE_HW_BREAKPOINT */
220#endif 220#endif
221 unsigned long dabr; /* Data address breakpoint register */ 221 unsigned long dabr; /* Data address breakpoint register */
222 unsigned long dabrx; /* ... extension */
222 unsigned long trap_nr; /* last trap # on this thread */ 223 unsigned long trap_nr; /* last trap # on this thread */
223#ifdef CONFIG_ALTIVEC 224#ifdef CONFIG_ALTIVEC
224 /* Complete AltiVec register set */ 225 /* Complete AltiVec register set */
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index ad400a535d23..121a90bbf778 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -208,6 +208,9 @@
208#define SPRN_DABRX 0x3F7 /* Data Address Breakpoint Register Extension */ 208#define SPRN_DABRX 0x3F7 /* Data Address Breakpoint Register Extension */
209#define DABRX_USER (1UL << 0) 209#define DABRX_USER (1UL << 0)
210#define DABRX_KERNEL (1UL << 1) 210#define DABRX_KERNEL (1UL << 1)
211#define DABRX_HYP (1UL << 2)
212#define DABRX_BTI (1UL << 3)
213#define DABRX_ALL (DABRX_BTI | DABRX_HYP | DABRX_KERNEL | DABRX_USER)
211#define SPRN_DAR 0x013 /* Data Address Register */ 214#define SPRN_DAR 0x013 /* Data Address Register */
212#define SPRN_DBCR 0x136 /* e300 Data Breakpoint Control Reg */ 215#define SPRN_DBCR 0x136 /* e300 Data Breakpoint Control Reg */
213#define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */ 216#define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 6767445ecb45..6891d79ecef6 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -73,7 +73,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
73 * If so, DABR will be populated in single_step_dabr_instruction(). 73 * If so, DABR will be populated in single_step_dabr_instruction().
74 */ 74 */
75 if (current->thread.last_hit_ubp != bp) 75 if (current->thread.last_hit_ubp != bp)
76 set_dabr(info->address | info->type | DABR_TRANSLATION); 76 set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
77 77
78 return 0; 78 return 0;
79} 79}
@@ -97,7 +97,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
97 } 97 }
98 98
99 *slot = NULL; 99 *slot = NULL;
100 set_dabr(0); 100 set_dabr(0, 0);
101} 101}
102 102
103/* 103/*
@@ -197,7 +197,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
197 197
198 info = counter_arch_bp(tsk->thread.last_hit_ubp); 198 info = counter_arch_bp(tsk->thread.last_hit_ubp);
199 regs->msr &= ~MSR_SE; 199 regs->msr &= ~MSR_SE;
200 set_dabr(info->address | info->type | DABR_TRANSLATION); 200 set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
201 tsk->thread.last_hit_ubp = NULL; 201 tsk->thread.last_hit_ubp = NULL;
202} 202}
203 203
@@ -215,7 +215,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
215 unsigned long dar = regs->dar; 215 unsigned long dar = regs->dar;
216 216
217 /* Disable breakpoints during exception handling */ 217 /* Disable breakpoints during exception handling */
218 set_dabr(0); 218 set_dabr(0, 0);
219 219
220 /* 220 /*
221 * The counter may be concurrently released but that can only 221 * The counter may be concurrently released but that can only
@@ -281,7 +281,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
281 if (!info->extraneous_interrupt) 281 if (!info->extraneous_interrupt)
282 perf_bp_event(bp, regs); 282 perf_bp_event(bp, regs);
283 283
284 set_dabr(info->address | info->type | DABR_TRANSLATION); 284 set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
285out: 285out:
286 rcu_read_unlock(); 286 rcu_read_unlock();
287 return rc; 287 return rc;
@@ -313,7 +313,7 @@ int __kprobes single_step_dabr_instruction(struct die_args *args)
313 if (!info->extraneous_interrupt) 313 if (!info->extraneous_interrupt)
314 perf_bp_event(bp, regs); 314 perf_bp_event(bp, regs);
315 315
316 set_dabr(info->address | info->type | DABR_TRANSLATION); 316 set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
317 current->thread.last_hit_ubp = NULL; 317 current->thread.last_hit_ubp = NULL;
318 318
319 /* 319 /*
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 2e743de545d0..50e504c29bb9 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -285,7 +285,7 @@ void do_dabr(struct pt_regs *regs, unsigned long address,
285 return; 285 return;
286 286
287 /* Clear the DABR */ 287 /* Clear the DABR */
288 set_dabr(0); 288 set_dabr(0, 0);
289 289
290 /* Deliver the signal to userspace */ 290 /* Deliver the signal to userspace */
291 info.si_signo = SIGTRAP; 291 info.si_signo = SIGTRAP;
@@ -366,18 +366,19 @@ static void set_debug_reg_defaults(struct thread_struct *thread)
366{ 366{
367 if (thread->dabr) { 367 if (thread->dabr) {
368 thread->dabr = 0; 368 thread->dabr = 0;
369 set_dabr(0); 369 thread->dabrx = 0;
370 set_dabr(0, 0);
370 } 371 }
371} 372}
372#endif /* !CONFIG_HAVE_HW_BREAKPOINT */ 373#endif /* !CONFIG_HAVE_HW_BREAKPOINT */
373#endif /* CONFIG_PPC_ADV_DEBUG_REGS */ 374#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
374 375
375int set_dabr(unsigned long dabr) 376int set_dabr(unsigned long dabr, unsigned long dabrx)
376{ 377{
377 __get_cpu_var(current_dabr) = dabr; 378 __get_cpu_var(current_dabr) = dabr;
378 379
379 if (ppc_md.set_dabr) 380 if (ppc_md.set_dabr)
380 return ppc_md.set_dabr(dabr); 381 return ppc_md.set_dabr(dabr, dabrx);
381 382
382 /* XXX should we have a CPU_FTR_HAS_DABR ? */ 383 /* XXX should we have a CPU_FTR_HAS_DABR ? */
383#ifdef CONFIG_PPC_ADV_DEBUG_REGS 384#ifdef CONFIG_PPC_ADV_DEBUG_REGS
@@ -387,9 +388,8 @@ int set_dabr(unsigned long dabr)
387#endif 388#endif
388#elif defined(CONFIG_PPC_BOOK3S) 389#elif defined(CONFIG_PPC_BOOK3S)
389 mtspr(SPRN_DABR, dabr); 390 mtspr(SPRN_DABR, dabr);
391 mtspr(SPRN_DABRX, dabrx);
390#endif 392#endif
391
392
393 return 0; 393 return 0;
394} 394}
395 395
@@ -482,7 +482,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
482 */ 482 */
483#ifndef CONFIG_HAVE_HW_BREAKPOINT 483#ifndef CONFIG_HAVE_HW_BREAKPOINT
484 if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) 484 if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr))
485 set_dabr(new->thread.dabr); 485 set_dabr(new->thread.dabr, new->thread.dabrx);
486#endif /* CONFIG_HAVE_HW_BREAKPOINT */ 486#endif /* CONFIG_HAVE_HW_BREAKPOINT */
487#endif 487#endif
488 488
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index c10fc28b9092..79d8e56470df 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -960,6 +960,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
960 thread->ptrace_bps[0] = bp; 960 thread->ptrace_bps[0] = bp;
961 ptrace_put_breakpoints(task); 961 ptrace_put_breakpoints(task);
962 thread->dabr = data; 962 thread->dabr = data;
963 thread->dabrx = DABRX_ALL;
963 return 0; 964 return 0;
964 } 965 }
965 966
@@ -983,6 +984,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
983 984
984 /* Move contents to the DABR register */ 985 /* Move contents to the DABR register */
985 task->thread.dabr = data; 986 task->thread.dabr = data;
987 task->thread.dabrx = DABRX_ALL;
986#else /* CONFIG_PPC_ADV_DEBUG_REGS */ 988#else /* CONFIG_PPC_ADV_DEBUG_REGS */
987 /* As described above, it was assumed 3 bits were passed with the data 989 /* As described above, it was assumed 3 bits were passed with the data
988 * address, but we will assume only the mode bits will be passed 990 * address, but we will assume only the mode bits will be passed
@@ -1397,6 +1399,7 @@ static long ppc_set_hwdebug(struct task_struct *child,
1397 dabr |= DABR_DATA_WRITE; 1399 dabr |= DABR_DATA_WRITE;
1398 1400
1399 child->thread.dabr = dabr; 1401 child->thread.dabr = dabr;
1402 child->thread.dabrx = DABRX_ALL;
1400 1403
1401 return 1; 1404 return 1;
1402#endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */ 1405#endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index 29be2712e560..a2dc75793bd5 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -131,7 +131,7 @@ static int do_signal(struct pt_regs *regs)
131 * triggered inside the kernel. 131 * triggered inside the kernel.
132 */ 132 */
133 if (current->thread.dabr) 133 if (current->thread.dabr)
134 set_dabr(current->thread.dabr); 134 set_dabr(current->thread.dabr, current->thread.dabrx);
135#endif 135#endif
136 /* Re-enable the breakpoints for the signal stack */ 136 /* Re-enable the breakpoints for the signal stack */
137 thread_change_pc(current, regs); 137 thread_change_pc(current, regs);
diff --git a/arch/powerpc/platforms/cell/beat.c b/arch/powerpc/platforms/cell/beat.c
index 852592b2b712..affcf566d460 100644
--- a/arch/powerpc/platforms/cell/beat.c
+++ b/arch/powerpc/platforms/cell/beat.c
@@ -136,9 +136,9 @@ ssize_t beat_nvram_get_size(void)
136 return BEAT_NVRAM_SIZE; 136 return BEAT_NVRAM_SIZE;
137} 137}
138 138
139int beat_set_xdabr(unsigned long dabr) 139int beat_set_xdabr(unsigned long dabr, unsigned long dabrx)
140{ 140{
141 if (beat_set_dabr(dabr, DABRX_KERNEL | DABRX_USER)) 141 if (beat_set_dabr(dabr, dabrx))
142 return -1; 142 return -1;
143 return 0; 143 return 0;
144} 144}
diff --git a/arch/powerpc/platforms/cell/beat.h b/arch/powerpc/platforms/cell/beat.h
index 32c8efcedc80..bfcb8e351ae5 100644
--- a/arch/powerpc/platforms/cell/beat.h
+++ b/arch/powerpc/platforms/cell/beat.h
@@ -32,7 +32,7 @@ void beat_get_rtc_time(struct rtc_time *);
32ssize_t beat_nvram_get_size(void); 32ssize_t beat_nvram_get_size(void);
33ssize_t beat_nvram_read(char *, size_t, loff_t *); 33ssize_t beat_nvram_read(char *, size_t, loff_t *);
34ssize_t beat_nvram_write(char *, size_t, loff_t *); 34ssize_t beat_nvram_write(char *, size_t, loff_t *);
35int beat_set_xdabr(unsigned long); 35int beat_set_xdabr(unsigned long, unsigned long);
36void beat_power_save(void); 36void beat_power_save(void);
37void beat_kexec_cpu_down(int, int); 37void beat_kexec_cpu_down(int, int);
38 38
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index 2d664c5a83b0..3f509f86432c 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -184,11 +184,15 @@ early_param("ps3flash", early_parse_ps3flash);
184#define prealloc_ps3flash_bounce_buffer() do { } while (0) 184#define prealloc_ps3flash_bounce_buffer() do { } while (0)
185#endif 185#endif
186 186
187static int ps3_set_dabr(unsigned long dabr) 187static int ps3_set_dabr(unsigned long dabr, unsigned long dabrx)
188{ 188{
189 enum {DABR_USER = 1, DABR_KERNEL = 2,}; 189 /* Have to set at least one bit in the DABRX */
190 if (dabrx == 0 && dabr == 0)
191 dabrx = DABRX_USER;
192 /* hypervisor only allows us to set BTI, Kernel and user */
193 dabrx &= DABRX_BTI | DABRX_KERNEL | DABRX_USER;
190 194
191 return lv1_set_dabr(dabr, DABR_KERNEL | DABR_USER) ? -1 : 0; 195 return lv1_set_dabr(dabr, dabrx) ? -1 : 0;
192} 196}
193 197
194static void __init ps3_setup_arch(void) 198static void __init ps3_setup_arch(void)
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 4a2cd48b21f6..a3a69658a6ec 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -414,16 +414,20 @@ static int __init pSeries_init_panel(void)
414} 414}
415machine_arch_initcall(pseries, pSeries_init_panel); 415machine_arch_initcall(pseries, pSeries_init_panel);
416 416
417static int pseries_set_dabr(unsigned long dabr) 417static int pseries_set_dabr(unsigned long dabr, unsigned long dabrx)
418{ 418{
419 return plpar_hcall_norets(H_SET_DABR, dabr); 419 return plpar_hcall_norets(H_SET_DABR, dabr);
420} 420}
421 421
422static int pseries_set_xdabr(unsigned long dabr) 422static int pseries_set_xdabr(unsigned long dabr, unsigned long dabrx)
423{ 423{
424 /* We want to catch accesses from kernel and userspace */ 424 /* Have to set at least one bit in the DABRX according to PAPR */
425 return plpar_hcall_norets(H_SET_XDABR, dabr, 425 if (dabrx == 0 && dabr == 0)
426 H_DABRX_KERNEL | H_DABRX_USER); 426 dabrx = DABRX_USER;
427 /* PAPR says we can only set kernel and user bits */
428 dabrx &= H_DABRX_KERNEL | H_DABRX_USER;
429
430 return plpar_hcall_norets(H_SET_XDABR, dabr, dabrx);
427} 431}
428 432
429#define CMO_CHARACTERISTICS_TOKEN 44 433#define CMO_CHARACTERISTICS_TOKEN 44
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 9b49c65ee7a4..987f441525cb 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -740,7 +740,7 @@ static void insert_bpts(void)
740static void insert_cpu_bpts(void) 740static void insert_cpu_bpts(void)
741{ 741{
742 if (dabr.enabled) 742 if (dabr.enabled)
743 set_dabr(dabr.address | (dabr.enabled & 7)); 743 set_dabr(dabr.address | (dabr.enabled & 7), DABRX_ALL);
744 if (iabr && cpu_has_feature(CPU_FTR_IABR)) 744 if (iabr && cpu_has_feature(CPU_FTR_IABR))
745 mtspr(SPRN_IABR, iabr->address 745 mtspr(SPRN_IABR, iabr->address
746 | (iabr->enabled & (BP_IABR|BP_IABR_TE))); 746 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
@@ -768,7 +768,7 @@ static void remove_bpts(void)
768 768
769static void remove_cpu_bpts(void) 769static void remove_cpu_bpts(void)
770{ 770{
771 set_dabr(0); 771 set_dabr(0, 0);
772 if (cpu_has_feature(CPU_FTR_IABR)) 772 if (cpu_has_feature(CPU_FTR_IABR))
773 mtspr(SPRN_IABR, 0); 773 mtspr(SPRN_IABR, 0);
774} 774}