Coherent4.2.10/i386/sys1632.c
/* $Header: /ker/i386/RCS/sys1632.c,v 2.7 93/10/29 00:57:24 nigel Exp Locker: nigel $ */
/*
* This file contains the implementations of system calls for Coherent 286,
* and the machinery for making a system call from a 286 process.
*
* $Log: sys1632.c,v $
* Revision 2.7 93/10/29 00:57:24 nigel
* R98 (aka 4.2 Beta) prior to removing System Global memory
*
* Revision 2.6 93/09/13 07:51:09 nigel
* Extra debugging (show 286 system-call return value)
*
* Revision 2.5 93/09/02 18:12:18 nigel
* Minor edits to use new flag system
*
* Revision 2.4 93/08/19 03:40:15 nigel
* Nigel's R83
*/
#include <common/_limits.h>
#include <common/_tricks.h>
#include <common/_gregset.h>
#include <sys/errno.h>
#include <sys/debug.h>
#include <sys/cmn_err.h>
#include <signal.h>
#include <stddef.h>
#define _KERNEL 1
#include <kernel/trace.h>
#include <kernel/reg.h>
#include <sys/acct.h>
#include <sys/buf.h>
#include <sys/con.h>
#include <sys/filsys.h>
#include <sys/ino.h>
#include <sys/inode.h>
#include <sys/proc.h>
#include <sys/uproc.h>
#include <sys/sched.h>
#include <sys/seg.h>
#include <sys/timeb.h>
#include <sys/fd.h>
#include <l.out.h>
#include <canon.h>
#include <kernel/systab.h>
/*
* Structure returned by COH-286 stat and fstat system calls.
*/
struct oldstat {
o_dev_t st_dev; /* Device */
o_ino_t st_ino; /* Inode number */
unsigned short st_mode; /* Mode */
short st_nlink; /* Link count */
short st_uid; /* User id */
short st_gid; /* Group id */
o_dev_t st_rdev; /* Real device */
#pragma align 2
long st_size __ALIGN (2); /* Size */
long st_atime __ALIGN (2); /* Access time */
long st_mtime __ALIGN (2); /* Modify time */
long st_ctime __ALIGN (2); /* Change time */
#pragma align
#pragma align 2
};
#pragma align /* controls structure padding in Coherent 'cc' */
/*
* emulate a 16 bit system call
* called from trap.c
*/
static char cvtsig [] =
{
0,
SIGHUP, SIGINT, SIGQUIT, SIGALRM, SIGTERM, SIGPWR,
SIGSYS, SIGPIPE, SIGKILL, SIGTRAP, SIGSEGV,
SIGEMT, /* SIGDIVE */
SIGEMT, /* SIGOVFL */
SIGUSR1,
SIGUSR2,
SIGUSR2
};
int ostat();
int ofstat();
int oftime();
int upgrp();
int ugetuid();
int ugetgid();
int usysi86();
int ulock();
int ufcntl();
int uexece();
long oalarm2 ();
long otick ();
/*
* Duplicate a file descriptor number. This has the same calling
* sequence as the dup2 system call and even uses the silly DUP2 bit.
*/
int
coh286dup(ofd, nfd)
unsigned ofd;
unsigned nfd;
{
__fd_t * fdp;
if ((fdp = fd_get (ofd & ~ DUP2)) == NULL)
return -1;
if ((ofd & DUP2) != 0) {
if (nfd >= NOFILE) {
SET_U_ERROR (EBADF, "coh286dup ()");
return -1;
}
ofd &= ~ DUP2;
if (ofd == nfd)
return nfd;
if (u.u_filep [nfd] != NULL) {
fd_close (nfd);
if (get_user_error ())
return -1;
}
} else
nfd = 0;
return fd_dup (ofd, nfd);
}
int
ostime (timep)
time_t * timep;
{
return ustime (getuwd (timep));
}
int
opipe (pipep)
short * pipep;
{
short res;
res = upipe ();
putusd (pipep, res);
putusd (pipep + 1, u.u_rval2);
return 0;
}
int
osetpgrp ()
{
return setpgrp ();
}
int
ogetpgrp ()
{
return getpgrp ();
}
int
ogeteuid ()
{
(void) ugetuid ();
return u.u_rval2;
}
int
ogetegid ()
{
(void) ugetgid ();
return u.u_rval2;
}
int
ounique ()
{
return usysi86 (SYI86UNEEK);
}
int
okill (pid, signal)
short pid;
unsigned signal;
{
if (signal >= __ARRAY_LENGTH (cvtsig)) {
SET_U_ERROR (EINVAL, "286 kill ()");
return -1;
}
return ukill (pid, cvtsig [signal]);
}
__sighand_t *
osignal (signal, func, regsetp)
unsigned signal;
__sighand_t * func;
gregset_t * regsetp;
{
if (signal >= __ARRAY_LENGTH (cvtsig)) {
SET_U_ERROR (EINVAL, "286 signal ()");
return (__sighand_t *) -1;
}
return (__sighand_t *) usigsys (cvtsig [signal], func, regsetp);
}
#if __SHRT_BIT != 16
# error This code expects 16-bit shorts
#endif
long
olseek (fd, seeklo, seekhi, whence)
unsigned fd;
unsigned short seeklo;
unsigned short seekhi;
unsigned whence;
{
return ulseek (fd, seeklo + (seekhi << 16), whence);
}
/* msgsys, shmsys, and semsys are not emulated */
/* poll is not emulated;NOTE:the code calls putuwd */
int
oldsys (regsetp)
gregset_t * regsetp;
{
register struct systab *stp;
unsigned int callnum;
int i;
int res;
int args [MSACOUNT];
struct __menv sigenv;
set_user_error (0);
callnum = getusd (NBPS + regsetp->_i286._ip - sizeof (short));
/*
* Check that we are on an INT instruction, and that the fetch did
* not cause a memory fault. Note that the magic NBPS number above,
* which presumably means "Number of Bytes Per Segment", is how to
* get to 286 code.
*/
if (get_user_error () || (callnum & 0xFF) != 0xCD)
return SIGSYS;
callnum = (callnum >> 8) & 0x7F;
if (callnum >= __ARRAY_LENGTH (sys286tab))
return SIGSYS;
stp = sys286tab + callnum;
/* Print out this 286 call only if tracing is on. */
T_ERRNO (4, cmn_err (CE_CONT, "[%s", stp->s_name));
stp->s_stat ++;
if (envsave (u.u_sigenvp = & sigenv)) {
set_user_error (EINTR);
goto done;
}
i = stp->s_nargs + 1;
while (-- i > 0) {
args [i - 1] = getusd (regsetp->_i286._usp +
i * sizeof (short));
}
if (get_user_error ())
return SIGSYS;
/*
* Perform the system call and collect the return value in "res".
*/
res = __DOSYSCALL (stp->s_nargs, stp->s_func, args, regsetp);
if (stp->s_type == __SYSCALL_LONG)
regsetp->_i286._dx = res >> 16;
else
regsetp->_i286._dx = u.u_rval2;
regsetp->_i286._ax = res;
done:
u.u_sigenvp = NULL;
if (get_user_error ()) {
T_ERRNO (4, cmn_err (CE_NOTE, "-err"));
regsetp->_i286._ax = regsetp->_i286._dx = -1;
putubd (MUERR, get_user_error ());
if (get_user_error () == EFAULT)
return SIGSYS;
}
T_ERRNO (4, cmn_err (CE_NOTE, "=%d] ", regsetp->_i286._ax));
return 0;
}
/*
* Copy the appropriate information from the inode to the stat buffer.
*/
#if __USE_PROTO__
__LOCAL__ void oistat (struct inode * ip, struct oldstat * sbp)
#else
__LOCAL__ void
oistat(ip, sbp)
struct inode * ip;
struct oldstat *sbp;
#endif
{
sbp->st_dev = ip->i_dev;
sbp->st_ino = ip->i_ino;
sbp->st_mode = ip->i_mode;
sbp->st_nlink = ip->i_nlink;
sbp->st_uid = ip->i_uid;
sbp->st_gid = ip->i_gid;
sbp->st_rdev = (o_dev_t) -1;
sbp->st_size = ip->i_size;
sbp->st_atime = ip->i_atime;
sbp->st_mtime = ip->i_mtime;
sbp->st_ctime = ip->i_ctime;
switch (ip->i_mode & IFMT) {
case IFBLK:
case IFCHR:
sbp->st_rdev = ip->i_rdev;
sbp->st_size = 0;
break;
case IFPIPE:
sbp->st_size = ip->i_pnc;
break;
}
}
/*
* Given a file descriptor, return a status structure.
*/
int
ofstat(fd, stp)
int fd;
struct oldstat *stp;
{
INODE *ip;
__fd_t * fdp;
struct oldstat stat;
if ((fdp = fd_get (fd)) == NULL)
return -1;
ip = fdp->f_ip;
oistat (ip, & stat);
kucopy (& stat, stp, sizeof (stat));
return 0;
}
/*
* Return a status structure for the given file name.
*/
int
ostat(np, stp)
char *np;
struct oldstat *stp;
{
struct oldstat stat;
struct direct dir;
if (ftoi (np, 'r', IOUSR, NULL, & dir, SELF->p_credp) != 0)
return -1;
oistat (u.u_cdiri, & stat);
if (kucopy (& stat, stp, sizeof (stat)) != sizeof (stat))
SET_U_ERROR (EFAULT, "286 stat ()");
idetach (u.u_cdiri);
return 0;
}
/*
* Return date and time.
*/
int
oftime(tbp)
struct timeb *tbp;
{
struct timeb timeb;
timeb.time = timer.t_time;
/* This should be a machine.h macro to avoid
* unnecessary long arithmetic and roundoff errors
*/
timeb.millitm = timer.t_tick*(1000/HZ);
timeb.timezone = timer.t_zone;
timeb.dstflag = timer.t_dstf;
if (kucopy (& timeb, tbp, sizeof (timeb)) != sizeof (timeb)) {
SET_U_ERROR (EFAULT, "286 ftime ()");
return -1;
}
return 0;
}
/*
* Send a SIGALARM signal in `n' clock ticks.
*/
long
oalarm2(n)
long n;
{
register PROC * pp = SELF;
long s;
extern sigalrm ();
/*
* Calculate time left before current alarm timeout.
*/
s = 0;
if (pp->p_alrmtim.t_last != NULL)
s = pp->p_alrmtim.t_lbolt - lbolt;
/*
* Cancel previous alarm [if any], start new alarm [if n != 0].
*/
timeout2 (& pp->p_alrmtim, (long) n, sigalrm, pp);
/*
* Return time left before previous alarm timeout.
*/
return s;
}
/*
* Return elapsed ticks since system startup.
*/
long
otick()
{
return lbolt;
}
/*
* Cause a signal routine to be executed.
* Called from [coh/sig.c]
*/
void
oldsigstart (sig, func, regsetp)
int sig;
__sighand_t * func;
gregset_t * regsetp;
{
int i;
struct {
ushort_t sf_signo;
ushort_t sf_prev_ip;
__286_flags_t sf_flags;
} signal_frame;
/*
* -1
* calculate cvtsig [sig]
*
*/
signal_frame.sf_signo = sig;
for (i = 0 ; i < __ARRAY_LENGTH (cvtsig) ; i ++)
if (cvtsig [i] == sig) {
signal_frame.sf_signo = i;
break;
}
signal_frame.sf_prev_ip = regsetp->_i286._ip;
signal_frame.sf_flags = regsetp->_i286._flags;
/*
* Turn off single-stepping in signal handler.
*/
__FLAG_REG (regsetp) = __FLAG_CLEAR_FLAG (__FLAG_REG (regsetp),
__TRAP);
regsetp->_i286._ip = (ushort_t) (ulong_t) func;
regsetp->_i286._usp -= sizeof (signal_frame);
i = kucopy (& signal_frame, regsetp->_i286._usp,
sizeof (signal_frame));
ASSERT (i == sizeof (signal_frame));
}
/*
* obrk()
*
* Argument is the new linear space value for the end of the PDATA segment.
* As was done in COH286, arg of zero asks for the old upper limit.
*/
__EXTERN_C__ caddr_t ubrk __PROTO ((unsigned cp));
caddr_t
obrk (cp)
unsigned cp;
{
/*
* If cp nonzero
* resize user data segment
* else
* just give info - current brk address
*/
if (cp)
return ubrk (cp);
else
return SELF->p_segl [SIPDATA].sr_base +
SELF->p_segl [SIPDATA].sr_segp->s_size;
}