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 int readtime(ulong, char*, int);
25 static int readbintime(char*, int);
26 static int writetime(char*, int);
27 static int writebintime(char*, int);
40 CMreboot, "reboot", 0,
54 return qlen(serialoq) > 0;
65 if(m->ticks - now >= HZ)
70 * Log console output so it can be retrieved via /dev/kmesg.
71 * This is good for catching boot-time messages after the fact.
80 kmesgputs(char *str, int n)
85 /* take the tail of huge writes */
86 if(n > sizeof kmesg.buf){
87 d = n - sizeof kmesg.buf;
92 /* slide the buffer down to make room */
94 if(nn + n >= sizeof kmesg.buf){
95 d = nn + n - sizeof kmesg.buf;
97 memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
101 /* copy the data in */
102 memmove(kmesg.buf+nn, str, n);
109 * Print a string on the console. Convert \n to \r\n for serial
110 * line consoles. Locking of the queues is left up to the screen
111 * or uart code. Multi-line messages to serial consoles may get
112 * interspersed with other messages.
115 putstrn0(char *str, int n, int usewrite)
124 * how many different output devices do we need?
129 * if someone is reading /dev/kprint,
130 * put the message there.
131 * if not and there's an attached bit mapped display,
132 * put the message there.
134 * if there's a serial line being used as a console,
135 * put the message there.
137 if(kprintoq != nil && !qisclosed(kprintoq)){
139 qwrite(kprintoq, str, n);
141 qiwrite(kprintoq, str, n);
142 }else if(screenputs != nil)
151 t = memchr(str, '\n', n);
155 qwrite(serialoq, str, m);
156 qwrite(serialoq, "\r\n", 2);
158 qiwrite(serialoq, str, m);
159 qiwrite(serialoq, "\r\n", 2);
165 qwrite(serialoq, str, n);
167 qiwrite(serialoq, str, n);
174 putstrn(char *str, int n)
180 print(char *fmt, ...)
187 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
195 * Want to interlock iprints to avoid interlaced output on
196 * multiprocessor, but don't want to deadlock if one processor
197 * dies during print and another has something important to say.
198 * Make a good faith effort.
200 static Lock iprintlock;
202 iprintcanlock(Lock *l)
206 for(i=0; i<1000; i++){
209 if(l->m == MACHP(m->machno))
217 iprint(char *fmt, ...)
225 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
227 locked = iprintcanlock(&iprintlock);
228 if(screenputs != nil && iprintscreenputs)
239 panic(char *fmt, ...)
245 kprintoq = nil; /* don't try to write to /dev/kprint */
252 strcpy(buf, "panic: ");
254 vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
263 /* reboot cpu servers and headless machines when not debugging */
264 if(getconf("*debug") == nil)
265 if(cpuserver || !conf.monitor)
268 /* otherwise, just hang */
269 while(islo()) idlehands();
273 /* libmp at least contains a few calls to sysfatal; simulate with panic */
275 sysfatal(char *fmt, ...)
281 vseprint(err, err + sizeof err, fmt, arg);
283 panic("sysfatal: %s", err);
289 panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
293 pprint(char *fmt, ...)
298 char buf[2*PRINTSIZE];
300 if(up == nil || up->fgrp == nil)
304 if(c==nil || (c->flag&CMSG)!=0 || (c->mode!=OWRITE && c->mode!=ORDWR))
306 n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
308 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
313 devtab[c->type]->write(c, buf, n, c->offset);
356 static Dirtab consdir[]={
357 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
358 "bintime", {Qbintime}, 24, 0664,
359 "cons", {Qcons}, 0, 0660,
360 "consctl", {Qconsctl}, 0, 0220,
361 "cputime", {Qcputime}, 6*NUMSIZE, 0444,
362 "drivers", {Qdrivers}, 0, 0444,
363 "hostdomain", {Qhostdomain}, DOMLEN, 0664,
364 "hostowner", {Qhostowner}, 0, 0664,
365 "kmesg", {Qkmesg}, 0, 0440,
366 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,
367 "null", {Qnull}, 0, 0666,
368 "osversion", {Qosversion}, 0, 0444,
369 "pgrpid", {Qpgrpid}, NUMSIZE, 0444,
370 "pid", {Qpid}, NUMSIZE, 0444,
371 "ppid", {Qppid}, NUMSIZE, 0444,
372 "random", {Qrandom}, 0, 0444,
373 "reboot", {Qreboot}, 0, 0664,
374 "swap", {Qswap}, 0, 0664,
375 "sysname", {Qsysname}, 0, 0664,
376 "sysstat", {Qsysstat}, 0, 0666,
377 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
378 "user", {Quser}, 0, 0666,
379 "zero", {Qzero}, 0, 0444,
380 "config", {Qconfig}, 0, 0444,
381 "mordor", {Qmordor}, 0, 0666,
385 readnum(ulong off, char *buf, ulong n, ulong val, int size)
389 snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
395 memmove(buf, tmp+off, n);
400 readstr(ulong off, char *buf, ulong n, char *str)
409 memmove(buf, str+off, n);
421 consattach(char *spec)
423 return devattach('c', spec);
427 conswalk(Chan *c, Chan *nc, char **name, int nname)
429 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
433 consstat(Chan *c, uchar *dp, int n)
435 return devstat(c, dp, n, consdir, nelem(consdir), devgen);
439 consopen(Chan *c, int omode)
442 c = devopen(c, omode, consdir, nelem(consdir), devgen);
443 switch((ulong)c->qid.path){
445 if(tas(&kprintinuse) != 0){
450 kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
455 qnoblock(kprintoq, 1);
458 c->iounit = qiomaxatomic;
467 switch((ulong)c->qid.path){
468 /* close of kprint allows other opens */
472 qhangup(kprintoq, nil);
479 consread(Chan *c, void *buf, long n, vlong off)
484 char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
487 extern char configfile[];
488 extern Image fscache;
489 extern Image swapimage;
494 switch((ulong)c->qid.path){
496 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
507 /* easiest to format in a separate buffer and copy out */
508 for(i=0; i<6 && NUMSIZE*i<k+n; i++){
511 l = MACHP(0)->ticks - l;
513 readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
515 memmove(buf, tmp+k, n);
520 * This is unlocked to avoid tying up a process
521 * that's writing to the buffer. kmesg.n never
522 * gets smaller, so worst case the reader will
523 * see a slurred buffer.
530 memmove(buf, kmesg.buf+off, n);
535 return qread(kprintoq, buf, n);
538 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
541 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
544 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
547 return readtime((ulong)offset, buf, n);
550 return readbintime(buf, n);
553 return readstr((ulong)offset, buf, n, eve);
556 return readstr((ulong)offset, buf, n, hostdomain);
559 return readstr((ulong)offset, buf, n, up->user);
565 return readstr((ulong)offset, buf, n, configfile);
568 b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */
570 for(id = 0; id < MAXMACH; id++) {
571 if(active.machs[id]) {
573 readnum(0, bp, NUMSIZE, id, NUMSIZE);
575 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
577 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
579 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
581 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
583 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
585 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
587 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
592 readnum(0, bp, NUMSIZE,
593 (mp->perf.avg_inidle*100)/l, NUMSIZE);
595 readnum(0, bp, NUMSIZE,
596 (mp->perf.avg_inintr*100)/l, NUMSIZE);
605 n = readstr((ulong)offset, buf, n, b);
611 snprint(tmp, sizeof tmp,
617 "%llud/%llud/%llud kernel malloc\n"
618 "%llud/%llud/%llud kernel draw\n"
619 "%llud/%llud/%llud kernel secret\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,
631 (uvlong)secrmem->curalloc,
632 (uvlong)secrmem->cursize,
633 (uvlong)secrmem->maxsize);
635 return readstr((ulong)offset, buf, n, tmp);
640 return readstr((ulong)offset, buf, n, sysname);
643 return randomread(buf, n);
646 b = smalloc(READSTR);
648 for(i = 0; devtab[i] != nil; i++)
649 k += snprint(b+k, READSTR-k, "#%C %s\n",
650 devtab[i]->dc, devtab[i]->name);
655 n = readstr((ulong)offset, buf, n, b);
665 error("one does not simply read from mordor");
669 snprint(tmp, sizeof tmp, "2000");
670 n = readstr((ulong)offset, buf, n, tmp);
674 print("consread %#llux\n", c->qid.path);
677 return -1; /* never reached */
681 conswrite(Chan *c, void *va, long n, vlong off)
696 switch((ulong)c->qid.path){
699 * Can't page fault in putstrn, so copy the data locally.
707 putstrn0(buf, bp, 1);
719 return writetime(a, n);
724 return writebintime(a, n);
727 return hostownerwrite(a, n);
730 return hostdomainwrite(a, n);
733 return userwrite(a, n);
751 ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
757 rebootcmd(cb->nf-1, cb->f+1);
761 panic("/dev/reboot");
773 for(id = 0; id < MAXMACH; id++) {
774 if(active.machs[id]) {
789 memmove(buf, va, n); /* so we can NUL-terminate */
791 /* start a pager if not already started */
792 if(strncmp(buf, "start", 5) == 0){
798 if(buf[0]<'0' || '9'<buf[0])
800 fd = strtoul(buf, 0, 0);
801 swc = fdtochan(fd, ORDWR, 1, 1);
808 if(n <= 0 || n >= sizeof buf)
814 kstrdup(&sysname, buf);
818 error("one does not simply write into mordor");
822 print("conswrite: %#llux\n", c->qid.path);
855 randomread((void*)&randn, sizeof(randn));
856 randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
864 return (randn>>16) % n;
867 static uvlong uvorder = 0x0001020304050607ULL;
870 le2vlong(vlong *to, uchar *f)
876 o = (uchar*)&uvorder;
877 for(i = 0; i < sizeof(vlong); i++)
879 return f+sizeof(vlong);
883 vlong2le(uchar *t, vlong from)
889 o = (uchar*)&uvorder;
890 for(i = 0; i < sizeof(vlong); i++)
892 return t+sizeof(vlong);
895 static long order = 0x00010203;
898 le2long(long *to, uchar *f)
905 for(i = 0; i < sizeof(long); i++)
907 return f+sizeof(long);
911 long2le(uchar *t, long from)
918 for(i = 0; i < sizeof(long); i++)
920 return t+sizeof(long);
923 char *Ebadtimectl = "bad time control";
926 * like the old #c/time but with added info. Return
928 * secs nanosecs fastticks fasthz
931 readtime(ulong off, char *buf, int n)
937 nsec = todget(&ticks);
939 fastticks((uvlong*)&fasthz);
940 sec = nsec/1000000000ULL;
941 snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
945 VLNUMSIZE-1, fasthz);
946 return readstr(off, buf, n, str);
950 * set the time in seconds
953 writetime(char *buf, int n)
966 now = i*1000000000LL;
972 * read binary time info. all numbers are little endian.
973 * ticks and nsec are syncronized.
976 readbintime(char *buf, int n)
980 uchar *b = (uchar*)buf;
984 fastticks((uvlong*)&fasthz);
985 nsec = todget(&ticks);
986 if(n >= 3*sizeof(uvlong)){
987 vlong2le(b+2*sizeof(uvlong), fasthz);
990 if(n >= 2*sizeof(uvlong)){
991 vlong2le(b+sizeof(uvlong), ticks);
1002 * set any of the following
1004 * - nsec trim applied over some seconds
1008 writebintime(char *buf, int n)
1015 p = (uchar*)buf + 1;
1018 if(n < sizeof(vlong))
1020 le2vlong(&delta, p);
1021 todset(delta, 0, 0);
1024 if(n < sizeof(vlong)+sizeof(long))
1026 p = le2vlong(&delta, p);
1027 le2long(&period, p);
1028 todset(-1, delta, period);
1031 if(n < sizeof(uvlong))
1033 le2vlong(&fasthz, p);
1048 once = active.machs[m->machno];
1049 active.machs[m->machno] = 0;
1054 iprint("cpu%d: exiting\n", m->machno);
1056 /* wait for any other processors to shutdown */
1058 for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
1060 if(memchr(active.machs, 1, MAXMACH) == nil && consactive() == 0)