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.
76 // char buf[16384]; /* normal */
77 char buf[256*1024]; /* for acpi debugging */
82 kmesgputs(char *str, int n)
87 /* take the tail of huge writes */
88 if(n > sizeof kmesg.buf){
89 d = n - sizeof kmesg.buf;
94 /* slide the buffer down to make room */
96 if(nn + n >= sizeof kmesg.buf){
97 d = nn + n - sizeof kmesg.buf;
99 memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
103 /* copy the data in */
104 memmove(kmesg.buf+nn, str, n);
111 * Print a string on the console. Convert \n to \r\n for serial
112 * line consoles. Locking of the queues is left up to the screen
113 * or uart code. Multi-line messages to serial consoles may get
114 * interspersed with other messages.
117 putstrn0(char *str, int n, int usewrite)
126 * how many different output devices do we need?
131 * if someone is reading /dev/kprint,
132 * put the message there.
133 * if not and there's an attached bit mapped display,
134 * put the message there.
136 * if there's a serial line being used as a console,
137 * put the message there.
139 if(kprintoq != nil && !qisclosed(kprintoq)){
141 qwrite(kprintoq, str, n);
143 qiwrite(kprintoq, str, n);
144 }else if(screenputs != nil)
153 t = memchr(str, '\n', n);
157 qwrite(serialoq, str, m);
158 qwrite(serialoq, "\r\n", 2);
160 qiwrite(serialoq, str, m);
161 qiwrite(serialoq, "\r\n", 2);
167 qwrite(serialoq, str, n);
169 qiwrite(serialoq, str, n);
176 putstrn(char *str, int n)
182 print(char *fmt, ...)
189 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
197 * Want to interlock iprints to avoid interlaced output on
198 * multiprocessor, but don't want to deadlock if one processor
199 * dies during print and another has something important to say.
200 * Make a good faith effort.
202 static Lock iprintlock;
204 iprintcanlock(Lock *l)
208 for(i=0; i<1000; i++){
211 if(l->m == MACHP(m->machno))
219 iprint(char *fmt, ...)
227 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
229 locked = iprintcanlock(&iprintlock);
230 if(screenputs != nil && iprintscreenputs)
241 panic(char *fmt, ...)
247 kprintoq = nil; /* don't try to write to /dev/kprint */
254 strcpy(buf, "panic: ");
256 vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
269 /* libmp at least contains a few calls to sysfatal; simulate with panic */
271 sysfatal(char *fmt, ...)
277 vseprint(err, err + sizeof err, fmt, arg);
279 panic("sysfatal: %s", err);
285 panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
289 pprint(char *fmt, ...)
294 char buf[2*PRINTSIZE];
296 if(up == nil || up->fgrp == nil)
300 if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
302 n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
304 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
309 devtab[c->type]->write(c, buf, n, c->offset);
352 static Dirtab consdir[]={
353 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
354 "bintime", {Qbintime}, 24, 0664,
355 "cons", {Qcons}, 0, 0660,
356 "consctl", {Qconsctl}, 0, 0220,
357 "cputime", {Qcputime}, 6*NUMSIZE, 0444,
358 "drivers", {Qdrivers}, 0, 0444,
359 "hostdomain", {Qhostdomain}, DOMLEN, 0664,
360 "hostowner", {Qhostowner}, 0, 0664,
361 "kmesg", {Qkmesg}, 0, 0440,
362 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,
363 "null", {Qnull}, 0, 0666,
364 "osversion", {Qosversion}, 0, 0444,
365 "pgrpid", {Qpgrpid}, NUMSIZE, 0444,
366 "pid", {Qpid}, NUMSIZE, 0444,
367 "ppid", {Qppid}, NUMSIZE, 0444,
368 "random", {Qrandom}, 0, 0444,
369 "reboot", {Qreboot}, 0, 0664,
370 "swap", {Qswap}, 0, 0664,
371 "sysname", {Qsysname}, 0, 0664,
372 "sysstat", {Qsysstat}, 0, 0666,
373 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
374 "user", {Quser}, 0, 0666,
375 "zero", {Qzero}, 0, 0444,
376 "config", {Qconfig}, 0, 0444,
377 "mordor", {Qmordor}, 0, 0666,
381 readnum(ulong off, char *buf, ulong n, ulong val, int size)
385 snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
391 memmove(buf, tmp+off, n);
396 readstr(ulong off, char *buf, ulong n, char *str)
405 memmove(buf, str+off, n);
417 consattach(char *spec)
419 return devattach('c', spec);
423 conswalk(Chan *c, Chan *nc, char **name, int nname)
425 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
429 consstat(Chan *c, uchar *dp, int n)
431 return devstat(c, dp, n, consdir, nelem(consdir), devgen);
435 consopen(Chan *c, int omode)
438 c = devopen(c, omode, consdir, nelem(consdir), devgen);
439 switch((ulong)c->qid.path){
441 if(tas(&kprintinuse) != 0){
446 kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
451 qnoblock(kprintoq, 1);
454 c->iounit = qiomaxatomic;
463 switch((ulong)c->qid.path){
464 /* close of kprint allows other opens */
468 qhangup(kprintoq, nil);
475 consread(Chan *c, void *buf, long n, vlong off)
480 char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
483 extern char configfile[];
488 switch((ulong)c->qid.path){
490 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
501 /* easiest to format in a separate buffer and copy out */
502 for(i=0; i<6 && NUMSIZE*i<k+n; i++){
505 l = MACHP(0)->ticks - l;
507 readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
509 memmove(buf, tmp+k, n);
514 * This is unlocked to avoid tying up a process
515 * that's writing to the buffer. kmesg.n never
516 * gets smaller, so worst case the reader will
517 * see a slurred buffer.
524 memmove(buf, kmesg.buf+off, n);
529 return qread(kprintoq, buf, n);
532 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
535 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
538 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
541 return readtime((ulong)offset, buf, n);
544 return readbintime(buf, n);
547 return readstr((ulong)offset, buf, n, eve);
550 return readstr((ulong)offset, buf, n, hostdomain);
553 return readstr((ulong)offset, buf, n, up->user);
559 return readstr((ulong)offset, buf, n, configfile);
562 b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */
564 for(id = 0; id < 32; id++) {
565 if(active.machs & (1<<id)) {
567 readnum(0, bp, NUMSIZE, id, NUMSIZE);
569 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
571 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
573 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
575 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
577 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
579 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
581 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
583 readnum(0, bp, NUMSIZE,
584 (mp->perf.avg_inidle*100)/mp->perf.period,
587 readnum(0, bp, NUMSIZE,
588 (mp->perf.avg_inintr*100)/mp->perf.period,
598 n = readstr((ulong)offset, buf, n, b);
604 snprint(tmp, sizeof tmp,
610 "%lud/%lud kernel malloc\n"
611 "%lud/%lud kernel draw\n",
614 conf.npage-conf.upages,
615 palloc.user-palloc.freecount, palloc.user,
616 conf.nswap-swapalloc.free, conf.nswap,
617 mainmem->cursize, mainmem->maxsize,
618 imagmem->cursize, imagmem->maxsize);
620 return readstr((ulong)offset, buf, n, tmp);
625 return readstr((ulong)offset, buf, n, sysname);
628 return randomread(buf, n);
631 b = smalloc(READSTR);
633 for(i = 0; devtab[i] != nil; i++)
634 k += snprint(b+k, READSTR-k, "#%C %s\n",
635 devtab[i]->dc, devtab[i]->name);
640 n = readstr((ulong)offset, buf, n, b);
650 error("one does not simply read from mordor");
654 snprint(tmp, sizeof tmp, "2000");
655 n = readstr((ulong)offset, buf, n, tmp);
659 print("consread %#llux\n", c->qid.path);
662 return -1; /* never reached */
666 conswrite(Chan *c, void *va, long n, vlong off)
681 switch((ulong)c->qid.path){
684 * Can't page fault in putstrn, so copy the data locally.
692 putstrn0(buf, bp, 1);
704 return writetime(a, n);
709 return writebintime(a, n);
712 return hostownerwrite(a, n);
715 return hostdomainwrite(a, n);
718 return userwrite(a, n);
736 ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
742 rebootcmd(cb->nf-1, cb->f+1);
746 panic("/dev/reboot");
758 for(id = 0; id < 32; id++) {
759 if(active.machs & (1<<id)) {
774 memmove(buf, va, n); /* so we can NUL-terminate */
776 /* start a pager if not already started */
777 if(strncmp(buf, "start", 5) == 0){
783 if(buf[0]<'0' || '9'<buf[0])
785 fd = strtoul(buf, 0, 0);
786 swc = fdtochan(fd, -1, 1, 1);
793 if(n <= 0 || n >= sizeof buf)
799 kstrdup(&sysname, buf);
803 error("one does not simply write into mordor");
807 print("conswrite: %#llux\n", c->qid.path);
840 randomread((void*)&randn, sizeof(randn));
850 randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
851 return (randn>>16) % n;
861 static uvlong uvorder = 0x0001020304050607ULL;
864 le2vlong(vlong *to, uchar *f)
870 o = (uchar*)&uvorder;
871 for(i = 0; i < sizeof(vlong); i++)
873 return f+sizeof(vlong);
877 vlong2le(uchar *t, vlong from)
883 o = (uchar*)&uvorder;
884 for(i = 0; i < sizeof(vlong); i++)
886 return t+sizeof(vlong);
889 static long order = 0x00010203;
892 le2long(long *to, uchar *f)
899 for(i = 0; i < sizeof(long); i++)
901 return f+sizeof(long);
905 long2le(uchar *t, long from)
912 for(i = 0; i < sizeof(long); i++)
914 return t+sizeof(long);
917 char *Ebadtimectl = "bad time control";
920 * like the old #c/time but with added info. Return
922 * secs nanosecs fastticks fasthz
925 readtime(ulong off, char *buf, int n)
931 nsec = todget(&ticks);
933 fastticks((uvlong*)&fasthz);
934 sec = nsec/1000000000ULL;
935 snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
939 VLNUMSIZE-1, fasthz);
940 return readstr(off, buf, n, str);
944 * set the time in seconds
947 writetime(char *buf, int n)
960 now = i*1000000000LL;
966 * read binary time info. all numbers are little endian.
967 * ticks and nsec are syncronized.
970 readbintime(char *buf, int n)
974 uchar *b = (uchar*)buf;
978 fastticks((uvlong*)&fasthz);
979 nsec = todget(&ticks);
980 if(n >= 3*sizeof(uvlong)){
981 vlong2le(b+2*sizeof(uvlong), fasthz);
984 if(n >= 2*sizeof(uvlong)){
985 vlong2le(b+sizeof(uvlong), ticks);
996 * set any of the following
998 * - nsec trim applied over some seconds
1002 writebintime(char *buf, int n)
1009 p = (uchar*)buf + 1;
1012 if(n < sizeof(vlong))
1014 le2vlong(&delta, p);
1015 todset(delta, 0, 0);
1018 if(n < sizeof(vlong)+sizeof(long))
1020 p = le2vlong(&delta, p);
1021 le2long(&period, p);
1022 todset(-1, delta, period);
1025 if(n < sizeof(uvlong))
1027 le2vlong(&fasthz, p);