2 #include "../port/lib.h"
6 #include "../port/error.h"
11 void (*consdebug)(void) = nil;
12 void (*screenputs)(char*, int) = nil;
14 Queue* serialoq; /* serial console output */
15 Queue* kprintoq; /* console output, for /dev/kprint */
16 ulong kprintinuse; /* test and set whether /dev/kprint is open */
17 int iprintscreenputs = 1;
24 static void seedrand(void);
25 static int readtime(ulong, char*, int);
26 static int readbintime(char*, int);
27 static int writetime(char*, int);
28 static int writebintime(char*, int);
41 CMreboot, "reboot", 0,
55 return qlen(serialoq) > 0;
66 if(m->ticks - now >= HZ)
71 * Log console output so it can be retrieved via /dev/kmesg.
72 * This is good for catching boot-time messages after the fact.
81 kmesgputs(char *str, int n)
86 /* take the tail of huge writes */
87 if(n > sizeof kmesg.buf){
88 d = n - sizeof kmesg.buf;
93 /* slide the buffer down to make room */
95 if(nn + n >= sizeof kmesg.buf){
96 d = nn + n - sizeof kmesg.buf;
98 memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
102 /* copy the data in */
103 memmove(kmesg.buf+nn, str, n);
110 * Print a string on the console. Convert \n to \r\n for serial
111 * line consoles. Locking of the queues is left up to the screen
112 * or uart code. Multi-line messages to serial consoles may get
113 * interspersed with other messages.
116 putstrn0(char *str, int n, int usewrite)
125 * how many different output devices do we need?
130 * if someone is reading /dev/kprint,
131 * put the message there.
132 * if not and there's an attached bit mapped display,
133 * put the message there.
135 * if there's a serial line being used as a console,
136 * put the message there.
138 if(kprintoq != nil && !qisclosed(kprintoq)){
140 qwrite(kprintoq, str, n);
142 qiwrite(kprintoq, str, n);
143 }else if(screenputs != nil)
152 t = memchr(str, '\n', n);
156 qwrite(serialoq, str, m);
157 qwrite(serialoq, "\r\n", 2);
159 qiwrite(serialoq, str, m);
160 qiwrite(serialoq, "\r\n", 2);
166 qwrite(serialoq, str, n);
168 qiwrite(serialoq, str, n);
175 putstrn(char *str, int n)
181 print(char *fmt, ...)
188 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
196 * Want to interlock iprints to avoid interlaced output on
197 * multiprocessor, but don't want to deadlock if one processor
198 * dies during print and another has something important to say.
199 * Make a good faith effort.
201 static Lock iprintlock;
203 iprintcanlock(Lock *l)
207 for(i=0; i<1000; i++){
210 if(l->m == MACHP(m->machno))
218 iprint(char *fmt, ...)
226 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
228 locked = iprintcanlock(&iprintlock);
229 if(screenputs != nil && iprintscreenputs)
240 panic(char *fmt, ...)
246 kprintoq = nil; /* don't try to write to /dev/kprint */
253 strcpy(buf, "panic: ");
255 vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
264 /* reboot cpu servers and headless machines when not debugging */
265 if(getconf("*debug") == nil)
266 if(cpuserver || !conf.monitor)
269 /* otherwise, just hang */
270 while(islo()) idlehands();
274 /* libmp at least contains a few calls to sysfatal; simulate with panic */
276 sysfatal(char *fmt, ...)
282 vseprint(err, err + sizeof err, fmt, arg);
284 panic("sysfatal: %s", err);
290 panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
294 pprint(char *fmt, ...)
299 char buf[2*PRINTSIZE];
301 if(up == nil || up->fgrp == nil)
305 if(c==nil || (c->mode!=OWRITE && c->mode!=ORDWR))
307 n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
309 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
314 devtab[c->type]->write(c, buf, n, c->offset);
357 static Dirtab consdir[]={
358 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
359 "bintime", {Qbintime}, 24, 0664,
360 "cons", {Qcons}, 0, 0660,
361 "consctl", {Qconsctl}, 0, 0220,
362 "cputime", {Qcputime}, 6*NUMSIZE, 0444,
363 "drivers", {Qdrivers}, 0, 0444,
364 "hostdomain", {Qhostdomain}, DOMLEN, 0664,
365 "hostowner", {Qhostowner}, 0, 0664,
366 "kmesg", {Qkmesg}, 0, 0440,
367 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,
368 "null", {Qnull}, 0, 0666,
369 "osversion", {Qosversion}, 0, 0444,
370 "pgrpid", {Qpgrpid}, NUMSIZE, 0444,
371 "pid", {Qpid}, NUMSIZE, 0444,
372 "ppid", {Qppid}, NUMSIZE, 0444,
373 "random", {Qrandom}, 0, 0444,
374 "reboot", {Qreboot}, 0, 0664,
375 "swap", {Qswap}, 0, 0664,
376 "sysname", {Qsysname}, 0, 0664,
377 "sysstat", {Qsysstat}, 0, 0666,
378 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
379 "user", {Quser}, 0, 0666,
380 "zero", {Qzero}, 0, 0444,
381 "config", {Qconfig}, 0, 0444,
382 "mordor", {Qmordor}, 0, 0666,
386 readnum(ulong off, char *buf, ulong n, ulong val, int size)
390 snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
396 memmove(buf, tmp+off, n);
401 readstr(ulong off, char *buf, ulong n, char *str)
410 memmove(buf, str+off, n);
422 consattach(char *spec)
424 return devattach('c', spec);
428 conswalk(Chan *c, Chan *nc, char **name, int nname)
430 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
434 consstat(Chan *c, uchar *dp, int n)
436 return devstat(c, dp, n, consdir, nelem(consdir), devgen);
440 consopen(Chan *c, int omode)
443 c = devopen(c, omode, consdir, nelem(consdir), devgen);
444 switch((ulong)c->qid.path){
446 if(tas(&kprintinuse) != 0){
451 kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
456 qnoblock(kprintoq, 1);
459 c->iounit = qiomaxatomic;
468 switch((ulong)c->qid.path){
469 /* close of kprint allows other opens */
473 qhangup(kprintoq, nil);
480 consread(Chan *c, void *buf, long n, vlong off)
485 char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
488 extern char configfile[];
489 extern Image fscache;
490 extern Image swapimage;
495 switch((ulong)c->qid.path){
497 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
508 /* easiest to format in a separate buffer and copy out */
509 for(i=0; i<6 && NUMSIZE*i<k+n; i++){
512 l = MACHP(0)->ticks - l;
514 readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
516 memmove(buf, tmp+k, n);
521 * This is unlocked to avoid tying up a process
522 * that's writing to the buffer. kmesg.n never
523 * gets smaller, so worst case the reader will
524 * see a slurred buffer.
531 memmove(buf, kmesg.buf+off, n);
536 return qread(kprintoq, buf, n);
539 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
542 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
545 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
548 return readtime((ulong)offset, buf, n);
551 return readbintime(buf, n);
554 return readstr((ulong)offset, buf, n, eve);
557 return readstr((ulong)offset, buf, n, hostdomain);
560 return readstr((ulong)offset, buf, n, up->user);
566 return readstr((ulong)offset, buf, n, configfile);
569 b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */
571 for(id = 0; id < MAXMACH; id++) {
572 if(active.machs[id]) {
574 readnum(0, bp, NUMSIZE, id, NUMSIZE);
576 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
578 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
580 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
582 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
584 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
586 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
588 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
593 readnum(0, bp, NUMSIZE,
594 (mp->perf.avg_inidle*100)/l, NUMSIZE);
596 readnum(0, bp, NUMSIZE,
597 (mp->perf.avg_inintr*100)/l, NUMSIZE);
606 n = readstr((ulong)offset, buf, n, b);
612 snprint(tmp, sizeof tmp,
618 "%llud/%llud/%llud kernel malloc\n"
619 "%llud/%llud/%llud kernel draw\n",
620 (uvlong)conf.npage*BY2PG,
622 conf.npage-conf.upages,
623 palloc.user-palloc.freecount-fscache.pgref-swapimage.pgref, palloc.user,
624 conf.nswap-swapalloc.free, conf.nswap,
625 (uvlong)mainmem->curalloc,
626 (uvlong)mainmem->cursize,
627 (uvlong)mainmem->maxsize,
628 (uvlong)imagmem->curalloc,
629 (uvlong)imagmem->cursize,
630 (uvlong)imagmem->maxsize);
632 return readstr((ulong)offset, buf, n, tmp);
637 return readstr((ulong)offset, buf, n, sysname);
640 return randomread(buf, n);
643 b = smalloc(READSTR);
645 for(i = 0; devtab[i] != nil; i++)
646 k += snprint(b+k, READSTR-k, "#%C %s\n",
647 devtab[i]->dc, devtab[i]->name);
652 n = readstr((ulong)offset, buf, n, b);
662 error("one does not simply read from mordor");
666 snprint(tmp, sizeof tmp, "2000");
667 n = readstr((ulong)offset, buf, n, tmp);
671 print("consread %#llux\n", c->qid.path);
674 return -1; /* never reached */
678 conswrite(Chan *c, void *va, long n, vlong off)
693 switch((ulong)c->qid.path){
696 * Can't page fault in putstrn, so copy the data locally.
704 putstrn0(buf, bp, 1);
716 return writetime(a, n);
721 return writebintime(a, n);
724 return hostownerwrite(a, n);
727 return hostdomainwrite(a, n);
730 return userwrite(a, n);
748 ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
754 rebootcmd(cb->nf-1, cb->f+1);
758 panic("/dev/reboot");
770 for(id = 0; id < MAXMACH; id++) {
771 if(active.machs[id]) {
786 memmove(buf, va, n); /* so we can NUL-terminate */
788 /* start a pager if not already started */
789 if(strncmp(buf, "start", 5) == 0){
795 if(buf[0]<'0' || '9'<buf[0])
797 fd = strtoul(buf, 0, 0);
798 swc = fdtochan(fd, -1, 1, 1);
805 if(n <= 0 || n >= sizeof buf)
811 kstrdup(&sysname, buf);
815 error("one does not simply write into mordor");
819 print("conswrite: %#llux\n", c->qid.path);
852 randomread((void*)&randn, sizeof(randn));
862 randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
863 return (randn>>16) % n;
873 static uvlong uvorder = 0x0001020304050607ULL;
876 le2vlong(vlong *to, uchar *f)
882 o = (uchar*)&uvorder;
883 for(i = 0; i < sizeof(vlong); i++)
885 return f+sizeof(vlong);
889 vlong2le(uchar *t, vlong from)
895 o = (uchar*)&uvorder;
896 for(i = 0; i < sizeof(vlong); i++)
898 return t+sizeof(vlong);
901 static long order = 0x00010203;
904 le2long(long *to, uchar *f)
911 for(i = 0; i < sizeof(long); i++)
913 return f+sizeof(long);
917 long2le(uchar *t, long from)
924 for(i = 0; i < sizeof(long); i++)
926 return t+sizeof(long);
929 char *Ebadtimectl = "bad time control";
932 * like the old #c/time but with added info. Return
934 * secs nanosecs fastticks fasthz
937 readtime(ulong off, char *buf, int n)
943 nsec = todget(&ticks);
945 fastticks((uvlong*)&fasthz);
946 sec = nsec/1000000000ULL;
947 snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
951 VLNUMSIZE-1, fasthz);
952 return readstr(off, buf, n, str);
956 * set the time in seconds
959 writetime(char *buf, int n)
972 now = i*1000000000LL;
978 * read binary time info. all numbers are little endian.
979 * ticks and nsec are syncronized.
982 readbintime(char *buf, int n)
986 uchar *b = (uchar*)buf;
990 fastticks((uvlong*)&fasthz);
991 nsec = todget(&ticks);
992 if(n >= 3*sizeof(uvlong)){
993 vlong2le(b+2*sizeof(uvlong), fasthz);
996 if(n >= 2*sizeof(uvlong)){
997 vlong2le(b+sizeof(uvlong), ticks);
1008 * set any of the following
1010 * - nsec trim applied over some seconds
1014 writebintime(char *buf, int n)
1021 p = (uchar*)buf + 1;
1024 if(n < sizeof(vlong))
1026 le2vlong(&delta, p);
1027 todset(delta, 0, 0);
1030 if(n < sizeof(vlong)+sizeof(long))
1032 p = le2vlong(&delta, p);
1033 le2long(&period, p);
1034 todset(-1, delta, period);
1037 if(n < sizeof(uvlong))
1039 le2vlong(&fasthz, p);
1054 once = active.machs[m->machno];
1055 active.machs[m->machno] = 0;
1060 iprint("cpu%d: exiting\n", m->machno);
1062 /* wait for any other processors to shutdown */
1064 for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
1066 if(memchr(active.machs, 1, MAXMACH) == nil && consactive() == 0)