Coherent4.2.10/i386/sys1632.c

Compare this file to the similar file:
Show the results in this format:

/* $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;
}