/*
 * Copyright (c) 1986 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 *
 *	@(#)kern_pdp.c	1.4 (2.11BSD) 1998/5/12
 */

#include "param.h"
#include "../machine/autoconfig.h"
#include "../machine/seg.h"

#include "user.h"
#include "ioctl.h"
#include "proc.h"
#include "kernel.h"
#include "systm.h"
#include "cpu.h"
#include "tty.h"

/*
 * used to pass result from int service to probe();
 * do not declare static!!
 */
int	conf_int = CONF_MAGIC;

/*
 * ucall allows user level code to call various kernel functions.
 * Autoconfig uses it to call the probe and attach routines of the
 * various device drivers.
 */
ucall()
{
	register struct a {
		int priority;
		int (*routine)();
		int arg1;
		int arg2;
	} *uap = (struct a *)u.u_ap;
	int s;

	if (!suser())
		return;
	switch(uap->priority) {
		case 0:
			s = spl0();
			break;
		case 1:
			s = spl1();
			break;
		case 2:
		case 3:
		case 4:
			s = spl4();
			break;
		case 5:
			s = spl5();
			break;
		case 6:
			s = spl6();
			break;
		case 7:
		default:
			s = spl7();
			break;
	}
	u.u_r.r_val1 = (*uap->routine)(uap->arg1,uap->arg2);
	splx(s);
}

/*
 * Lock user into core as much as possible.  Swapping may still
 * occur if core grows.
 */
lock()
{
	struct a {
		int	flag;
	};

	if (!suser())
		return;
	if (((struct a *)u.u_ap)->flag)
		u.u_procp->p_flag |= SULOCK;
	else
		u.u_procp->p_flag &= ~SULOCK;
}

/*
 * fetch the word at iaddr from user I-space.  This system call is
 * required on machines with separate I/D space because the mfpi
 * instruction reads from D-space if the current and previous modes
 * in the program status word are both user.
 */
fetchi()
{
	struct a {
		caddr_t iaddr;
	};
#ifdef NONSEPARATE
	u.u_error = EINVAL;
#else !NONSEPARATE
	u.u_error = copyiin((struct a *)u.u_ap, u.u_r.r_val1, NBPW);
#endif NONSEPARATE
}

/*
 * return the floating point error registers as they were following
 * the last floating point exception generated by the calling process.
 * Required because the error registers may have been changed so the
 * system saves them at the time of the exception.
 */
fperr()
{
	u.u_r.r_val1 = (int)u.u_fperr.f_fec;
	u.u_r.r_val2 = (int)u.u_fperr.f_fea;
}

/*
 * set up the process to have no stack segment.  The process is
 * responsible for the management of its own stack, and can thus
 * use the full 64K byte address space.
 */
nostk()
{
	if (estabur(u.u_tsize, u.u_dsize, 0, u.u_sep, RO))
		return;
	expand(0,S_STACK);
	u.u_ssize = 0;
}

/*
 * set up a physical address
 * into users virtual address space.
 */
phys()
{
	register struct a {
		int segno;
		int size;
		int phys;
	} *uap = (struct a *)u.u_ap;
	register int i, s;
	int d;

	if (!suser())
		return;

	i = uap->segno;
	if (i < 0 || i >= 8)
		goto bad;
	s = uap->size;
	if (s < 0 || s > 128)
		goto bad;
#ifdef NONSEPARATE
	d = u.u_uisd[i];
#else
	d = u.u_uisd[i + 8];
#endif
	if (d != 0 && (d & ABS) == 0)
		goto bad;
#ifdef NONSEPARATE
	u.u_uisd[i] = 0;
	u.u_uisa[i] = 0;
#else
	u.u_uisd[i + 8] = 0;
	u.u_uisa[i + 8] = 0;
	if (!u.u_sep) {
		u.u_uisd[i] = 0;
		u.u_uisa[i] = 0;
	}
#endif
	if (s) {
#ifdef NONSEPARATE
		u.u_uisd[i] = ((s - 1) << 8) | RW | ABS;
		u.u_uisa[i] = uap->phys;
#else
		u.u_uisd[i + 8] = ((s - 1) << 8) | RW | ABS;
		u.u_uisa[i + 8] = uap->phys;
		if (!u.u_sep) {
			u.u_uisa[i] = u.u_uisa[i + 8];
			u.u_uisd[i] = u.u_uisd[i + 8];
		}
#endif
	}
	sureg();
	return;
bad:
	u.u_error = EINVAL;
}

/*
 * This is ugly but it's either this or always include [T]MSCP code even
 * for systems without that type of device.
*/
#include "tms.h"
#include "ra.h"
#if NTMSCP > 0
	extern	int tmscpprintf, tmscpcache;		/* see pdpuba/tmscp.c */
#endif
#if	NRAC > 0
	extern	int mscpprintf;
#endif
	extern	struct tty cons[];

/*
 * This was moved here when the TMSCP portion was added.  At that time it
 * became (even more) system specific and didn't belong in kern_sysctl.c
*/

int
cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
	int *name;
	u_int namelen;
	void *oldp;
	size_t *oldlenp;
	void *newp;
	size_t newlen;
	{

	switch	(name[0])
		{
		case	CPU_CONSDEV:
			if	(namelen != 1)
				return(ENOTDIR);
			return(sysctl_rdstruct(oldp, oldlenp, newp, 
					&cons[0].t_dev, sizeof &cons[0].t_dev));
#if NTMSCP > 0
		case	CPU_TMSCP:
		/* All sysctl names at this level are terminal */
			if	(namelen != 2)
				return(ENOTDIR);
			switch	(name[1])
				{
				case	TMSCP_CACHE:
					return(sysctl_int(oldp, oldlenp, newp, 
						newlen, &tmscpcache));
				case	TMSCP_PRINTF:
					return(sysctl_int(oldp, oldlenp, newp,
						newlen,&tmscpprintf));
				default:
					return(EOPNOTSUPP);
				}
#endif
#if	NRAC > 0
		case	CPU_MSCP:
		/* All sysctl names at this level are terminal */
			if	(namelen != 2)
				return(ENOTDIR);
			switch	(name[1])
				{
				case	MSCP_PRINTF:
					return(sysctl_int(oldp, oldlenp, newp,
						newlen,&mscpprintf));
				default:
					return(EOPNOTSUPP);
				}
#endif
		default:
			return(EOPNOTSUPP);
		}
	/* NOTREACHED */
	}
