aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/a.out-core.h8
-rw-r--r--arch/x86/include/asm/debugreg.h29
-rw-r--r--arch/x86/include/asm/hw_breakpoint.h55
-rw-r--r--arch/x86/include/asm/processor.h8
-rw-r--r--arch/x86/kernel/process.c16
-rw-r--r--arch/x86/kernel/ptrace.c16
-rw-r--r--arch/x86/power/cpu_32.c8
-rw-r--r--arch/x86/power/cpu_64.c8
8 files changed, 116 insertions, 32 deletions
diff --git a/arch/x86/include/asm/a.out-core.h b/arch/x86/include/asm/a.out-core.h
index bb70e397aa84..fc4685dd6e4d 100644
--- a/arch/x86/include/asm/a.out-core.h
+++ b/arch/x86/include/asm/a.out-core.h
@@ -32,10 +32,10 @@ static inline void aout_dump_thread(struct pt_regs *regs, struct user *dump)
32 >> PAGE_SHIFT; 32 >> PAGE_SHIFT;
33 dump->u_dsize -= dump->u_tsize; 33 dump->u_dsize -= dump->u_tsize;
34 dump->u_ssize = 0; 34 dump->u_ssize = 0;
35 dump->u_debugreg[0] = current->thread.debugreg0; 35 dump->u_debugreg[0] = current->thread.debugreg[0];
36 dump->u_debugreg[1] = current->thread.debugreg1; 36 dump->u_debugreg[1] = current->thread.debugreg[1];
37 dump->u_debugreg[2] = current->thread.debugreg2; 37 dump->u_debugreg[2] = current->thread.debugreg[2];
38 dump->u_debugreg[3] = current->thread.debugreg3; 38 dump->u_debugreg[3] = current->thread.debugreg[3];
39 dump->u_debugreg[4] = 0; 39 dump->u_debugreg[4] = 0;
40 dump->u_debugreg[5] = 0; 40 dump->u_debugreg[5] = 0;
41 dump->u_debugreg[6] = current->thread.debugreg6; 41 dump->u_debugreg[6] = current->thread.debugreg6;
diff --git a/arch/x86/include/asm/debugreg.h b/arch/x86/include/asm/debugreg.h
index 3ea6f37be9e2..23439fbb1d0e 100644
--- a/arch/x86/include/asm/debugreg.h
+++ b/arch/x86/include/asm/debugreg.h
@@ -18,6 +18,7 @@
18#define DR_TRAP1 (0x2) /* db1 */ 18#define DR_TRAP1 (0x2) /* db1 */
19#define DR_TRAP2 (0x4) /* db2 */ 19#define DR_TRAP2 (0x4) /* db2 */
20#define DR_TRAP3 (0x8) /* db3 */ 20#define DR_TRAP3 (0x8) /* db3 */
21#define DR_TRAP_BITS (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)
21 22
22#define DR_STEP (0x4000) /* single-step */ 23#define DR_STEP (0x4000) /* single-step */
23#define DR_SWITCH (0x8000) /* task switch */ 24#define DR_SWITCH (0x8000) /* task switch */
@@ -49,6 +50,8 @@
49 50
50#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit */ 51#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit */
51#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit */ 52#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit */
53#define DR_LOCAL_ENABLE (0x1) /* Local enable for reg 0 */
54#define DR_GLOBAL_ENABLE (0x2) /* Global enable for reg 0 */
52#define DR_ENABLE_SIZE 2 /* 2 enable bits per register */ 55#define DR_ENABLE_SIZE 2 /* 2 enable bits per register */
53 56
54#define DR_LOCAL_ENABLE_MASK (0x55) /* Set local bits for all 4 regs */ 57#define DR_LOCAL_ENABLE_MASK (0x55) /* Set local bits for all 4 regs */
@@ -67,4 +70,30 @@
67#define DR_LOCAL_SLOWDOWN (0x100) /* Local slow the pipeline */ 70#define DR_LOCAL_SLOWDOWN (0x100) /* Local slow the pipeline */
68#define DR_GLOBAL_SLOWDOWN (0x200) /* Global slow the pipeline */ 71#define DR_GLOBAL_SLOWDOWN (0x200) /* Global slow the pipeline */
69 72
73/*
74 * HW breakpoint additions
75 */
76#ifdef __KERNEL__
77
78/* For process management */
79extern void flush_thread_hw_breakpoint(struct task_struct *tsk);
80extern int copy_thread_hw_breakpoint(struct task_struct *tsk,
81 struct task_struct *child, unsigned long clone_flags);
82
83/* For CPU management */
84extern void load_debug_registers(void);
85static inline void hw_breakpoint_disable(void)
86{
87 /* Zero the control register for HW Breakpoint */
88 set_debugreg(0UL, 7);
89
90 /* Zero-out the individual HW breakpoint address registers */
91 set_debugreg(0UL, 0);
92 set_debugreg(0UL, 1);
93 set_debugreg(0UL, 2);
94 set_debugreg(0UL, 3);
95}
96
97#endif /* __KERNEL__ */
98
70#endif /* _ASM_X86_DEBUGREG_H */ 99#endif /* _ASM_X86_DEBUGREG_H */
diff --git a/arch/x86/include/asm/hw_breakpoint.h b/arch/x86/include/asm/hw_breakpoint.h
new file mode 100644
index 000000000000..1acb4d45de70
--- /dev/null
+++ b/arch/x86/include/asm/hw_breakpoint.h
@@ -0,0 +1,55 @@
1#ifndef _I386_HW_BREAKPOINT_H
2#define _I386_HW_BREAKPOINT_H
3
4#ifdef __KERNEL__
5#define __ARCH_HW_BREAKPOINT_H
6
7struct arch_hw_breakpoint {
8 char *name; /* Contains name of the symbol to set bkpt */
9 unsigned long address;
10 u8 len;
11 u8 type;
12};
13
14#include <linux/kdebug.h>
15#include <asm-generic/hw_breakpoint.h>
16
17/* Available HW breakpoint length encodings */
18#define HW_BREAKPOINT_LEN_1 0x40
19#define HW_BREAKPOINT_LEN_2 0x44
20#define HW_BREAKPOINT_LEN_4 0x4c
21#define HW_BREAKPOINT_LEN_EXECUTE 0x40
22
23#ifdef CONFIG_X86_64
24#define HW_BREAKPOINT_LEN_8 0x48
25#endif
26
27/* Available HW breakpoint type encodings */
28
29/* trigger on instruction execute */
30#define HW_BREAKPOINT_EXECUTE 0x80
31/* trigger on memory write */
32#define HW_BREAKPOINT_WRITE 0x81
33/* trigger on memory read or write */
34#define HW_BREAKPOINT_RW 0x83
35
36/* Total number of available HW breakpoint registers */
37#define HBP_NUM 4
38
39extern struct hw_breakpoint *hbp_kernel[HBP_NUM];
40DECLARE_PER_CPU(struct hw_breakpoint*, this_hbp_kernel[HBP_NUM]);
41extern unsigned int hbp_user_refcount[HBP_NUM];
42
43extern void arch_install_thread_hw_breakpoint(struct task_struct *tsk);
44extern void arch_uninstall_thread_hw_breakpoint(void);
45extern int arch_check_va_in_userspace(unsigned long va, u8 hbp_len);
46extern int arch_validate_hwbkpt_settings(struct hw_breakpoint *bp,
47 struct task_struct *tsk);
48extern void arch_update_user_hw_breakpoint(int pos, struct task_struct *tsk);
49extern void arch_flush_thread_hw_breakpoint(struct task_struct *tsk);
50extern void arch_update_kernel_hw_breakpoint(void *);
51extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
52 unsigned long val, void *data);
53#endif /* __KERNEL__ */
54#endif /* _I386_HW_BREAKPOINT_H */
55
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 0b2fab0051e0..448b34a8e393 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -29,6 +29,7 @@ struct mm_struct;
29#include <linux/threads.h> 29#include <linux/threads.h>
30#include <linux/init.h> 30#include <linux/init.h>
31 31
32#define HBP_NUM 4
32/* 33/*
33 * Default implementation of macro that returns current 34 * Default implementation of macro that returns current
34 * instruction pointer ("program counter"). 35 * instruction pointer ("program counter").
@@ -431,12 +432,11 @@ struct thread_struct {
431 unsigned long fs; 432 unsigned long fs;
432 unsigned long gs; 433 unsigned long gs;
433 /* Hardware debugging registers: */ 434 /* Hardware debugging registers: */
434 unsigned long debugreg0; 435 unsigned long debugreg[HBP_NUM];
435 unsigned long debugreg1;
436 unsigned long debugreg2;
437 unsigned long debugreg3;
438 unsigned long debugreg6; 436 unsigned long debugreg6;
439 unsigned long debugreg7; 437 unsigned long debugreg7;
438 /* Hardware breakpoint info */
439 struct hw_breakpoint *hbp[HBP_NUM];
440 /* Fault info: */ 440 /* Fault info: */
441 unsigned long cr2; 441 unsigned long cr2;
442 unsigned long trap_no; 442 unsigned long trap_no;
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index fb5dfb891f0f..291527cb438a 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -106,10 +106,10 @@ void flush_thread(void)
106 106
107 clear_tsk_thread_flag(tsk, TIF_DEBUG); 107 clear_tsk_thread_flag(tsk, TIF_DEBUG);
108 108
109 tsk->thread.debugreg0 = 0; 109 tsk->thread.debugreg[0] = 0;
110 tsk->thread.debugreg1 = 0; 110 tsk->thread.debugreg[1] = 0;
111 tsk->thread.debugreg2 = 0; 111 tsk->thread.debugreg[2] = 0;
112 tsk->thread.debugreg3 = 0; 112 tsk->thread.debugreg[3] = 0;
113 tsk->thread.debugreg6 = 0; 113 tsk->thread.debugreg6 = 0;
114 tsk->thread.debugreg7 = 0; 114 tsk->thread.debugreg7 = 0;
115 memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); 115 memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
@@ -194,10 +194,10 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
194 update_debugctlmsr(next->debugctlmsr); 194 update_debugctlmsr(next->debugctlmsr);
195 195
196 if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { 196 if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
197 set_debugreg(next->debugreg0, 0); 197 set_debugreg(next->debugreg[0], 0);
198 set_debugreg(next->debugreg1, 1); 198 set_debugreg(next->debugreg[1], 1);
199 set_debugreg(next->debugreg2, 2); 199 set_debugreg(next->debugreg[2], 2);
200 set_debugreg(next->debugreg3, 3); 200 set_debugreg(next->debugreg[3], 3);
201 /* no 4 and 5 */ 201 /* no 4 and 5 */
202 set_debugreg(next->debugreg6, 6); 202 set_debugreg(next->debugreg6, 6);
203 set_debugreg(next->debugreg7, 7); 203 set_debugreg(next->debugreg7, 7);
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 09ecbde91c13..313be40be55a 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -471,10 +471,10 @@ static int genregs_set(struct task_struct *target,
471static unsigned long ptrace_get_debugreg(struct task_struct *child, int n) 471static unsigned long ptrace_get_debugreg(struct task_struct *child, int n)
472{ 472{
473 switch (n) { 473 switch (n) {
474 case 0: return child->thread.debugreg0; 474 case 0: return child->thread.debugreg[0];
475 case 1: return child->thread.debugreg1; 475 case 1: return child->thread.debugreg[1];
476 case 2: return child->thread.debugreg2; 476 case 2: return child->thread.debugreg[2];
477 case 3: return child->thread.debugreg3; 477 case 3: return child->thread.debugreg[3];
478 case 6: return child->thread.debugreg6; 478 case 6: return child->thread.debugreg6;
479 case 7: return child->thread.debugreg7; 479 case 7: return child->thread.debugreg7;
480 } 480 }
@@ -493,10 +493,10 @@ static int ptrace_set_debugreg(struct task_struct *child,
493 return -EIO; 493 return -EIO;
494 494
495 switch (n) { 495 switch (n) {
496 case 0: child->thread.debugreg0 = data; break; 496 case 0: child->thread.debugreg[0] = data; break;
497 case 1: child->thread.debugreg1 = data; break; 497 case 1: child->thread.debugreg[1] = data; break;
498 case 2: child->thread.debugreg2 = data; break; 498 case 2: child->thread.debugreg[2] = data; break;
499 case 3: child->thread.debugreg3 = data; break; 499 case 3: child->thread.debugreg[3] = data; break;
500 500
501 case 6: 501 case 6:
502 if ((data & ~0xffffffffUL) != 0) 502 if ((data & ~0xffffffffUL) != 0)
diff --git a/arch/x86/power/cpu_32.c b/arch/x86/power/cpu_32.c
index ce702c5b3a2c..519913948003 100644
--- a/arch/x86/power/cpu_32.c
+++ b/arch/x86/power/cpu_32.c
@@ -84,10 +84,10 @@ static void fix_processor_context(void)
84 * Now maybe reload the debug registers 84 * Now maybe reload the debug registers
85 */ 85 */
86 if (current->thread.debugreg7) { 86 if (current->thread.debugreg7) {
87 set_debugreg(current->thread.debugreg0, 0); 87 set_debugreg(current->thread.debugreg[0], 0);
88 set_debugreg(current->thread.debugreg1, 1); 88 set_debugreg(current->thread.debugreg[1], 1);
89 set_debugreg(current->thread.debugreg2, 2); 89 set_debugreg(current->thread.debugreg[2], 2);
90 set_debugreg(current->thread.debugreg3, 3); 90 set_debugreg(current->thread.debugreg[3], 3);
91 /* no 4 and 5 */ 91 /* no 4 and 5 */
92 set_debugreg(current->thread.debugreg6, 6); 92 set_debugreg(current->thread.debugreg6, 6);
93 set_debugreg(current->thread.debugreg7, 7); 93 set_debugreg(current->thread.debugreg7, 7);
diff --git a/arch/x86/power/cpu_64.c b/arch/x86/power/cpu_64.c
index 5343540f2607..1e3bdcc959ff 100644
--- a/arch/x86/power/cpu_64.c
+++ b/arch/x86/power/cpu_64.c
@@ -163,10 +163,10 @@ static void fix_processor_context(void)
163 * Now maybe reload the debug registers 163 * Now maybe reload the debug registers
164 */ 164 */
165 if (current->thread.debugreg7){ 165 if (current->thread.debugreg7){
166 loaddebug(&current->thread, 0); 166 set_debugreg(current->thread.debugreg[0], 0);
167 loaddebug(&current->thread, 1); 167 set_debugreg(current->thread.debugreg[1], 1);
168 loaddebug(&current->thread, 2); 168 set_debugreg(current->thread.debugreg[2], 2);
169 loaddebug(&current->thread, 3); 169 set_debugreg(current->thread.debugreg[3], 3);
170 /* no 4 and 5 */ 170 /* no 4 and 5 */
171 loaddebug(&current->thread, 6); 171 loaddebug(&current->thread, 6);
172 loaddebug(&current->thread, 7); 172 loaddebug(&current->thread, 7);