1 /*	$NetBSD: process_machdep.c,v 1.29 2011/01/18 01:02:55 matt Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5  * Copyright (C) 1995, 1996 TooLs GmbH.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.29 2011/01/18 01:02:55 matt Exp $");
36 
37 #include "opt_altivec.h"
38 
39 #include <sys/param.h>
40 #include <sys/proc.h>
41 #include <sys/systm.h>
42 #include <sys/ptrace.h>
43 
44 #include <machine/fpu.h>
45 #include <machine/pcb.h>
46 #include <machine/reg.h>
47 
48 #include <uvm/uvm_extern.h>
49 
50 #include <powerpc/altivec.h>
51 
52 int
53 process_read_regs(struct lwp *l, struct reg *regs)
54 {
55 	struct trapframe * const tf = trapframe(l);
56 
57 	memcpy(regs->fixreg, tf->tf_fixreg, sizeof(regs->fixreg));
58 	regs->lr = tf->tf_lr;
59 	regs->cr = tf->tf_cr;
60 	regs->xer = tf->tf_xer;
61 	regs->ctr = tf->tf_ctr;
62 	regs->pc = tf->tf_srr0;
63 
64 	return 0;
65 }
66 
67 int
68 process_write_regs(struct lwp *l, const struct reg *regs)
69 {
70 	struct trapframe * const tf = trapframe(l);
71 
72 	memcpy(tf->tf_fixreg, regs->fixreg, sizeof(regs->fixreg));
73 	tf->tf_lr = regs->lr;
74 	tf->tf_cr = regs->cr;
75 	tf->tf_xer = regs->xer;
76 	tf->tf_ctr = regs->ctr;
77 	tf->tf_srr0 = regs->pc;
78 
79 	return 0;
80 }
81 
82 int
83 process_read_fpregs(struct lwp *l, struct fpreg *fpregs)
84 {
85 	struct pcb * const pcb = lwp_getpcb(l);
86 
87 	/* Is the process using the fpu? */
88 	if ((l->l_md.md_flags & MDLWP_USEDFPU) == 0) {
89 		memset(fpregs, 0, sizeof (*fpregs));
90 		return 0;
91 	}
92 
93 #ifdef PPC_HAVE_FPU
94 	fpu_save_lwp(l, FPU_SAVE_AND_RELEASE);
95 #endif
96 	*fpregs = pcb->pcb_fpu;
97 
98 	return 0;
99 }
100 
101 int
102 process_write_fpregs(struct lwp *l, const struct fpreg *fpregs)
103 {
104 	struct pcb * const pcb = lwp_getpcb(l);
105 
106 #ifdef PPC_HAVE_FPU
107 	fpu_save_lwp(l, FPU_DISCARD);
108 #endif
109 
110 	pcb->pcb_fpu = *fpregs;
111 
112 	/* pcb_fpu is initialized now. */
113 	l->l_md.md_flags |= MDLWP_USEDFPU;
114 
115 	return 0;
116 }
117 
118 /*
119  * Set the process's program counter.
120  */
121 int
122 process_set_pc(struct lwp *l, void *addr)
123 {
124 	struct trapframe * const tf = trapframe(l);
125 
126 	tf->tf_srr0 = (register_t)addr;
127 
128 	return 0;
129 }
130 
131 int
132 process_sstep(struct lwp *l, int sstep)
133 {
134 	struct trapframe *tf = trapframe(l);
135 
136 	if (sstep)
137 		tf->tf_srr1 |= PSL_SE;
138 	else
139 		tf->tf_srr1 &= ~PSL_SE;
140 	return 0;
141 }
142 
143 
144 #ifdef __HAVE_PTRACE_MACHDEP
145 static int
146 process_machdep_read_vecregs(struct lwp *l, struct vreg *vregs)
147 {
148 	struct pcb * const pcb = lwp_getpcb(l);
149 
150 #ifdef ALTIVEC
151 	if (cpu_altivec == 0)
152 		return (EINVAL);
153 #endif
154 
155 	/* Is the process using AltiVEC? */
156 	if ((l->l_md.md_flags & MDLWP_USEDVEC) == 0) {
157 		memset(vregs, 0, sizeof (*vregs));
158 		return 0;
159 	}
160 	vec_save_lwp(l, VEC_SAVE_AND_RELEASE);
161 	*vregs = pcb->pcb_vr;
162 
163 	return (0);
164 }
165 
166 static int
167 process_machdep_write_vecregs(struct lwp *l, struct vreg *vregs)
168 {
169 	struct pcb * const pcb = lwp_getpcb(l);
170 
171 #ifdef ALTIVEC
172 	if (cpu_altivec == 0)
173 		return (EINVAL);
174 #endif
175 
176 	vec_save_lwp(l, VEC_DISCARD);
177 	pcb->pcb_vr = *vregs;
178 	l->l_md.md_flags |= MDLWP_USEDVEC;	/* pcb_vr is initialized now. */
179 
180 	return (0);
181 }
182 
183 int
184 ptrace_machdep_dorequest(struct lwp *l, struct lwp *lt,
185 	int req, void *addr, int data)
186 {
187 	struct uio uio;
188 	struct iovec iov;
189 	int write = 0;
190 
191 	switch (req) {
192 	case PT_SETVECREGS:
193 		write = 1;
194 
195 	case PT_GETVECREGS:
196 		/* write = 0 done above. */
197 		if (!process_machdep_validvecregs(lt->l_proc))
198 			return (EINVAL);
199 		iov.iov_base = addr;
200 		iov.iov_len = sizeof(struct vreg);
201 		uio.uio_iov = &iov;
202 		uio.uio_iovcnt = 1;
203 		uio.uio_offset = 0;
204 		uio.uio_resid = sizeof(struct vreg);
205 		uio.uio_rw = write ? UIO_WRITE : UIO_READ;
206 		uio.uio_vmspace = l->l_proc->p_vmspace;
207 		return process_machdep_dovecregs(l, lt, &uio);
208 	}
209 
210 #ifdef DIAGNOSTIC
211 	panic("ptrace_machdep: impossible");
212 #endif
213 
214 	return (0);
215 }
216 
217 /*
218  * The following functions are used by both ptrace(2) and procfs.
219  */
220 
221 int
222 process_machdep_dovecregs(struct lwp *curl, struct lwp *l, struct uio *uio)
223 {
224 	struct vreg r;
225 	int error;
226 	char *kv;
227 	int kl;
228 
229 	kl = sizeof(r);
230 	kv = (char *) &r;
231 
232 	kv += uio->uio_offset;
233 	kl -= uio->uio_offset;
234 	if (kl > uio->uio_resid)
235 		kl = uio->uio_resid;
236 
237 	if (kl < 0)
238 		error = EINVAL;
239 	else
240 		error = process_machdep_read_vecregs(l, &r);
241 	if (error == 0)
242 		error = uiomove(kv, kl, uio);
243 	if (error == 0 && uio->uio_rw == UIO_WRITE) {
244 		if (l->l_proc->p_stat != SSTOP)
245 			error = EBUSY;
246 		else
247 			error = process_machdep_write_vecregs(l, &r);
248 	}
249 
250 	uio->uio_offset = 0;
251 	return (error);
252 }
253 
254 int
255 process_machdep_validvecregs(struct proc *p)
256 {
257 	if (p->p_flag & PK_SYSTEM)
258 		return (0);
259 
260 #ifdef ALTIVEC
261 	return (cpu_altivec);
262 #endif
263 #ifdef PPC_HAVE_SPE
264 	return 1;
265 #endif
266 }
267 #endif /* __HAVE_PTRACE_MACHDEP */
268