2 #include "../port/lib.h"
6 #include "../port/error.h"
11 void (*consdebug)(void) = nil;
12 void (*screenputs)(char*, int) = nil;
14 Queue* kbdq; /* unprocessed console input */
15 Queue* lineq; /* processed console input */
16 Queue* serialoq; /* serial console output */
17 Queue* kprintoq; /* console output, for /dev/kprint */
18 ulong kprintinuse; /* test and set whether /dev/kprint is open */
19 int iprintscreenputs = 1;
27 int raw; /* true if we shouldn't process input */
28 Ref ctl; /* number of opens to the control file */
29 int x; /* index into line */
30 char line[1024]; /* current input line */
35 /* a place to save up characters at interrupt time before dumping them in the queue */
44 .ie = kbd.istage + sizeof(kbd.istage),
50 static void seedrand(void);
51 static int readtime(ulong, char*, int);
52 static int readbintime(char*, int);
53 static int writetime(char*, int);
54 static int writebintime(char*, int);
66 CMreboot, "reboot", 0,
73 lineq = qopen(2*1024, 0, nil, nil);
83 return qlen(serialoq) > 0;
94 if(m->ticks - now >= HZ)
99 * Log console output so it can be retrieved via /dev/kmesg.
100 * This is good for catching boot-time messages after the fact.
104 // char buf[16384]; /* normal */
105 char buf[256*1024]; /* for acpi debugging */
110 kmesgputs(char *str, int n)
115 /* take the tail of huge writes */
116 if(n > sizeof kmesg.buf){
117 d = n - sizeof kmesg.buf;
122 /* slide the buffer down to make room */
124 if(nn + n >= sizeof kmesg.buf){
125 d = nn + n - sizeof kmesg.buf;
127 memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
131 /* copy the data in */
132 memmove(kmesg.buf+nn, str, n);
139 * Print a string on the console. Convert \n to \r\n for serial
140 * line consoles. Locking of the queues is left up to the screen
141 * or uart code. Multi-line messages to serial consoles may get
142 * interspersed with other messages.
145 putstrn0(char *str, int n, int usewrite)
154 * how many different output devices do we need?
159 * if someone is reading /dev/kprint,
160 * put the message there.
161 * if not and there's an attached bit mapped display,
162 * put the message there.
164 * if there's a serial line being used as a console,
165 * put the message there.
167 if(kprintoq != nil && !qisclosed(kprintoq)){
169 qwrite(kprintoq, str, n);
171 qiwrite(kprintoq, str, n);
172 }else if(screenputs != nil)
181 t = memchr(str, '\n', n);
185 qwrite(serialoq, str, m);
186 qwrite(serialoq, "\r\n", 2);
188 qiwrite(serialoq, str, m);
189 qiwrite(serialoq, "\r\n", 2);
195 qwrite(serialoq, str, n);
197 qiwrite(serialoq, str, n);
204 putstrn(char *str, int n)
212 print(char *fmt, ...)
222 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
230 * Want to interlock iprints to avoid interlaced output on
231 * multiprocessor, but don't want to deadlock if one processor
232 * dies during print and another has something important to say.
233 * Make a good faith effort.
235 static Lock iprintlock;
237 iprintcanlock(Lock *l)
241 for(i=0; i<1000; i++){
244 if(l->m == MACHP(m->machno))
252 iprint(char *fmt, ...)
260 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
262 locked = iprintcanlock(&iprintlock);
263 if(screenputs != nil && iprintscreenputs)
274 panic(char *fmt, ...)
280 kprintoq = nil; /* don't try to write to /dev/kprint */
287 strcpy(buf, "panic: ");
289 n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
303 /* libmp at least contains a few calls to sysfatal; simulate with panic */
305 sysfatal(char *fmt, ...)
311 vseprint(err, err + sizeof err, fmt, arg);
313 panic("sysfatal: %s", err);
319 panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
323 pprint(char *fmt, ...)
328 char buf[2*PRINTSIZE];
330 if(up == nil || up->fgrp == nil)
334 if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
336 n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
338 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
343 devtab[c->type]->write(c, buf, n, c->offset);
354 echoscreen(char *buf, int n)
361 e = ebuf + sizeof(ebuf) - 4;
364 screenputs(ebuf, p - ebuf);
376 screenputs(ebuf, p - ebuf);
380 echoserialoq(char *buf, int n)
387 e = ebuf + sizeof(ebuf) - 4;
390 qiwrite(serialoq, ebuf, p - ebuf);
397 } else if(x == 0x15){
405 qiwrite(serialoq, ebuf, p - ebuf);
409 echo(char *buf, int n)
411 static int ctrlt, pid;
419 for(p = buf; p < e; p++){
422 if(cpuserver && !kbd.ctlpoff){
461 print("consdebug now %#p\n", consdebug);
485 qproduce(kbdq, buf, n);
489 if(screenputs != nil)
492 echoserialoq(buf, n);
496 * Called by a uart interrupt for console input.
498 * turn '\r' into '\n' before putting it into the queue.
501 kbdcr2nl(Queue*, int ch)
505 ilock(&kbd.lockputc); /* just a mutex */
506 if(ch == '\r' && !kbd.raw)
515 iunlock(&kbd.lockputc);
520 * Put character, possibly a rune, into read queue at interrupt time.
521 * Called at interrupt time to process a character.
524 kbdputc(Queue*, int ch)
532 return 0; /* in case we're not inited yet */
534 ilock(&kbd.lockputc); /* just a mutex */
536 n = runetochar(buf, &r);
537 for(i = 0; i < n; i++){
546 iunlock(&kbd.lockputc);
551 * we save up input characters till clock time to reduce
552 * per character interrupt overhead.
559 /* this amortizes cost of qproduce */
560 if(kbd.iw != kbd.ir){
563 echo(kbd.ir, kbd.ie-kbd.ir);
567 echo(kbd.ir, iw-kbd.ir);
605 static Dirtab consdir[]={
606 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
607 "bintime", {Qbintime}, 24, 0664,
608 "cons", {Qcons}, 0, 0660,
609 "consctl", {Qconsctl}, 0, 0220,
610 "cputime", {Qcputime}, 6*NUMSIZE, 0444,
611 "drivers", {Qdrivers}, 0, 0444,
612 "hostdomain", {Qhostdomain}, DOMLEN, 0664,
613 "hostowner", {Qhostowner}, 0, 0664,
614 "kmesg", {Qkmesg}, 0, 0440,
615 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,
616 "null", {Qnull}, 0, 0666,
617 "osversion", {Qosversion}, 0, 0444,
618 "pgrpid", {Qpgrpid}, NUMSIZE, 0444,
619 "pid", {Qpid}, NUMSIZE, 0444,
620 "ppid", {Qppid}, NUMSIZE, 0444,
621 "random", {Qrandom}, 0, 0444,
622 "reboot", {Qreboot}, 0, 0664,
623 "swap", {Qswap}, 0, 0664,
624 "sysname", {Qsysname}, 0, 0664,
625 "sysstat", {Qsysstat}, 0, 0666,
626 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
627 "user", {Quser}, 0, 0666,
628 "zero", {Qzero}, 0, 0444,
629 "config", {Qconfig}, 0, 0444,
633 readnum(ulong off, char *buf, ulong n, ulong val, int size)
637 snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
643 memmove(buf, tmp+off, n);
648 readstr(ulong off, char *buf, ulong n, char *str)
657 memmove(buf, str+off, n);
667 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
668 * processing it every 22 ms should be fine
670 addclock0link(kbdputcclock, 22);
674 consattach(char *spec)
676 return devattach('c', spec);
680 conswalk(Chan *c, Chan *nc, char **name, int nname)
682 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
686 consstat(Chan *c, uchar *dp, int n)
688 return devstat(c, dp, n, consdir, nelem(consdir), devgen);
692 consopen(Chan *c, int omode)
695 c = devopen(c, omode, consdir, nelem(consdir), devgen);
696 switch((ulong)c->qid.path){
702 if(tas(&kprintinuse) != 0){
707 kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
712 qnoblock(kprintoq, 1);
715 c->iounit = qiomaxatomic;
724 switch((ulong)c->qid.path){
725 /* last close of control file turns off raw */
728 if(decref(&kbd.ctl) == 0)
733 /* close of kprint allows other opens */
737 qhangup(kprintoq, nil);
744 consread(Chan *c, void *buf, long n, vlong off)
749 char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
752 extern char configfile[];
757 switch((ulong)c->qid.path){
759 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
767 while(!qcanread(lineq)){
768 if(qread(kbdq, &ch, 1) == 0)
772 /* flush output on rawoff -> rawon */
774 send = !qcanread(kbdq);
776 kbd.line[kbd.x++] = ch;
777 send = !qcanread(kbdq);
792 kbd.line[kbd.x++] = ch;
796 if(send || kbd.x == sizeof kbd.line){
797 qwrite(lineq, kbd.line, kbd.x);
801 n = qread(lineq, buf, n);
812 /* easiest to format in a separate buffer and copy out */
813 for(i=0; i<6 && NUMSIZE*i<k+n; i++){
816 l = MACHP(0)->ticks - l;
818 readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
820 memmove(buf, tmp+k, n);
825 * This is unlocked to avoid tying up a process
826 * that's writing to the buffer. kmesg.n never
827 * gets smaller, so worst case the reader will
828 * see a slurred buffer.
835 memmove(buf, kmesg.buf+off, n);
840 return qread(kprintoq, buf, n);
843 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
846 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
849 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
852 return readtime((ulong)offset, buf, n);
855 return readbintime(buf, n);
858 return readstr((ulong)offset, buf, n, eve);
861 return readstr((ulong)offset, buf, n, hostdomain);
864 return readstr((ulong)offset, buf, n, up->user);
870 return readstr((ulong)offset, buf, n, configfile);
873 b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */
875 for(id = 0; id < 32; id++) {
876 if(active.machs & (1<<id)) {
878 readnum(0, bp, NUMSIZE, id, NUMSIZE);
880 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
882 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
884 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
886 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
888 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
890 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
892 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
894 readnum(0, bp, NUMSIZE,
895 (mp->perf.avg_inidle*100)/mp->perf.period,
898 readnum(0, bp, NUMSIZE,
899 (mp->perf.avg_inintr*100)/mp->perf.period,
909 n = readstr((ulong)offset, buf, n, b);
915 snprint(tmp, sizeof tmp,
921 "%lud/%lud kernel malloc\n"
922 "%lud/%lud kernel draw\n",
925 conf.npage-conf.upages,
926 palloc.user-palloc.freecount, palloc.user,
927 conf.nswap-swapalloc.free, conf.nswap,
928 mainmem->cursize, mainmem->maxsize,
929 imagmem->cursize, imagmem->maxsize);
931 return readstr((ulong)offset, buf, n, tmp);
936 return readstr((ulong)offset, buf, n, sysname);
939 return randomread(buf, n);
946 for(i = 0; devtab[i] != nil; i++)
947 k += snprint(b+k, READSTR-k, "#%C %s\n",
948 devtab[i]->dc, devtab[i]->name);
953 n = readstr((ulong)offset, buf, n, b);
963 snprint(tmp, sizeof tmp, "2000");
964 n = readstr((ulong)offset, buf, n, tmp);
968 print("consread %#llux\n", c->qid.path);
971 return -1; /* never reached */
975 conswrite(Chan *c, void *va, long n, vlong off)
990 switch((ulong)c->qid.path){
993 * Can't page fault in putstrn, so copy the data locally.
1000 memmove(buf, a, bp);
1001 putstrn0(buf, bp, 1);
1008 if(n >= sizeof(buf))
1013 if(strncmp(a, "rawon", 5) == 0){
1015 /* clumsy hack - wake up reader */
1017 qwrite(kbdq, &ch, 1);
1018 } else if(strncmp(a, "rawoff", 6) == 0){
1020 } else if(strncmp(a, "ctlpon", 6) == 0){
1022 } else if(strncmp(a, "ctlpoff", 7) == 0){
1025 if(a = strchr(a, ' '))
1033 return writetime(a, n);
1038 return writebintime(a, n);
1041 return hostownerwrite(a, n);
1044 return hostdomainwrite(a, n);
1047 return userwrite(a, n);
1059 cb = parsecmd(a, n);
1065 ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
1071 rebootcmd(cb->nf-1, cb->f+1);
1075 panic("/dev/reboot");
1082 for(id = 0; id < 32; id++) {
1083 if(active.machs & (1<<id)) {
1098 memmove(buf, va, n); /* so we can NUL-terminate */
1100 /* start a pager if not already started */
1101 if(strncmp(buf, "start", 5) == 0){
1107 if(buf[0]<'0' || '9'<buf[0])
1109 fd = strtoul(buf, 0, 0);
1110 swc = fdtochan(fd, -1, 1, 1);
1117 if(n <= 0 || n >= sizeof buf)
1121 if(buf[n-1] == '\n')
1123 kstrdup(&sysname, buf);
1127 print("conswrite: %#llux\n", c->qid.path);
1160 randomread((void*)&randn, sizeof(randn));
1170 randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
1171 return (randn>>16) % n;
1181 static uvlong uvorder = 0x0001020304050607ULL;
1184 le2vlong(vlong *to, uchar *f)
1190 o = (uchar*)&uvorder;
1191 for(i = 0; i < sizeof(vlong); i++)
1193 return f+sizeof(vlong);
1197 vlong2le(uchar *t, vlong from)
1203 o = (uchar*)&uvorder;
1204 for(i = 0; i < sizeof(vlong); i++)
1206 return t+sizeof(vlong);
1209 static long order = 0x00010203;
1212 le2long(long *to, uchar *f)
1219 for(i = 0; i < sizeof(long); i++)
1221 return f+sizeof(long);
1225 long2le(uchar *t, long from)
1232 for(i = 0; i < sizeof(long); i++)
1234 return t+sizeof(long);
1237 char *Ebadtimectl = "bad time control";
1240 * like the old #c/time but with added info. Return
1242 * secs nanosecs fastticks fasthz
1245 readtime(ulong off, char *buf, int n)
1249 char str[7*NUMSIZE];
1251 nsec = todget(&ticks);
1253 fastticks((uvlong*)&fasthz);
1254 sec = nsec/1000000000ULL;
1255 snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
1259 VLNUMSIZE-1, fasthz);
1260 return readstr(off, buf, n, str);
1264 * set the time in seconds
1267 writetime(char *buf, int n)
1277 i = strtol(b, 0, 0);
1280 now = i*1000000000LL;
1286 * read binary time info. all numbers are little endian.
1287 * ticks and nsec are syncronized.
1290 readbintime(char *buf, int n)
1294 uchar *b = (uchar*)buf;
1298 fastticks((uvlong*)&fasthz);
1299 nsec = todget(&ticks);
1300 if(n >= 3*sizeof(uvlong)){
1301 vlong2le(b+2*sizeof(uvlong), fasthz);
1302 i += sizeof(uvlong);
1304 if(n >= 2*sizeof(uvlong)){
1305 vlong2le(b+sizeof(uvlong), ticks);
1306 i += sizeof(uvlong);
1316 * set any of the following
1318 * - nsec trim applied over some seconds
1322 writebintime(char *buf, int n)
1329 p = (uchar*)buf + 1;
1332 if(n < sizeof(vlong))
1334 le2vlong(&delta, p);
1335 todset(delta, 0, 0);
1338 if(n < sizeof(vlong)+sizeof(long))
1340 p = le2vlong(&delta, p);
1341 le2long(&period, p);
1342 todset(-1, delta, period);
1345 if(n < sizeof(uvlong))
1347 le2vlong(&fasthz, p);