1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 #include "pool.h"
8
9 #include <authsrv.h>
10
11 void (*consdebug)(void) = nil;
12 void (*screenputs)(char*, int) = nil;
13
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;
20
21 int panicking;
22
23 static struct
24 {
25 QLock;
26
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 */
31
32 int count;
33 int ctlpoff;
34
35 /* a place to save up characters at interrupt time before dumping them in the queue */
36 Lock lockputc;
37 char istage[1024];
38 char *iw;
39 char *ir;
40 char *ie;
41 } kbd = {
42 .iw = kbd.istage,
43 .ir = kbd.istage,
44 .ie = kbd.istage + sizeof(kbd.istage),
45 };
46
47 char *sysname;
48 vlong fasthz;
49
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);
55
56 enum
57 {
58 CMhalt,
59 CMreboot,
60 CMpanic,
61 };
62
63 Cmdtab rebootmsg[] =
64 {
65 CMhalt, "halt", 1,
66 CMreboot, "reboot", 0,
67 CMpanic, "panic", 0,
68 };
69
70 void
printinit(void)71 printinit(void)
72 {
73 lineq = qopen(2*1024, 0, nil, nil);
74 if(lineq == nil)
75 panic("printinit");
76 qnoblock(lineq, 1);
77 }
78
79 int
consactive(void)80 consactive(void)
81 {
82 if(serialoq)
83 return qlen(serialoq) > 0;
84 return 0;
85 }
86
87 void
prflush(void)88 prflush(void)
89 {
90 ulong now;
91
92 now = m->ticks;
93 while(consactive())
94 if(m->ticks - now >= HZ)
95 break;
96 }
97
98 /*
99 * Log console output so it can be retrieved via /dev/kmesg.
100 * This is good for catching boot-time messages after the fact.
101 */
102 struct {
103 Lock lk;
104 char buf[KMESGSIZE];
105 uint n;
106 } kmesg;
107
108 static void
kmesgputs(char * str,int n)109 kmesgputs(char *str, int n)
110 {
111 uint nn, d;
112
113 ilock(&kmesg.lk);
114 /* take the tail of huge writes */
115 if(n > sizeof kmesg.buf){
116 d = n - sizeof kmesg.buf;
117 str += d;
118 n -= d;
119 }
120
121 /* slide the buffer down to make room */
122 nn = kmesg.n;
123 if(nn + n >= sizeof kmesg.buf){
124 d = nn + n - sizeof kmesg.buf;
125 if(d)
126 memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
127 nn -= d;
128 }
129
130 /* copy the data in */
131 memmove(kmesg.buf+nn, str, n);
132 nn += n;
133 kmesg.n = nn;
134 iunlock(&kmesg.lk);
135 }
136
137 /*
138 * Print a string on the console. Convert \n to \r\n for serial
139 * line consoles. Locking of the queues is left up to the screen
140 * or uart code. Multi-line messages to serial consoles may get
141 * interspersed with other messages.
142 */
143 static void
putstrn0(char * str,int n,int usewrite)144 putstrn0(char *str, int n, int usewrite)
145 {
146 int m;
147 char *t;
148
149 if(!islo())
150 usewrite = 0;
151
152 /*
153 * how many different output devices do we need?
154 */
155 kmesgputs(str, n);
156
157 /*
158 * if someone is reading /dev/kprint,
159 * put the message there.
160 * if not and there's an attached bit mapped display,
161 * put the message there.
162 *
163 * if there's a serial line being used as a console,
164 * put the message there.
165 */
166 if(kprintoq != nil && !qisclosed(kprintoq)){
167 if(usewrite)
168 qwrite(kprintoq, str, n);
169 else
170 qiwrite(kprintoq, str, n);
171 }else if(screenputs != nil)
172 screenputs(str, n);
173
174 if(serialoq == nil){
175 uartputs(str, n);
176 return;
177 }
178
179 while(n > 0) {
180 t = memchr(str, '\n', n);
181 if(t && !kbd.raw) {
182 m = t-str;
183 if(usewrite){
184 qwrite(serialoq, str, m);
185 qwrite(serialoq, "\r\n", 2);
186 } else {
187 qiwrite(serialoq, str, m);
188 qiwrite(serialoq, "\r\n", 2);
189 }
190 n -= m+1;
191 str = t+1;
192 } else {
193 if(usewrite)
194 qwrite(serialoq, str, n);
195 else
196 qiwrite(serialoq, str, n);
197 break;
198 }
199 }
200 }
201
202 void
putstrn(char * str,int n)203 putstrn(char *str, int n)
204 {
205 putstrn0(str, n, 0);
206 }
207
208 int noprint;
209
210 int
print(char * fmt,...)211 print(char *fmt, ...)
212 {
213 int n;
214 va_list arg;
215 char buf[PRINTSIZE];
216
217 if(noprint)
218 return -1;
219
220 va_start(arg, fmt);
221 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
222 va_end(arg);
223
224 if(!normalprint) {
225 if(0) iprint("\nprint called too early from %#lux\n",
226 getcallerpc(&fmt));
227 iprint("%.*s", n, buf);
228 } else
229 putstrn(buf, n);
230
231 return n;
232 }
233
234 /*
235 * Want to interlock iprints to avoid interlaced output on
236 * multiprocessor, but don't want to deadlock if one processor
237 * dies during print and another has something important to say.
238 * Make a good faith effort.
239 */
240 static Lock iprintlock;
241 static int
iprintcanlock(Lock * l)242 iprintcanlock(Lock *l)
243 {
244 int i;
245
246 for(i=0; i<1000; i++){
247 if(canlock(l))
248 return 1;
249 if(l->m == MACHP(m->machno))
250 return 0;
251 microdelay(100);
252 }
253 return 0;
254 }
255
256 int
iprint(char * fmt,...)257 iprint(char *fmt, ...)
258 {
259 int n, s, locked;
260 va_list arg;
261 char buf[PRINTSIZE];
262
263 s = splhi();
264 va_start(arg, fmt);
265 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
266 va_end(arg);
267 locked = iprintcanlock(&iprintlock);
268 if(screenputs != nil && iprintscreenputs)
269 screenputs(buf, n);
270 if(consuart == nil || consuart->phys == nil ||
271 consuart->phys->putc == nil)
272 _uartputs(buf, n);
273 else
274 uartputs(buf, n);
275 if(locked)
276 unlock(&iprintlock);
277 splx(s);
278
279 return n;
280 }
281
282 void
panic(char * fmt,...)283 panic(char *fmt, ...)
284 {
285 int n, s;
286 va_list arg;
287 char buf[PRINTSIZE];
288
289 kprintoq = nil; /* don't try to write to /dev/kprint */
290
291 if(panicking)
292 for(;;);
293 panicking = 1;
294
295 s = splhi();
296 delay(2000);
297 strcpy(buf, "\npanic: ");
298 va_start(arg, fmt);
299 n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
300 va_end(arg);
301 iprint("%s\n", buf);
302 if(consdebug)
303 (*consdebug)();
304 splx(s);
305 prflush();
306 USED(n);
307 // buf[n] = '\n';
308 // putstrn(buf, n+1); /* redundant */
309 // dumpstack();
310
311 delay(2000);
312 exit(1);
313 }
314
315 /* libmp at least contains a few calls to sysfatal; simulate with panic */
316 void
sysfatal(char * fmt,...)317 sysfatal(char *fmt, ...)
318 {
319 char err[256];
320 va_list arg;
321
322 va_start(arg, fmt);
323 vseprint(err, err + sizeof err, fmt, arg);
324 va_end(arg);
325 panic("sysfatal: %s", err);
326 }
327
328 void
_assert(char * fmt)329 _assert(char *fmt)
330 {
331 panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
332 }
333
334 int
pprint(char * fmt,...)335 pprint(char *fmt, ...)
336 {
337 int n;
338 Chan *c;
339 va_list arg;
340 char buf[2*PRINTSIZE];
341
342 if(up == nil || up->fgrp == nil)
343 return 0;
344
345 c = up->fgrp->fd[2];
346 if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
347 return 0;
348 n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
349 va_start(arg, fmt);
350 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
351 va_end(arg);
352
353 if(waserror())
354 return 0;
355 devtab[c->type]->write(c, buf, n, c->offset);
356 poperror();
357
358 lock(c);
359 c->offset += n;
360 unlock(c);
361
362 return n;
363 }
364
365 static void
echoscreen(char * buf,int n)366 echoscreen(char *buf, int n)
367 {
368 char *e, *p;
369 char ebuf[128];
370 int x;
371
372 p = ebuf;
373 e = ebuf + sizeof(ebuf) - 4;
374 while(n-- > 0){
375 if(p >= e){
376 screenputs(ebuf, p - ebuf);
377 p = ebuf;
378 }
379 x = *buf++;
380 if(x == 0x15){
381 *p++ = '^';
382 *p++ = 'U';
383 *p++ = '\n';
384 } else
385 *p++ = x;
386 }
387 if(p != ebuf)
388 screenputs(ebuf, p - ebuf);
389 }
390
391 static void
echoserialoq(char * buf,int n)392 echoserialoq(char *buf, int n)
393 {
394 int x;
395 char *e, *p;
396 char ebuf[128];
397
398 p = ebuf;
399 e = ebuf + sizeof(ebuf) - 4;
400 while(n-- > 0){
401 if(p >= e){
402 qiwrite(serialoq, ebuf, p - ebuf);
403 p = ebuf;
404 }
405 x = *buf++;
406 if(x == '\n'){
407 *p++ = '\r';
408 *p++ = '\n';
409 } else if(x == 0x15){
410 *p++ = '^';
411 *p++ = 'U';
412 *p++ = '\n';
413 } else
414 *p++ = x;
415 }
416 if(p != ebuf)
417 qiwrite(serialoq, ebuf, p - ebuf);
418 }
419
420 static void
echo(char * buf,int n)421 echo(char *buf, int n)
422 {
423 static int ctrlt, pid;
424 int x;
425 char *e, *p;
426
427 if(n == 0)
428 return;
429
430 e = buf+n;
431 for(p = buf; p < e; p++){
432 switch(*p){
433 case 0x10: /* ^P */
434 if(cpuserver && !kbd.ctlpoff){
435 active.exiting = 1;
436 return;
437 }
438 break;
439 case 0x14: /* ^T */
440 ctrlt++;
441 if(ctrlt > 2)
442 ctrlt = 2;
443 continue;
444 }
445
446 if(ctrlt != 2)
447 continue;
448
449 /* ^T escapes */
450 ctrlt = 0;
451 switch(*p){
452 case 'S':
453 x = splhi();
454 dumpstack();
455 procdump();
456 splx(x);
457 return;
458 case 's':
459 dumpstack();
460 return;
461 case 'x':
462 xsummary();
463 ixsummary();
464 mallocsummary();
465 // memorysummary();
466 pagersummary();
467 return;
468 case 'd':
469 if(consdebug == nil)
470 consdebug = rdb;
471 else
472 consdebug = nil;
473 print("consdebug now %#p\n", consdebug);
474 return;
475 case 'D':
476 if(consdebug == nil)
477 consdebug = rdb;
478 consdebug();
479 return;
480 case 'p':
481 x = spllo();
482 procdump();
483 splx(x);
484 return;
485 case 'q':
486 scheddump();
487 return;
488 case 'k':
489 killbig("^t ^t k");
490 return;
491 case 'r':
492 exit(0);
493 return;
494 }
495 }
496
497 qproduce(kbdq, buf, n);
498 if(kbd.raw)
499 return;
500 kmesgputs(buf, n);
501 if(screenputs != nil)
502 echoscreen(buf, n);
503 if(serialoq)
504 echoserialoq(buf, n);
505 }
506
507 /*
508 * Called by a uart interrupt for console input.
509 *
510 * turn '\r' into '\n' before putting it into the queue.
511 */
512 int
kbdcr2nl(Queue *,int ch)513 kbdcr2nl(Queue*, int ch)
514 {
515 char *next;
516
517 ilock(&kbd.lockputc); /* just a mutex */
518 if(ch == '\r' && !kbd.raw)
519 ch = '\n';
520 next = kbd.iw+1;
521 if(next >= kbd.ie)
522 next = kbd.istage;
523 if(next != kbd.ir){
524 *kbd.iw = ch;
525 kbd.iw = next;
526 }
527 iunlock(&kbd.lockputc);
528 return 0;
529 }
530
531 /*
532 * Put character, possibly a rune, into read queue at interrupt time.
533 * Called at interrupt time to process a character.
534 */
535 int
kbdputc(Queue *,int ch)536 kbdputc(Queue*, int ch)
537 {
538 int i, n;
539 char buf[3];
540 Rune r;
541 char *next;
542
543 if(kbd.ir == nil)
544 return 0; /* in case we're not inited yet */
545
546 ilock(&kbd.lockputc); /* just a mutex */
547 r = ch;
548 n = runetochar(buf, &r);
549 for(i = 0; i < n; i++){
550 next = kbd.iw+1;
551 if(next >= kbd.ie)
552 next = kbd.istage;
553 if(next == kbd.ir)
554 break;
555 *kbd.iw = buf[i];
556 kbd.iw = next;
557 }
558 iunlock(&kbd.lockputc);
559 return 0;
560 }
561
562 /*
563 * we save up input characters till clock time to reduce
564 * per character interrupt overhead.
565 */
566 static void
kbdputcclock(void)567 kbdputcclock(void)
568 {
569 char *iw;
570
571 /* this amortizes cost of qproduce */
572 if(kbd.iw != kbd.ir){
573 iw = kbd.iw;
574 if(iw < kbd.ir){
575 echo(kbd.ir, kbd.ie-kbd.ir);
576 kbd.ir = kbd.istage;
577 }
578 if(kbd.ir != iw){
579 echo(kbd.ir, iw-kbd.ir);
580 kbd.ir = iw;
581 }
582 }
583 }
584
585 enum{
586 Qdir,
587 Qbintime,
588 Qcons,
589 Qconsctl,
590 Qcputime,
591 Qdrivers,
592 Qkmesg,
593 Qkprint,
594 Qhostdomain,
595 Qhostowner,
596 Qnull,
597 Qosversion,
598 Qpgrpid,
599 Qpid,
600 Qppid,
601 Qrandom,
602 Qreboot,
603 Qswap,
604 Qsysname,
605 Qsysstat,
606 Qtime,
607 Quser,
608 Qzero,
609 Qconfig,
610 };
611
612 enum
613 {
614 VLNUMSIZE= 22,
615 };
616
617 static Dirtab consdir[]={
618 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
619 "bintime", {Qbintime}, 24, 0664,
620 "cons", {Qcons}, 0, 0660,
621 "consctl", {Qconsctl}, 0, 0220,
622 "cputime", {Qcputime}, 6*NUMSIZE, 0444,
623 "drivers", {Qdrivers}, 0, 0444,
624 "hostdomain", {Qhostdomain}, DOMLEN, 0664,
625 "hostowner", {Qhostowner}, 0, 0664,
626 "kmesg", {Qkmesg}, 0, 0440,
627 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,
628 "null", {Qnull}, 0, 0666,
629 "osversion", {Qosversion}, 0, 0444,
630 "pgrpid", {Qpgrpid}, NUMSIZE, 0444,
631 "pid", {Qpid}, NUMSIZE, 0444,
632 "ppid", {Qppid}, NUMSIZE, 0444,
633 "random", {Qrandom}, 0, 0444,
634 "reboot", {Qreboot}, 0, 0664,
635 "swap", {Qswap}, 0, 0664,
636 "sysname", {Qsysname}, 0, 0664,
637 "sysstat", {Qsysstat}, 0, 0666,
638 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
639 "user", {Quser}, 0, 0666,
640 "zero", {Qzero}, 0, 0444,
641 "config", {Qconfig}, 0, 0444,
642 };
643
644 int
readnum(ulong off,char * buf,ulong n,ulong val,int size)645 readnum(ulong off, char *buf, ulong n, ulong val, int size)
646 {
647 char tmp[64];
648
649 snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
650 tmp[size-1] = ' ';
651 if(off >= size)
652 return 0;
653 if(off+n > size)
654 n = size-off;
655 memmove(buf, tmp+off, n);
656 return n;
657 }
658
659 int
readstr(ulong off,char * buf,ulong n,char * str)660 readstr(ulong off, char *buf, ulong n, char *str)
661 {
662 int size;
663
664 size = strlen(str);
665 if(off >= size)
666 return 0;
667 if(off+n > size)
668 n = size-off;
669 memmove(buf, str+off, n);
670 return n;
671 }
672
673 static void
consinit(void)674 consinit(void)
675 {
676 todinit();
677 randominit();
678 /*
679 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
680 * processing it every 22 ms should be fine
681 */
682 addclock0link(kbdputcclock, 22);
683 }
684
685 static Chan*
consattach(char * spec)686 consattach(char *spec)
687 {
688 return devattach('c', spec);
689 }
690
691 static Walkqid*
conswalk(Chan * c,Chan * nc,char ** name,int nname)692 conswalk(Chan *c, Chan *nc, char **name, int nname)
693 {
694 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
695 }
696
697 static int
consstat(Chan * c,uchar * dp,int n)698 consstat(Chan *c, uchar *dp, int n)
699 {
700 return devstat(c, dp, n, consdir, nelem(consdir), devgen);
701 }
702
703 static Chan*
consopen(Chan * c,int omode)704 consopen(Chan *c, int omode)
705 {
706 c->aux = nil;
707 c = devopen(c, omode, consdir, nelem(consdir), devgen);
708 switch((ulong)c->qid.path){
709 case Qconsctl:
710 incref(&kbd.ctl);
711 break;
712
713 case Qkprint:
714 if(tas(&kprintinuse) != 0){
715 c->flag &= ~COPEN;
716 error(Einuse);
717 }
718 if(kprintoq == nil){
719 kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
720 if(kprintoq == nil){
721 c->flag &= ~COPEN;
722 error(Enomem);
723 }
724 qnoblock(kprintoq, 1);
725 }else
726 qreopen(kprintoq);
727 c->iounit = qiomaxatomic;
728 break;
729 }
730 return c;
731 }
732
733 static void
consclose(Chan * c)734 consclose(Chan *c)
735 {
736 switch((ulong)c->qid.path){
737 /* last close of control file turns off raw */
738 case Qconsctl:
739 if(c->flag&COPEN){
740 if(decref(&kbd.ctl) == 0)
741 kbd.raw = 0;
742 }
743 break;
744
745 /* close of kprint allows other opens */
746 case Qkprint:
747 if(c->flag & COPEN){
748 kprintinuse = 0;
749 qhangup(kprintoq, nil);
750 }
751 break;
752 }
753 }
754
755 static long
consread(Chan * c,void * buf,long n,vlong off)756 consread(Chan *c, void *buf, long n, vlong off)
757 {
758 ulong l;
759 Mach *mp;
760 char *b, *bp, ch;
761 char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
762 int i, k, id, send;
763 vlong offset = off;
764 extern char configfile[];
765
766 if(n <= 0)
767 return n;
768
769 switch((ulong)c->qid.path){
770 case Qdir:
771 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
772
773 case Qcons:
774 qlock(&kbd);
775 if(waserror()) {
776 qunlock(&kbd);
777 nexterror();
778 }
779 while(!qcanread(lineq)){
780 if(qread(kbdq, &ch, 1) == 0)
781 continue;
782 send = 0;
783 if(ch == 0){
784 /* flush output on rawoff -> rawon */
785 if(kbd.x > 0)
786 send = !qcanread(kbdq);
787 }else if(kbd.raw){
788 kbd.line[kbd.x++] = ch;
789 send = !qcanread(kbdq);
790 }else{
791 switch(ch){
792 case '\b':
793 if(kbd.x > 0)
794 kbd.x--;
795 break;
796 case 0x15: /* ^U */
797 kbd.x = 0;
798 break;
799 case '\n':
800 case 0x04: /* ^D */
801 send = 1;
802 default:
803 if(ch != 0x04)
804 kbd.line[kbd.x++] = ch;
805 break;
806 }
807 }
808 if(send || kbd.x == sizeof kbd.line){
809 qwrite(lineq, kbd.line, kbd.x);
810 kbd.x = 0;
811 }
812 }
813 n = qread(lineq, buf, n);
814 qunlock(&kbd);
815 poperror();
816 return n;
817
818 case Qcputime:
819 k = offset;
820 if(k >= 6*NUMSIZE)
821 return 0;
822 if(k+n > 6*NUMSIZE)
823 n = 6*NUMSIZE - k;
824 /* easiest to format in a separate buffer and copy out */
825 for(i=0; i<6 && NUMSIZE*i<k+n; i++){
826 l = up->time[i];
827 if(i == TReal)
828 l = MACHP(0)->ticks - l;
829 l = TK2MS(l);
830 readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
831 }
832 memmove(buf, tmp+k, n);
833 return n;
834
835 case Qkmesg:
836 /*
837 * This is unlocked to avoid tying up a process
838 * that's writing to the buffer. kmesg.n never
839 * gets smaller, so worst case the reader will
840 * see a slurred buffer.
841 */
842 if(off >= kmesg.n)
843 n = 0;
844 else{
845 if(off+n > kmesg.n)
846 n = kmesg.n - off;
847 memmove(buf, kmesg.buf+off, n);
848 }
849 return n;
850
851 case Qkprint:
852 return qread(kprintoq, buf, n);
853
854 case Qpgrpid:
855 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
856
857 case Qpid:
858 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
859
860 case Qppid:
861 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
862
863 case Qtime:
864 return readtime((ulong)offset, buf, n);
865
866 case Qbintime:
867 return readbintime(buf, n);
868
869 case Qhostowner:
870 return readstr((ulong)offset, buf, n, eve);
871
872 case Qhostdomain:
873 return readstr((ulong)offset, buf, n, hostdomain);
874
875 case Quser:
876 return readstr((ulong)offset, buf, n, up->user);
877
878 case Qnull:
879 return 0;
880
881 case Qconfig:
882 return readstr((ulong)offset, buf, n, configfile);
883
884 case Qsysstat:
885 b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */
886 bp = b;
887 for(id = 0; id < 32; id++) {
888 if(active.machs & (1<<id)) {
889 mp = MACHP(id);
890 readnum(0, bp, NUMSIZE, id, NUMSIZE);
891 bp += NUMSIZE;
892 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
893 bp += NUMSIZE;
894 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
895 bp += NUMSIZE;
896 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
897 bp += NUMSIZE;
898 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
899 bp += NUMSIZE;
900 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
901 bp += NUMSIZE;
902 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
903 bp += NUMSIZE;
904 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
905 bp += NUMSIZE;
906 readnum(0, bp, NUMSIZE,
907 (mp->perf.avg_inidle*100)/mp->perf.period,
908 NUMSIZE);
909 bp += NUMSIZE;
910 readnum(0, bp, NUMSIZE,
911 (mp->perf.avg_inintr*100)/mp->perf.period,
912 NUMSIZE);
913 bp += NUMSIZE;
914 *bp++ = '\n';
915 }
916 }
917 if(waserror()){
918 free(b);
919 nexterror();
920 }
921 n = readstr((ulong)offset, buf, n, b);
922 free(b);
923 poperror();
924 return n;
925
926 case Qswap:
927 snprint(tmp, sizeof tmp,
928 "%lud memory\n"
929 "%d pagesize\n"
930 "%lud kernel\n"
931 "%lud/%lud user\n"
932 "%lud/%lud swap\n"
933 "%lud/%lud kernel malloc\n"
934 "%lud/%lud kernel draw\n",
935 conf.npage*BY2PG,
936 BY2PG,
937 conf.npage-conf.upages,
938 palloc.user-palloc.freecount, palloc.user,
939 conf.nswap-swapalloc.free, conf.nswap,
940 mainmem->cursize, mainmem->maxsize,
941 imagmem->cursize, imagmem->maxsize);
942
943 return readstr((ulong)offset, buf, n, tmp);
944
945 case Qsysname:
946 if(sysname == nil)
947 return 0;
948 return readstr((ulong)offset, buf, n, sysname);
949
950 case Qrandom:
951 return randomread(buf, n);
952
953 case Qdrivers:
954 b = malloc(READSTR);
955 if(b == nil)
956 error(Enomem);
957 k = 0;
958 for(i = 0; devtab[i] != nil; i++)
959 k += snprint(b+k, READSTR-k, "#%C %s\n",
960 devtab[i]->dc, devtab[i]->name);
961 if(waserror()){
962 free(b);
963 nexterror();
964 }
965 n = readstr((ulong)offset, buf, n, b);
966 free(b);
967 poperror();
968 return n;
969
970 case Qzero:
971 memset(buf, 0, n);
972 return n;
973
974 case Qosversion:
975 snprint(tmp, sizeof tmp, "2000");
976 n = readstr((ulong)offset, buf, n, tmp);
977 return n;
978
979 default:
980 print("consread %#llux\n", c->qid.path);
981 error(Egreg);
982 }
983 return -1; /* never reached */
984 }
985
986 static long
conswrite(Chan * c,void * va,long n,vlong off)987 conswrite(Chan *c, void *va, long n, vlong off)
988 {
989 char buf[256], ch;
990 long l, bp;
991 char *a;
992 Mach *mp;
993 int id, fd;
994 Chan *swc;
995 ulong offset;
996 Cmdbuf *cb;
997 Cmdtab *ct;
998
999 a = va;
1000 offset = off;
1001
1002 switch((ulong)c->qid.path){
1003 case Qcons:
1004 /*
1005 * Can't page fault in putstrn, so copy the data locally.
1006 */
1007 l = n;
1008 while(l > 0){
1009 bp = l;
1010 if(bp > sizeof buf)
1011 bp = sizeof buf;
1012 memmove(buf, a, bp);
1013 putstrn0(buf, bp, 1);
1014 a += bp;
1015 l -= bp;
1016 }
1017 break;
1018
1019 case Qconsctl:
1020 if(n >= sizeof(buf))
1021 n = sizeof(buf)-1;
1022 strncpy(buf, a, n);
1023 buf[n] = 0;
1024 for(a = buf; a;){
1025 if(strncmp(a, "rawon", 5) == 0){
1026 kbd.raw = 1;
1027 /* clumsy hack - wake up reader */
1028 ch = 0;
1029 qwrite(kbdq, &ch, 1);
1030 } else if(strncmp(a, "rawoff", 6) == 0){
1031 kbd.raw = 0;
1032 } else if(strncmp(a, "ctlpon", 6) == 0){
1033 kbd.ctlpoff = 0;
1034 } else if(strncmp(a, "ctlpoff", 7) == 0){
1035 kbd.ctlpoff = 1;
1036 }
1037 if(a = strchr(a, ' '))
1038 a++;
1039 }
1040 break;
1041
1042 case Qtime:
1043 if(!iseve())
1044 error(Eperm);
1045 return writetime(a, n);
1046
1047 case Qbintime:
1048 if(!iseve())
1049 error(Eperm);
1050 return writebintime(a, n);
1051
1052 case Qhostowner:
1053 return hostownerwrite(a, n);
1054
1055 case Qhostdomain:
1056 return hostdomainwrite(a, n);
1057
1058 case Quser:
1059 return userwrite(a, n);
1060
1061 case Qnull:
1062 break;
1063
1064 case Qconfig:
1065 error(Eperm);
1066 break;
1067
1068 case Qreboot:
1069 if(!iseve())
1070 error(Eperm);
1071 cb = parsecmd(a, n);
1072
1073 if(waserror()) {
1074 free(cb);
1075 nexterror();
1076 }
1077 ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
1078 switch(ct->index) {
1079 case CMhalt:
1080 reboot(nil, 0, 0);
1081 break;
1082 case CMreboot:
1083 rebootcmd(cb->nf-1, cb->f+1);
1084 break;
1085 case CMpanic:
1086 *(ulong*)0=0;
1087 panic("/dev/reboot");
1088 }
1089 poperror();
1090 free(cb);
1091 break;
1092
1093 case Qsysstat:
1094 for(id = 0; id < 32; id++) {
1095 if(active.machs & (1<<id)) {
1096 mp = MACHP(id);
1097 mp->cs = 0;
1098 mp->intr = 0;
1099 mp->syscall = 0;
1100 mp->pfault = 0;
1101 mp->tlbfault = 0;
1102 mp->tlbpurge = 0;
1103 }
1104 }
1105 break;
1106
1107 case Qswap:
1108 if(n >= sizeof buf)
1109 error(Egreg);
1110 memmove(buf, va, n); /* so we can NUL-terminate */
1111 buf[n] = 0;
1112 /* start a pager if not already started */
1113 if(strncmp(buf, "start", 5) == 0){
1114 kickpager();
1115 break;
1116 }
1117 if(!iseve())
1118 error(Eperm);
1119 if(buf[0]<'0' || '9'<buf[0])
1120 error(Ebadarg);
1121 fd = strtoul(buf, 0, 0);
1122 swc = fdtochan(fd, -1, 1, 1);
1123 setswapchan(swc);
1124 break;
1125
1126 case Qsysname:
1127 if(offset != 0)
1128 error(Ebadarg);
1129 if(n <= 0 || n >= sizeof buf)
1130 error(Ebadarg);
1131 strncpy(buf, a, n);
1132 buf[n] = 0;
1133 if(buf[n-1] == '\n')
1134 buf[n-1] = 0;
1135 kstrdup(&sysname, buf);
1136 break;
1137
1138 default:
1139 print("conswrite: %#llux\n", c->qid.path);
1140 error(Egreg);
1141 }
1142 return n;
1143 }
1144
1145 Dev consdevtab = {
1146 'c',
1147 "cons",
1148
1149 devreset,
1150 consinit,
1151 devshutdown,
1152 consattach,
1153 conswalk,
1154 consstat,
1155 consopen,
1156 devcreate,
1157 consclose,
1158 consread,
1159 devbread,
1160 conswrite,
1161 devbwrite,
1162 devremove,
1163 devwstat,
1164 };
1165
1166 static ulong randn;
1167
1168 static void
seedrand(void)1169 seedrand(void)
1170 {
1171 if(!waserror()){
1172 randomread((void*)&randn, sizeof(randn));
1173 poperror();
1174 }
1175 }
1176
1177 int
nrand(int n)1178 nrand(int n)
1179 {
1180 if(randn == 0)
1181 seedrand();
1182 randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
1183 return (randn>>16) % n;
1184 }
1185
1186 int
rand(void)1187 rand(void)
1188 {
1189 nrand(1);
1190 return randn;
1191 }
1192
1193 static uvlong uvorder = 0x0001020304050607ULL;
1194
1195 static uchar*
le2vlong(vlong * to,uchar * f)1196 le2vlong(vlong *to, uchar *f)
1197 {
1198 uchar *t, *o;
1199 int i;
1200
1201 t = (uchar*)to;
1202 o = (uchar*)&uvorder;
1203 for(i = 0; i < sizeof(vlong); i++)
1204 t[o[i]] = f[i];
1205 return f+sizeof(vlong);
1206 }
1207
1208 static uchar*
vlong2le(uchar * t,vlong from)1209 vlong2le(uchar *t, vlong from)
1210 {
1211 uchar *f, *o;
1212 int i;
1213
1214 f = (uchar*)&from;
1215 o = (uchar*)&uvorder;
1216 for(i = 0; i < sizeof(vlong); i++)
1217 t[i] = f[o[i]];
1218 return t+sizeof(vlong);
1219 }
1220
1221 static long order = 0x00010203;
1222
1223 static uchar*
le2long(long * to,uchar * f)1224 le2long(long *to, uchar *f)
1225 {
1226 uchar *t, *o;
1227 int i;
1228
1229 t = (uchar*)to;
1230 o = (uchar*)ℴ
1231 for(i = 0; i < sizeof(long); i++)
1232 t[o[i]] = f[i];
1233 return f+sizeof(long);
1234 }
1235
1236 static uchar*
long2le(uchar * t,long from)1237 long2le(uchar *t, long from)
1238 {
1239 uchar *f, *o;
1240 int i;
1241
1242 f = (uchar*)&from;
1243 o = (uchar*)ℴ
1244 for(i = 0; i < sizeof(long); i++)
1245 t[i] = f[o[i]];
1246 return t+sizeof(long);
1247 }
1248
1249 char *Ebadtimectl = "bad time control";
1250
1251 /*
1252 * like the old #c/time but with added info. Return
1253 *
1254 * secs nanosecs fastticks fasthz
1255 */
1256 static int
readtime(ulong off,char * buf,int n)1257 readtime(ulong off, char *buf, int n)
1258 {
1259 vlong nsec, ticks;
1260 long sec;
1261 char str[7*NUMSIZE];
1262
1263 nsec = todget(&ticks);
1264 if(fasthz == 0LL)
1265 fastticks((uvlong*)&fasthz);
1266 sec = nsec/1000000000ULL;
1267 snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
1268 NUMSIZE-1, sec,
1269 VLNUMSIZE-1, nsec,
1270 VLNUMSIZE-1, ticks,
1271 VLNUMSIZE-1, fasthz);
1272 return readstr(off, buf, n, str);
1273 }
1274
1275 /*
1276 * set the time in seconds
1277 */
1278 static int
writetime(char * buf,int n)1279 writetime(char *buf, int n)
1280 {
1281 char b[13];
1282 long i;
1283 vlong now;
1284
1285 if(n >= sizeof(b))
1286 error(Ebadtimectl);
1287 strncpy(b, buf, n);
1288 b[n] = 0;
1289 i = strtol(b, 0, 0);
1290 if(i <= 0)
1291 error(Ebadtimectl);
1292 now = i*1000000000LL;
1293 todset(now, 0, 0);
1294 return n;
1295 }
1296
1297 /*
1298 * read binary time info. all numbers are little endian.
1299 * ticks and nsec are syncronized.
1300 */
1301 static int
readbintime(char * buf,int n)1302 readbintime(char *buf, int n)
1303 {
1304 int i;
1305 vlong nsec, ticks;
1306 uchar *b = (uchar*)buf;
1307
1308 i = 0;
1309 if(fasthz == 0LL)
1310 fastticks((uvlong*)&fasthz);
1311 nsec = todget(&ticks);
1312 if(n >= 3*sizeof(uvlong)){
1313 vlong2le(b+2*sizeof(uvlong), fasthz);
1314 i += sizeof(uvlong);
1315 }
1316 if(n >= 2*sizeof(uvlong)){
1317 vlong2le(b+sizeof(uvlong), ticks);
1318 i += sizeof(uvlong);
1319 }
1320 if(n >= 8){
1321 vlong2le(b, nsec);
1322 i += sizeof(vlong);
1323 }
1324 return i;
1325 }
1326
1327 /*
1328 * set any of the following
1329 * - time in nsec
1330 * - nsec trim applied over some seconds
1331 * - clock frequency
1332 */
1333 static int
writebintime(char * buf,int n)1334 writebintime(char *buf, int n)
1335 {
1336 uchar *p;
1337 vlong delta;
1338 long period;
1339
1340 n--;
1341 p = (uchar*)buf + 1;
1342 switch(*buf){
1343 case 'n':
1344 if(n < sizeof(vlong))
1345 error(Ebadtimectl);
1346 le2vlong(&delta, p);
1347 todset(delta, 0, 0);
1348 break;
1349 case 'd':
1350 if(n < sizeof(vlong)+sizeof(long))
1351 error(Ebadtimectl);
1352 p = le2vlong(&delta, p);
1353 le2long(&period, p);
1354 todset(-1, delta, period);
1355 break;
1356 case 'f':
1357 if(n < sizeof(uvlong))
1358 error(Ebadtimectl);
1359 le2vlong(&fasthz, p);
1360 if(fasthz <= 0)
1361 error(Ebadtimectl);
1362 todsetfreq(fasthz);
1363 break;
1364 }
1365 return n;
1366 }
1367