/* $NetBSD: netbsd32_machdep.c,v 1.14.6.1 2019/01/27 18:43:09 martin Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Matt Thomas . * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.14.6.1 2019/01/27 18:43:09 martin Exp $"); #include "opt_compat_netbsd.h" #include "opt_coredump.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char machine32[] = MACHINE; const char machine_arch32[] = MACHINE32_ARCH; #if 0 cpu_coredump32 netbsd32_cpu_upcall netbsd32_vm_default_addr #endif int netbsd32_sysarch(struct lwp *l, const struct netbsd32_sysarch_args *uap, register_t *retval) { /* { syscallarg(int) op; syscallarg(netbsd32_voidp) parms; } */ struct proc *p = l->l_proc; void *parms = SCARG_P32(uap, parms); int error = 0; switch(SCARG(uap, op)) { case MIPS_CACHEFLUSH: { struct mips_cacheflush_args32 cfua; error = copyin(parms, &cfua, sizeof(cfua)); if (error != 0) return (error); error = mips_user_cacheflush(p, cfua.va, cfua.nbytes, cfua.whichcache); break; } case MIPS_CACHECTL: { struct mips_cachectl_args32 ccua; error = copyin(parms, &ccua, sizeof(ccua)); if (error != 0) return (error); error = mips_user_cachectl(p, ccua.va, ccua.nbytes, ccua.ctl); break; } default: error = ENOSYS; break; } return (error); } #ifdef COMPAT_13 int compat_13_netbsd32_sigreturn(struct lwp *l, const struct compat_13_netbsd32_sigreturn_args *uap, register_t *retval) { struct compat_13_sys_sigreturn_args ua; NETBSD32TOP_UAP(sigcntxp, struct sigcontext13 *); return compat_13_sys_sigreturn(l, &ua, retval); } #endif #ifdef COMPAT_16 int compat_16_netbsd32___sigreturn14(struct lwp *l, const struct compat_16_netbsd32___sigreturn14_args *uap, register_t *retval) { struct compat_16_sys___sigreturn14_args ua; NETBSD32TOP_UAP(sigcntxp, struct sigcontext *); return compat_16_sys___sigreturn14(l, &ua, retval); } #endif vaddr_t netbsd32_vm_default_addr(struct proc *p, vaddr_t base, vsize_t size, int topdown) { if (topdown) return VM_DEFAULT_ADDRESS32_TOPDOWN(base, size); else return VM_DEFAULT_ADDRESS32_BOTTOMUP(base, size); } struct sigframe_siginfo32 { siginfo32_t sf_si; ucontext32_t sf_uc; }; /* * Send a signal to process. */ static void netbsd32_sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp * const l = curlwp; struct proc * const p = l->l_proc; struct sigacts * const ps = p->p_sigacts; int onstack, error; int sig = ksi->ksi_signo; struct sigframe_siginfo32 *sfp = getframe(l, sig, &onstack); struct sigframe_siginfo32 sf; struct trapframe * const tf = l->l_md.md_utf; size_t sfsz; sig_t catcher = SIGACTION(p, sig).sa_handler; sfp--; memset(&sf, 0, sizeof(sf)); netbsd32_si_to_si32(&sf.sf_si, (const siginfo_t *)&ksi->ksi_info); /* Build stack frame for signal trampoline. */ switch (ps->sa_sigdesc[sig].sd_vers) { case 0: /* handled by sendsig_sigcontext */ case 1: /* handled by sendsig_sigcontext */ default: /* unknown version */ printf("sendsig_siginfo: bad version %d\n", ps->sa_sigdesc[sig].sd_vers); sigexit(l, SIGILL); case 2: break; } sf.sf_uc.uc_flags = _UC_SIGMASK | ((l->l_sigstk.ss_flags & SS_ONSTACK) ? _UC_SETSTACK : _UC_CLRSTACK); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_link = (intptr_t)l->l_ctxlink; sfsz = offsetof(struct sigframe_siginfo32, sf_uc.uc_mcontext); if (p->p_md.md_abi == _MIPS_BSD_API_O32) sfsz += sizeof(mcontext_o32_t); else sfsz += sizeof(mcontext32_t); sendsig_reset(l, sig); mutex_exit(p->p_lock); cpu_getmcontext32(l, &sf.sf_uc.uc_mcontext, &sf.sf_uc.uc_flags); error = copyout(&sf, sfp, sfsz); mutex_enter(p->p_lock); if (error != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ sigexit(l, SIGILL); /* NOTREACHED */ } /* * Set up the registers to directly invoke the signal * handler. The return address will be set up to point * to the signal trampoline to bounce us back. */ tf->tf_regs[_R_A0] = sig; tf->tf_regs[_R_A1] = (intptr_t)&sfp->sf_si; tf->tf_regs[_R_A2] = (intptr_t)&sfp->sf_uc; tf->tf_regs[_R_PC] = (intptr_t)catcher; tf->tf_regs[_R_T9] = (intptr_t)catcher; tf->tf_regs[_R_SP] = (intptr_t)sfp; tf->tf_regs[_R_RA] = (intptr_t)ps->sa_sigdesc[sig].sd_tramp; /* Remember that we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; } void netbsd32_sendsig(const ksiginfo_t *ksi, const sigset_t *mask) { #ifdef COMPAT_16 if (curproc->p_sigacts->sa_sigdesc[ksi->ksi_signo].sd_vers < 2) sendsig_sigcontext(ksi, mask); else #endif netbsd32_sendsig_siginfo(ksi, mask); } void cpu_getmcontext32(struct lwp *l, mcontext32_t *mc32, unsigned int *flagsp) { mcontext_o32_t * const mco32 = (mcontext_o32_t *)mc32; mcontext_t mc; size_t i; if (l->l_proc->p_md.md_abi == _MIPS_BSD_API_N32) { cpu_getmcontext(l, (mcontext_t *)mc32, flagsp); return; } cpu_getmcontext(l, &mc, flagsp); for (i = 1; i < __arraycount(mc.__gregs); i++) mco32->__gregs[i] = mc.__gregs[i]; if (*flagsp & _UC_FPU) memcpy(&mco32->__fpregs, &mc.__fpregs, sizeof(struct fpreg_oabi)); mco32->_mc_tlsbase = mc._mc_tlsbase; *flagsp |= _UC_TLSBASE; } int cpu_mcontext32_validate(struct lwp *l, const mcontext32_t *mc32) { return 0; } int cpu_setmcontext32(struct lwp *l, const mcontext32_t *mc32, unsigned int flags) { const mcontext_o32_t * const mco32 = (const mcontext_o32_t *)mc32; mcontext_t mc; size_t i, error; if (flags & _UC_CPU) { error = cpu_mcontext32_validate(l, mc32); if (error) return error; } if (l->l_proc->p_md.md_abi == _MIPS_BSD_API_N32) return cpu_setmcontext(l, (const mcontext_t *)mc32, flags); for (i = 0; i < __arraycount(mc.__gregs); i++) mc.__gregs[i] = mco32->__gregs[i]; if (flags & _UC_FPU) memcpy(&mc.__fpregs, &mco32->__fpregs, sizeof(struct fpreg_oabi)); mc._mc_tlsbase = mco32->_mc_tlsbase; return cpu_setmcontext(l, &mc, flags); } #ifdef COREDUMP /* * Dump the machine specific segment at the start of a core dump. */ int cpu_coredump32(struct lwp *l, struct coredump_iostate *iocookie, struct core32 *chdr) { int error; struct coreseg cseg; struct cpustate { struct trapframe frame; struct fpreg fpregs; } cpustate; if (iocookie == NULL) { CORE_SETMAGIC(*chdr, COREMAGIC, MID_MACHINE, 0); chdr->c_hdrsize = ALIGN(sizeof(struct core)); chdr->c_seghdrsize = ALIGN(sizeof(struct coreseg)); chdr->c_cpusize = sizeof(struct cpustate); chdr->c_nseg++; return 0; } fpu_save(l); struct pcb * const pcb = lwp_getpcb(l); cpustate.frame = *l->l_md.md_utf; cpustate.fpregs = pcb->pcb_fpregs; CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_MACHINE, CORE_CPU); cseg.c_addr = 0; cseg.c_size = chdr->c_cpusize; error = coredump_write(iocookie, UIO_SYSSPACE, &cseg, chdr->c_seghdrsize); if (error) return error; return coredump_write(iocookie, UIO_SYSSPACE, &cpustate, chdr->c_cpusize); } #endif int cpu_machinearch32(SYSCTLFN_ARGS) { struct sysctlnode node = *rnode; const char *march = l->l_proc->p_md.md_abi == _MIPS_BSD_API_O32 ? machine_arch32 : machine_arch; node.sysctl_data = __UNCONST(march); node.sysctl_size = strlen(march) + 1; return sysctl_lookup(SYSCTLFN_CALL(&node)); }