diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/a.out-core.h | 8 | ||||
-rw-r--r-- | arch/x86/include/asm/debugreg.h | 29 | ||||
-rw-r--r-- | arch/x86/include/asm/hw_breakpoint.h | 55 | ||||
-rw-r--r-- | arch/x86/include/asm/processor.h | 8 | ||||
-rw-r--r-- | arch/x86/kernel/process.c | 16 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 16 | ||||
-rw-r--r-- | arch/x86/power/cpu_32.c | 8 | ||||
-rw-r--r-- | arch/x86/power/cpu_64.c | 8 |
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 */ | ||
79 | extern void flush_thread_hw_breakpoint(struct task_struct *tsk); | ||
80 | extern int copy_thread_hw_breakpoint(struct task_struct *tsk, | ||
81 | struct task_struct *child, unsigned long clone_flags); | ||
82 | |||
83 | /* For CPU management */ | ||
84 | extern void load_debug_registers(void); | ||
85 | static 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 | |||
7 | struct 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 | |||
39 | extern struct hw_breakpoint *hbp_kernel[HBP_NUM]; | ||
40 | DECLARE_PER_CPU(struct hw_breakpoint*, this_hbp_kernel[HBP_NUM]); | ||
41 | extern unsigned int hbp_user_refcount[HBP_NUM]; | ||
42 | |||
43 | extern void arch_install_thread_hw_breakpoint(struct task_struct *tsk); | ||
44 | extern void arch_uninstall_thread_hw_breakpoint(void); | ||
45 | extern int arch_check_va_in_userspace(unsigned long va, u8 hbp_len); | ||
46 | extern int arch_validate_hwbkpt_settings(struct hw_breakpoint *bp, | ||
47 | struct task_struct *tsk); | ||
48 | extern void arch_update_user_hw_breakpoint(int pos, struct task_struct *tsk); | ||
49 | extern void arch_flush_thread_hw_breakpoint(struct task_struct *tsk); | ||
50 | extern void arch_update_kernel_hw_breakpoint(void *); | ||
51 | extern 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, | |||
471 | static unsigned long ptrace_get_debugreg(struct task_struct *child, int n) | 471 | static 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(¤t->thread, 0); | 166 | set_debugreg(current->thread.debugreg[0], 0); |
167 | loaddebug(¤t->thread, 1); | 167 | set_debugreg(current->thread.debugreg[1], 1); |
168 | loaddebug(¤t->thread, 2); | 168 | set_debugreg(current->thread.debugreg[2], 2); |
169 | loaddebug(¤t->thread, 3); | 169 | set_debugreg(current->thread.debugreg[3], 3); |
170 | /* no 4 and 5 */ | 170 | /* no 4 and 5 */ |
171 | loaddebug(¤t->thread, 6); | 171 | loaddebug(¤t->thread, 6); |
172 | loaddebug(¤t->thread, 7); | 172 | loaddebug(¤t->thread, 7); |