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 putstrn(buf, n);
224
225 return n;
226 }
227
228 /*
229 * Want to interlock iprints to avoid interlaced output on
230 * multiprocessor, but don't want to deadlock if one processor
231 * dies during print and another has something important to say.
232 * Make a good faith effort.
233 */
234 static Lock iprintlock;
235 static int
iprintcanlock(Lock * l)236 iprintcanlock(Lock *l)
237 {
238 int i;
239
240 for(i=0; i<1000; i++){
241 if(canlock(l))
242 return 1;
243 if(l->m == MACHP(m->machno))
244 return 0;
245 microdelay(100);
246 }
247 return 0;
248 }
249
250 int
iprint(char * fmt,...)251 iprint(char *fmt, ...)
252 {
253 int n, s, locked;
254 va_list arg;
255 char buf[PRINTSIZE];
256
257 s = splhi();
258 va_start(arg, fmt);
259 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
260 va_end(arg);
261 locked = iprintcanlock(&iprintlock);
262 if(screenputs != nil && iprintscreenputs)
263 screenputs(buf, n);
264 uartputs(buf, n);
265 if(locked)
266 unlock(&iprintlock);
267 splx(s);
268
269 return n;
270 }
271
272 void
panic(char * fmt,...)273 panic(char *fmt, ...)
274 {
275 int n, s;
276 va_list arg;
277 char buf[PRINTSIZE];
278
279 kprintoq = nil; /* don't try to write to /dev/kprint */
280
281 if(panicking)
282 for(;;);
283 panicking = 1;
284
285 s = splhi();
286 strcpy(buf, "panic: ");
287 va_start(arg, fmt);
288 n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
289 va_end(arg);
290 iprint("%s\n", buf);
291 if(consdebug)
292 (*consdebug)();
293 splx(s);
294 prflush();
295 buf[n] = '\n';
296 putstrn(buf, n+1);
297 dumpstack();
298
299 exit(1);
300 }
301
302 /* libmp at least contains a few calls to sysfatal; simulate with panic */
303 void
sysfatal(char * fmt,...)304 sysfatal(char *fmt, ...)
305 {
306 char err[256];
307 va_list arg;
308
309 va_start(arg, fmt);
310 vseprint(err, err + sizeof err, fmt, arg);
311 va_end(arg);
312 panic("sysfatal: %s", err);
313 }
314
315 void
_assert(char * fmt)316 _assert(char *fmt)
317 {
318 panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
319 }
320
321 int
pprint(char * fmt,...)322 pprint(char *fmt, ...)
323 {
324 int n;
325 Chan *c;
326 va_list arg;
327 char buf[2*PRINTSIZE];
328
329 if(up == nil || up->fgrp == nil)
330 return 0;
331
332 c = up->fgrp->fd[2];
333 if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
334 return 0;
335 n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
336 va_start(arg, fmt);
337 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
338 va_end(arg);
339
340 if(waserror())
341 return 0;
342 devtab[c->type]->write(c, buf, n, c->offset);
343 poperror();
344
345 lock(c);
346 c->offset += n;
347 unlock(c);
348
349 return n;
350 }
351
352 static void
echoscreen(char * buf,int n)353 echoscreen(char *buf, int n)
354 {
355 char *e, *p;
356 char ebuf[128];
357 int x;
358
359 p = ebuf;
360 e = ebuf + sizeof(ebuf) - 4;
361 while(n-- > 0){
362 if(p >= e){
363 screenputs(ebuf, p - ebuf);
364 p = ebuf;
365 }
366 x = *buf++;
367 if(x == 0x15){
368 *p++ = '^';
369 *p++ = 'U';
370 *p++ = '\n';
371 } else
372 *p++ = x;
373 }
374 if(p != ebuf)
375 screenputs(ebuf, p - ebuf);
376 }
377
378 static void
echoserialoq(char * buf,int n)379 echoserialoq(char *buf, int n)
380 {
381 char *e, *p;
382 char ebuf[128];
383 int x;
384
385 p = ebuf;
386 e = ebuf + sizeof(ebuf) - 4;
387 while(n-- > 0){
388 if(p >= e){
389 qiwrite(serialoq, ebuf, p - ebuf);
390 p = ebuf;
391 }
392 x = *buf++;
393 if(x == '\n'){
394 *p++ = '\r';
395 *p++ = '\n';
396 } else if(x == 0x15){
397 *p++ = '^';
398 *p++ = 'U';
399 *p++ = '\n';
400 } else
401 *p++ = x;
402 }
403 if(p != ebuf)
404 qiwrite(serialoq, ebuf, p - ebuf);
405 }
406
407 static void
echo(char * buf,int n)408 echo(char *buf, int n)
409 {
410 static int ctrlt, pid;
411 int x;
412 char *e, *p;
413
414 if(n == 0)
415 return;
416
417 e = buf+n;
418 for(p = buf; p < e; p++){
419 switch(*p){
420 case 0x10: /* ^P */
421 if(cpuserver && !kbd.ctlpoff){
422 active.exiting = 1;
423 return;
424 }
425 break;
426 case 0x14: /* ^T */
427 ctrlt++;
428 if(ctrlt > 2)
429 ctrlt = 2;
430 continue;
431 }
432
433 if(ctrlt != 2)
434 continue;
435
436 /* ^T escapes */
437 ctrlt = 0;
438 switch(*p){
439 case 'S':
440 x = splhi();
441 dumpstack();
442 procdump();
443 splx(x);
444 return;
445 case 's':
446 dumpstack();
447 return;
448 case 'x':
449 xsummary();
450 ixsummary();
451 mallocsummary();
452 // memorysummary();
453 pagersummary();
454 return;
455 case 'd':
456 if(consdebug == nil)
457 consdebug = rdb;
458 else
459 consdebug = nil;
460 print("consdebug now %#p\n", consdebug);
461 return;
462 case 'D':
463 if(consdebug == nil)
464 consdebug = rdb;
465 consdebug();
466 return;
467 case 'p':
468 x = spllo();
469 procdump();
470 splx(x);
471 return;
472 case 'q':
473 scheddump();
474 return;
475 case 'k':
476 killbig("^t ^t k");
477 return;
478 case 'r':
479 exit(0);
480 return;
481 }
482 }
483
484 qproduce(kbdq, buf, n);
485 if(kbd.raw)
486 return;
487 kmesgputs(buf, n);
488 if(screenputs != nil)
489 echoscreen(buf, n);
490 if(serialoq)
491 echoserialoq(buf, n);
492 }
493
494 /*
495 * Called by a uart interrupt for console input.
496 *
497 * turn '\r' into '\n' before putting it into the queue.
498 */
499 int
kbdcr2nl(Queue *,int ch)500 kbdcr2nl(Queue*, int ch)
501 {
502 char *next;
503
504 ilock(&kbd.lockputc); /* just a mutex */
505 if(ch == '\r' && !kbd.raw)
506 ch = '\n';
507 next = kbd.iw+1;
508 if(next >= kbd.ie)
509 next = kbd.istage;
510 if(next != kbd.ir){
511 *kbd.iw = ch;
512 kbd.iw = next;
513 }
514 iunlock(&kbd.lockputc);
515 return 0;
516 }
517
518 /*
519 * Put character, possibly a rune, into read queue at interrupt time.
520 * Called at interrupt time to process a character.
521 */
522 int
kbdputc(Queue *,int ch)523 kbdputc(Queue*, int ch)
524 {
525 int i, n;
526 char buf[3];
527 Rune r;
528 char *next;
529
530 if(kbd.ir == nil)
531 return 0; /* in case we're not inited yet */
532
533 ilock(&kbd.lockputc); /* just a mutex */
534 r = ch;
535 n = runetochar(buf, &r);
536 for(i = 0; i < n; i++){
537 next = kbd.iw+1;
538 if(next >= kbd.ie)
539 next = kbd.istage;
540 if(next == kbd.ir)
541 break;
542 *kbd.iw = buf[i];
543 kbd.iw = next;
544 }
545 iunlock(&kbd.lockputc);
546 return 0;
547 }
548
549 /*
550 * we save up input characters till clock time to reduce
551 * per character interrupt overhead.
552 */
553 static void
kbdputcclock(void)554 kbdputcclock(void)
555 {
556 char *iw;
557
558 /* this amortizes cost of qproduce */
559 if(kbd.iw != kbd.ir){
560 iw = kbd.iw;
561 if(iw < kbd.ir){
562 echo(kbd.ir, kbd.ie-kbd.ir);
563 kbd.ir = kbd.istage;
564 }
565 if(kbd.ir != iw){
566 echo(kbd.ir, iw-kbd.ir);
567 kbd.ir = iw;
568 }
569 }
570 }
571
572 enum{
573 Qdir,
574 Qbintime,
575 Qcons,
576 Qconsctl,
577 Qcputime,
578 Qdrivers,
579 Qkmesg,
580 Qkprint,
581 Qhostdomain,
582 Qhostowner,
583 Qnull,
584 Qosversion,
585 Qpgrpid,
586 Qpid,
587 Qppid,
588 Qrandom,
589 Qreboot,
590 Qswap,
591 Qsysname,
592 Qsysstat,
593 Qtime,
594 Quser,
595 Qzero,
596 Qconfig,
597 };
598
599 enum
600 {
601 VLNUMSIZE= 22,
602 };
603
604 static Dirtab consdir[]={
605 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
606 "bintime", {Qbintime}, 24, 0664,
607 "cons", {Qcons}, 0, 0660,
608 "consctl", {Qconsctl}, 0, 0220,
609 "cputime", {Qcputime}, 6*NUMSIZE, 0444,
610 "drivers", {Qdrivers}, 0, 0444,
611 "hostdomain", {Qhostdomain}, DOMLEN, 0664,
612 "hostowner", {Qhostowner}, 0, 0664,
613 "kmesg", {Qkmesg}, 0, 0440,
614 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,
615 "null", {Qnull}, 0, 0666,
616 "osversion", {Qosversion}, 0, 0444,
617 "pgrpid", {Qpgrpid}, NUMSIZE, 0444,
618 "pid", {Qpid}, NUMSIZE, 0444,
619 "ppid", {Qppid}, NUMSIZE, 0444,
620 "random", {Qrandom}, 0, 0444,
621 "reboot", {Qreboot}, 0, 0660,
622 "swap", {Qswap}, 0, 0664,
623 "sysname", {Qsysname}, 0, 0664,
624 "sysstat", {Qsysstat}, 0, 0666,
625 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
626 "user", {Quser}, 0, 0666,
627 "zero", {Qzero}, 0, 0444,
628 "config", {Qconfig}, 0, 0444,
629 };
630
631 int
readnum(ulong off,char * buf,ulong n,ulong val,int size)632 readnum(ulong off, char *buf, ulong n, ulong val, int size)
633 {
634 char tmp[64];
635
636 snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
637 tmp[size-1] = ' ';
638 if(off >= size)
639 return 0;
640 if(off+n > size)
641 n = size-off;
642 memmove(buf, tmp+off, n);
643 return n;
644 }
645
646 int
readstr(ulong off,char * buf,ulong n,char * str)647 readstr(ulong off, char *buf, ulong n, char *str)
648 {
649 int size;
650
651 size = strlen(str);
652 if(off >= size)
653 return 0;
654 if(off+n > size)
655 n = size-off;
656 memmove(buf, str+off, n);
657 return n;
658 }
659
660 static void
consinit(void)661 consinit(void)
662 {
663 todinit();
664 randominit();
665 /*
666 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
667 * processing it every 22 ms should be fine
668 */
669 addclock0link(kbdputcclock, 22);
670 }
671
672 static Chan*
consattach(char * spec)673 consattach(char *spec)
674 {
675 return devattach('c', spec);
676 }
677
678 static Walkqid*
conswalk(Chan * c,Chan * nc,char ** name,int nname)679 conswalk(Chan *c, Chan *nc, char **name, int nname)
680 {
681 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
682 }
683
684 static int
consstat(Chan * c,uchar * dp,int n)685 consstat(Chan *c, uchar *dp, int n)
686 {
687 return devstat(c, dp, n, consdir, nelem(consdir), devgen);
688 }
689
690 static Chan*
consopen(Chan * c,int omode)691 consopen(Chan *c, int omode)
692 {
693 c->aux = nil;
694 c = devopen(c, omode, consdir, nelem(consdir), devgen);
695 switch((ulong)c->qid.path){
696 case Qconsctl:
697 incref(&kbd.ctl);
698 break;
699
700 case Qkprint:
701 if(tas(&kprintinuse) != 0){
702 c->flag &= ~COPEN;
703 error(Einuse);
704 }
705 if(kprintoq == nil){
706 kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
707 if(kprintoq == nil){
708 c->flag &= ~COPEN;
709 error(Enomem);
710 }
711 qnoblock(kprintoq, 1);
712 }else
713 qreopen(kprintoq);
714 c->iounit = qiomaxatomic;
715 break;
716 }
717 return c;
718 }
719
720 static void
consclose(Chan * c)721 consclose(Chan *c)
722 {
723 switch((ulong)c->qid.path){
724 /* last close of control file turns off raw */
725 case Qconsctl:
726 if(c->flag&COPEN){
727 if(decref(&kbd.ctl) == 0)
728 kbd.raw = 0;
729 }
730 break;
731
732 /* close of kprint allows other opens */
733 case Qkprint:
734 if(c->flag & COPEN){
735 kprintinuse = 0;
736 qhangup(kprintoq, nil);
737 }
738 break;
739 }
740 }
741
742 static long
consread(Chan * c,void * buf,long n,vlong off)743 consread(Chan *c, void *buf, long n, vlong off)
744 {
745 ulong l;
746 Mach *mp;
747 char *b, *bp, ch;
748 char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
749 int i, k, id, send;
750 vlong offset = off;
751 extern char configfile[];
752
753 if(n <= 0)
754 return n;
755
756 switch((ulong)c->qid.path){
757 case Qdir:
758 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
759
760 case Qcons:
761 qlock(&kbd);
762 if(waserror()) {
763 qunlock(&kbd);
764 nexterror();
765 }
766 while(!qcanread(lineq)){
767 if(qread(kbdq, &ch, 1) == 0)
768 continue;
769 send = 0;
770 if(ch == 0){
771 /* flush output on rawoff -> rawon */
772 if(kbd.x > 0)
773 send = !qcanread(kbdq);
774 }else if(kbd.raw){
775 kbd.line[kbd.x++] = ch;
776 send = !qcanread(kbdq);
777 }else{
778 switch(ch){
779 case '\b':
780 if(kbd.x > 0)
781 kbd.x--;
782 break;
783 case 0x15: /* ^U */
784 kbd.x = 0;
785 break;
786 case '\n':
787 case 0x04: /* ^D */
788 send = 1;
789 default:
790 if(ch != 0x04)
791 kbd.line[kbd.x++] = ch;
792 break;
793 }
794 }
795 if(send || kbd.x == sizeof kbd.line){
796 qwrite(lineq, kbd.line, kbd.x);
797 kbd.x = 0;
798 }
799 }
800 n = qread(lineq, buf, n);
801 qunlock(&kbd);
802 poperror();
803 return n;
804
805 case Qcputime:
806 k = offset;
807 if(k >= 6*NUMSIZE)
808 return 0;
809 if(k+n > 6*NUMSIZE)
810 n = 6*NUMSIZE - k;
811 /* easiest to format in a separate buffer and copy out */
812 for(i=0; i<6 && NUMSIZE*i<k+n; i++){
813 l = up->time[i];
814 if(i == TReal)
815 l = MACHP(0)->ticks - l;
816 l = TK2MS(l);
817 readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
818 }
819 memmove(buf, tmp+k, n);
820 return n;
821
822 case Qkmesg:
823 /*
824 * This is unlocked to avoid tying up a process
825 * that's writing to the buffer. kmesg.n never
826 * gets smaller, so worst case the reader will
827 * see a slurred buffer.
828 */
829 if(off >= kmesg.n)
830 n = 0;
831 else{
832 if(off+n > kmesg.n)
833 n = kmesg.n - off;
834 memmove(buf, kmesg.buf+off, n);
835 }
836 return n;
837
838 case Qkprint:
839 return qread(kprintoq, buf, n);
840
841 case Qpgrpid:
842 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
843
844 case Qpid:
845 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
846
847 case Qppid:
848 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
849
850 case Qtime:
851 return readtime((ulong)offset, buf, n);
852
853 case Qbintime:
854 return readbintime(buf, n);
855
856 case Qhostowner:
857 return readstr((ulong)offset, buf, n, eve);
858
859 case Qhostdomain:
860 return readstr((ulong)offset, buf, n, hostdomain);
861
862 case Quser:
863 return readstr((ulong)offset, buf, n, up->user);
864
865 case Qnull:
866 return 0;
867
868 case Qconfig:
869 return readstr((ulong)offset, buf, n, configfile);
870
871 case Qsysstat:
872 b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */
873 bp = b;
874 for(id = 0; id < 32; id++) {
875 if(active.machs & (1<<id)) {
876 mp = MACHP(id);
877 readnum(0, bp, NUMSIZE, id, NUMSIZE);
878 bp += NUMSIZE;
879 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
880 bp += NUMSIZE;
881 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
882 bp += NUMSIZE;
883 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
884 bp += NUMSIZE;
885 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
886 bp += NUMSIZE;
887 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
888 bp += NUMSIZE;
889 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
890 bp += NUMSIZE;
891 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
892 bp += NUMSIZE;
893 readnum(0, bp, NUMSIZE,
894 (mp->perf.avg_inidle*100)/mp->perf.period,
895 NUMSIZE);
896 bp += NUMSIZE;
897 readnum(0, bp, NUMSIZE,
898 (mp->perf.avg_inintr*100)/mp->perf.period,
899 NUMSIZE);
900 bp += NUMSIZE;
901 *bp++ = '\n';
902 }
903 }
904 if(waserror()){
905 free(b);
906 nexterror();
907 }
908 n = readstr((ulong)offset, buf, n, b);
909 free(b);
910 poperror();
911 return n;
912
913 case Qswap:
914 snprint(tmp, sizeof tmp,
915 "%lud memory\n"
916 "%d pagesize\n"
917 "%lud kernel\n"
918 "%lud/%lud user\n"
919 "%lud/%lud swap\n"
920 "%lud/%lud kernel malloc\n"
921 "%lud/%lud kernel draw\n",
922 conf.npage*BY2PG,
923 BY2PG,
924 conf.npage-conf.upages,
925 palloc.user-palloc.freecount, palloc.user,
926 conf.nswap-swapalloc.free, conf.nswap,
927 mainmem->cursize, mainmem->maxsize,
928 imagmem->cursize, imagmem->maxsize);
929
930 return readstr((ulong)offset, buf, n, tmp);
931
932 case Qsysname:
933 if(sysname == nil)
934 return 0;
935 return readstr((ulong)offset, buf, n, sysname);
936
937 case Qrandom:
938 return randomread(buf, n);
939
940 case Qdrivers:
941 b = malloc(READSTR);
942 if(b == nil)
943 error(Enomem);
944 k = 0;
945 for(i = 0; devtab[i] != nil; i++)
946 k += snprint(b+k, READSTR-k, "#%C %s\n",
947 devtab[i]->dc, devtab[i]->name);
948 if(waserror()){
949 free(b);
950 nexterror();
951 }
952 n = readstr((ulong)offset, buf, n, b);
953 free(b);
954 poperror();
955 return n;
956
957 case Qzero:
958 memset(buf, 0, n);
959 return n;
960
961 case Qosversion:
962 snprint(tmp, sizeof tmp, "2000");
963 n = readstr((ulong)offset, buf, n, tmp);
964 return n;
965
966 default:
967 print("consread %#llux\n", c->qid.path);
968 error(Egreg);
969 }
970 return -1; /* never reached */
971 }
972
973 static long
conswrite(Chan * c,void * va,long n,vlong off)974 conswrite(Chan *c, void *va, long n, vlong off)
975 {
976 char buf[256], ch;
977 long l, bp;
978 char *a;
979 Mach *mp;
980 int id, fd;
981 Chan *swc;
982 ulong offset;
983 Cmdbuf *cb;
984 Cmdtab *ct;
985
986 a = va;
987 offset = off;
988
989 switch((ulong)c->qid.path){
990 case Qcons:
991 /*
992 * Can't page fault in putstrn, so copy the data locally.
993 */
994 l = n;
995 while(l > 0){
996 bp = l;
997 if(bp > sizeof buf)
998 bp = sizeof buf;
999 memmove(buf, a, bp);
1000 putstrn0(buf, bp, 1);
1001 a += bp;
1002 l -= bp;
1003 }
1004 break;
1005
1006 case Qconsctl:
1007 if(n >= sizeof(buf))
1008 n = sizeof(buf)-1;
1009 strncpy(buf, a, n);
1010 buf[n] = 0;
1011 for(a = buf; a;){
1012 if(strncmp(a, "rawon", 5) == 0){
1013 kbd.raw = 1;
1014 /* clumsy hack - wake up reader */
1015 ch = 0;
1016 qwrite(kbdq, &ch, 1);
1017 } else if(strncmp(a, "rawoff", 6) == 0){
1018 kbd.raw = 0;
1019 } else if(strncmp(a, "ctlpon", 6) == 0){
1020 kbd.ctlpoff = 0;
1021 } else if(strncmp(a, "ctlpoff", 7) == 0){
1022 kbd.ctlpoff = 1;
1023 }
1024 if(a = strchr(a, ' '))
1025 a++;
1026 }
1027 break;
1028
1029 case Qtime:
1030 if(!iseve())
1031 error(Eperm);
1032 return writetime(a, n);
1033
1034 case Qbintime:
1035 if(!iseve())
1036 error(Eperm);
1037 return writebintime(a, n);
1038
1039 case Qhostowner:
1040 return hostownerwrite(a, n);
1041
1042 case Qhostdomain:
1043 return hostdomainwrite(a, n);
1044
1045 case Quser:
1046 return userwrite(a, n);
1047
1048 case Qnull:
1049 break;
1050
1051 case Qconfig:
1052 error(Eperm);
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