1 /* $NetBSD: netbsd32_machdep.c,v 1.4 2011/01/14 02:06:28 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas <matt@3am-software.com>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.4 2011/01/14 02:06:28 rmind Exp $"); 34 35 #include "opt_compat_netbsd.h" 36 #include "opt_sa.h" 37 #include "opt_coredump.h" 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/ioctl.h> 42 #include <sys/exec.h> 43 #include <sys/cpu.h> 44 #include <sys/core.h> 45 #include <sys/file.h> 46 #include <sys/time.h> 47 #include <sys/proc.h> 48 #include <sys/uio.h> 49 #include <sys/kernel.h> 50 #include <sys/buf.h> 51 #include <sys/signal.h> 52 #include <sys/signalvar.h> 53 #include <sys/mount.h> 54 #include <sys/syscallargs.h> 55 56 #include <compat/netbsd32/netbsd32.h> 57 #include <compat/netbsd32/netbsd32_exec.h> 58 #include <compat/netbsd32/netbsd32_syscallargs.h> 59 60 #include <mips/cache.h> 61 #include <mips/sysarch.h> 62 #include <mips/cachectl.h> 63 #include <mips/locore.h> 64 #include <mips/frame.h> 65 #include <mips/regnum.h> 66 #include <mips/pcb.h> 67 68 #include <uvm/uvm_extern.h> 69 70 char machine32[] = MACHINE; 71 char machine_arch32[] = MACHINE32_ARCH; 72 73 #if 0 74 cpu_coredump32 75 netbsd32_cpu_upcall 76 netbsd32_vm_default_addr 77 #endif 78 79 int 80 netbsd32_sysarch(struct lwp *l, const struct netbsd32_sysarch_args *uap, 81 register_t *retval) 82 { 83 /* { 84 syscallarg(int) op; 85 syscallarg(netbsd32_voidp) parms; 86 } */ 87 struct proc *p = l->l_proc; 88 void *parms = SCARG_P32(uap, parms); 89 int error = 0; 90 91 switch(SCARG(uap, op)) { 92 case MIPS_CACHEFLUSH: { 93 struct mips_cacheflush_args32 cfua; 94 95 error = copyin(parms, &cfua, sizeof(cfua)); 96 if (error != 0) 97 return (error); 98 error = mips_user_cacheflush(p, cfua.va, cfua.nbytes, 99 cfua.whichcache); 100 break; 101 } 102 case MIPS_CACHECTL: { 103 struct mips_cachectl_args32 ccua; 104 105 error = copyin(parms, &ccua, sizeof(ccua)); 106 if (error != 0) 107 return (error); 108 error = mips_user_cachectl(p, ccua.va, ccua.nbytes, ccua.ctl); 109 break; 110 } 111 default: 112 error = ENOSYS; 113 break; 114 } 115 return (error); 116 } 117 118 #ifdef COMPAT_13 119 int 120 compat_13_netbsd32_sigreturn(struct lwp *l, 121 const struct compat_13_netbsd32_sigreturn_args *uap, 122 register_t *retval) 123 { 124 struct compat_13_sys_sigreturn_args ua; 125 126 NETBSD32TOP_UAP(sigcntxp, struct sigcontext13 *); 127 128 return compat_13_sys_sigreturn(l, &ua, retval); 129 } 130 #endif 131 132 #ifdef COMPAT_16 133 int 134 compat_16_netbsd32___sigreturn14(struct lwp *l, 135 const struct compat_16_netbsd32___sigreturn14_args *uap, 136 register_t *retval) 137 { 138 struct compat_16_sys___sigreturn14_args ua; 139 140 NETBSD32TOP_UAP(sigcntxp, struct sigcontext *); 141 142 return compat_16_sys___sigreturn14(l, &ua, retval); 143 } 144 #endif 145 146 vaddr_t 147 netbsd32_vm_default_addr(struct proc *p, vaddr_t base, vsize_t size) 148 { 149 return VM_DEFAULT_ADDRESS32(base, size); 150 } 151 152 153 struct sigframe_siginfo32 { 154 siginfo32_t sf_si; 155 ucontext32_t sf_uc; 156 }; 157 158 /* 159 * Send a signal to process. 160 */ 161 static void 162 netbsd32_sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask) 163 { 164 struct lwp * const l = curlwp; 165 struct proc * const p = l->l_proc; 166 struct sigacts * const ps = p->p_sigacts; 167 int onstack, error; 168 int sig = ksi->ksi_signo; 169 struct sigframe_siginfo32 *sfp = getframe(l, sig, &onstack); 170 struct sigframe_siginfo32 sf; 171 struct frame * const tf = l->l_md.md_regs; 172 size_t sfsz; 173 sig_t catcher = SIGACTION(p, sig).sa_handler; 174 175 sfp--; 176 177 netbsd32_si_to_si32(&sf.sf_si, (const siginfo_t *)&ksi->ksi_info); 178 179 /* Build stack frame for signal trampoline. */ 180 switch (ps->sa_sigdesc[sig].sd_vers) { 181 case 0: /* handled by sendsig_sigcontext */ 182 case 1: /* handled by sendsig_sigcontext */ 183 default: /* unknown version */ 184 printf("sendsig_siginfo: bad version %d\n", 185 ps->sa_sigdesc[sig].sd_vers); 186 sigexit(l, SIGILL); 187 case 2: 188 break; 189 } 190 191 sf.sf_uc.uc_flags = _UC_SIGMASK 192 | ((l->l_sigstk.ss_flags & SS_ONSTACK) 193 ? _UC_SETSTACK : _UC_CLRSTACK); 194 sf.sf_uc.uc_sigmask = *mask; 195 sf.sf_uc.uc_link = (intptr_t)l->l_ctxlink; 196 memset(&sf.sf_uc.uc_stack, 0, sizeof(sf.sf_uc.uc_stack)); 197 sfsz = offsetof(struct sigframe_siginfo32, sf_uc.uc_mcontext); 198 if (p->p_md.md_abi == _MIPS_BSD_API_O32) 199 sfsz += sizeof(mcontext_o32_t); 200 else 201 sfsz += sizeof(mcontext32_t); 202 sendsig_reset(l, sig); 203 mutex_exit(p->p_lock); 204 cpu_getmcontext32(l, &sf.sf_uc.uc_mcontext, &sf.sf_uc.uc_flags); 205 error = copyout(&sf, sfp, sfsz); 206 mutex_enter(p->p_lock); 207 208 if (error != 0) { 209 /* 210 * Process has trashed its stack; give it an illegal 211 * instruction to halt it in its tracks. 212 */ 213 sigexit(l, SIGILL); 214 /* NOTREACHED */ 215 } 216 217 /* 218 * Set up the registers to directly invoke the signal 219 * handler. The return address will be set up to point 220 * to the signal trampoline to bounce us back. 221 */ 222 tf->f_regs[_R_A0] = sig; 223 tf->f_regs[_R_A1] = (intptr_t)&sfp->sf_si; 224 tf->f_regs[_R_A2] = (intptr_t)&sfp->sf_uc; 225 226 tf->f_regs[_R_PC] = (intptr_t)catcher; 227 tf->f_regs[_R_T9] = (intptr_t)catcher; 228 tf->f_regs[_R_SP] = (intptr_t)sfp; 229 tf->f_regs[_R_RA] = (intptr_t)ps->sa_sigdesc[sig].sd_tramp; 230 231 /* Remember that we're now on the signal stack. */ 232 if (onstack) 233 l->l_sigstk.ss_flags |= SS_ONSTACK; 234 } 235 236 void 237 netbsd32_sendsig(const ksiginfo_t *ksi, const sigset_t *mask) 238 { 239 #ifdef COMPAT_16 240 if (curproc->p_sigacts->sa_sigdesc[ksi->ksi_signo].sd_vers < 2) 241 sendsig_sigcontext(ksi, mask); 242 else 243 #endif 244 netbsd32_sendsig_siginfo(ksi, mask); 245 } 246 247 void 248 cpu_getmcontext32(struct lwp *l, mcontext32_t *mc32, unsigned int *flagsp) 249 { 250 mcontext_o32_t * const mco32 = (mcontext_o32_t *)mc32; 251 mcontext_t mc; 252 size_t i; 253 254 if (l->l_proc->p_md.md_abi == _MIPS_BSD_API_N32) { 255 cpu_getmcontext(l, (mcontext_t *)mc32, flagsp); 256 return; 257 } 258 259 cpu_getmcontext(l, &mc, flagsp); 260 for (i = 0; i < __arraycount(mc.__gregs); i++) 261 mco32->__gregs[i] = mc.__gregs[i]; 262 if (*flagsp & _UC_FPU) 263 memcpy(&mco32->__fpregs, &mc.__fpregs, 264 sizeof(struct fpreg_oabi)); 265 } 266 267 int 268 cpu_setmcontext32(struct lwp *l, const mcontext32_t *mc32, unsigned int flags) 269 { 270 const mcontext_o32_t * const mco32 = (const mcontext_o32_t *)mc32; 271 mcontext_t mc; 272 size_t i; 273 274 if (l->l_proc->p_md.md_abi == _MIPS_BSD_API_N32) 275 return cpu_setmcontext(l, (const mcontext_t *)mc32, flags); 276 277 for (i = 0; i < __arraycount(mc.__gregs); i++) 278 mc.__gregs[i] = mco32->__gregs[i]; 279 if (flags & _UC_FPU) 280 memcpy(&mc.__fpregs, &mco32->__fpregs, 281 sizeof(struct fpreg_oabi)); 282 return cpu_setmcontext(l, &mc, flags); 283 } 284 285 #ifdef COREDUMP 286 /* 287 * Dump the machine specific segment at the start of a core dump. 288 */ 289 int 290 cpu_coredump32(struct lwp *l, void *iocookie, struct core32 *chdr) 291 { 292 int error; 293 struct coreseg cseg; 294 struct cpustate { 295 struct frame frame; 296 struct fpreg fpregs; 297 } cpustate; 298 299 if (iocookie == NULL) { 300 CORE_SETMAGIC(*chdr, COREMAGIC, MID_MACHINE, 0); 301 chdr->c_hdrsize = ALIGN(sizeof(struct core)); 302 chdr->c_seghdrsize = ALIGN(sizeof(struct coreseg)); 303 chdr->c_cpusize = sizeof(struct cpustate); 304 chdr->c_nseg++; 305 return 0; 306 } 307 308 if ((l->l_md.md_flags & MDP_FPUSED) && l == fpcurlwp) 309 savefpregs(l); 310 311 struct pcb * const pcb = lwp_getpcb(l); 312 cpustate.frame = *l->l_md.md_regs; 313 cpustate.fpregs = pcb->pcb_fpregs; 314 315 CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_MACHINE, CORE_CPU); 316 cseg.c_addr = 0; 317 cseg.c_size = chdr->c_cpusize; 318 319 error = coredump_write(iocookie, UIO_SYSSPACE, &cseg, 320 chdr->c_seghdrsize); 321 if (error) 322 return error; 323 324 return coredump_write(iocookie, UIO_SYSSPACE, &cpustate, 325 chdr->c_cpusize); 326 } 327 #endif 328