8c25a4d2ac
This is the main files for the iBCS2 emulator. It can be use compiled into the kernel by using: options IBCS2 options COMPAT_IBCS2 or as a lkm module using: options COMPAT_IBCS2 and then loading it via the ibcs2 script in /usr/bin REMEMBER: this code is still experimental ! NO WARRENTY ! Submitted by: sef@kithrup.com, mostyn@mrl.com, sos@kmd-ac.dk
463 lines
12 KiB
C
463 lines
12 KiB
C
/*-
|
|
* Copyright (c) 1994 Sean Eric Fagan
|
|
* Copyright (c) 1994 Søren Schmidt
|
|
* All rights reserved.
|
|
*
|
|
* Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* 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
|
|
* in this position and unchanged.
|
|
* 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.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
|
*
|
|
* $Id: ibcs2_signal.c,v 1.9 1994/10/12 19:38:03 sos Exp $
|
|
*/
|
|
|
|
#include <i386/ibcs2/ibcs2.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/ioctl_compat.h>
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/fcntl.h>
|
|
#include <sys/file.h>
|
|
#include <sys/filedesc.h>
|
|
#include <sys/namei.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/resourcevar.h>
|
|
#include <sys/signal.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/tty.h>
|
|
#include <sys/termios.h>
|
|
#include <sys/time.h>
|
|
#include <sys/times.h>
|
|
#include <sys/vnode.h>
|
|
#include <vm/vm.h>
|
|
#include <vm/vm_param.h>
|
|
#include <vm/vm_map.h>
|
|
#include <vm/vm_kern.h>
|
|
|
|
|
|
#define DONTMASK (sigmask(SIGKILL)|sigmask(SIGSTOP)|sigmask(SIGCHLD))
|
|
|
|
int bsd_to_ibcs2_signal[NSIG] = {
|
|
0, IBCS2_SIGHUP, IBCS2_SIGINT, IBCS2_SIGQUIT,
|
|
IBCS2_SIGILL, IBCS2_SIGTRAP, IBCS2_SIGABRT, IBCS2_SIGEMT,
|
|
IBCS2_SIGFPE, IBCS2_SIGKILL, IBCS2_SIGBUS, IBCS2_SIGSEGV,
|
|
IBCS2_SIGSYS, IBCS2_SIGPIPE, IBCS2_SIGALRM, IBCS2_SIGTERM,
|
|
IBCS2_SIGURG, IBCS2_SIGSTOP, IBCS2_SIGTSTP, IBCS2_SIGCONT,
|
|
IBCS2_SIGCHLD, IBCS2_SIGTTIN, IBCS2_SIGTTOU, IBCS2_SIGIO,
|
|
IBCS2_SIGGXCPU, IBCS2_SIGGXFSZ, IBCS2_SIGVTALRM, IBCS2_SIGPROF,
|
|
IBCS2_SIGWINCH, 0, IBCS2_SIGUSR1, IBCS2_SIGUSR2
|
|
};
|
|
|
|
int ibcs2_to_bsd_signal[IBCS2_NSIG] = {
|
|
0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGEMT,
|
|
SIGFPE, SIGKILL, SIGBUS, SIGSEGV, SIGSYS, SIGPIPE, SIGALRM, SIGTERM,
|
|
SIGUSR1, SIGUSR2, SIGCHLD, 0, SIGWINCH, SIGURG, SIGIO, SIGSTOP,
|
|
SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU, SIGVTALRM, SIGPROF, SIGXCPU, SIGXFSZ
|
|
};
|
|
|
|
static char ibcs2_sig_name[IBCS2_NSIG][10] = {
|
|
"UNKNOWN", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP",
|
|
"SIGABRT", "SIGEMT", "SIGFPE", "SIGKILL", "SIGBUS", "SIGSEGV",
|
|
"SIGSYS", "SIGPIPE", "SIGALRM", "SIGTERM", "SIGUSR1", "SIGUSR2",
|
|
"SIGCHLD", "SIGPWR", "SIGWINCH", "SIGURG", "SIGIO", "SIGSTOP",
|
|
"SIGTSTP", "SIGCONT", "SIGTTIN", "SIGTTOU", "SIGVTALRM",
|
|
"SIGPROF", "SIGXCPU", "SIGXFSZ"
|
|
};
|
|
|
|
/*#define LEGAL_SIG(x) \
|
|
(((x & IBCS2_SIGMASK) < IBCS2_NSIG) ? (x & IBCS2_SIGMASK) : (0))*/
|
|
int
|
|
LEGAL_SIG(int sig)
|
|
{
|
|
if ((sig & IBCS2_SIGMASK) > IBCS2_NSIG) {
|
|
printf("IBCS2: illegal ibcs2 signal %d(%08x)\n",
|
|
sig & IBCS2_SIGMASK, sig);
|
|
return 0;
|
|
}
|
|
else
|
|
return (sig & IBCS2_SIGMASK);
|
|
}
|
|
|
|
char *
|
|
ibcs2_sig_to_str(int sig)
|
|
{
|
|
if (sig > IBCS2_NSIG) {
|
|
printf("IBCS2: ibcs2 signal out of range (%d)\n", sig);
|
|
return ibcs2_sig_name[0];
|
|
}
|
|
else
|
|
return ibcs2_sig_name[sig];
|
|
}
|
|
|
|
static sig_t
|
|
ibcs2_to_bsd_sigfunc(ibcs2_sig_t func) {
|
|
switch ((int)func) {
|
|
case IBCS2_SIG_DFL:
|
|
return SIG_DFL;
|
|
case IBCS2_SIG_IGN:
|
|
return SIG_IGN;
|
|
case IBCS2_SIG_HOLD:
|
|
return SIG_HOLD;
|
|
default:
|
|
return func;
|
|
}
|
|
}
|
|
|
|
static ibcs2_sig_t
|
|
bsd_to_ibcs2_sigfunc(sig_t func) {
|
|
switch ((int)func) {
|
|
case SIG_DFL:
|
|
return IBCS2_SIG_DFL;
|
|
case SIG_IGN:
|
|
return IBCS2_SIG_IGN;
|
|
case SIG_CATCH:
|
|
printf("IBCS2: Oops - SIG_CATCH does not translate :-(\n");
|
|
return IBCS2_SIG_DFL;
|
|
case SIG_HOLD:
|
|
return IBCS2_SIG_HOLD;
|
|
default:
|
|
return func;
|
|
}
|
|
}
|
|
|
|
static sigset_t
|
|
ibcs2_to_bsd_sigmask(ibcs2_sigset_t mask) {
|
|
int i;
|
|
sigset_t new = 0;
|
|
|
|
for (i = 1; i < NSIG; i++)
|
|
if (mask & (1 << i-1))
|
|
new |= (1 << (ibcs2_to_bsd_signal[i]-1));
|
|
return new;
|
|
}
|
|
|
|
static ibcs2_sigset_t
|
|
bsd_to_ibcs2_sigmask(sigset_t mask) {
|
|
int i;
|
|
sigset_t new = 0;
|
|
|
|
for (i = 1; i < IBCS2_NSIG; i++)
|
|
if (mask & (1 << i-1))
|
|
new |= (1 << (bsd_to_ibcs2_signal[i]-1));
|
|
return new;
|
|
}
|
|
|
|
struct ibcs2_signal_args {
|
|
int signo;
|
|
ibcs2_sig_t func;
|
|
};
|
|
|
|
static int
|
|
ibcs2_sigset(struct proc *p, struct ibcs2_signal_args *args, int *retval)
|
|
{
|
|
struct sigaction tmp;
|
|
int sig_bsd = ibcs2_to_bsd_signal[LEGAL_SIG(args->signo)];
|
|
|
|
*retval = (int)bsd_to_ibcs2_sigfunc(p->p_sigacts->ps_sigact[sig_bsd]);
|
|
if (args->func == IBCS2_SIG_HOLD) {
|
|
(void) splhigh();
|
|
p->p_sigmask |= (sigmask(sig_bsd) &~ DONTMASK);
|
|
(void) spl0();
|
|
}
|
|
else {
|
|
tmp.sa_mask = sigmask(sig_bsd);
|
|
tmp.sa_handler = ibcs2_to_bsd_sigfunc(args->func);
|
|
tmp.sa_flags = 0;
|
|
setsigvec(p, sig_bsd, &tmp);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ibcs2_sighold(struct proc *p, struct ibcs2_signal_args *args, int *retval)
|
|
{
|
|
int sig_bsd = ibcs2_to_bsd_signal[LEGAL_SIG(args->signo)];
|
|
|
|
(void) splhigh();
|
|
*retval = p->p_sigmask;
|
|
p->p_sigmask |= (sigmask(sig_bsd) & ~DONTMASK);
|
|
(void) spl0();
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ibcs2_sigrelse(struct proc *p, struct ibcs2_signal_args *args, int *retval)
|
|
{
|
|
int sig_bsd = ibcs2_to_bsd_signal[LEGAL_SIG(args->signo)];
|
|
|
|
(void) splhigh();
|
|
*retval = p->p_sigmask;
|
|
p->p_sigmask &= ~sigmask(sig_bsd);
|
|
(void) spl0();
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ibcs2_sigignore(struct proc *p, struct ibcs2_signal_args *args, int *retval)
|
|
{
|
|
struct sigaction tmp;
|
|
int sig_bsd = ibcs2_to_bsd_signal[LEGAL_SIG(args->signo)];
|
|
|
|
tmp.sa_mask = sigmask(sig_bsd);
|
|
tmp.sa_handler = SIG_IGN;
|
|
tmp.sa_flags = 0;
|
|
*retval = (int)bsd_to_ibcs2_sigfunc(p->p_sigacts->ps_sigact[sig_bsd]);
|
|
setsigvec(p, sig_bsd, &tmp);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ibcs2_sigpause(struct proc *p, struct ibcs2_signal_args *args, int *retval)
|
|
{
|
|
struct sigacts *ps = p->p_sigacts;
|
|
int sig_bsd = ibcs2_to_bsd_signal[LEGAL_SIG(args->signo)];
|
|
|
|
ps->ps_oldmask = p->p_sigmask;
|
|
ps->ps_flags |= SAS_OLDMASK;
|
|
p->p_sigmask = sigmask(sig_bsd) &~ DONTMASK;
|
|
(void) tsleep((caddr_t) ps, PPAUSE|PCATCH, "i-pause", 0);
|
|
*retval = -1;
|
|
return EINTR;
|
|
}
|
|
|
|
static int
|
|
ibcs2_signal(struct proc *p, struct ibcs2_signal_args *args, int *retval)
|
|
{
|
|
struct sigaction tmp;
|
|
int sig_bsd = ibcs2_to_bsd_signal[LEGAL_SIG(args->signo)];
|
|
|
|
tmp.sa_mask = sigmask(sig_bsd);
|
|
tmp.sa_handler = ibcs2_to_bsd_sigfunc(args->func);
|
|
tmp.sa_flags = 0;
|
|
*retval = (int)bsd_to_ibcs2_sigfunc(p->p_sigacts->ps_sigact[sig_bsd]);
|
|
setsigvec(p, sig_bsd, &tmp);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ibcs2_sigsys(struct proc *p, struct ibcs2_signal_args *args, int *retval)
|
|
{
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("IBCS2: 'sigsys' signo=%d(%s) ",
|
|
args->signo & IBCS2_SIGMASK,
|
|
ibcs2_sig_to_str(args->signo & IBCS2_SIGMASK));
|
|
|
|
switch (args->signo & ~IBCS2_SIGMASK ) {
|
|
case 0x0000:
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("signal() func=%x\n", args->func);
|
|
return ibcs2_signal(p, args, retval);
|
|
case 0x0100:
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("sigset() func=%x\n", args->func);
|
|
return ibcs2_sigset(p, args, retval);
|
|
case 0x0200:
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("sighold()\n");
|
|
return ibcs2_sighold(p, args, retval);
|
|
case 0x0400:
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("sigrelse()\n");
|
|
return ibcs2_sigrelse(p, args, retval);
|
|
case 0x0800:
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("sigignore()\n");
|
|
return ibcs2_sigignore(p, args, retval);
|
|
case 0x1000:
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("sigpause()\n");
|
|
return ibcs2_sigpause(p, args, retval);
|
|
default:
|
|
printf("IBCS2: unknown signal action\n"); break;
|
|
}
|
|
*retval = -1;
|
|
return EINVAL;
|
|
}
|
|
|
|
struct ibcs2_sigaction_args {
|
|
int signo;
|
|
struct sigaction *osa, *nsa;
|
|
};
|
|
|
|
int
|
|
ibcs2_sigaction(struct proc *p, struct ibcs2_sigaction_args *args, int *retval)
|
|
{
|
|
struct sigaction vec;
|
|
register struct sigaction *sa;
|
|
register struct sigacts *ps = p->p_sigacts;
|
|
register int sig;
|
|
int bit, error;
|
|
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("IBCS2: 'sigaction' signo=%d(%s)\n",
|
|
args->signo, ibcs2_sig_to_str(args->signo));
|
|
sig = ibcs2_to_bsd_signal[LEGAL_SIG(args->signo)];
|
|
if (sig <= 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP) {
|
|
*retval = -1;
|
|
return EINVAL;
|
|
}
|
|
sa = &vec;
|
|
if (args->osa) {
|
|
sa->sa_handler = ps->ps_sigact[sig];
|
|
sa->sa_mask = ps->ps_catchmask[sig];
|
|
bit = sigmask(sig);
|
|
sa->sa_flags = 0;
|
|
if (p->p_flag & SA_NOCLDSTOP)
|
|
sa->sa_flags = IBCS2_SA_NOCLDSTOP;
|
|
if (error = copyout((caddr_t)sa, (caddr_t)args->osa,
|
|
sizeof(vec))) {
|
|
*retval = -1;
|
|
return error;
|
|
}
|
|
}
|
|
if (args->nsa) {
|
|
if (error = copyin((caddr_t)args->nsa, (caddr_t)sa,
|
|
sizeof(vec))) {
|
|
*retval = -1;
|
|
return error;
|
|
}
|
|
/*
|
|
* iBCS2 only defines one SA_ flag right now
|
|
*/
|
|
if (vec.sa_flags & IBCS2_SA_NOCLDSTOP)
|
|
vec.sa_flags = SA_NOCLDSTOP;
|
|
setsigvec(p, sig, sa);
|
|
}
|
|
*retval = 0;
|
|
return 0;
|
|
}
|
|
|
|
struct ibcs2_sigprocmask_args {
|
|
int how;
|
|
unsigned long *mask;
|
|
unsigned long *omask;
|
|
};
|
|
|
|
int
|
|
ibcs2_sigprocmask(struct proc *p, struct ibcs2_sigprocmask_args *args, int *retval)
|
|
{
|
|
int error;
|
|
sigset_t umask;
|
|
sigset_t omask = bsd_to_ibcs2_sigmask(p->p_sigmask);
|
|
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("IBCS2: 'sigprocmask' how=%d\n", args->how);
|
|
if (error = copyin(args->mask, &umask, sizeof(args->mask))) {
|
|
*retval = -1;
|
|
return error;
|
|
}
|
|
umask = ibcs2_to_bsd_sigmask(umask);
|
|
if (args->omask)
|
|
if (error = copyout(&omask, args->omask, sizeof(args->omask))) {
|
|
*retval = -1;
|
|
return error;
|
|
}
|
|
(void) splhigh();
|
|
switch (args->how) {
|
|
case 0: /* SIG_SETMASK */
|
|
p->p_sigmask = umask &~ DONTMASK;
|
|
break;
|
|
|
|
case 1: /* SIG_BLOCK */
|
|
p->p_sigmask |= (umask &~ DONTMASK);
|
|
break;
|
|
|
|
case 2: /* SIG_UNBLOCK */
|
|
p->p_sigmask &= ~umask;
|
|
break;
|
|
|
|
default:
|
|
error = EINVAL;
|
|
break;
|
|
}
|
|
(void) spl0();
|
|
if (error)
|
|
*retval = -1;
|
|
else
|
|
*retval = 0;
|
|
return error;
|
|
}
|
|
|
|
struct ibcs2_sigpending_args {
|
|
unsigned long *sigs;
|
|
};
|
|
|
|
int
|
|
ibcs2_sigpending(struct proc *p, struct ibcs2_sigpending_args *args, int *retval)
|
|
{
|
|
int error;
|
|
sigset_t mask = bsd_to_ibcs2_sigmask(p->p_siglist);
|
|
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("IBCS2: 'sigpending' which=%x\n", args->sigs);
|
|
if (error = copyout(&mask, args->sigs, sizeof(unsigned long)))
|
|
*retval = -1;
|
|
else
|
|
*retval = 0;
|
|
return error;
|
|
}
|
|
|
|
struct ibcs2_sigsuspend_args {
|
|
sigset_t *mask;
|
|
};
|
|
|
|
int
|
|
ibcs2_sigsuspend(struct proc *p, struct ibcs2_sigsuspend_args *args, int *retval)
|
|
{
|
|
sigset_t mask = ibcs2_to_bsd_sigmask((sigset_t)args->mask);
|
|
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("IBCS2: 'sigsuspend'\n");
|
|
return sigsuspend(p, &mask, retval);
|
|
}
|
|
|
|
struct kill_args {
|
|
int pid;
|
|
int signo;
|
|
};
|
|
|
|
int
|
|
ibcs2_kill(struct proc *p, struct kill_args *args, int *retval)
|
|
{
|
|
struct kill_args tmp;
|
|
|
|
if (ibcs2_trace & IBCS2_TRACE_SIGNAL)
|
|
printf("IBCS2: 'kill' pid=%d, sig=%d(%s)\n", args->pid,
|
|
args->signo, ibcs2_sig_to_str(args->signo));
|
|
tmp.pid = args->pid;
|
|
tmp.signo = (args->signo < IBCS2_NSIG) ?
|
|
ibcs2_to_bsd_signal[args->signo] : IBCS2_NSIG;
|
|
return kill(p, &tmp, retval);
|
|
}
|
|
|