diff options
-rw-r--r-- | Documentation/powerpc/ptrace.txt | 134 | ||||
-rw-r--r-- | arch/powerpc/include/asm/ptrace.h | 77 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 90 |
3 files changed, 301 insertions, 0 deletions
diff --git a/Documentation/powerpc/ptrace.txt b/Documentation/powerpc/ptrace.txt new file mode 100644 index 000000000000..f4a5499b7bc6 --- /dev/null +++ b/Documentation/powerpc/ptrace.txt | |||
@@ -0,0 +1,134 @@ | |||
1 | GDB intends to support the following hardware debug features of BookE | ||
2 | processors: | ||
3 | |||
4 | 4 hardware breakpoints (IAC) | ||
5 | 2 hardware watchpoints (read, write and read-write) (DAC) | ||
6 | 2 value conditions for the hardware watchpoints (DVC) | ||
7 | |||
8 | For that, we need to extend ptrace so that GDB can query and set these | ||
9 | resources. Since we're extending, we're trying to create an interface | ||
10 | that's extendable and that covers both BookE and server processors, so | ||
11 | that GDB doesn't need to special-case each of them. We added the | ||
12 | following 3 new ptrace requests. | ||
13 | |||
14 | 1. PTRACE_PPC_GETHWDEBUGINFO | ||
15 | |||
16 | Query for GDB to discover the hardware debug features. The main info to | ||
17 | be returned here is the minimum alignment for the hardware watchpoints. | ||
18 | BookE processors don't have restrictions here, but server processors have | ||
19 | an 8-byte alignment restriction for hardware watchpoints. We'd like to avoid | ||
20 | adding special cases to GDB based on what it sees in AUXV. | ||
21 | |||
22 | Since we're at it, we added other useful info that the kernel can return to | ||
23 | GDB: this query will return the number of hardware breakpoints, hardware | ||
24 | watchpoints and whether it supports a range of addresses and a condition. | ||
25 | The query will fill the following structure provided by the requesting process: | ||
26 | |||
27 | struct ppc_debug_info { | ||
28 | unit32_t version; | ||
29 | unit32_t num_instruction_bps; | ||
30 | unit32_t num_data_bps; | ||
31 | unit32_t num_condition_regs; | ||
32 | unit32_t data_bp_alignment; | ||
33 | unit32_t sizeof_condition; /* size of the DVC register */ | ||
34 | uint64_t features; /* bitmask of the individual flags */ | ||
35 | }; | ||
36 | |||
37 | features will have bits indicating whether there is support for: | ||
38 | |||
39 | #define PPC_DEBUG_FEATURE_INSN_BP_RANGE 0x1 | ||
40 | #define PPC_DEBUG_FEATURE_INSN_BP_MASK 0x2 | ||
41 | #define PPC_DEBUG_FEATURE_DATA_BP_RANGE 0x4 | ||
42 | #define PPC_DEBUG_FEATURE_DATA_BP_MASK 0x8 | ||
43 | |||
44 | 2. PTRACE_SETHWDEBUG | ||
45 | |||
46 | Sets a hardware breakpoint or watchpoint, according to the provided structure: | ||
47 | |||
48 | struct ppc_hw_breakpoint { | ||
49 | uint32_t version; | ||
50 | #define PPC_BREAKPOINT_TRIGGER_EXECUTE 0x1 | ||
51 | #define PPC_BREAKPOINT_TRIGGER_READ 0x2 | ||
52 | #define PPC_BREAKPOINT_TRIGGER_WRITE 0x4 | ||
53 | uint32_t trigger_type; /* only some combinations allowed */ | ||
54 | #define PPC_BREAKPOINT_MODE_EXACT 0x0 | ||
55 | #define PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE 0x1 | ||
56 | #define PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE 0x2 | ||
57 | #define PPC_BREAKPOINT_MODE_MASK 0x3 | ||
58 | uint32_t addr_mode; /* address match mode */ | ||
59 | |||
60 | #define PPC_BREAKPOINT_CONDITION_MODE 0x3 | ||
61 | #define PPC_BREAKPOINT_CONDITION_NONE 0x0 | ||
62 | #define PPC_BREAKPOINT_CONDITION_AND 0x1 | ||
63 | #define PPC_BREAKPOINT_CONDITION_EXACT 0x1 /* different name for the same thing as above */ | ||
64 | #define PPC_BREAKPOINT_CONDITION_OR 0x2 | ||
65 | #define PPC_BREAKPOINT_CONDITION_AND_OR 0x3 | ||
66 | #define PPC_BREAKPOINT_CONDITION_BE_ALL 0x00ff0000 /* byte enable bits */ | ||
67 | #define PPC_BREAKPOINT_CONDITION_BE(n) (1<<((n)+16)) | ||
68 | uint32_t condition_mode; /* break/watchpoint condition flags */ | ||
69 | |||
70 | uint64_t addr; | ||
71 | uint64_t addr2; | ||
72 | uint64_t condition_value; | ||
73 | }; | ||
74 | |||
75 | A request specifies one event, not necessarily just one register to be set. | ||
76 | For instance, if the request is for a watchpoint with a condition, both the | ||
77 | DAC and DVC registers will be set in the same request. | ||
78 | |||
79 | With this GDB can ask for all kinds of hardware breakpoints and watchpoints | ||
80 | that the BookE supports. COMEFROM breakpoints available in server processors | ||
81 | are not contemplated, but that is out of the scope of this work. | ||
82 | |||
83 | ptrace will return an integer (handle) uniquely identifying the breakpoint or | ||
84 | watchpoint just created. This integer will be used in the PTRACE_DELHWDEBUG | ||
85 | request to ask for its removal. Return -ENOSPC if the requested breakpoint | ||
86 | can't be allocated on the registers. | ||
87 | |||
88 | Some examples of using the structure to: | ||
89 | |||
90 | - set a breakpoint in the first breakpoint register | ||
91 | |||
92 | p.version = PPC_DEBUG_CURRENT_VERSION; | ||
93 | p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE; | ||
94 | p.addr_mode = PPC_BREAKPOINT_MODE_EXACT; | ||
95 | p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; | ||
96 | p.addr = (uint64_t) address; | ||
97 | p.addr2 = 0; | ||
98 | p.condition_value = 0; | ||
99 | |||
100 | - set a watchpoint which triggers on reads in the second watchpoint register | ||
101 | |||
102 | p.version = PPC_DEBUG_CURRENT_VERSION; | ||
103 | p.trigger_type = PPC_BREAKPOINT_TRIGGER_READ; | ||
104 | p.addr_mode = PPC_BREAKPOINT_MODE_EXACT; | ||
105 | p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; | ||
106 | p.addr = (uint64_t) address; | ||
107 | p.addr2 = 0; | ||
108 | p.condition_value = 0; | ||
109 | |||
110 | - set a watchpoint which triggers only with a specific value | ||
111 | |||
112 | p.version = PPC_DEBUG_CURRENT_VERSION; | ||
113 | p.trigger_type = PPC_BREAKPOINT_TRIGGER_READ; | ||
114 | p.addr_mode = PPC_BREAKPOINT_MODE_EXACT; | ||
115 | p.condition_mode = PPC_BREAKPOINT_CONDITION_AND | PPC_BREAKPOINT_CONDITION_BE_ALL; | ||
116 | p.addr = (uint64_t) address; | ||
117 | p.addr2 = 0; | ||
118 | p.condition_value = (uint64_t) condition; | ||
119 | |||
120 | - set a ranged hardware breakpoint | ||
121 | |||
122 | p.version = PPC_DEBUG_CURRENT_VERSION; | ||
123 | p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE; | ||
124 | p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; | ||
125 | p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; | ||
126 | p.addr = (uint64_t) begin_range; | ||
127 | p.addr2 = (uint64_t) end_range; | ||
128 | p.condition_value = 0; | ||
129 | |||
130 | 3. PTRACE_DELHWDEBUG | ||
131 | |||
132 | Takes an integer which identifies an existing breakpoint or watchpoint | ||
133 | (i.e., the value returned from PTRACE_SETHWDEBUG), and deletes the | ||
134 | corresponding breakpoint or watchpoint.. | ||
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index cbd759e3cd78..b45108126562 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h | |||
@@ -24,6 +24,12 @@ | |||
24 | * 2 of the License, or (at your option) any later version. | 24 | * 2 of the License, or (at your option) any later version. |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #ifdef __KERNEL__ | ||
28 | #include <linux/types.h> | ||
29 | #else | ||
30 | #include <stdint.h> | ||
31 | #endif | ||
32 | |||
27 | #ifndef __ASSEMBLY__ | 33 | #ifndef __ASSEMBLY__ |
28 | 34 | ||
29 | struct pt_regs { | 35 | struct pt_regs { |
@@ -294,4 +300,75 @@ extern void user_disable_single_step(struct task_struct *); | |||
294 | 300 | ||
295 | #define PTRACE_SINGLEBLOCK 0x100 /* resume execution until next branch */ | 301 | #define PTRACE_SINGLEBLOCK 0x100 /* resume execution until next branch */ |
296 | 302 | ||
303 | #define PPC_PTRACE_GETHWDBGINFO 0x89 | ||
304 | #define PPC_PTRACE_SETHWDEBUG 0x88 | ||
305 | #define PPC_PTRACE_DELHWDEBUG 0x87 | ||
306 | |||
307 | #ifndef __ASSEMBLY__ | ||
308 | |||
309 | struct ppc_debug_info { | ||
310 | uint32_t version; /* Only version 1 exists to date */ | ||
311 | uint32_t num_instruction_bps; | ||
312 | uint32_t num_data_bps; | ||
313 | uint32_t num_condition_regs; | ||
314 | uint32_t data_bp_alignment; | ||
315 | uint32_t sizeof_condition; /* size of the DVC register */ | ||
316 | uint64_t features; | ||
317 | }; | ||
318 | |||
319 | #endif /* __ASSEMBLY__ */ | ||
320 | |||
321 | /* | ||
322 | * features will have bits indication whether there is support for: | ||
323 | */ | ||
324 | #define PPC_DEBUG_FEATURE_INSN_BP_RANGE 0x0000000000000001 | ||
325 | #define PPC_DEBUG_FEATURE_INSN_BP_MASK 0x0000000000000002 | ||
326 | #define PPC_DEBUG_FEATURE_DATA_BP_RANGE 0x0000000000000004 | ||
327 | #define PPC_DEBUG_FEATURE_DATA_BP_MASK 0x0000000000000008 | ||
328 | |||
329 | #ifndef __ASSEMBLY__ | ||
330 | |||
331 | struct ppc_hw_breakpoint { | ||
332 | uint32_t version; /* currently, version must be 1 */ | ||
333 | uint32_t trigger_type; /* only some combinations allowed */ | ||
334 | uint32_t addr_mode; /* address match mode */ | ||
335 | uint32_t condition_mode; /* break/watchpoint condition flags */ | ||
336 | uint64_t addr; /* break/watchpoint address */ | ||
337 | uint64_t addr2; /* range end or mask */ | ||
338 | uint64_t condition_value; /* contents of the DVC register */ | ||
339 | }; | ||
340 | |||
341 | #endif /* __ASSEMBLY__ */ | ||
342 | |||
343 | /* | ||
344 | * Trigger Type | ||
345 | */ | ||
346 | #define PPC_BREAKPOINT_TRIGGER_EXECUTE 0x00000001 | ||
347 | #define PPC_BREAKPOINT_TRIGGER_READ 0x00000002 | ||
348 | #define PPC_BREAKPOINT_TRIGGER_WRITE 0x00000004 | ||
349 | #define PPC_BREAKPOINT_TRIGGER_RW \ | ||
350 | (PPC_BREAKPOINT_TRIGGER_READ | PPC_BREAKPOINT_TRIGGER_WRITE) | ||
351 | |||
352 | /* | ||
353 | * Address Mode | ||
354 | */ | ||
355 | #define PPC_BREAKPOINT_MODE_EXACT 0x00000000 | ||
356 | #define PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE 0x00000001 | ||
357 | #define PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE 0x00000002 | ||
358 | #define PPC_BREAKPOINT_MODE_MASK 0x00000003 | ||
359 | |||
360 | /* | ||
361 | * Condition Mode | ||
362 | */ | ||
363 | #define PPC_BREAKPOINT_CONDITION_MODE 0x00000003 | ||
364 | #define PPC_BREAKPOINT_CONDITION_NONE 0x00000000 | ||
365 | #define PPC_BREAKPOINT_CONDITION_AND 0x00000001 | ||
366 | #define PPC_BREAKPOINT_CONDITION_EXACT PPC_BREAKPOINT_CONDITION_AND | ||
367 | #define PPC_BREAKPOINT_CONDITION_OR 0x00000002 | ||
368 | #define PPC_BREAKPOINT_CONDITION_AND_OR 0x00000003 | ||
369 | #define PPC_BREAKPOINT_CONDITION_BE_ALL 0x00ff0000 | ||
370 | #define PPC_BREAKPOINT_CONDITION_BE_SHIFT 16 | ||
371 | #define PPC_BREAKPOINT_CONDITION_BE(n) \ | ||
372 | (1<<((n)+PPC_BREAKPOINT_CONDITION_BE_SHIFT)) | ||
373 | |||
297 | #endif /* _ASM_POWERPC_PTRACE_H */ | 374 | #endif /* _ASM_POWERPC_PTRACE_H */ |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 292c81432014..8847bd618cec 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -835,6 +835,52 @@ void ptrace_disable(struct task_struct *child) | |||
835 | user_disable_single_step(child); | 835 | user_disable_single_step(child); |
836 | } | 836 | } |
837 | 837 | ||
838 | static long ppc_set_hwdebug(struct task_struct *child, | ||
839 | struct ppc_hw_breakpoint *bp_info) | ||
840 | { | ||
841 | /* | ||
842 | * We currently support one data breakpoint | ||
843 | */ | ||
844 | if (((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0) || | ||
845 | ((bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0) || | ||
846 | (bp_info->trigger_type != PPC_BREAKPOINT_TRIGGER_WRITE) || | ||
847 | (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) || | ||
848 | (bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)) | ||
849 | return -EINVAL; | ||
850 | |||
851 | if (child->thread.dabr) | ||
852 | return -ENOSPC; | ||
853 | |||
854 | if ((unsigned long)bp_info->addr >= TASK_SIZE) | ||
855 | return -EIO; | ||
856 | |||
857 | child->thread.dabr = (unsigned long)bp_info->addr; | ||
858 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | ||
859 | child->thread.dbcr0 = DBCR0_IDM; | ||
860 | if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ) | ||
861 | child->thread.dbcr0 |= DBSR_DAC1R; | ||
862 | if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE) | ||
863 | child->thread.dbcr0 |= DBSR_DAC1W; | ||
864 | child->thread.regs->msr |= MSR_DE; | ||
865 | #endif | ||
866 | return 1; | ||
867 | } | ||
868 | |||
869 | static long ppc_del_hwdebug(struct task_struct *child, long addr, long data) | ||
870 | { | ||
871 | if (data != 1) | ||
872 | return -EINVAL; | ||
873 | if (child->thread.dabr == 0) | ||
874 | return -ENOENT; | ||
875 | |||
876 | child->thread.dabr = 0; | ||
877 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | ||
878 | child->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W | DBCR0_IDM); | ||
879 | child->thread.regs->msr &= ~MSR_DE; | ||
880 | #endif | ||
881 | return 0; | ||
882 | } | ||
883 | |||
838 | /* | 884 | /* |
839 | * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls, | 885 | * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls, |
840 | * we mark them as obsolete now, they will be removed in a future version | 886 | * we mark them as obsolete now, they will be removed in a future version |
@@ -928,6 +974,50 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
928 | break; | 974 | break; |
929 | } | 975 | } |
930 | 976 | ||
977 | case PPC_PTRACE_GETHWDBGINFO: { | ||
978 | struct ppc_debug_info dbginfo; | ||
979 | |||
980 | dbginfo.version = 1; | ||
981 | dbginfo.num_instruction_bps = 0; | ||
982 | dbginfo.num_data_bps = 1; | ||
983 | dbginfo.num_condition_regs = 0; | ||
984 | #ifdef CONFIG_PPC64 | ||
985 | dbginfo.data_bp_alignment = 8; | ||
986 | #else | ||
987 | dbginfo.data_bp_alignment = 4; | ||
988 | #endif | ||
989 | dbginfo.sizeof_condition = 0; | ||
990 | dbginfo.features = 0; | ||
991 | |||
992 | if (!access_ok(VERIFY_WRITE, data, | ||
993 | sizeof(struct ppc_debug_info))) | ||
994 | return -EFAULT; | ||
995 | ret = __copy_to_user((struct ppc_debug_info __user *)data, | ||
996 | &dbginfo, sizeof(struct ppc_debug_info)) ? | ||
997 | -EFAULT : 0; | ||
998 | break; | ||
999 | } | ||
1000 | |||
1001 | case PPC_PTRACE_SETHWDEBUG: { | ||
1002 | struct ppc_hw_breakpoint bp_info; | ||
1003 | |||
1004 | if (!access_ok(VERIFY_READ, data, | ||
1005 | sizeof(struct ppc_hw_breakpoint))) | ||
1006 | return -EFAULT; | ||
1007 | ret = __copy_from_user(&bp_info, | ||
1008 | (struct ppc_hw_breakpoint __user *)data, | ||
1009 | sizeof(struct ppc_hw_breakpoint)) ? | ||
1010 | -EFAULT : 0; | ||
1011 | if (!ret) | ||
1012 | ret = ppc_set_hwdebug(child, &bp_info); | ||
1013 | break; | ||
1014 | } | ||
1015 | |||
1016 | case PPC_PTRACE_DELHWDEBUG: { | ||
1017 | ret = ppc_del_hwdebug(child, addr, data); | ||
1018 | break; | ||
1019 | } | ||
1020 | |||
931 | case PTRACE_GET_DEBUGREG: { | 1021 | case PTRACE_GET_DEBUGREG: { |
932 | ret = -EINVAL; | 1022 | ret = -EINVAL; |
933 | /* We only support one DABR and no IABRS at the moment */ | 1023 | /* We only support one DABR and no IABRS at the moment */ |