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);
268 /* libmp at least contains a few calls to sysfatal; simulate with panic */
270 sysfatal(char *fmt, ...)
276 vseprint(err, err + sizeof err, fmt, arg);
278 panic("sysfatal: %s", err);
284 panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
288 pprint(char *fmt, ...)
293 char buf[2*PRINTSIZE];
295 if(up == nil || up->fgrp == nil)
299 if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
301 n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
303 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
308 devtab[c->type]->write(c, buf, n, c->offset);
351 static Dirtab consdir[]={
352 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
353 "bintime", {Qbintime}, 24, 0664,
354 "cons", {Qcons}, 0, 0660,
355 "consctl", {Qconsctl}, 0, 0220,
356 "cputime", {Qcputime}, 6*NUMSIZE, 0444,
357 "drivers", {Qdrivers}, 0, 0444,
358 "hostdomain", {Qhostdomain}, DOMLEN, 0664,
359 "hostowner", {Qhostowner}, 0, 0664,
360 "kmesg", {Qkmesg}, 0, 0440,
361 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,
362 "null", {Qnull}, 0, 0666,
363 "osversion", {Qosversion}, 0, 0444,
364 "pgrpid", {Qpgrpid}, NUMSIZE, 0444,
365 "pid", {Qpid}, NUMSIZE, 0444,
366 "ppid", {Qppid}, NUMSIZE, 0444,
367 "random", {Qrandom}, 0, 0444,
368 "reboot", {Qreboot}, 0, 0664,
369 "swap", {Qswap}, 0, 0664,
370 "sysname", {Qsysname}, 0, 0664,
371 "sysstat", {Qsysstat}, 0, 0666,
372 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
373 "user", {Quser}, 0, 0666,
374 "zero", {Qzero}, 0, 0444,
375 "config", {Qconfig}, 0, 0444,
376 "mordor", {Qmordor}, 0, 0666,
380 readnum(ulong off, char *buf, ulong n, ulong val, int size)
384 snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
390 memmove(buf, tmp+off, n);
395 readstr(ulong off, char *buf, ulong n, char *str)
404 memmove(buf, str+off, n);
416 consattach(char *spec)
418 return devattach('c', spec);
422 conswalk(Chan *c, Chan *nc, char **name, int nname)
424 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
428 consstat(Chan *c, uchar *dp, int n)
430 return devstat(c, dp, n, consdir, nelem(consdir), devgen);
434 consopen(Chan *c, int omode)
437 c = devopen(c, omode, consdir, nelem(consdir), devgen);
438 switch((ulong)c->qid.path){
440 if(tas(&kprintinuse) != 0){
445 kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
450 qnoblock(kprintoq, 1);
453 c->iounit = qiomaxatomic;
462 switch((ulong)c->qid.path){
463 /* close of kprint allows other opens */
467 qhangup(kprintoq, nil);
474 consread(Chan *c, void *buf, long n, vlong off)
479 char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
482 extern char configfile[];
487 switch((ulong)c->qid.path){
489 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
500 /* easiest to format in a separate buffer and copy out */
501 for(i=0; i<6 && NUMSIZE*i<k+n; i++){
504 l = MACHP(0)->ticks - l;
506 readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
508 memmove(buf, tmp+k, n);
513 * This is unlocked to avoid tying up a process
514 * that's writing to the buffer. kmesg.n never
515 * gets smaller, so worst case the reader will
516 * see a slurred buffer.
523 memmove(buf, kmesg.buf+off, n);
528 return qread(kprintoq, buf, n);
531 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
534 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
537 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
540 return readtime((ulong)offset, buf, n);
543 return readbintime(buf, n);
546 return readstr((ulong)offset, buf, n, eve);
549 return readstr((ulong)offset, buf, n, hostdomain);
552 return readstr((ulong)offset, buf, n, up->user);
558 return readstr((ulong)offset, buf, n, configfile);
561 b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */
563 for(id = 0; id < 32; id++) {
564 if(active.machs & (1<<id)) {
566 readnum(0, bp, NUMSIZE, id, NUMSIZE);
568 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
570 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
572 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
574 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
576 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
578 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
580 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
582 readnum(0, bp, NUMSIZE,
583 (mp->perf.avg_inidle*100)/mp->perf.period,
586 readnum(0, bp, NUMSIZE,
587 (mp->perf.avg_inintr*100)/mp->perf.period,
597 n = readstr((ulong)offset, buf, n, b);
603 snprint(tmp, sizeof tmp,
609 "%lud/%lud kernel malloc\n"
610 "%lud/%lud kernel draw\n",
613 conf.npage-conf.upages,
614 palloc.user-palloc.freecount, palloc.user,
615 conf.nswap-swapalloc.free, conf.nswap,
616 mainmem->cursize, mainmem->maxsize,
617 imagmem->cursize, imagmem->maxsize);
619 return readstr((ulong)offset, buf, n, tmp);
624 return readstr((ulong)offset, buf, n, sysname);
627 return randomread(buf, n);
630 b = smalloc(READSTR);
632 for(i = 0; devtab[i] != nil; i++)
633 k += snprint(b+k, READSTR-k, "#%C %s\n",
634 devtab[i]->dc, devtab[i]->name);
639 n = readstr((ulong)offset, buf, n, b);
649 error("one does not simply read from mordor");
653 snprint(tmp, sizeof tmp, "2000");
654 n = readstr((ulong)offset, buf, n, tmp);
658 print("consread %#llux\n", c->qid.path);
661 return -1; /* never reached */
665 conswrite(Chan *c, void *va, long n, vlong off)
680 switch((ulong)c->qid.path){
683 * Can't page fault in putstrn, so copy the data locally.
691 putstrn0(buf, bp, 1);
703 return writetime(a, n);
708 return writebintime(a, n);
711 return hostownerwrite(a, n);
714 return hostdomainwrite(a, n);
717 return userwrite(a, n);
735 ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
741 rebootcmd(cb->nf-1, cb->f+1);
745 panic("/dev/reboot");
757 for(id = 0; id < 32; id++) {
758 if(active.machs & (1<<id)) {
773 memmove(buf, va, n); /* so we can NUL-terminate */
775 /* start a pager if not already started */
776 if(strncmp(buf, "start", 5) == 0){
782 if(buf[0]<'0' || '9'<buf[0])
784 fd = strtoul(buf, 0, 0);
785 swc = fdtochan(fd, -1, 1, 1);
792 if(n <= 0 || n >= sizeof buf)
798 kstrdup(&sysname, buf);
802 error("one does not simply write into mordor");
806 print("conswrite: %#llux\n", c->qid.path);
839 randomread((void*)&randn, sizeof(randn));
849 randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
850 return (randn>>16) % n;
860 static uvlong uvorder = 0x0001020304050607ULL;
863 le2vlong(vlong *to, uchar *f)
869 o = (uchar*)&uvorder;
870 for(i = 0; i < sizeof(vlong); i++)
872 return f+sizeof(vlong);
876 vlong2le(uchar *t, vlong from)
882 o = (uchar*)&uvorder;
883 for(i = 0; i < sizeof(vlong); i++)
885 return t+sizeof(vlong);
888 static long order = 0x00010203;
891 le2long(long *to, uchar *f)
898 for(i = 0; i < sizeof(long); i++)
900 return f+sizeof(long);
904 long2le(uchar *t, long from)
911 for(i = 0; i < sizeof(long); i++)
913 return t+sizeof(long);
916 char *Ebadtimectl = "bad time control";
919 * like the old #c/time but with added info. Return
921 * secs nanosecs fastticks fasthz
924 readtime(ulong off, char *buf, int n)
930 nsec = todget(&ticks);
932 fastticks((uvlong*)&fasthz);
933 sec = nsec/1000000000ULL;
934 snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
938 VLNUMSIZE-1, fasthz);
939 return readstr(off, buf, n, str);
943 * set the time in seconds
946 writetime(char *buf, int n)
959 now = i*1000000000LL;
965 * read binary time info. all numbers are little endian.
966 * ticks and nsec are syncronized.
969 readbintime(char *buf, int n)
973 uchar *b = (uchar*)buf;
977 fastticks((uvlong*)&fasthz);
978 nsec = todget(&ticks);
979 if(n >= 3*sizeof(uvlong)){
980 vlong2le(b+2*sizeof(uvlong), fasthz);
983 if(n >= 2*sizeof(uvlong)){
984 vlong2le(b+sizeof(uvlong), ticks);
995 * set any of the following
997 * - nsec trim applied over some seconds
1001 writebintime(char *buf, int n)
1008 p = (uchar*)buf + 1;
1011 if(n < sizeof(vlong))
1013 le2vlong(&delta, p);
1014 todset(delta, 0, 0);
1017 if(n < sizeof(vlong)+sizeof(long))
1019 p = le2vlong(&delta, p);
1020 le2long(&period, p);
1021 todset(-1, delta, period);
1024 if(n < sizeof(uvlong))
1026 le2vlong(&fasthz, p);