aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/ptrace-common.h89
-rw-r--r--arch/powerpc/kernel/ptrace-ppc32.h100
-rw-r--r--arch/powerpc/kernel/ptrace-ppc64.h51
-rw-r--r--arch/powerpc/kernel/ptrace.c198
-rw-r--r--arch/powerpc/kernel/ptrace32.c1
5 files changed, 197 insertions, 242 deletions
diff --git a/arch/powerpc/kernel/ptrace-common.h b/arch/powerpc/kernel/ptrace-common.h
index 8797ae737a7b..f0746eca8f44 100644
--- a/arch/powerpc/kernel/ptrace-common.h
+++ b/arch/powerpc/kernel/ptrace-common.h
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2002 Stephen Rothwell, IBM Coproration 2 * Copyright (c) 2002 Stephen Rothwell, IBM Coproration
3 * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration
3 * Extracted from ptrace.c and ptrace32.c 4 * Extracted from ptrace.c and ptrace32.c
4 * 5 *
5 * This file is subject to the terms and conditions of the GNU General 6 * This file is subject to the terms and conditions of the GNU General
@@ -7,15 +8,8 @@
7 * this archive for more details. 8 * this archive for more details.
8 */ 9 */
9 10
10#ifndef _PPC64_PTRACE_COMMON_H 11#ifndef _POWERPC_PTRACE_COMMON_H
11#define _PPC64_PTRACE_COMMON_H 12#define _POWERPC_PTRACE_COMMON_H
12
13#include <asm/system.h>
14
15/*
16 * Set of msr bits that gdb can change on behalf of a process.
17 */
18#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
19 13
20/* 14/*
21 * Get contents of register REGNO in task TASK. 15 * Get contents of register REGNO in task TASK.
@@ -24,18 +18,18 @@ static inline unsigned long get_reg(struct task_struct *task, int regno)
24{ 18{
25 unsigned long tmp = 0; 19 unsigned long tmp = 0;
26 20
27 /* 21 if (task->thread.regs == NULL)
28 * Put the correct FP bits in, they might be wrong as a result 22 return -EIO;
29 * of our lazy FP restore. 23
30 */
31 if (regno == PT_MSR) { 24 if (regno == PT_MSR) {
32 tmp = ((unsigned long *)task->thread.regs)[PT_MSR]; 25 tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
33 tmp |= task->thread.fpexc_mode; 26 return PT_MUNGE_MSR(tmp, task);
34 } else if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) {
35 tmp = ((unsigned long *)task->thread.regs)[regno];
36 } 27 }
37 28
38 return tmp; 29 if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
30 return ((unsigned long *)task->thread.regs)[regno];
31
32 return -EIO;
39} 33}
40 34
41/* 35/*
@@ -44,7 +38,10 @@ static inline unsigned long get_reg(struct task_struct *task, int regno)
44static inline int put_reg(struct task_struct *task, int regno, 38static inline int put_reg(struct task_struct *task, int regno,
45 unsigned long data) 39 unsigned long data)
46{ 40{
47 if (regno < PT_SOFTE) { 41 if (task->thread.regs == NULL)
42 return -EIO;
43
44 if (regno <= PT_MAX_PUT_REG) {
48 if (regno == PT_MSR) 45 if (regno == PT_MSR)
49 data = (data & MSR_DEBUGCHANGE) 46 data = (data & MSR_DEBUGCHANGE)
50 | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); 47 | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
@@ -54,21 +51,6 @@ static inline int put_reg(struct task_struct *task, int regno,
54 return -EIO; 51 return -EIO;
55} 52}
56 53
57static inline void set_single_step(struct task_struct *task)
58{
59 struct pt_regs *regs = task->thread.regs;
60 if (regs != NULL)
61 regs->msr |= MSR_SE;
62 set_tsk_thread_flag(task, TIF_SINGLESTEP);
63}
64
65static inline void clear_single_step(struct task_struct *task)
66{
67 struct pt_regs *regs = task->thread.regs;
68 if (regs != NULL)
69 regs->msr &= ~MSR_SE;
70 clear_tsk_thread_flag(task, TIF_SINGLESTEP);
71}
72 54
73#ifdef CONFIG_ALTIVEC 55#ifdef CONFIG_ALTIVEC
74/* 56/*
@@ -137,25 +119,36 @@ static inline int set_vrregs(struct task_struct *task,
137 119
138 return 0; 120 return 0;
139} 121}
140#endif 122#endif /* CONFIG_ALTIVEC */
141 123
142static inline int ptrace_set_debugreg(struct task_struct *task, 124static inline void set_single_step(struct task_struct *task)
143 unsigned long addr, unsigned long data)
144{ 125{
145 /* We only support one DABR and no IABRS at the moment */ 126 struct pt_regs *regs = task->thread.regs;
146 if (addr > 0)
147 return -EINVAL;
148 127
149 /* The bottom 3 bits are flags */ 128 if (regs != NULL) {
150 if ((data & ~0x7UL) >= TASK_SIZE) 129#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
151 return -EIO; 130 task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
131 regs->msr |= MSR_DE;
132#else
133 regs->msr |= MSR_SE;
134#endif
135 }
136 set_tsk_thread_flag(task, TIF_SINGLESTEP);
137}
152 138
153 /* Ensure translation is on */ 139static inline void clear_single_step(struct task_struct *task)
154 if (data && !(data & DABR_TRANSLATION)) 140{
155 return -EIO; 141 struct pt_regs *regs = task->thread.regs;
156 142
157 task->thread.dabr = data; 143 if (regs != NULL) {
158 return 0; 144#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
145 task->thread.dbcr0 = 0;
146 regs->msr &= ~MSR_DE;
147#else
148 regs->msr &= ~MSR_SE;
149#endif
150 }
151 clear_tsk_thread_flag(task, TIF_SINGLESTEP);
159} 152}
160 153
161#endif /* _PPC64_PTRACE_COMMON_H */ 154#endif /* _POWERPC_PTRACE_COMMON_H */
diff --git a/arch/powerpc/kernel/ptrace-ppc32.h b/arch/powerpc/kernel/ptrace-ppc32.h
new file mode 100644
index 000000000000..24d7a2f680af
--- /dev/null
+++ b/arch/powerpc/kernel/ptrace-ppc32.h
@@ -0,0 +1,100 @@
1/*
2 * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration
3 * Extracted from ptrace.c and ptrace32.c
4 *
5 * This file is subject to the terms and conditions of the GNU General
6 * Public License. See the file README.legal in the main directory of
7 * this archive for more details.
8 */
9
10#ifndef _POWERPC_PTRACE_PPC32_H
11#define _POWERPC_PTRACE_PPC32_H
12
13/*
14 * Set of msr bits that gdb can change on behalf of a process.
15 */
16#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
17#define MSR_DEBUGCHANGE 0
18#else
19#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE)
20#endif
21
22/*
23 * Max register writeable via put_reg
24 */
25#define PT_MAX_PUT_REG PT_MQ
26
27/*
28 * Munging of MSR on return from get_regs
29 *
30 * Nothing to do on ppc32
31 */
32#define PT_MUNGE_MSR(msr, task) (msr)
33
34
35#ifdef CONFIG_SPE
36
37/*
38 * For get_evrregs/set_evrregs functions 'data' has the following layout:
39 *
40 * struct {
41 * u32 evr[32];
42 * u64 acc;
43 * u32 spefscr;
44 * }
45 */
46
47/*
48 * Get contents of SPE register state in task TASK.
49 */
50static inline int get_evrregs(unsigned long *data, struct task_struct *task)
51{
52 int i;
53
54 if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
55 return -EFAULT;
56
57 /* copy SPEFSCR */
58 if (__put_user(task->thread.spefscr, &data[34]))
59 return -EFAULT;
60
61 /* copy SPE registers EVR[0] .. EVR[31] */
62 for (i = 0; i < 32; i++, data++)
63 if (__put_user(task->thread.evr[i], data))
64 return -EFAULT;
65
66 /* copy ACC */
67 if (__put_user64(task->thread.acc, (unsigned long long *)data))
68 return -EFAULT;
69
70 return 0;
71}
72
73/*
74 * Write contents of SPE register state into task TASK.
75 */
76static inline int set_evrregs(struct task_struct *task, unsigned long *data)
77{
78 int i;
79
80 if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
81 return -EFAULT;
82
83 /* copy SPEFSCR */
84 if (__get_user(task->thread.spefscr, &data[34]))
85 return -EFAULT;
86
87 /* copy SPE registers EVR[0] .. EVR[31] */
88 for (i = 0; i < 32; i++, data++)
89 if (__get_user(task->thread.evr[i], data))
90 return -EFAULT;
91 /* copy ACC */
92 if (__get_user64(task->thread.acc, (unsigned long long*)data))
93 return -EFAULT;
94
95 return 0;
96}
97#endif /* CONFIG_SPE */
98
99
100#endif /* _POWERPC_PTRACE_PPC32_H */
diff --git a/arch/powerpc/kernel/ptrace-ppc64.h b/arch/powerpc/kernel/ptrace-ppc64.h
new file mode 100644
index 000000000000..e450ce01392b
--- /dev/null
+++ b/arch/powerpc/kernel/ptrace-ppc64.h
@@ -0,0 +1,51 @@
1/*
2 * Copyright (c) 2002 Stephen Rothwell, IBM Coproration
3 * Extracted from ptrace.c and ptrace32.c
4 *
5 * This file is subject to the terms and conditions of the GNU General
6 * Public License. See the file README.legal in the main directory of
7 * this archive for more details.
8 */
9
10#ifndef _POWERPC_PTRACE_PPC64_H
11#define _POWERPC_PTRACE_PPC64_H
12
13/*
14 * Set of msr bits that gdb can change on behalf of a process.
15 */
16#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
17
18/*
19 * Max register writeable via put_reg
20 */
21#define PT_MAX_PUT_REG PT_CCR
22
23/*
24 * Munging of MSR on return from get_regs
25 *
26 * Put the correct FP bits in, they might be wrong as a result
27 * of our lazy FP restore.
28 */
29
30#define PT_MUNGE_MSR(msr, task) ({ (msr) | (task)->thread.fpexc_mode; })
31
32static inline int ptrace_set_debugreg(struct task_struct *task,
33 unsigned long addr, unsigned long data)
34{
35 /* We only support one DABR and no IABRS at the moment */
36 if (addr > 0)
37 return -EINVAL;
38
39 /* The bottom 3 bits are flags */
40 if ((data & ~0x7UL) >= TASK_SIZE)
41 return -EIO;
42
43 /* Ensure translation is on */
44 if (data && !(data & DABR_TRANSLATION))
45 return -EIO;
46
47 task->thread.dabr = data;
48 return 0;
49}
50
51#endif /* _POWERPC_PTRACE_PPC64_H */
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 36db6f5cb54c..da53b0d4114b 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -36,208 +36,18 @@
36#include <asm/system.h> 36#include <asm/system.h>
37 37
38#ifdef CONFIG_PPC64 38#ifdef CONFIG_PPC64
39#include "ptrace-common.h" 39#include "ptrace-ppc64.h"
40#endif
41
42#ifdef CONFIG_PPC32
43/*
44 * Set of msr bits that gdb can change on behalf of a process.
45 */
46#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
47#define MSR_DEBUGCHANGE 0
48#else 40#else
49#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE) 41#include "ptrace-ppc32.h"
50#endif 42#endif
51#endif /* CONFIG_PPC32 */ 43
44#include "ptrace-common.h"
52 45
53/* 46/*
54 * does not yet catch signals sent when the child dies. 47 * does not yet catch signals sent when the child dies.
55 * in exit.c or in signal.c. 48 * in exit.c or in signal.c.
56 */ 49 */
57 50
58#ifdef CONFIG_PPC32
59/*
60 * Get contents of register REGNO in task TASK.
61 */
62static inline unsigned long get_reg(struct task_struct *task, int regno)
63{
64 if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)
65 && task->thread.regs != NULL)
66 return ((unsigned long *)task->thread.regs)[regno];
67 return (0);
68}
69
70/*
71 * Write contents of register REGNO in task TASK.
72 */
73static inline int put_reg(struct task_struct *task, int regno,
74 unsigned long data)
75{
76 if (regno <= PT_MQ && task->thread.regs != NULL) {
77 if (regno == PT_MSR)
78 data = (data & MSR_DEBUGCHANGE)
79 | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
80 ((unsigned long *)task->thread.regs)[regno] = data;
81 return 0;
82 }
83 return -EIO;
84}
85
86#ifdef CONFIG_ALTIVEC
87/*
88 * Get contents of AltiVec register state in task TASK
89 */
90static inline int get_vrregs(unsigned long __user *data, struct task_struct *task)
91{
92 int i, j;
93
94 if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long)))
95 return -EFAULT;
96
97 /* copy AltiVec registers VR[0] .. VR[31] */
98 for (i = 0; i < 32; i++)
99 for (j = 0; j < 4; j++, data++)
100 if (__put_user(task->thread.vr[i].u[j], data))
101 return -EFAULT;
102
103 /* copy VSCR */
104 for (i = 0; i < 4; i++, data++)
105 if (__put_user(task->thread.vscr.u[i], data))
106 return -EFAULT;
107
108 /* copy VRSAVE */
109 if (__put_user(task->thread.vrsave, data))
110 return -EFAULT;
111
112 return 0;
113}
114
115/*
116 * Write contents of AltiVec register state into task TASK.
117 */
118static inline int set_vrregs(struct task_struct *task, unsigned long __user *data)
119{
120 int i, j;
121
122 if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long)))
123 return -EFAULT;
124
125 /* copy AltiVec registers VR[0] .. VR[31] */
126 for (i = 0; i < 32; i++)
127 for (j = 0; j < 4; j++, data++)
128 if (__get_user(task->thread.vr[i].u[j], data))
129 return -EFAULT;
130
131 /* copy VSCR */
132 for (i = 0; i < 4; i++, data++)
133 if (__get_user(task->thread.vscr.u[i], data))
134 return -EFAULT;
135
136 /* copy VRSAVE */
137 if (__get_user(task->thread.vrsave, data))
138 return -EFAULT;
139
140 return 0;
141}
142#endif
143
144#ifdef CONFIG_SPE
145
146/*
147 * For get_evrregs/set_evrregs functions 'data' has the following layout:
148 *
149 * struct {
150 * u32 evr[32];
151 * u64 acc;
152 * u32 spefscr;
153 * }
154 */
155
156/*
157 * Get contents of SPE register state in task TASK.
158 */
159static inline int get_evrregs(unsigned long *data, struct task_struct *task)
160{
161 int i;
162
163 if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
164 return -EFAULT;
165
166 /* copy SPEFSCR */
167 if (__put_user(task->thread.spefscr, &data[34]))
168 return -EFAULT;
169
170 /* copy SPE registers EVR[0] .. EVR[31] */
171 for (i = 0; i < 32; i++, data++)
172 if (__put_user(task->thread.evr[i], data))
173 return -EFAULT;
174
175 /* copy ACC */
176 if (__put_user64(task->thread.acc, (unsigned long long *)data))
177 return -EFAULT;
178
179 return 0;
180}
181
182/*
183 * Write contents of SPE register state into task TASK.
184 */
185static inline int set_evrregs(struct task_struct *task, unsigned long *data)
186{
187 int i;
188
189 if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
190 return -EFAULT;
191
192 /* copy SPEFSCR */
193 if (__get_user(task->thread.spefscr, &data[34]))
194 return -EFAULT;
195
196 /* copy SPE registers EVR[0] .. EVR[31] */
197 for (i = 0; i < 32; i++, data++)
198 if (__get_user(task->thread.evr[i], data))
199 return -EFAULT;
200 /* copy ACC */
201 if (__get_user64(task->thread.acc, (unsigned long long*)data))
202 return -EFAULT;
203
204 return 0;
205}
206#endif /* CONFIG_SPE */
207
208static inline void
209set_single_step(struct task_struct *task)
210{
211 struct pt_regs *regs = task->thread.regs;
212
213 if (regs != NULL) {
214#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
215 task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
216 regs->msr |= MSR_DE;
217#else
218 regs->msr |= MSR_SE;
219#endif
220 }
221 set_tsk_thread_flag(task, TIF_SINGLESTEP);
222}
223
224static inline void
225clear_single_step(struct task_struct *task)
226{
227 struct pt_regs *regs = task->thread.regs;
228
229 if (regs != NULL) {
230#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
231 task->thread.dbcr0 = 0;
232 regs->msr &= ~MSR_DE;
233#else
234 regs->msr &= ~MSR_SE;
235#endif
236 }
237 clear_tsk_thread_flag(task, TIF_SINGLESTEP);
238}
239#endif /* CONFIG_PPC32 */
240
241/* 51/*
242 * Called by kernel/ptrace.c when detaching.. 52 * Called by kernel/ptrace.c when detaching..
243 * 53 *
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 9b9a230349bc..1bf1f450e1ab 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -33,6 +33,7 @@
33#include <asm/pgtable.h> 33#include <asm/pgtable.h>
34#include <asm/system.h> 34#include <asm/system.h>
35 35
36#include "ptrace-ppc64.h"
36#include "ptrace-common.h" 37#include "ptrace-common.h"
37 38
38/* 39/*