#include "dat.h"
#include "fns.h"
#include "../port/error.h"
-#include "pool.h"
#include <authsrv.h>
void (*consdebug)(void) = nil;
void (*screenputs)(char*, int) = nil;
-Queue* kbdq; /* unprocessed console input */
-Queue* lineq; /* processed console input */
Queue* serialoq; /* serial console output */
Queue* kprintoq; /* console output, for /dev/kprint */
ulong kprintinuse; /* test and set whether /dev/kprint is open */
int panicking;
-static struct
-{
- QLock;
-
- int raw; /* true if we shouldn't process input */
- Ref ctl; /* number of opens to the control file */
- int x; /* index into line */
- char line[1024]; /* current input line */
-
- int count;
- int ctlpoff;
-
- /* a place to save up characters at interrupt time before dumping them in the queue */
- Lock lockputc;
- char istage[1024];
- char *iw;
- char *ir;
- char *ie;
-} kbd = {
- .iw = kbd.istage,
- .ir = kbd.istage,
- .ie = kbd.istage + sizeof(kbd.istage),
-};
-
char *sysname;
vlong fasthz;
-static void seedrand(void);
static int readtime(ulong, char*, int);
static int readbintime(char*, int);
static int writetime(char*, int);
enum
{
- CMhalt,
CMreboot,
CMpanic,
+ CMrdb,
};
Cmdtab rebootmsg[] =
{
- CMhalt, "halt", 1,
CMreboot, "reboot", 0,
CMpanic, "panic", 0,
+ CMrdb, "rdb", 0,
};
void
printinit(void)
{
- lineq = qopen(2*1024, 0, nil, nil);
- if(lineq == nil)
- panic("printinit");
- qnoblock(lineq, 1);
}
int
break;
}
-/*
- * Log console output so it can be retrieved via /dev/kmesg.
- * This is good for catching boot-time messages after the fact.
- */
-struct {
- Lock lk;
-// char buf[16384]; /* normal */
- char buf[256*1024]; /* for acpi debugging */
- uint n;
-} kmesg;
-
static void
kmesgputs(char *str, int n)
{
{
int m;
char *t;
-
- if(!islo())
- usewrite = 0;
+ int (*wq)(Queue*, void*, int);
/*
* how many different output devices do we need?
* if there's a serial line being used as a console,
* put the message there.
*/
- if(kprintoq != nil && !qisclosed(kprintoq)){
- if(usewrite)
- qwrite(kprintoq, str, n);
- else
- qiwrite(kprintoq, str, n);
- }else if(screenputs != nil)
+ wq = usewrite && islo() ? qwrite : qiwrite;
+ if(kprintoq != nil && !qisclosed(kprintoq))
+ (*wq)(kprintoq, str, n);
+ else if(screenputs != nil)
screenputs(str, n);
if(serialoq == nil){
while(n > 0) {
t = memchr(str, '\n', n);
- if(t && !kbd.raw) {
+ if(t != nil) {
m = t-str;
- if(usewrite){
- qwrite(serialoq, str, m);
- qwrite(serialoq, "\r\n", 2);
- } else {
- qiwrite(serialoq, str, m);
- qiwrite(serialoq, "\r\n", 2);
- }
+ (*wq)(serialoq, str, m);
+ (*wq)(serialoq, "\r\n", 2);
n -= m+1;
str = t+1;
} else {
- if(usewrite)
- qwrite(serialoq, str, n);
- else
- qiwrite(serialoq, str, n);
+ (*wq)(serialoq, str, n);
break;
}
}
putstrn0(str, n, 0);
}
-int noprint;
-
int
print(char *fmt, ...)
{
va_list arg;
char buf[PRINTSIZE];
- if(noprint)
- return -1;
-
va_start(arg, fmt);
n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
va_end(arg);
void
panic(char *fmt, ...)
{
- int n, s;
+ int s;
va_list arg;
char buf[PRINTSIZE];
s = splhi();
strcpy(buf, "panic: ");
va_start(arg, fmt);
- n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
+ vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
va_end(arg);
iprint("%s\n", buf);
if(consdebug)
(*consdebug)();
splx(s);
prflush();
- buf[n] = '\n';
- putstrn(buf, n+1);
dumpstack();
- exit(1);
+ /* reboot cpu servers and headless machines when not debugging */
+ if(getconf("*debug") == nil)
+ if(cpuserver || !conf.monitor)
+ exit(1);
+
+ /* otherwise, just hang */
+ while(islo()) idlehands();
+ for(;;);
}
/* libmp at least contains a few calls to sysfatal; simulate with panic */
return 0;
c = up->fgrp->fd[2];
- if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
+ if(c==nil || (c->flag&CMSG)!=0 || (c->mode!=OWRITE && c->mode!=ORDWR))
return 0;
n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
va_start(arg, fmt);
return n;
}
-static void
-echoscreen(char *buf, int n)
-{
- char *e, *p;
- char ebuf[128];
- int x;
-
- p = ebuf;
- e = ebuf + sizeof(ebuf) - 4;
- while(n-- > 0){
- if(p >= e){
- screenputs(ebuf, p - ebuf);
- p = ebuf;
- }
- x = *buf++;
- if(x == 0x15){
- *p++ = '^';
- *p++ = 'U';
- *p++ = '\n';
- } else
- *p++ = x;
- }
- if(p != ebuf)
- screenputs(ebuf, p - ebuf);
-}
-
-static void
-echoserialoq(char *buf, int n)
-{
- char *e, *p;
- char ebuf[128];
- int x;
-
- p = ebuf;
- e = ebuf + sizeof(ebuf) - 4;
- while(n-- > 0){
- if(p >= e){
- qiwrite(serialoq, ebuf, p - ebuf);
- p = ebuf;
- }
- x = *buf++;
- if(x == '\n'){
- *p++ = '\r';
- *p++ = '\n';
- } else if(x == 0x15){
- *p++ = '^';
- *p++ = 'U';
- *p++ = '\n';
- } else
- *p++ = x;
- }
- if(p != ebuf)
- qiwrite(serialoq, ebuf, p - ebuf);
-}
-
-static void
-echo(char *buf, int n)
-{
- static int ctrlt, pid;
- int x;
- char *e, *p;
-
- if(n == 0)
- return;
-
- e = buf+n;
- for(p = buf; p < e; p++){
- switch(*p){
- case 0x10: /* ^P */
- if(cpuserver && !kbd.ctlpoff){
- active.exiting = 1;
- return;
- }
- break;
- case 0x14: /* ^T */
- ctrlt++;
- if(ctrlt > 2)
- ctrlt = 2;
- continue;
- }
-
- if(ctrlt != 2)
- continue;
-
- /* ^T escapes */
- ctrlt = 0;
- switch(*p){
- case 'S':
- x = splhi();
- dumpstack();
- procdump();
- splx(x);
- return;
- case 's':
- dumpstack();
- return;
- case 'x':
- xsummary();
- ixsummary();
- mallocsummary();
- // memorysummary();
- pagersummary();
- return;
- case 'd':
- if(consdebug == nil)
- consdebug = rdb;
- else
- consdebug = nil;
- print("consdebug now %#p\n", consdebug);
- return;
- case 'D':
- if(consdebug == nil)
- consdebug = rdb;
- consdebug();
- return;
- case 'p':
- x = spllo();
- procdump();
- splx(x);
- return;
- case 'q':
- scheddump();
- return;
- case 'k':
- killbig("^t ^t k");
- return;
- case 'r':
- exit(0);
- return;
- }
- }
-
- qproduce(kbdq, buf, n);
- if(kbd.raw)
- return;
- kmesgputs(buf, n);
- if(screenputs != nil)
- echoscreen(buf, n);
- if(serialoq)
- echoserialoq(buf, n);
-}
-
-/*
- * Called by a uart interrupt for console input.
- *
- * turn '\r' into '\n' before putting it into the queue.
- */
-int
-kbdcr2nl(Queue*, int ch)
-{
- char *next;
-
- ilock(&kbd.lockputc); /* just a mutex */
- if(ch == '\r' && !kbd.raw)
- ch = '\n';
- next = kbd.iw+1;
- if(next >= kbd.ie)
- next = kbd.istage;
- if(next != kbd.ir){
- *kbd.iw = ch;
- kbd.iw = next;
- }
- iunlock(&kbd.lockputc);
- return 0;
-}
-
-/*
- * Put character, possibly a rune, into read queue at interrupt time.
- * Called at interrupt time to process a character.
- */
-int
-kbdputc(Queue*, int ch)
-{
- int i, n;
- char buf[3];
- Rune r;
- char *next;
-
- if(kbd.ir == nil)
- return 0; /* in case we're not inited yet */
-
- ilock(&kbd.lockputc); /* just a mutex */
- r = ch;
- n = runetochar(buf, &r);
- for(i = 0; i < n; i++){
- next = kbd.iw+1;
- if(next >= kbd.ie)
- next = kbd.istage;
- if(next == kbd.ir)
- break;
- *kbd.iw = buf[i];
- kbd.iw = next;
- }
- iunlock(&kbd.lockputc);
- return 0;
-}
-
-/*
- * we save up input characters till clock time to reduce
- * per character interrupt overhead.
- */
-static void
-kbdputcclock(void)
-{
- char *iw;
-
- /* this amortizes cost of qproduce */
- if(kbd.iw != kbd.ir){
- iw = kbd.iw;
- if(iw < kbd.ir){
- echo(kbd.ir, kbd.ie-kbd.ir);
- kbd.ir = kbd.istage;
- }
- if(kbd.ir != iw){
- echo(kbd.ir, iw-kbd.ir);
- kbd.ir = iw;
- }
- }
-}
-
enum{
Qdir,
Qbintime,
Qppid,
Qrandom,
Qreboot,
- Qswap,
Qsysname,
Qsysstat,
Qtime,
Quser,
Qzero,
+ Qmordor,
Qconfig,
};
"ppid", {Qppid}, NUMSIZE, 0444,
"random", {Qrandom}, 0, 0444,
"reboot", {Qreboot}, 0, 0664,
- "swap", {Qswap}, 0, 0664,
"sysname", {Qsysname}, 0, 0664,
"sysstat", {Qsysstat}, 0, 0666,
"time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
"user", {Quser}, 0, 0666,
"zero", {Qzero}, 0, 0444,
"config", {Qconfig}, 0, 0444,
+ "mordor", {Qmordor}, 0, 0666,
};
int
{
todinit();
randominit();
- /*
- * at 115200 baud, the 1024 char buffer takes 56 ms to process,
- * processing it every 22 ms should be fine
- */
- addclock0link(kbdputcclock, 22);
}
static Chan*
c->aux = nil;
c = devopen(c, omode, consdir, nelem(consdir), devgen);
switch((ulong)c->qid.path){
- case Qconsctl:
- incref(&kbd.ctl);
- break;
-
case Qkprint:
if(tas(&kprintinuse) != 0){
c->flag &= ~COPEN;
consclose(Chan *c)
{
switch((ulong)c->qid.path){
- /* last close of control file turns off raw */
- case Qconsctl:
- if(c->flag&COPEN){
- if(decref(&kbd.ctl) == 0)
- kbd.raw = 0;
- }
- break;
-
/* close of kprint allows other opens */
case Qkprint:
if(c->flag & COPEN){
{
ulong l;
Mach *mp;
- char *b, *bp, ch;
- char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
- int i, k, id, send;
+ char *b, *bp;
+ char tmp[256];
+ int i, k, id;
vlong offset = off;
extern char configfile[];
return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
case Qcons:
- qlock(&kbd);
- if(waserror()) {
- qunlock(&kbd);
- nexterror();
- }
- while(!qcanread(lineq)){
- if(qread(kbdq, &ch, 1) == 0)
- continue;
- send = 0;
- if(ch == 0){
- /* flush output on rawoff -> rawon */
- if(kbd.x > 0)
- send = !qcanread(kbdq);
- }else if(kbd.raw){
- kbd.line[kbd.x++] = ch;
- send = !qcanread(kbdq);
- }else{
- switch(ch){
- case '\b':
- if(kbd.x > 0)
- kbd.x--;
- break;
- case 0x15: /* ^U */
- kbd.x = 0;
- break;
- case '\n':
- case 0x04: /* ^D */
- send = 1;
- default:
- if(ch != 0x04)
- kbd.line[kbd.x++] = ch;
- break;
- }
- }
- if(send || kbd.x == sizeof kbd.line){
- qwrite(lineq, kbd.line, kbd.x);
- kbd.x = 0;
- }
- }
- n = qread(lineq, buf, n);
- qunlock(&kbd);
- poperror();
- return n;
+ error(Egreg);
case Qcputime:
k = offset;
l = up->time[i];
if(i == TReal)
l = MACHP(0)->ticks - l;
- l = TK2MS(l);
- readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
+ readnum(0, tmp+NUMSIZE*i, NUMSIZE, tk2ms(l), NUMSIZE);
}
memmove(buf, tmp+k, n);
return n;
case Qsysstat:
b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */
bp = b;
- for(id = 0; id < 32; id++) {
- if(active.machs & (1<<id)) {
+ for(id = 0; id < MAXMACH; id++) {
+ if(active.machs[id]) {
mp = MACHP(id);
readnum(0, bp, NUMSIZE, id, NUMSIZE);
bp += 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)/mp->perf.period,
- NUMSIZE);
+ (mp->perf.avg_inidle*100)/l, NUMSIZE);
bp += NUMSIZE;
readnum(0, bp, NUMSIZE,
- (mp->perf.avg_inintr*100)/mp->perf.period,
- NUMSIZE);
+ (mp->perf.avg_inintr*100)/l, NUMSIZE);
bp += NUMSIZE;
*bp++ = '\n';
}
poperror();
return n;
- case Qswap:
- snprint(tmp, sizeof tmp,
- "%lud memory\n"
- "%d pagesize\n"
- "%lud kernel\n"
- "%lud/%lud user\n"
- "%lud/%lud swap\n"
- "%lud/%lud kernel malloc\n"
- "%lud/%lud kernel draw\n",
- conf.npage*BY2PG,
- BY2PG,
- conf.npage-conf.upages,
- palloc.user-palloc.freecount, palloc.user,
- conf.nswap-swapalloc.free, conf.nswap,
- mainmem->cursize, mainmem->maxsize,
- imagmem->cursize, imagmem->maxsize);
-
- return readstr((ulong)offset, buf, n, tmp);
-
case Qsysname:
if(sysname == nil)
return 0;
return randomread(buf, n);
case Qdrivers:
- b = malloc(READSTR);
- if(b == nil)
- error(Enomem);
+ b = smalloc(READSTR);
k = 0;
for(i = 0; devtab[i] != nil; i++)
k += snprint(b+k, READSTR-k, "#%C %s\n",
nexterror();
}
n = readstr((ulong)offset, buf, n, b);
- free(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");
static long
conswrite(Chan *c, void *va, long n, vlong off)
{
- char buf[256], ch;
+ char buf[256];
long l, bp;
char *a;
Mach *mp;
- int id, fd;
- Chan *swc;
+ int id;
ulong offset;
Cmdbuf *cb;
Cmdtab *ct;
break;
case Qconsctl:
- if(n >= sizeof(buf))
- n = sizeof(buf)-1;
- strncpy(buf, a, n);
- buf[n] = 0;
- for(a = buf; a;){
- if(strncmp(a, "rawon", 5) == 0){
- kbd.raw = 1;
- /* clumsy hack - wake up reader */
- ch = 0;
- qwrite(kbdq, &ch, 1);
- } else if(strncmp(a, "rawoff", 6) == 0){
- kbd.raw = 0;
- } else if(strncmp(a, "ctlpon", 6) == 0){
- kbd.ctlpoff = 0;
- } else if(strncmp(a, "ctlpoff", 7) == 0){
- kbd.ctlpoff = 1;
- }
- if(a = strchr(a, ' '))
- a++;
- }
- break;
+ error(Egreg);
case Qtime:
if(!iseve())
}
ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
switch(ct->index) {
- case CMhalt:
- reboot(nil, 0, 0);
- break;
case CMreboot:
rebootcmd(cb->nf-1, cb->f+1);
break;
case CMpanic:
*(ulong*)0=0;
panic("/dev/reboot");
+ case CMrdb:
+ if(consdebug == nil)
+ consdebug = rdb;
+ consdebug();
+ break;
}
poperror();
free(cb);
break;
case Qsysstat:
- for(id = 0; id < 32; id++) {
- if(active.machs & (1<<id)) {
+ for(id = 0; id < MAXMACH; id++) {
+ if(active.machs[id]) {
mp = MACHP(id);
mp->cs = 0;
mp->intr = 0;
}
break;
- case Qswap:
- if(n >= sizeof buf)
- error(Egreg);
- memmove(buf, va, n); /* so we can NUL-terminate */
- buf[n] = 0;
- /* start a pager if not already started */
- if(strncmp(buf, "start", 5) == 0){
- kickpager();
- break;
- }
- if(!iseve())
- error(Eperm);
- if(buf[0]<'0' || '9'<buf[0])
- error(Ebadarg);
- fd = strtoul(buf, 0, 0);
- swc = fdtochan(fd, -1, 1, 1);
- setswapchan(swc);
- break;
-
case Qsysname:
if(offset != 0)
error(Ebadarg);
buf[n-1] = 0;
kstrdup(&sysname, buf);
break;
+
+ case Qmordor:
+ error("one does not simply write into mordor");
+ return 0;
default:
print("conswrite: %#llux\n", c->qid.path);
devwstat,
};
-static ulong randn;
-
-static void
-seedrand(void)
-{
- if(!waserror()){
- randomread((void*)&randn, sizeof(randn));
- poperror();
- }
-}
-
-int
-nrand(int n)
-{
- if(randn == 0)
- seedrand();
- randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
- return (randn>>16) % n;
-}
-
-int
-rand(void)
-{
- nrand(1);
- return randn;
-}
-
static uvlong uvorder = 0x0001020304050607ULL;
static uchar*
vlong delta;
long period;
- n--;
+ if(--n <= 0)
+ error(Ebadtimectl);
p = (uchar*)buf + 1;
switch(*buf){
case 'n':
todsetfreq(fasthz);
break;
}
- return n;
+ return n+1;
+}
+
+void
+cpushutdown(void)
+{
+ int ms, once;
+
+ once = active.machs[m->machno];
+ active.machs[m->machno] = 0;
+ active.exiting = 1;
+
+ if(once)
+ iprint("cpu%d: exiting\n", m->machno);
+
+ /* wait for any other processors to shutdown */
+ spllo();
+ for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
+ delay(TK2MS(2));
+ if(memchr(active.machs, 1, MAXMACH) == nil && consactive() == 0)
+ break;
+ }
}