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