1 /* $NetBSD: process_machdep.c,v 1.43 2022/12/05 16:03:50 martin 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.43 2022/12/05 16:03:50 martin Exp $");
36
37 #ifdef _KERNEL_OPT
38 #include "opt_altivec.h"
39 #include "opt_ppcarch.h"
40 #endif
41
42 #include <sys/param.h>
43 #include <sys/cpu.h>
44 #include <sys/proc.h>
45 #include <sys/ptrace.h>
46 #include <sys/systm.h>
47
48 #include <uvm/uvm_extern.h>
49
50 #include <powerpc/fpu.h>
51 #include <powerpc/pcb.h>
52 #include <powerpc/psl.h>
53 #include <powerpc/reg.h>
54
55 #include <powerpc/altivec.h> /* also for e500 SPE */
56
57 int
process_read_regs(struct lwp * l,struct reg * regs)58 process_read_regs(struct lwp *l, struct reg *regs)
59 {
60 struct trapframe * const tf = l->l_md.md_utf;
61
62 memcpy(regs->fixreg, tf->tf_fixreg, sizeof(regs->fixreg));
63 regs->lr = tf->tf_lr;
64 regs->cr = tf->tf_cr;
65 regs->xer = tf->tf_xer;
66 regs->ctr = tf->tf_ctr;
67 regs->pc = tf->tf_srr0;
68
69 return 0;
70 }
71
72 int
process_write_regs(struct lwp * l,const struct reg * regs)73 process_write_regs(struct lwp *l, const struct reg *regs)
74 {
75 struct trapframe * const tf = l->l_md.md_utf;
76
77 memcpy(tf->tf_fixreg, regs->fixreg, sizeof(regs->fixreg));
78 tf->tf_lr = regs->lr;
79 tf->tf_cr = regs->cr;
80 tf->tf_xer = regs->xer;
81 tf->tf_ctr = regs->ctr;
82 tf->tf_srr0 = regs->pc;
83
84 return 0;
85 }
86
87 int
process_read_fpregs(struct lwp * l,struct fpreg * fpregs,size_t * sz)88 process_read_fpregs(struct lwp *l, struct fpreg *fpregs, size_t *sz)
89 {
90 struct pcb * const pcb = lwp_getpcb(l);
91
92 /* Is the process using the fpu? */
93 if (!fpu_used_p(l)) {
94 memset(fpregs, 0, sizeof (*fpregs));
95 #ifdef PPC_HAVE_FPU
96 } else {
97 fpu_save(l);
98 #endif
99 }
100 *fpregs = pcb->pcb_fpu;
101 fpu_mark_used(l);
102
103 return 0;
104 }
105
106 int
process_write_fpregs(struct lwp * l,const struct fpreg * fpregs,size_t sz)107 process_write_fpregs(struct lwp *l, const struct fpreg *fpregs, size_t sz)
108 {
109 struct pcb * const pcb = lwp_getpcb(l);
110
111 #ifdef PPC_HAVE_FPU
112 fpu_discard(l);
113 #endif
114 pcb->pcb_fpu = *fpregs;
115 fpu_mark_used(l); /* pcb_fpu is initialized now. */
116
117 return 0;
118 }
119
120 /*
121 * Set the process's program counter.
122 */
123 int
process_set_pc(struct lwp * l,void * addr)124 process_set_pc(struct lwp *l, void *addr)
125 {
126 struct trapframe * const tf = l->l_md.md_utf;
127
128 tf->tf_srr0 = (register_t)addr;
129
130 return 0;
131 }
132
133 int
process_sstep(struct lwp * l,int sstep)134 process_sstep(struct lwp *l, int sstep)
135 {
136 #if !defined(PPC_BOOKE) && !defined(PPC_IBM4XX)
137 struct trapframe * const tf = l->l_md.md_utf;
138
139 if (sstep) {
140 tf->tf_srr1 |= PSL_SE;
141 } else {
142 tf->tf_srr1 &= ~PSL_SE;
143 }
144 return 0;
145 #else
146 /*
147 * We use the software single-stepping for booke/ibm4xx.
148 */
149 return ppc_sstep(l, sstep);
150 #endif
151 }
152
153
154 #ifdef __HAVE_PTRACE_MACHDEP
155 static int
process_machdep_read_vecregs(struct lwp * l,struct vreg * vregs)156 process_machdep_read_vecregs(struct lwp *l, struct vreg *vregs)
157 {
158 struct pcb * const pcb = lwp_getpcb(l);
159
160 #ifdef ALTIVEC
161 if (cpu_altivec == 0)
162 return EINVAL;
163 #endif
164
165 /* Is the process using AltiVEC? */
166 if (!vec_used_p(l)) {
167 memset(vregs, 0, sizeof (*vregs));
168 } else {
169 vec_save(l);
170 *vregs = pcb->pcb_vr;
171 }
172 vec_mark_used(l);
173
174 return 0;
175 }
176
177 static int
process_machdep_write_vecregs(struct lwp * l,struct vreg * vregs)178 process_machdep_write_vecregs(struct lwp *l, struct vreg *vregs)
179 {
180 struct pcb * const pcb = lwp_getpcb(l);
181
182 #ifdef ALTIVEC
183 if (cpu_altivec == 0)
184 return (EINVAL);
185 #endif
186
187 #if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
188 vec_discard(l);
189 #endif
190 pcb->pcb_vr = *vregs; /* pcb_vr is initialized now. */
191 vec_mark_used(l);
192
193 return (0);
194 }
195
196 int
ptrace_machdep_dorequest(struct lwp * l,struct lwp ** lt,int req,void * addr,int data)197 ptrace_machdep_dorequest(struct lwp *l, struct lwp **lt,
198 int req, void *addr, int data)
199 {
200 struct uio uio;
201 struct iovec iov;
202 int write = 0, error;
203
204 switch (req) {
205 case PT_SETVECREGS:
206 write = 1;
207
208 case PT_GETVECREGS:
209 /* write = 0 done above. */
210 if ((error = ptrace_update_lwp((*lt)->l_proc, lt, data)) != 0)
211 return error;
212 if (!process_machdep_validvecregs((*lt)->l_proc))
213 return (EINVAL);
214 iov.iov_base = addr;
215 iov.iov_len = sizeof(struct vreg);
216 uio.uio_iov = &iov;
217 uio.uio_iovcnt = 1;
218 uio.uio_offset = 0;
219 uio.uio_resid = sizeof(struct vreg);
220 uio.uio_rw = write ? UIO_WRITE : UIO_READ;
221 uio.uio_vmspace = l->l_proc->p_vmspace;
222 return process_machdep_dovecregs(l, *lt, &uio);
223 }
224
225 #ifdef DIAGNOSTIC
226 panic("ptrace_machdep: impossible");
227 #endif
228
229 return (0);
230 }
231
232 /*
233 * The following functions are used by both ptrace(2) and procfs.
234 */
235
236 int
process_machdep_dovecregs(struct lwp * curl,struct lwp * l,struct uio * uio)237 process_machdep_dovecregs(struct lwp *curl, struct lwp *l, struct uio *uio)
238 {
239 struct vreg r;
240 int error;
241 char *kv;
242 int kl;
243
244 kl = sizeof(r);
245 kv = (char *) &r;
246
247 kv += uio->uio_offset;
248 kl -= uio->uio_offset;
249 if (kl > uio->uio_resid)
250 kl = uio->uio_resid;
251
252 if (kl < 0)
253 error = EINVAL;
254 else
255 error = process_machdep_read_vecregs(l, &r);
256 if (error == 0)
257 error = uiomove(kv, kl, uio);
258 if (error == 0 && uio->uio_rw == UIO_WRITE) {
259 if (l->l_proc->p_stat != SSTOP)
260 error = EBUSY;
261 else
262 error = process_machdep_write_vecregs(l, &r);
263 }
264
265 uio->uio_offset = 0;
266 return (error);
267 }
268
269 int
process_machdep_validvecregs(struct proc * p)270 process_machdep_validvecregs(struct proc *p)
271 {
272 if (p->p_flag & PK_SYSTEM)
273 return (0);
274
275 #ifdef ALTIVEC
276 return (cpu_altivec);
277 #endif
278 #ifdef PPC_HAVE_SPE
279 return 1;
280 #endif
281 }
282 #endif /* __HAVE_PTRACE_MACHDEP */
283
284 #if defined(PPC_BOOKE) || defined(PPC_IBM4XX)
285 /*
286 * ppc_ifetch and ppc_istore:
287 * fetch/store instructions from/to given process (therefore, we cannot use
288 * ufetch/ustore(9) here).
289 */
290
291 static int
ppc_ifetch(struct lwp * l,vaddr_t va,uint32_t * insn)292 ppc_ifetch(struct lwp *l, vaddr_t va, uint32_t *insn)
293 {
294 struct uio uio;
295 struct iovec iov;
296
297 iov.iov_base = insn;
298 iov.iov_len = sizeof(*insn);
299 uio.uio_iov = &iov;
300 uio.uio_iovcnt = 1;
301 uio.uio_offset = (off_t)va;
302 uio.uio_resid = sizeof(*insn);
303 uio.uio_rw = UIO_READ;
304 UIO_SETUP_SYSSPACE(&uio);
305
306 return process_domem(curlwp, l, &uio);
307 }
308
309 static int
ppc_istore(struct lwp * l,vaddr_t va,uint32_t insn)310 ppc_istore(struct lwp *l, vaddr_t va, uint32_t insn)
311 {
312 struct uio uio;
313 struct iovec iov;
314
315 iov.iov_base = &insn;
316 iov.iov_len = sizeof(insn);
317 uio.uio_iov = &iov;
318 uio.uio_iovcnt = 1;
319 uio.uio_offset = (off_t)va;
320 uio.uio_resid = sizeof(insn);
321 uio.uio_rw = UIO_WRITE;
322 UIO_SETUP_SYSSPACE(&uio);
323
324 return process_domem(curlwp, l, &uio);
325 }
326
327 /*
328 * Insert or remove single-step breakpoints:
329 * We need two breakpoints, in general, at (SRR0 + 4) and the address to
330 * which the process can branch into.
331 */
332
333 int
ppc_sstep(struct lwp * l,int step)334 ppc_sstep(struct lwp *l, int step)
335 {
336 struct trapframe * const tf = l->l_md.md_utf;
337 struct proc * const p = l->l_proc;
338 const uint32_t trap = 0x7d821008; /* twge %r2, %r2 */
339 uint32_t insn;
340 vaddr_t va[2];
341 int i, rv;
342
343 if (step) {
344 if (p->p_md.md_ss_addr[0] != 0)
345 return 0; /* XXX Should we reset breakpoints? */
346
347 va[0] = (vaddr_t)tf->tf_srr0;
348 va[1] = 0;
349
350 /*
351 * Find the address to which the process can branch into.
352 */
353 if ((rv = ppc_ifetch(l, va[0], &insn)) != 0)
354 return rv;
355 if ((insn >> 28) == 4) {
356 if ((insn >> 26) == 0x12) {
357 const int32_t off =
358 ((int32_t)(insn << 6) >> 6) & ~3;
359 va[1] = ((insn & 2) ? 0 : va[0]) + off;
360 } else if ((insn >> 26) == 0x10) {
361 const int16_t off = (int16_t)insn & ~3;
362 va[1] = ((insn & 2) ? 0 : va[0]) + off;
363 } else if ((insn & 0xfc00fffe) == 0x4c000420)
364 va[1] = tf->tf_ctr;
365 else if ((insn & 0xfc00fffe) == 0x4c000020)
366 va[1] = tf->tf_lr;
367 }
368 va[0] += sizeof(insn);
369 if (va[1] == va[0])
370 va[1] = 0;
371
372 for (i = 0; i < 2; i++) {
373 if (va[i] == 0)
374 return 0;
375 if ((rv = ppc_ifetch(l, va[i], &insn)) != 0)
376 goto error;
377 p->p_md.md_ss_insn[i] = insn;
378 if ((rv = ppc_istore(l, va[i], trap)) != 0) {
379 error: /* Recover as far as possible. */
380 if (i == 1 && ppc_istore(l, va[0],
381 p->p_md.md_ss_insn[0]) == 0)
382 p->p_md.md_ss_addr[0] = 0;
383 return rv;
384 }
385 p->p_md.md_ss_addr[i] = va[i];
386 }
387 } else {
388 for (i = 0; i < 2; i++) {
389 va[i] = p->p_md.md_ss_addr[i];
390 if (va[i] == 0)
391 return 0;
392 if ((rv = ppc_ifetch(l, va[i], &insn)) != 0)
393 return rv;
394 if (insn != trap) {
395 panic("%s: ss_insn[%d] = 0x%x != trap",
396 __func__, i, insn);
397 }
398 if ((rv = ppc_istore(l, va[i], p->p_md.md_ss_insn[i]))
399 != 0)
400 return rv;
401 p->p_md.md_ss_addr[i] = 0;
402 }
403 }
404 return 0;
405 }
406 #endif /* PPC_BOOKE || PPC_IBM4XX */
407