1284345Ssjg/*
2284345Ssjg * ptrace for 32-bit processes running on a 64-bit kernel.
3284345Ssjg *
4284345Ssjg *  PowerPC version
5284345Ssjg *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
6284345Ssjg *
7284345Ssjg *  Derived from "arch/m68k/kernel/ptrace.c"
8284345Ssjg *  Copyright (C) 1994 by Hamish Macdonald
9284345Ssjg *  Taken from linux/kernel/ptrace.c and modified for M680x0.
10295979Sbdrewery *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
11284345Ssjg *
12284345Ssjg * Modified by Cort Dougan (cort@hq.fsmlabs.com)
13284345Ssjg * and Paul Mackerras (paulus@samba.org).
14284345Ssjg *
15284345Ssjg * This file is subject to the terms and conditions of the GNU General
16284345Ssjg * Public License.  See the file COPYING in the main directory of
17284345Ssjg * this archive for more details.
18284345Ssjg */
19284345Ssjg
20284345Ssjg#include <linux/ptrace.h>
21284345Ssjg#include <linux/regset.h>
22#include <linux/compat.h>
23
24#include <asm/switch_to.h>
25
26#include "ptrace-decl.h"
27
28/*
29 * does not yet catch signals sent when the child dies.
30 * in exit.c or in signal.c.
31 */
32
33/* Macros to workout the correct index for the FPR in the thread struct */
34#define FPRNUMBER(i) (((i) - PT_FPR0) >> 1)
35#define FPRHALF(i) (((i) - PT_FPR0) & 1)
36#define FPRINDEX(i) TS_FPRWIDTH * FPRNUMBER(i) * 2 + FPRHALF(i)
37
38long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
39			compat_ulong_t caddr, compat_ulong_t cdata)
40{
41	unsigned long addr = caddr;
42	unsigned long data = cdata;
43	int ret;
44
45	switch (request) {
46	/*
47	 * Read 4 bytes of the other process' storage
48	 *  data is a pointer specifying where the user wants the
49	 *	4 bytes copied into
50	 *  addr is a pointer in the user's storage that contains an 8 byte
51	 *	address in the other process of the 4 bytes that is to be read
52	 * (this is run in a 32-bit process looking at a 64-bit process)
53	 * when I and D space are separate, these will need to be fixed.
54	 */
55	case PPC_PTRACE_PEEKTEXT_3264:
56	case PPC_PTRACE_PEEKDATA_3264: {
57		u32 tmp;
58		int copied;
59		u32 __user * addrOthers;
60
61		ret = -EIO;
62
63		/* Get the addr in the other process that we want to read */
64		if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
65			break;
66
67		copied = ptrace_access_vm(child, (u64)addrOthers, &tmp,
68				sizeof(tmp), FOLL_FORCE);
69		if (copied != sizeof(tmp))
70			break;
71		ret = put_user(tmp, (u32 __user *)data);
72		break;
73	}
74
75	/* Read a register (specified by ADDR) out of the "user area" */
76	case PTRACE_PEEKUSR: {
77		int index;
78		unsigned long tmp;
79
80		ret = -EIO;
81		/* convert to index and check */
82		index = (unsigned long) addr >> 2;
83		if ((addr & 3) || (index > PT_FPSCR32))
84			break;
85
86		if (index < PT_FPR0) {
87			ret = ptrace_get_reg(child, index, &tmp);
88			if (ret)
89				break;
90		} else {
91			flush_fp_to_thread(child);
92			/*
93			 * the user space code considers the floating point
94			 * to be an array of unsigned int (32 bits) - the
95			 * index passed in is based on this assumption.
96			 */
97			tmp = ((unsigned int *)child->thread.fp_state.fpr)
98				[FPRINDEX(index)];
99		}
100		ret = put_user((unsigned int)tmp, (u32 __user *)data);
101		break;
102	}
103
104	/*
105	 * Read 4 bytes out of the other process' pt_regs area
106	 *  data is a pointer specifying where the user wants the
107	 *	4 bytes copied into
108	 *  addr is the offset into the other process' pt_regs structure
109	 *	that is to be read
110	 * (this is run in a 32-bit process looking at a 64-bit process)
111	 */
112	case PPC_PTRACE_PEEKUSR_3264: {
113		u32 index;
114		u32 reg32bits;
115		u64 tmp;
116		u32 numReg;
117		u32 part;
118
119		ret = -EIO;
120		/* Determine which register the user wants */
121		index = (u64)addr >> 2;
122		numReg = index / 2;
123		/* Determine which part of the register the user wants */
124		if (index % 2)
125			part = 1;  /* want the 2nd half of the register (right-most). */
126		else
127			part = 0;  /* want the 1st half of the register (left-most). */
128
129		/* Validate the input - check to see if address is on the wrong boundary
130		 * or beyond the end of the user area
131		 */
132		if ((addr & 3) || numReg > PT_FPSCR)
133			break;
134
135		if (numReg >= PT_FPR0) {
136			flush_fp_to_thread(child);
137			/* get 64 bit FPR */
138			tmp = child->thread.fp_state.fpr[numReg - PT_FPR0][0];
139		} else { /* register within PT_REGS struct */
140			unsigned long tmp2;
141			ret = ptrace_get_reg(child, numReg, &tmp2);
142			if (ret)
143				break;
144			tmp = tmp2;
145		}
146		reg32bits = ((u32*)&tmp)[part];
147		ret = put_user(reg32bits, (u32 __user *)data);
148		break;
149	}
150
151	/*
152	 * Write 4 bytes into the other process' storage
153	 *  data is the 4 bytes that the user wants written
154	 *  addr is a pointer in the user's storage that contains an
155	 *	8 byte address in the other process where the 4 bytes
156	 *	that is to be written
157	 * (this is run in a 32-bit process looking at a 64-bit process)
158	 * when I and D space are separate, these will need to be fixed.
159	 */
160	case PPC_PTRACE_POKETEXT_3264:
161	case PPC_PTRACE_POKEDATA_3264: {
162		u32 tmp = data;
163		u32 __user * addrOthers;
164
165		/* Get the addr in the other process that we want to write into */
166		ret = -EIO;
167		if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
168			break;
169		ret = 0;
170		if (ptrace_access_vm(child, (u64)addrOthers, &tmp,
171					sizeof(tmp),
172					FOLL_FORCE | FOLL_WRITE) == sizeof(tmp))
173			break;
174		ret = -EIO;
175		break;
176	}
177
178	/* write the word at location addr in the USER area */
179	case PTRACE_POKEUSR: {
180		unsigned long index;
181
182		ret = -EIO;
183		/* convert to index and check */
184		index = (unsigned long) addr >> 2;
185		if ((addr & 3) || (index > PT_FPSCR32))
186			break;
187
188		if (index < PT_FPR0) {
189			ret = ptrace_put_reg(child, index, data);
190		} else {
191			flush_fp_to_thread(child);
192			/*
193			 * the user space code considers the floating point
194			 * to be an array of unsigned int (32 bits) - the
195			 * index passed in is based on this assumption.
196			 */
197			((unsigned int *)child->thread.fp_state.fpr)
198				[FPRINDEX(index)] = data;
199			ret = 0;
200		}
201		break;
202	}
203
204	/*
205	 * Write 4 bytes into the other process' pt_regs area
206	 *  data is the 4 bytes that the user wants written
207	 *  addr is the offset into the other process' pt_regs structure
208	 *	that is to be written into
209	 * (this is run in a 32-bit process looking at a 64-bit process)
210	 */
211	case PPC_PTRACE_POKEUSR_3264: {
212		u32 index;
213		u32 numReg;
214
215		ret = -EIO;
216		/* Determine which register the user wants */
217		index = (u64)addr >> 2;
218		numReg = index / 2;
219
220		/*
221		 * Validate the input - check to see if address is on the
222		 * wrong boundary or beyond the end of the user area
223		 */
224		if ((addr & 3) || (numReg > PT_FPSCR))
225			break;
226		if (numReg < PT_FPR0) {
227			unsigned long freg;
228			ret = ptrace_get_reg(child, numReg, &freg);
229			if (ret)
230				break;
231			if (index % 2)
232				freg = (freg & ~0xfffffffful) | (data & 0xfffffffful);
233			else
234				freg = (freg & 0xfffffffful) | (data << 32);
235			ret = ptrace_put_reg(child, numReg, freg);
236		} else {
237			u64 *tmp;
238			flush_fp_to_thread(child);
239			/* get 64 bit FPR ... */
240			tmp = &child->thread.fp_state.fpr[numReg - PT_FPR0][0];
241			/* ... write the 32 bit part we want */
242			((u32 *)tmp)[index % 2] = data;
243			ret = 0;
244		}
245		break;
246	}
247
248	case PTRACE_GET_DEBUGREG: {
249#ifndef CONFIG_PPC_ADV_DEBUG_REGS
250		unsigned long dabr_fake;
251#endif
252		ret = -EINVAL;
253		/* We only support one DABR and no IABRS at the moment */
254		if (addr > 0)
255			break;
256#ifdef CONFIG_PPC_ADV_DEBUG_REGS
257		ret = put_user(child->thread.debug.dac1, (u32 __user *)data);
258#else
259		dabr_fake = (
260			(child->thread.hw_brk[0].address & (~HW_BRK_TYPE_DABR)) |
261			(child->thread.hw_brk[0].type & HW_BRK_TYPE_DABR));
262		ret = put_user(dabr_fake, (u32 __user *)data);
263#endif
264		break;
265	}
266
267	case PTRACE_GETREGS:	/* Get all pt_regs from the child. */
268		return copy_regset_to_user(
269			child, task_user_regset_view(current), 0,
270			0, PT_REGS_COUNT * sizeof(compat_long_t),
271			compat_ptr(data));
272
273	case PTRACE_SETREGS:	/* Set all gp regs in the child. */
274		return copy_regset_from_user(
275			child, task_user_regset_view(current), 0,
276			0, PT_REGS_COUNT * sizeof(compat_long_t),
277			compat_ptr(data));
278
279	case PTRACE_GETFPREGS:
280	case PTRACE_SETFPREGS:
281	case PTRACE_GETVRREGS:
282	case PTRACE_SETVRREGS:
283	case PTRACE_GETVSRREGS:
284	case PTRACE_SETVSRREGS:
285	case PTRACE_GETREGS64:
286	case PTRACE_SETREGS64:
287	case PTRACE_KILL:
288	case PTRACE_SINGLESTEP:
289	case PTRACE_DETACH:
290	case PTRACE_SET_DEBUGREG:
291	case PTRACE_SYSCALL:
292	case PTRACE_CONT:
293	case PPC_PTRACE_GETHWDBGINFO:
294	case PPC_PTRACE_SETHWDEBUG:
295	case PPC_PTRACE_DELHWDEBUG:
296		ret = arch_ptrace(child, request, addr, data);
297		break;
298
299	default:
300		ret = compat_ptrace_request(child, request, addr, data);
301		break;
302	}
303
304	return ret;
305}
306