Coherent4.2.10/coh.386/syscoh.c

/* $Header: /ker/coh.386/RCS/syscoh.c,v 2.7 93/10/29 00:55:59 nigel Exp Locker: nigel $ */
/*
 * Functions for the COHERENT-specific system call.
 *
 * $Log:	syscoh.c,v $
 * Revision 2.7  93/10/29  00:55:59  nigel
 * R98 (aka 4.2 Beta) prior to removing System Global memory
 * 
 * Revision 2.6  93/09/02  18:08:41  nigel
 * Nigel's r85, minor edits only
 * 
 * Revision 2.5  93/08/19  03:27:00  nigel
 * Nigel's r83 (Stylistic cleanup)
 */

#include <kernel/proc_lib.h>
#include <sys/errno.h>

#define	_KERNEL		1

#include <kernel/trace.h>
#include <sys/uproc.h>
#include <sys/con.h>
#include <sys/types.h>
#include <sys/cyrix.h>


/*
 * Allow user to write to his own text segment.
 */

static int
cohWtext (dest,src,numBytes)
caddr_t dest;
caddr_t src;
size_t numBytes;
{
	if ((accdata(src, numBytes) || accstack(src, numBytes) ||
	     acctext(src, numBytes) || accShm(src, numBytes)) &&
	     acctext (dest, numBytes)) {
		memcpy (dest, src, numBytes);
		return 0;
	}
	set_user_error (EINVAL);
	return -1;
}


/*
 * Test of shared memory support.
 */

static int
coh_shm(x1, x2, x3, x4)
int x1, x2, x3, x4;
{
	int index, base;

	switch (x1) {
	case 0:
		return shmAlloc(x2);
		break;

	case 1:
		return shmFree(x2);
		break;

	case 2:
		/* Since we are out of args, will use interface
		 * cohcall(COH_SHM, 2, numBytes, base+index, segp)
		 * to call shmAttach, using low bits of base to
		 * carry the index into p_shmsr. */

		base =  x3 & 0xFFFFF000;
		index = x3 & 0x00000FFF;
		if (index >= 0 && index < NSHMSEG) {
			return shmAttach(index, x2, base, x4);
		} else
			SET_U_ERROR(EINVAL, "bad COH shm index");
		break;

	case 3:
		return shmDetach(x2);
		break;

	default:
		SET_U_ERROR(EINVAL, "bad COH shm function");
		break;
	}
	return -1;
}

/*
 * Test of video io map support.
 */

static int
vio(x1, x2, x3, x4)
int x1, x2, x3, x4;
{
	switch (x1) {
	case 0:
		return iomapOr(x2, x3);
		break;

	case 1:
		return iomapAnd(x2, x3);
		break;

	case 2:
		return kiopriv(x2, x3);
		break;

	case 3:
		return mapPhysUser(x2, x3, x4);
		break;

	default:
		SET_U_ERROR(EINVAL, "bad COH vio function");
		break;
	}
	return -1;
}


unsigned int DR0,DR1,DR2,DR3,DR7;

/*
 * Set a kernel breakpoint.
 */

static int
setbp(bp_num, addr, type, len)
unsigned int bp_num, addr, type, len;
{
	/* Range check arguments.
	 * Update RAM images of writeable debug registers.
	 * Call routine (while in RING 1) which will cause GP fault.
	 * GP Fault handler (in RING 0) will copy RAM images to DR's.
	 */
	if (bp_num >= 4 || type >= 4 || len >= 4 || type == 2 || len == 2) {
		SET_U_ERROR(EINVAL, "bad bp setting");
		return -1;
	}

	switch(bp_num) {
	case 0:
		DR0 = addr;
		write_dr0 (DR0);
		DR7 |= (type << 16) | (len << 18) | 0x303;
		break;

	case 1:
		DR1 = addr;
		write_dr1 (DR1);
		DR7 |= (type << 20) | (len << 22) | 0x30C;
		break;

	case 2:
		DR2 = addr;
		write_dr2 (DR2);
		DR7 |= (type << 24) | (len << 26) | 0x330;
		break;

	case 3:
		DR3 = addr;
		write_dr3 (DR3);
		DR7 |= (type << 28) | (len << 30) | 0x3C0;
		break;
	}
	write_dr7 (DR7);
	return 0;
}


/*
 * Clear a kernel breakpoint.
 */

static int
clrbp(bp_num)
unsigned int bp_num;
{
	/* Range check arguments.
	 * Update RAM images of writeable debug registers.
	 * Call routine (while in RING 1) which will cause GP fault.
	 * GP Fault handler (in RING 0) will copy RAM images to DR's.
	 */

	if (bp_num >= 4) {
		SET_U_ERROR(EINVAL, "bad bp # to clear");
		return -1;
	}

	switch(bp_num) {
	case 0:
		DR7 &= ~ 0x3;
		break;

	case 1:
		DR7 &= ~ 0xC;
		break;

	case 2:
		DR7 &= ~ 0x30;
		break;

	case 3:
		DR7 &= ~ 0xC0;
		break;
	}
	if ((DR7 & 0xFF) == 0)
		DR7 &= ~0x300;

	write_dr7 (DR7);
	return 0;
}


/*
 * Only allow this if running as superuser.
 *
 * a1		call type
 * ----------	----------
 * COH_PRINTF	kernel printf
 * COH_DEVLOAD	call load() routine for device with major number a2
 * COH_SETBP	a2=bp#,a3=addr,a4=type,a5=len;  set kernel breakpoint
 * COH_CLRBP	a2=bp#;  clear kernel breakpoint
 * COH_REBOOT	reboot
 * COH_GETINT11 returns hardware equipment word saved at boot time
 * COH_GETCYRIX returns Cyrix CPU id (see cyrix.c for details)
 */

int
ucohcall(a1,a2,a3,a4,a5)
int a1, a2, a3, a4, a5;
{
	int ret = 0;

	if (! super()) {
		SET_U_ERROR (EPERM, "cohcall, must be root");
		return -1;
	}

	switch(a1) {
	case COH_PRINTF:
		printf (a2);
		break;

#if	0
	case COH_DEVLOAD:
		ret = devload (a2);
		break;
#endif
	case COH_SETBP:
		ret = setbp (a2, a3, a4, a5);
		break;

	case COH_CLRBP:
		ret = clrbp (a2);
		break;

	case COH_REBOOT:
		ret = boot ();
		break;

	case COH_VIO:
		ret = vio (a2, a3, a4, a5);
		break;

	case COH_SHM:
		ret = coh_shm (a2, a3, a4, a5);
		break;

	case COH_WTEXT:
		ret = cohWtext (a2, a3, a4);
		break;

	case COH_GETINT11:
		ret = (int11 () & 0x0000FFFF);
		break;

	case COH_GETCYRIX:
		ret = CYRIX_CPU;
		break;

	default:
		SET_U_ERROR (EINVAL, "bad COH function");
	}
	return ret;
}

#if	0
/*
 * Initialize a device.
 */
int
devload(maj_num)
int maj_num;
{
	int ret = -1;
	int mask = 1<<maj_num;

	if (dev_loaded & mask) {
		SET_U_ERROR (EIO, "already loaded");
		return -1;
	}

	if (drvl [maj_num].d_conp == 0) {
		SET_U_ERROR (EIO, "no driver");
		return -1;
	}

	if (drvl [maj_num].d_conp->c_load) {
		(* drvl [maj_num].d_conp->c_load) ();
		dev_loaded |= mask;
		ret = 0;
	}

	return ret;
}

#endif