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