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