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);
38 CMreboot, "reboot", 0,
52 return qlen(serialoq) > 0;
63 if(m->ticks - now >= HZ)
68 * Log console output so it can be retrieved via /dev/kmesg.
69 * This is good for catching boot-time messages after the fact.
78 kmesgputs(char *str, int n)
83 /* take the tail of huge writes */
84 if(n > sizeof kmesg.buf){
85 d = n - sizeof kmesg.buf;
90 /* slide the buffer down to make room */
92 if(nn + n >= sizeof kmesg.buf){
93 d = nn + n - sizeof kmesg.buf;
95 memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
99 /* copy the data in */
100 memmove(kmesg.buf+nn, str, n);
107 * Print a string on the console. Convert \n to \r\n for serial
108 * line consoles. Locking of the queues is left up to the screen
109 * or uart code. Multi-line messages to serial consoles may get
110 * interspersed with other messages.
113 putstrn0(char *str, int n, int usewrite)
122 * how many different output devices do we need?
127 * if someone is reading /dev/kprint,
128 * put the message there.
129 * if not and there's an attached bit mapped display,
130 * put the message there.
132 * if there's a serial line being used as a console,
133 * put the message there.
135 if(kprintoq != nil && !qisclosed(kprintoq)){
137 qwrite(kprintoq, str, n);
139 qiwrite(kprintoq, str, n);
140 }else if(screenputs != nil)
149 t = memchr(str, '\n', n);
153 qwrite(serialoq, str, m);
154 qwrite(serialoq, "\r\n", 2);
156 qiwrite(serialoq, str, m);
157 qiwrite(serialoq, "\r\n", 2);
163 qwrite(serialoq, str, n);
165 qiwrite(serialoq, str, n);
172 putstrn(char *str, int n)
178 print(char *fmt, ...)
185 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
193 * Want to interlock iprints to avoid interlaced output on
194 * multiprocessor, but don't want to deadlock if one processor
195 * dies during print and another has something important to say.
196 * Make a good faith effort.
198 static Lock iprintlock;
200 iprintcanlock(Lock *l)
204 for(i=0; i<1000; i++){
207 if(l->m == MACHP(m->machno))
215 iprint(char *fmt, ...)
223 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
225 locked = iprintcanlock(&iprintlock);
226 if(screenputs != nil && iprintscreenputs)
237 panic(char *fmt, ...)
243 kprintoq = nil; /* don't try to write to /dev/kprint */
250 strcpy(buf, "panic: ");
252 vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
261 /* reboot cpu servers and headless machines when not debugging */
262 if(getconf("*debug") == nil)
263 if(cpuserver || !conf.monitor)
266 /* otherwise, just hang */
267 while(islo()) idlehands();
271 /* libmp at least contains a few calls to sysfatal; simulate with panic */
273 sysfatal(char *fmt, ...)
279 vseprint(err, err + sizeof err, fmt, arg);
281 panic("sysfatal: %s", err);
287 panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
291 pprint(char *fmt, ...)
296 char buf[2*PRINTSIZE];
298 if(up == nil || up->fgrp == nil)
302 if(c==nil || (c->flag&CMSG)!=0 || (c->mode!=OWRITE && c->mode!=ORDWR))
304 n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
306 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
311 devtab[c->type]->write(c, buf, n, c->offset);
354 static Dirtab consdir[]={
355 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
356 "bintime", {Qbintime}, 24, 0664,
357 "cons", {Qcons}, 0, 0660,
358 "consctl", {Qconsctl}, 0, 0220,
359 "cputime", {Qcputime}, 6*NUMSIZE, 0444,
360 "drivers", {Qdrivers}, 0, 0444,
361 "hostdomain", {Qhostdomain}, DOMLEN, 0664,
362 "hostowner", {Qhostowner}, 0, 0664,
363 "kmesg", {Qkmesg}, 0, 0440,
364 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,
365 "null", {Qnull}, 0, 0666,
366 "osversion", {Qosversion}, 0, 0444,
367 "pgrpid", {Qpgrpid}, NUMSIZE, 0444,
368 "pid", {Qpid}, NUMSIZE, 0444,
369 "ppid", {Qppid}, NUMSIZE, 0444,
370 "random", {Qrandom}, 0, 0444,
371 "reboot", {Qreboot}, 0, 0664,
372 "swap", {Qswap}, 0, 0664,
373 "sysname", {Qsysname}, 0, 0664,
374 "sysstat", {Qsysstat}, 0, 0666,
375 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
376 "user", {Quser}, 0, 0666,
377 "zero", {Qzero}, 0, 0444,
378 "config", {Qconfig}, 0, 0444,
379 "mordor", {Qmordor}, 0, 0666,
383 readnum(ulong off, char *buf, ulong n, ulong val, int size)
387 snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
393 memmove(buf, tmp+off, n);
398 readstr(ulong off, char *buf, ulong n, char *str)
407 memmove(buf, str+off, n);
419 consattach(char *spec)
421 return devattach('c', spec);
425 conswalk(Chan *c, Chan *nc, char **name, int nname)
427 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
431 consstat(Chan *c, uchar *dp, int n)
433 return devstat(c, dp, n, consdir, nelem(consdir), devgen);
437 consopen(Chan *c, int omode)
440 c = devopen(c, omode, consdir, nelem(consdir), devgen);
441 switch((ulong)c->qid.path){
443 if(tas(&kprintinuse) != 0){
448 kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
453 qnoblock(kprintoq, 1);
456 c->iounit = qiomaxatomic;
465 switch((ulong)c->qid.path){
466 /* close of kprint allows other opens */
470 qhangup(kprintoq, nil);
477 consread(Chan *c, void *buf, long n, vlong off)
482 char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
485 extern char configfile[];
486 extern Image fscache;
487 extern Image swapimage;
492 switch((ulong)c->qid.path){
494 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
505 /* easiest to format in a separate buffer and copy out */
506 for(i=0; i<6 && NUMSIZE*i<k+n; i++){
509 l = MACHP(0)->ticks - l;
510 readnum(0, tmp+NUMSIZE*i, NUMSIZE, tk2ms(l), NUMSIZE);
512 memmove(buf, tmp+k, n);
517 * This is unlocked to avoid tying up a process
518 * that's writing to the buffer. kmesg.n never
519 * gets smaller, so worst case the reader will
520 * see a slurred buffer.
527 memmove(buf, kmesg.buf+off, n);
532 return qread(kprintoq, buf, n);
535 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
538 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
541 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
544 return readtime((ulong)offset, buf, n);
547 return readbintime(buf, n);
550 return readstr((ulong)offset, buf, n, eve);
553 return readstr((ulong)offset, buf, n, hostdomain);
556 return readstr((ulong)offset, buf, n, up->user);
562 return readstr((ulong)offset, buf, n, configfile);
565 b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */
567 for(id = 0; id < MAXMACH; id++) {
568 if(active.machs[id]) {
570 readnum(0, bp, NUMSIZE, id, NUMSIZE);
572 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
574 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
576 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
578 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
580 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
582 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
584 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
589 readnum(0, bp, NUMSIZE,
590 (mp->perf.avg_inidle*100)/l, NUMSIZE);
592 readnum(0, bp, NUMSIZE,
593 (mp->perf.avg_inintr*100)/l, NUMSIZE);
602 n = readstr((ulong)offset, buf, n, b);
608 snprint(tmp, sizeof tmp,
614 "%llud/%llud/%llud kernel malloc\n"
615 "%llud/%llud/%llud kernel draw\n"
616 "%llud/%llud/%llud kernel secret\n",
617 (uvlong)conf.npage*BY2PG,
619 conf.npage-conf.upages,
620 palloc.user-palloc.freecount-fscache.pgref-swapimage.pgref, palloc.user,
621 conf.nswap-swapalloc.free, conf.nswap,
622 (uvlong)mainmem->curalloc,
623 (uvlong)mainmem->cursize,
624 (uvlong)mainmem->maxsize,
625 (uvlong)imagmem->curalloc,
626 (uvlong)imagmem->cursize,
627 (uvlong)imagmem->maxsize,
628 (uvlong)secrmem->curalloc,
629 (uvlong)secrmem->cursize,
630 (uvlong)secrmem->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));
751 rebootcmd(cb->nf-1, cb->f+1);
755 panic("/dev/reboot");
767 for(id = 0; id < MAXMACH; id++) {
768 if(active.machs[id]) {
783 memmove(buf, va, n); /* so we can NUL-terminate */
785 /* start a pager if not already started */
786 if(strncmp(buf, "start", 5) == 0){
792 if(buf[0]<'0' || '9'<buf[0])
794 fd = strtoul(buf, 0, 0);
795 swc = fdtochan(fd, ORDWR, 1, 1);
802 if(n <= 0 || n >= sizeof buf)
808 kstrdup(&sysname, buf);
812 error("one does not simply write into mordor");
816 print("conswrite: %#llux\n", c->qid.path);
843 static uvlong uvorder = 0x0001020304050607ULL;
846 le2vlong(vlong *to, uchar *f)
852 o = (uchar*)&uvorder;
853 for(i = 0; i < sizeof(vlong); i++)
855 return f+sizeof(vlong);
859 vlong2le(uchar *t, vlong from)
865 o = (uchar*)&uvorder;
866 for(i = 0; i < sizeof(vlong); i++)
868 return t+sizeof(vlong);
871 static long order = 0x00010203;
874 le2long(long *to, uchar *f)
881 for(i = 0; i < sizeof(long); i++)
883 return f+sizeof(long);
887 long2le(uchar *t, long from)
894 for(i = 0; i < sizeof(long); i++)
896 return t+sizeof(long);
899 char *Ebadtimectl = "bad time control";
902 * like the old #c/time but with added info. Return
904 * secs nanosecs fastticks fasthz
907 readtime(ulong off, char *buf, int n)
913 nsec = todget(&ticks);
915 fastticks((uvlong*)&fasthz);
916 sec = nsec/1000000000ULL;
917 snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
921 VLNUMSIZE-1, fasthz);
922 return readstr(off, buf, n, str);
926 * set the time in seconds
929 writetime(char *buf, int n)
942 now = i*1000000000LL;
948 * read binary time info. all numbers are little endian.
949 * ticks and nsec are syncronized.
952 readbintime(char *buf, int n)
956 uchar *b = (uchar*)buf;
960 fastticks((uvlong*)&fasthz);
961 nsec = todget(&ticks);
962 if(n >= 3*sizeof(uvlong)){
963 vlong2le(b+2*sizeof(uvlong), fasthz);
966 if(n >= 2*sizeof(uvlong)){
967 vlong2le(b+sizeof(uvlong), ticks);
978 * set any of the following
980 * - nsec trim applied over some seconds
984 writebintime(char *buf, int n)
994 if(n < sizeof(vlong))
1000 if(n < sizeof(vlong)+sizeof(long))
1002 p = le2vlong(&delta, p);
1003 le2long(&period, p);
1004 todset(-1, delta, period);
1007 if(n < sizeof(uvlong))
1009 le2vlong(&fasthz, p);
1024 once = active.machs[m->machno];
1025 active.machs[m->machno] = 0;
1030 iprint("cpu%d: exiting\n", m->machno);
1032 /* wait for any other processors to shutdown */
1034 for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
1036 if(memchr(active.machs, 1, MAXMACH) == nil && consactive() == 0)