|
|
coherent
/* $Header: /var/lib/cvsd/repos/coherent/coherent/b/kernel/coh.386/null.c,v 1.1.1.1 2019/05/29 04:56:37 root Exp $ */
/* (lgl-
* The information contained herein is a trade secret of Mark Williams
* Company, and is confidential information. It is provided under a
* license agreement, and may be copied or disclosed only under the
* terms of that agreement. Any reproduction or disclosure of this
* material without the express written authorization of Mark Williams
* Company or persuant to the license agreement is unlawful.
*
* COHERENT Version 2.3.37
* Copyright (c) 1982, 1983, 1984.
* An unpublished work by Mark Williams Company, Chicago.
* All rights reserved.
-lgl) */
/*
* Null and memory driver.
* Minor device 0 is /dev/null
* Minor device 1 is /dev/mem, physical memory
* Minor device 2 is /dev/kmem, kernel data
* Minor device 3 is /dev/cmos
* Minor device 4 is /dev/boot_gift
* Minor device 5 is /dev/clock
* Minor device 6 is /dev/ps
* Minor device 7 is /dev/kmemhi, virtual memory 0x8000_0000-0xFFFF_FFFF
*
* $Log: null.c,v $
* Revision 1.1.1.1 2019/05/29 04:56:37 root
* coherent
*
* Revision 1.7 93/04/14 10:06:37 root
* r75
*
* Revision 1.10 93/03/02 08:16:25 bin
* kernel 73 update
*
* Revision 1.6 92/11/09 17:10:54 root
* Just before adding vio segs.
*
* Revision 1.2 92/01/06 11:59:49 hal
* Compile with cc.mwc.
*
* Revision 1.1 88/03/24 16:14:04 src
* Initial revision
*
*/
/*
* The symbol "DANGEROUS" should be undefined for a production system.
*/
#ifdef TRACER
#define NULL_IOCTL /* Allow ioctl()s for /dev/kmem. */
#define DANGEROUS /* Allow dangerous ioctl()s for /dev/null. */
#endif
#include <sys/coherent.h>
#include <sys/con.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/typed.h>
#include <sys/inode.h>
#include <sys/seg.h>
#include <sys/coh_ps.h>
#ifdef NULL_IOCTL
#include <sys/null.h>
#endif /* NULL_IOCTL */
/* These are minor numbers. */
#define DEV_NULL 0 /* /dev/null */
#define DEV_MEM 1 /* /dev/mem */
#define DEV_KMEM 2 /* /dev/kmem */
#define DEV_CMOS 3 /* /dev/cmos */
#define DEV_BOOTGIFT 4 /* /dev/bootgift */
#define DEV_CLOCK 5 /* /dev/clock */
#define DEV_PS 6 /* /dev/ps */
#define DEV_KMEMHI 7 /* /dev/kmemhi */
#define KMEMHI_BASE 0x80000000
#define PXCOPY_LIM 4096
/*
* CMOS devices are limited by an 8 bit address.
*/
#define MAX_CMOS 255
#define CMOS_LEN 256
/*
* The first 14 bytes of the CMOS are the clock.
*/
#define MAX_CLOCK 13
#define CLOCK_LEN 14
/*
* These are definitions for mucking with the CMOS clock.
*/
#define SRA 10 /* Status Register A */
#define SRB 11 /* Status Register B */
#define SRC 12 /* Status Register C */
#define SRD 13 /* Status Register D */
#define UIP 0x80 /* Update In Progress bit of SRA. */
#define NO_UPD 0x80 /* No Update bit of SRB. */
/*
* Functions for configuration.
*/
void nlopen();
void nlclose();
void nlread();
void nlwrite();
int nlioctl();
int nulldev();
int nonedev();
/*
* Configuration table.
*/
CON nlcon ={
DFCHR, /* Flags */
0, /* Major index */
nlopen, /* Open */
nlclose, /* Close */
nulldev, /* Block */
nlread, /* Read */
nlwrite, /* Write */
#ifdef NULL_IOCTL
nlioctl, /* Ioctl */
#else /* NULL_IOCTL */
nonedev, /* Ioctl */
#endif /* NULL_IOCTL */
nulldev, /* Powerfail */
nulldev, /* Timeout */
nulldev, /* Load */
nulldev /* Unload */
};
int lock_clock();
void unlock_clock();
/*
* Null/memory open routine.
*/
void
nlopen(dev, mode)
dev_t dev;
int mode;
{
switch (minor(dev)) {
case DEV_PS:
/* /dev/ps is read only */
if (IPR != (IPR & mode))
SET_U_ERROR( EACCES, "/dev/ps is read only" );
break;
default:
/*
* For minor devices on NULL there is
* usually no action for open().
*/
break;
}
return;
} /* nlopen() */
/*
* Null/memory close routine.
*/
void
nlclose(dev, mode)
dev_t dev;
int mode;
{
/*
* For minor devices on NULL there is
* Usually no action for close().
*/
return;
} /* nlclose() */
/*
* Null/memory read routine.
*/
void
nlread(dev, iop)
dev_t dev;
register IO *iop;
{
register unsigned bytesRead;
register SEG *sp; /* u area segment */
register PROC *pp1; /* */
char psBuf[ARGSZ]; /* buffer for command line
* arguments for ps. */
stMonitor psData; /* All process data for */
UPROC *uprc; /* pointer to u area */
int ndpUseg; /* System global address
* of U segment */
unsigned int seek;
unsigned char read_cmos();
extern typed_space boot_gift;
switch (minor(dev)) {
case DEV_NULL:
/*
* Read nothing.
* Do NOT update iop->io_ioc.
* This way, caller knows 0 bytes were read.
*/
break;
case DEV_MEM:
while (iop->io_ioc) {
int src = iop->io_seek;
int dest = iop->io.pbase;
int numBytes = PXCOPY_LIM;
if (numBytes > iop->io_ioc)
numBytes = iop->io_ioc;
bytesRead = pxcopy(src, dest, numBytes, SEG_386_UD);
src += bytesRead;
dest += bytesRead;
iop->io_ioc -= bytesRead;
if (u.u_error == EFAULT) {
u.u_error = 0;
break;
}
}
break;
case DEV_KMEM:
iowrite(iop, iop->io_seek, iop->io_ioc);
if (u.u_error == EFAULT)
u.u_error = 0;
break;
case DEV_CLOCK:
/*
* Don't go past the end of the CLOCK.
*/
if (iop->io_seek >= CLOCK_LEN)
break;
/*
* Lock the clock before any reading.
*/
if (lock_clock() == 0) {
SET_U_ERROR(EIO, "RT clock will not settle.");
break;
}
/*
* Read the requested data out of the CMOS.
*/
for (seek = iop->io_seek; seek < CLOCK_LEN; seek++) {
if(ioputc(read_cmos(seek), iop) == -1)
break;
}
/*
* Now that we are done reading the CMOS, let
* the clock loose.
*/
unlock_clock();
break;
case DEV_CMOS:
/*
* Don't go past the end of the CMOS.
*/
if (iop->io_seek >= CMOS_LEN)
break;
/*
* Read the requested data out of the CMOS.
*/
for (seek = iop->io_seek; seek < CMOS_LEN; seek++) {
if(ioputc(read_cmos(seek), iop) == -1)
break;
}
break;
case DEV_BOOTGIFT:
/*
* Reads all from the data structure boot_gift.
*/
if (iop->io_seek < BG_LEN) {
bytesRead = iop->io_ioc;
/*
* Copy no more than to the end of boot_gift.
*/
if (iop->io_seek + bytesRead > BG_LEN) {
bytesRead = BG_LEN - (iop->io_seek);
}
iowrite(iop,
(char *)(&boot_gift) + iop->io_seek,
bytesRead);
}
break;
case DEV_PS:
/* Lock the process table. It allows to have an atomic ps. */
lock(pnxgate);
/* Main driver loop. Go through all processes. Fill struct PS
* and send put to user buffer.
*/
for (pp1 = &procq; (pp1=pp1->p_nforw) != &procq; ) {
register int i; /* loop index */
register unsigned uLen, /* Process size */
uLenR; /* Real process size */
int work; /* virtual click number */
/* Check if driver can send next proc data */
if ( iop->io_ioc < sizeof(stMonitor))
break;
/* Calculate the size of process. */
uLen = uLenR = 0;
for (i = 0; i < NUSEG + 1; i++) {
if ((sp=pp1->p_segp[i]) == NULL)
continue;
uLenR += sp->s_size;
if (i == SIUSERP || i == SIAUXIL)
continue;
uLen += sp->s_size;
}
/* Find u area for process pp1 */
sp = pp1->p_segp[SIUSERP];
ndpUseg = MAPIO(sp->s_vmem, U_OFFSET);
work = workAlloc();
ptable1_v[work] =
sysmem.u.pbase[btocrd(ndpUseg)] | SEG_RW;
mmuupd();
uprc = (UPROC *) (ctob(work) + U_OFFSET);
kkcopy(uprc->u_comm, psData.u_comm, ARGSZ);
kkcopy(uprc->u_sleep, psData.u_sleep, U_SLEEP_LEN);
workFree(work);
/* fill up stMonitor */
psData.p_pid = pp1->p_pid;
psData.p_ppid = pp1->p_ppid;
psData.p_uid = pp1->p_uid;
psData.p_ruid = pp1->p_ruid;
psData.p_rgid = pp1->p_rgid;
psData.p_state = pp1->p_state;
psData.p_flags = pp1->p_flags;
psData.rrun = (char *) pp1 != pp1->p_event;
psData.p_event = pp1->p_event;
psData.p_ttdev = pp1->p_ttdev;
psData.p_nice = pp1->p_nice;
psData.size = (short) (uLen>>10);
psData.rsize = (short) (uLenR>>10);
psData.p_schedPri = pp1->p_schedPri;
psData.p_utime = pp1->p_utime;
psData.p_stime = pp1->p_stime;
kkcopy(psBuf, psData.pr_argv, ARGSZ);
/* send data to user */
iowrite(iop, (char *) &psData, sizeof(stMonitor));
}
unlock(pnxgate);
break;
case DEV_KMEMHI:
iowrite(iop, iop->io_seek - KMEMHI_BASE, iop->io_ioc);
if (u.u_error == EFAULT)
u.u_error = 0;
break;
default:
SET_U_ERROR(ENXIO, "nlread(): illegal minor device for null");
}
return;
}
/*
* Null/memory write routine.
*/
void
nlwrite(dev, iop)
dev_t dev;
register IO *iop;
{
register unsigned bytesWrit;
unsigned write_cmos();
unsigned seek;
int ch;
switch (minor(dev)) {
case DEV_NULL:
/*
* Tell caller all bytes were written.
*/
iop->io_ioc = 0;
break;
case DEV_MEM:
while(iop->io_ioc) {
int src = iop->io.pbase;
int dest = iop->io_seek;
int numBytes = PXCOPY_LIM;
if (numBytes > iop->io_ioc)
numBytes = iop->io_ioc;
bytesWrit = xpcopy(src, dest, numBytes, SEG_386_UD);
src += bytesWrit;
dest += bytesWrit;
iop->io_ioc -= bytesWrit;
if (u.u_error == EFAULT) {
u.u_error = 0;
break;
}
}
break;
case DEV_KMEM:
ioread(iop, iop->io_seek, iop->io_ioc);
break;
case DEV_CLOCK:
/*
* Don't go past the end of the CLOCK.
*/
if (iop->io_seek >= CLOCK_LEN)
break;
/*
* Lock the clock before any writing.
*/
if (lock_clock() == 0) {
SET_U_ERROR(EIO, "RT clock will not settle.");
break;
}
/*
* Write the requested data into the CMOS.
*/
for (seek = iop->io_seek; seek < CLOCK_LEN; seek++) {
if((ch = iogetc(iop)) == -1)
break;
write_cmos(seek, ch);
}
/*
* Now that we are done writing the CMOS, let
* the clock loose.
*/
unlock_clock();
break;
case DEV_CMOS:
/*
* Don't go past the end of the CMOS.
*/
if (iop->io_seek >= CMOS_LEN)
break;
/*
* Write the requested data into the CMOS.
*/
for (seek = iop->io_seek; seek < CMOS_LEN; seek++) {
if((ch = iogetc(iop)) == -1)
break;
write_cmos(seek, ch);
}
break;
case DEV_BOOTGIFT:
/*
* /dev/bootgift is not writable.
*/
break;
case DEV_PS:
/* We should not be able to open /dev/ps to write.
* Just paranoya.
*/
break;
case DEV_KMEMHI:
ioread(iop, iop->io_seek - KMEMHI_BASE, iop->io_ioc);
break;
default:
SET_U_ERROR(ENXIO,
"nlwrite(): illegal minor device for null");
}
return;
}
#ifdef NULL_IOCTL /* Includes all of nlioctl(). */
/*
* Do an ioctl call for /dev/null.
*/
int
nlioctl(dev, cmd, vec)
dev_t dev;
int cmd;
char * vec;
{
/* Only /dev/kmem has an ioctl. */
switch (minor(dev)) {
case DEV_KMEM:
switch (cmd) {
#ifdef DANGEROUS
case NLCALL: /* Call a function. */
return docall(vec);
#endif /* DANGEROUS */
default:
SET_U_ERROR(EINVAL,
"nioctl(): illegal command for kmem");
return(-1);
}
default:
SET_U_ERROR(EINVAL, "illegal minor device for null ioctl");
return (-1);
} /* switch on minor device */
} /* nlioctl() */
#endif /* NULL_IOCTL */
#ifdef DANGEROUS /* Includes all of docall(). */
/*
* MASSIVE SECURITY HOLE! This should NOT be included in a distribution
* system. Among other problems, it becomes possible to do "setuid(0)".
*
* Call a function with arguments.
*
* Takes an array of unsigned ints. The first element is the length of
* the whole array, the second element is a pointer to the function to
* call, all other elements are arguments. At most 5 arguments may be
* passed.
*
* Returns the return value of the called fuction in uvec[0].
*/
int
docall(uvec)
unsigned uvec[];
{
int (* func)();
unsigned kvec[7];
int retval;
printf("NLCALL security hole.\n");
/* Fetch the first element of vec. */
ukcopy(uvec, kvec, sizeof(unsigned));
if ((kvec[0] < 2) || (kvec[0] > 7)) {
/* Invalid number of elements in uvec. */
SET_U_ERROR(EINVAL, "Invalid number of elements in uvec");
return(-1);
}
/* Fetch the whole vector. */
ukcopy(uvec, kvec, kvec[0] * sizeof(unsigned));
/* Extract the function. */
func = (int (*)()) kvec[1];
/* Call the function with all arguments. */
retval = (*func)(kvec[2], kvec[3], kvec[4], kvec[5], kvec[6]);
kucopy(&retval, uvec, sizeof(unsigned));
} /* docall() */
#endif /* DANGEROUS */
/*
* int lock_clock() -- Stop the update cycle on the CMOS RT clock and
* wait for it to settle. Returns 0 if the clock would not settle
* in time.
*/
int
lock_clock()
{
register int i;
/*
* Wait for the clock to settle. If it does not settle in
* a reasonable amount of time, give up.
*/
i = 65536; /* Loop for a longish time. */
while (--i > 0) {
if (0 == (UIP & read_cmos(SRA))) {
break; /* Break if there is no update in progress. */
}
}
if (0 == i) {
/* The clock would not settle. */
return 0;
}
/*
* There is a tiny race here--an interrupt could conceivably
* come here, thus allowing enough delay for another update to
* begin. But if we take interrupts that take a full second
* to process, other things are going to break horribly.
*/
/*
* Lock out updates.
* We set the No Updates bit in Clock Status Register B.
*/
write_cmos(SRB, (NO_UPD | read_cmos(SRB)));
return 1;
} /* lock_clock() */
/*
* void unlock_clock() -- Restart the update cycle on the CMOS RT clock.
*/
void
unlock_clock()
{
/*
* We clear the No Updates bit in Clock Status Register B.
*/
write_cmos(SRB, ((~ NO_UPD) & read_cmos(SRB)));
} /* unlock_clock() */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.