Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Michael Neuling and committed by
Benjamin Herrenschmidt
4474ef05 3ab96a02

+46 -30
+1 -1
arch/powerpc/include/asm/debug.h
··· 44 44 static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } 45 45 #endif 46 46 47 - extern int set_dabr(unsigned long dabr); 47 + extern int set_dabr(unsigned long dabr, unsigned long dabrx); 48 48 #ifdef CONFIG_PPC_ADV_DEBUG_REGS 49 49 extern void do_send_trap(struct pt_regs *regs, unsigned long address, 50 50 unsigned long error_code, int signal_code, int brkpt);
+1 -1
arch/powerpc/include/asm/hw_breakpoint.h
··· 61 61 struct perf_sample_data *data, struct pt_regs *regs); 62 62 static inline void hw_breakpoint_disable(void) 63 63 { 64 - set_dabr(0); 64 + set_dabr(0, 0); 65 65 } 66 66 extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs); 67 67
+2 -1
arch/powerpc/include/asm/machdep.h
··· 180 180 void (*enable_pmcs)(void); 181 181 182 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 186 #ifdef CONFIG_PPC32 /* XXX for now */ 186 187 /* A general init function, called by ppc_init in init/main.c.
+1
arch/powerpc/include/asm/processor.h
··· 219 219 #endif /* CONFIG_HAVE_HW_BREAKPOINT */ 220 220 #endif 221 221 unsigned long dabr; /* Data address breakpoint register */ 222 + unsigned long dabrx; /* ... extension */ 222 223 unsigned long trap_nr; /* last trap # on this thread */ 223 224 #ifdef CONFIG_ALTIVEC 224 225 /* Complete AltiVec register set */
+3
arch/powerpc/include/asm/reg.h
··· 208 208 #define SPRN_DABRX 0x3F7 /* Data Address Breakpoint Register Extension */ 209 209 #define DABRX_USER (1UL << 0) 210 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 214 #define SPRN_DAR 0x013 /* Data Address Register */ 212 215 #define SPRN_DBCR 0x136 /* e300 Data Breakpoint Control Reg */ 213 216 #define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */
+6 -6
arch/powerpc/kernel/hw_breakpoint.c
··· 73 73 * If so, DABR will be populated in single_step_dabr_instruction(). 74 74 */ 75 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 78 return 0; 79 79 } ··· 97 97 } 98 98 99 99 *slot = NULL; 100 - set_dabr(0); 100 + set_dabr(0, 0); 101 101 } 102 102 103 103 /* ··· 197 197 198 198 info = counter_arch_bp(tsk->thread.last_hit_ubp); 199 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 201 tsk->thread.last_hit_ubp = NULL; 202 202 } 203 203 ··· 215 215 unsigned long dar = regs->dar; 216 216 217 217 /* Disable breakpoints during exception handling */ 218 - set_dabr(0); 218 + set_dabr(0, 0); 219 219 220 220 /* 221 221 * The counter may be concurrently released but that can only ··· 281 281 if (!info->extraneous_interrupt) 282 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); 285 285 out: 286 286 rcu_read_unlock(); 287 287 return rc; ··· 313 313 if (!info->extraneous_interrupt) 314 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 317 current->thread.last_hit_ubp = NULL; 318 318 319 319 /*
+7 -7
arch/powerpc/kernel/process.c
··· 285 285 return; 286 286 287 287 /* Clear the DABR */ 288 - set_dabr(0); 288 + set_dabr(0, 0); 289 289 290 290 /* Deliver the signal to userspace */ 291 291 info.si_signo = SIGTRAP; ··· 366 366 { 367 367 if (thread->dabr) { 368 368 thread->dabr = 0; 369 - set_dabr(0); 369 + thread->dabrx = 0; 370 + set_dabr(0, 0); 370 371 } 371 372 } 372 373 #endif /* !CONFIG_HAVE_HW_BREAKPOINT */ 373 374 #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ 374 375 375 - int set_dabr(unsigned long dabr) 376 + int set_dabr(unsigned long dabr, unsigned long dabrx) 376 377 { 377 378 __get_cpu_var(current_dabr) = dabr; 378 379 379 380 if (ppc_md.set_dabr) 380 - return ppc_md.set_dabr(dabr); 381 + return ppc_md.set_dabr(dabr, dabrx); 381 382 382 383 /* XXX should we have a CPU_FTR_HAS_DABR ? */ 383 384 #ifdef CONFIG_PPC_ADV_DEBUG_REGS ··· 388 387 #endif 389 388 #elif defined(CONFIG_PPC_BOOK3S) 390 389 mtspr(SPRN_DABR, dabr); 390 + mtspr(SPRN_DABRX, dabrx); 391 391 #endif 392 - 393 - 394 392 return 0; 395 393 } 396 394 ··· 482 482 */ 483 483 #ifndef CONFIG_HAVE_HW_BREAKPOINT 484 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 486 #endif /* CONFIG_HAVE_HW_BREAKPOINT */ 487 487 #endif 488 488
+3
arch/powerpc/kernel/ptrace.c
··· 960 960 thread->ptrace_bps[0] = bp; 961 961 ptrace_put_breakpoints(task); 962 962 thread->dabr = data; 963 + thread->dabrx = DABRX_ALL; 963 964 return 0; 964 965 } 965 966 ··· 984 983 985 984 /* Move contents to the DABR register */ 986 985 task->thread.dabr = data; 986 + task->thread.dabrx = DABRX_ALL; 987 987 #else /* CONFIG_PPC_ADV_DEBUG_REGS */ 988 988 /* As described above, it was assumed 3 bits were passed with the data 989 989 * address, but we will assume only the mode bits will be passed ··· 1399 1397 dabr |= DABR_DATA_WRITE; 1400 1398 1401 1399 child->thread.dabr = dabr; 1400 + child->thread.dabrx = DABRX_ALL; 1402 1401 1403 1402 return 1; 1404 1403 #endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */
+1 -1
arch/powerpc/kernel/signal.c
··· 131 131 * triggered inside the kernel. 132 132 */ 133 133 if (current->thread.dabr) 134 - set_dabr(current->thread.dabr); 134 + set_dabr(current->thread.dabr, current->thread.dabrx); 135 135 #endif 136 136 /* Re-enable the breakpoints for the signal stack */ 137 137 thread_change_pc(current, regs);
+2 -2
arch/powerpc/platforms/cell/beat.c
··· 136 136 return BEAT_NVRAM_SIZE; 137 137 } 138 138 139 - int beat_set_xdabr(unsigned long dabr) 139 + int 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 142 return -1; 143 143 return 0; 144 144 }
+1 -1
arch/powerpc/platforms/cell/beat.h
··· 32 32 ssize_t beat_nvram_get_size(void); 33 33 ssize_t beat_nvram_read(char *, size_t, loff_t *); 34 34 ssize_t beat_nvram_write(char *, size_t, loff_t *); 35 - int beat_set_xdabr(unsigned long); 35 + int beat_set_xdabr(unsigned long, unsigned long); 36 36 void beat_power_save(void); 37 37 void beat_kexec_cpu_down(int, int); 38 38
+7 -3
arch/powerpc/platforms/ps3/setup.c
··· 184 184 #define prealloc_ps3flash_bounce_buffer() do { } while (0) 185 185 #endif 186 186 187 - static int ps3_set_dabr(unsigned long dabr) 187 + static 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 194 198 static void __init ps3_setup_arch(void)
+9 -5
arch/powerpc/platforms/pseries/setup.c
··· 414 414 } 415 415 machine_arch_initcall(pseries, pSeries_init_panel); 416 416 417 - static int pseries_set_dabr(unsigned long dabr) 417 + static int pseries_set_dabr(unsigned long dabr, unsigned long dabrx) 418 418 { 419 419 return plpar_hcall_norets(H_SET_DABR, dabr); 420 420 } 421 421 422 - static int pseries_set_xdabr(unsigned long dabr) 422 + static int pseries_set_xdabr(unsigned long dabr, unsigned long dabrx) 423 423 { 424 - /* We want to catch accesses from kernel and userspace */ 425 - return plpar_hcall_norets(H_SET_XDABR, dabr, 426 - H_DABRX_KERNEL | H_DABRX_USER); 424 + /* Have to set at least one bit in the DABRX according to PAPR */ 425 + if (dabrx == 0 && dabr == 0) 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 433 #define CMO_CHARACTERISTICS_TOKEN 44
+2 -2
arch/powerpc/xmon/xmon.c
··· 740 740 static void insert_cpu_bpts(void) 741 741 { 742 742 if (dabr.enabled) 743 - set_dabr(dabr.address | (dabr.enabled & 7)); 743 + set_dabr(dabr.address | (dabr.enabled & 7), DABRX_ALL); 744 744 if (iabr && cpu_has_feature(CPU_FTR_IABR)) 745 745 mtspr(SPRN_IABR, iabr->address 746 746 | (iabr->enabled & (BP_IABR|BP_IABR_TE))); ··· 768 768 769 769 static void remove_cpu_bpts(void) 770 770 { 771 - set_dabr(0); 771 + set_dabr(0, 0); 772 772 if (cpu_has_feature(CPU_FTR_IABR)) 773 773 mtspr(SPRN_IABR, 0); 774 774 }