mirror of
https://github.com/Stichting-MINIX-Research-Foundation/netbsd.git
synced 2025-08-09 14:09:10 -04:00
357 lines
9.4 KiB
C
357 lines
9.4 KiB
C
/* $NetBSD: netbsd32_machdep.c,v 1.12 2015/05/17 18:52:37 matt 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 <matt@3am-software.com>.
|
|
*
|
|
* 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 <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.12 2015/05/17 18:52:37 matt Exp $");
|
|
|
|
#include "opt_compat_netbsd.h"
|
|
#include "opt_coredump.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/exec.h>
|
|
#include <sys/cpu.h>
|
|
#include <sys/core.h>
|
|
#include <sys/file.h>
|
|
#include <sys/time.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/signal.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/syscallargs.h>
|
|
|
|
#include <compat/netbsd32/netbsd32.h>
|
|
#include <compat/netbsd32/netbsd32_exec.h>
|
|
#include <compat/netbsd32/netbsd32_syscallargs.h>
|
|
|
|
#include <mips/cache.h>
|
|
#include <mips/sysarch.h>
|
|
#include <mips/cachectl.h>
|
|
#include <mips/locore.h>
|
|
#include <mips/frame.h>
|
|
#include <mips/regnum.h>
|
|
#include <mips/pcb.h>
|
|
|
|
#include <uvm/uvm_extern.h>
|
|
|
|
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)
|
|
{
|
|
if (p->p_vmspace->vm_map.flags & VM_MAP_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--;
|
|
|
|
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;
|
|
memset(&sf.sf_uc.uc_stack, 0, sizeof(sf.sf_uc.uc_stack));
|
|
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;
|
|
}
|
|
|
|
KASSERT(l == curlwp);
|
|
fpu_save();
|
|
|
|
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));
|
|
}
|