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 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 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 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 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 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 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 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 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 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 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 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 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 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 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