Queue* serialoq; /* serial console output */
Queue* kprintoq; /* console output, for /dev/kprint */
ulong kprintinuse; /* test and set whether /dev/kprint is open */
int iprintscreenputs = 1;
int panicking;
char *sysname;
vlong fasthz;
static int readtime(ulong, char*, int);
static int readbintime(char*, int);
static int writetime(char*, int);
static int writebintime(char*, int);
now = m->ticks;
while(consactive())
if(m->ticks - now >= HZ)
break;
}
static void
kmesgputs(char *str, int n)
{
uint nn, d;
ilock(&kmesg.lk);
/* take the tail of huge writes */
if(n > sizeof kmesg.buf){
d = n - sizeof kmesg.buf;
str += d;
n -= d;
}
/* slide the buffer down to make room */
nn = kmesg.n;
if(nn + n >= sizeof kmesg.buf){
d = nn + n - sizeof kmesg.buf;
if(d)
memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
nn -= d;
}
/* copy the data in */
memmove(kmesg.buf+nn, str, n);
nn += n;
kmesg.n = nn;
iunlock(&kmesg.lk);
}
/*
* Print a string on the console. Convert \n to \r\n for serial
* line consoles. Locking of the queues is left up to the screen
* or uart code. Multi-line messages to serial consoles may get
* interspersed with other messages.
*/
static void
putstrn0(char *str, int n, int usewrite)
{
int m;
char *t;
int (*wq)(Queue*, void*, int);
/*
* how many different output devices do we need?
*/
kmesgputs(str, n);
/*
* if someone is reading /dev/kprint,
* put the message there.
* if not and there's an attached bit mapped display,
* put the message there.
*
* if there's a serial line being used as a console,
* put the message there.
*/
wq = usewrite && islo() ? qwrite : qiwrite;
if(kprintoq != nil && !qisclosed(kprintoq))
(*wq)(kprintoq, str, n);
else if(screenputs != nil)
screenputs(str, n);
/*
* Want to interlock iprints to avoid interlaced output on
* multiprocessor, but don't want to deadlock if one processor
* dies during print and another has something important to say.
* Make a good faith effort.
*/
static Lock iprintlock;
static int
iprintcanlock(Lock *l)
{
int i;
static void
consclose(Chan *c)
{
switch((ulong)c->qid.path){
/* close of kprint allows other opens */
case Qkprint:
if(c->flag & COPEN){
kprintinuse = 0;
qhangup(kprintoq, nil);
}
break;
}
}
static long
consread(Chan *c, void *buf, long n, vlong off)
{
ulong l;
Mach *mp;
char *b, *bp;
char tmp[256];
int i, k, id;
vlong offset = off;
extern char configfile[];
if(n <= 0)
return n;
switch((ulong)c->qid.path){
case Qdir:
return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
case Qcons:
error(Egreg);
case Qcputime:
k = offset;
if(k >= 6*NUMSIZE)
return 0;
if(k+n > 6*NUMSIZE)
n = 6*NUMSIZE - k;
/* easiest to format in a separate buffer and copy out */
for(i=0; i<6 && NUMSIZE*i<k+n; i++){
l = up->time[i];
if(i == TReal)
l = MACHP(0)->ticks - l;
readnum(0, tmp+NUMSIZE*i, NUMSIZE, tk2ms(l), NUMSIZE);
}
memmove(buf, tmp+k, n);
return n;
case Qkmesg:
/*
* This is unlocked to avoid tying up a process
* that's writing to the buffer. kmesg.n never
* gets smaller, so worst case the reader will
* see a slurred buffer.
*/
if(off >= kmesg.n)
n = 0;
else{
if(off+n > kmesg.n)
n = kmesg.n - off;
memmove(buf, kmesg.buf+off, n);
}
return n;
case Qkprint:
return qread(kprintoq, buf, n);
case Qpgrpid:
return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
case Qpid:
return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
case Qppid:
return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
case Qtime:
return readtime((ulong)offset, buf, n);
case Qbintime:
return readbintime(buf, n);
case Qhostowner:
return readstr((ulong)offset, buf, n, eve);
case Qhostdomain:
return readstr((ulong)offset, buf, n, hostdomain);
case Quser:
return readstr((ulong)offset, buf, n, up->user);
case Qnull:
return 0;
case Qconfig:
return readstr((ulong)offset, buf, n, configfile);
case Qsysstat:
b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */
bp = b;
for(id = 0; id < MAXMACH; id++) {
if(active.machs[id]) {
mp = MACHP(id);
readnum(0, bp, NUMSIZE, id, NUMSIZE);
bp += NUMSIZE;
readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
bp += NUMSIZE;
readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
bp += NUMSIZE;
readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
bp += NUMSIZE;
readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
bp += NUMSIZE;
readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
bp += NUMSIZE;
readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
bp += NUMSIZE;
readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
bp += NUMSIZE;
l = mp->perf.period;
if(l == 0)
l = 1;
readnum(0, bp, NUMSIZE,
(mp->perf.avg_inidle*100)/l, NUMSIZE);
bp += NUMSIZE;
readnum(0, bp, NUMSIZE,
(mp->perf.avg_inintr*100)/l, NUMSIZE);
bp += NUMSIZE;
*bp++ = '\n';
}
}
if(waserror()){
free(b);
nexterror();
}
n = readstr((ulong)offset, buf, n, b);
free(b);
poperror();
return n;
case Qsysname:
if(sysname == nil)
return 0;
return readstr((ulong)offset, buf, n, sysname);
case Qrandom:
return randomread(buf, n);
case Qdrivers:
b = smalloc(READSTR);
k = 0;
for(i = 0; devtab[i] != nil; i++)
k += snprint(b+k, READSTR-k, "#%C %s\n",
devtab[i]->dc, devtab[i]->name);
if(waserror()){
free(b);
nexterror();
}
n = readstr((ulong)offset, buf, n, b);
poperror();
free(b);
return n;
case Qzero:
memset(buf, 0, n);
return n;
case Qmordor:
error("one does not simply read from mordor");
return 0;
case Qosversion:
snprint(tmp, sizeof tmp, "2000");
n = readstr((ulong)offset, buf, n, tmp);
return n;
static long
conswrite(Chan *c, void *va, long n, vlong off)
{
char buf[256];
long l, bp;
char *a;
Mach *mp;
int id;
ulong offset;
Cmdbuf *cb;
Cmdtab *ct;
a = va;
offset = off;
switch((ulong)c->qid.path){
case Qcons:
/*
* Can't page fault in putstrn, so copy the data locally.
*/
l = n;
while(l > 0){
bp = l;
if(bp > sizeof buf)
bp = sizeof buf;
memmove(buf, a, bp);
putstrn0(buf, bp, 1);
a += bp;
l -= bp;
}
break;
case Qconsctl:
error(Egreg);
case Qtime:
if(!iseve())
error(Eperm);
return writetime(a, n);
case Qbintime:
if(!iseve())
error(Eperm);
return writebintime(a, n);
case Qhostowner:
return hostownerwrite(a, n);
case Qhostdomain:
return hostdomainwrite(a, n);
case Quser:
return userwrite(a, n);
case Qnull:
break;
case Qconfig:
error(Eperm);
break;
case Qreboot:
if(!iseve())
error(Eperm);
cb = parsecmd(a, n);
t = (uchar*)to;
o = (uchar*)ℴ
for(i = 0; i < sizeof(long); i++)
t[o[i]] = f[i];
return f+sizeof(long);
}
static uchar*
long2le(uchar *t, long from)
{
uchar *f, *o;
int i;
f = (uchar*)&from;
o = (uchar*)ℴ
for(i = 0; i < sizeof(long); i++)
t[i] = f[o[i]];
return t+sizeof(long);
}
char *Ebadtimectl = "bad time control";
/*
* like the old #c/time but with added info. Return
*
* secs nanosecs fastticks fasthz
*/
static int
readtime(ulong off, char *buf, int n)
{
vlong nsec, ticks;
long sec;
char str[7*NUMSIZE];
/*
* read binary time info. all numbers are little endian.
* ticks and nsec are syncronized.
*/
static int
readbintime(char *buf, int n)
{
int i;
vlong nsec, ticks;
uchar *b = (uchar*)buf;
i = 0;
if(fasthz == 0LL)
fastticks((uvlong*)&fasthz);
nsec = todget(&ticks);
if(n >= 3*sizeof(uvlong)){
vlong2le(b+2*sizeof(uvlong), fasthz);
i += sizeof(uvlong);
}
if(n >= 2*sizeof(uvlong)){
vlong2le(b+sizeof(uvlong), ticks);
i += sizeof(uvlong);
}
if(n >= 8){
vlong2le(b, nsec);
i += sizeof(vlong);
}
return i;
}
/*
* set any of the following
* - time in nsec
* - nsec trim applied over some seconds
* - clock frequency
*/
static int
writebintime(char *buf, int n)
{
uchar *p;
vlong delta;
long period;