FreeBSD/Linux Kernel Cross Reference
sys/port/devcons.c
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
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
80 consactive(void)
81 {
82 if(serialoq)
83 return qlen(serialoq) > 0;
84 return 0;
85 }
86
87 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[16384];
105 uint n;
106 } kmesg;
107
108 static void
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
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
203 putstrn(char *str, int n)
204 {
205 putstrn0(str, n, 0);
206 }
207
208 int noprint;
209
210 int
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
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
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
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
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
316 _assert(char *fmt)
317 {
318 panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
319 }
320
321 int
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
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
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
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
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
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
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 };
597
598 enum
599 {
600 VLNUMSIZE= 22,
601 };
602
603 static Dirtab consdir[]={
604 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
605 "bintime", {Qbintime}, 24, 0664,
606 "cons", {Qcons}, 0, 0660,
607 "consctl", {Qconsctl}, 0, 0220,
608 "cputime", {Qcputime}, 6*NUMSIZE, 0444,
609 "drivers", {Qdrivers}, 0, 0444,
610 "hostdomain", {Qhostdomain}, DOMLEN, 0664,
611 "hostowner", {Qhostowner}, 0, 0664,
612 "kmesg", {Qkmesg}, 0, 0440,
613 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,
614 "null", {Qnull}, 0, 0666,
615 "osversion", {Qosversion}, 0, 0444,
616 "pgrpid", {Qpgrpid}, NUMSIZE, 0444,
617 "pid", {Qpid}, NUMSIZE, 0444,
618 "ppid", {Qppid}, NUMSIZE, 0444,
619 "random", {Qrandom}, 0, 0444,
620 "reboot", {Qreboot}, 0, 0664,
621 "swap", {Qswap}, 0, 0664,
622 "sysname", {Qsysname}, 0, 0664,
623 "sysstat", {Qsysstat}, 0, 0666,
624 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
625 "user", {Quser}, 0, 0666,
626 "zero", {Qzero}, 0, 0444,
627 };
628
629 int
630 readnum(ulong off, char *buf, ulong n, ulong val, int size)
631 {
632 char tmp[64];
633
634 snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
635 tmp[size-1] = ' ';
636 if(off >= size)
637 return 0;
638 if(off+n > size)
639 n = size-off;
640 memmove(buf, tmp+off, n);
641 return n;
642 }
643
644 int
645 readstr(ulong off, char *buf, ulong n, char *str)
646 {
647 int size;
648
649 size = strlen(str);
650 if(off >= size)
651 return 0;
652 if(off+n > size)
653 n = size-off;
654 memmove(buf, str+off, n);
655 return n;
656 }
657
658 static void
659 consinit(void)
660 {
661 todinit();
662 randominit();
663 /*
664 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
665 * processing it every 22 ms should be fine
666 */
667 addclock0link(kbdputcclock, 22);
668 }
669
670 static Chan*
671 consattach(char *spec)
672 {
673 return devattach('c', spec);
674 }
675
676 static Walkqid*
677 conswalk(Chan *c, Chan *nc, char **name, int nname)
678 {
679 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
680 }
681
682 static int
683 consstat(Chan *c, uchar *dp, int n)
684 {
685 return devstat(c, dp, n, consdir, nelem(consdir), devgen);
686 }
687
688 static Chan*
689 consopen(Chan *c, int omode)
690 {
691 c->aux = nil;
692 c = devopen(c, omode, consdir, nelem(consdir), devgen);
693 switch((ulong)c->qid.path){
694 case Qconsctl:
695 incref(&kbd.ctl);
696 break;
697
698 case Qkprint:
699 if(tas(&kprintinuse) != 0){
700 c->flag &= ~COPEN;
701 error(Einuse);
702 }
703 if(kprintoq == nil){
704 kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
705 if(kprintoq == nil){
706 c->flag &= ~COPEN;
707 error(Enomem);
708 }
709 qnoblock(kprintoq, 1);
710 }else
711 qreopen(kprintoq);
712 c->iounit = qiomaxatomic;
713 break;
714 }
715 return c;
716 }
717
718 static void
719 consclose(Chan *c)
720 {
721 switch((ulong)c->qid.path){
722 /* last close of control file turns off raw */
723 case Qconsctl:
724 if(c->flag&COPEN){
725 if(decref(&kbd.ctl) == 0)
726 kbd.raw = 0;
727 }
728 break;
729
730 /* close of kprint allows other opens */
731 case Qkprint:
732 if(c->flag & COPEN){
733 kprintinuse = 0;
734 qhangup(kprintoq, nil);
735 }
736 break;
737 }
738 }
739
740 static long
741 consread(Chan *c, void *buf, long n, vlong off)
742 {
743 ulong l;
744 Mach *mp;
745 char *b, *bp, ch;
746 char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
747 int i, k, id, send;
748 vlong offset = off;
749
750 if(n <= 0)
751 return n;
752
753 switch((ulong)c->qid.path){
754 case Qdir:
755 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
756
757 case Qcons:
758 qlock(&kbd);
759 if(waserror()) {
760 qunlock(&kbd);
761 nexterror();
762 }
763 while(!qcanread(lineq)){
764 if(qread(kbdq, &ch, 1) == 0)
765 continue;
766 send = 0;
767 if(ch == 0){
768 /* flush output on rawoff -> rawon */
769 if(kbd.x > 0)
770 send = !qcanread(kbdq);
771 }else if(kbd.raw){
772 kbd.line[kbd.x++] = ch;
773 send = !qcanread(kbdq);
774 }else{
775 switch(ch){
776 case '\b':
777 if(kbd.x > 0)
778 kbd.x--;
779 break;
780 case 0x15: /* ^U */
781 kbd.x = 0;
782 break;
783 case '\n':
784 case 0x04: /* ^D */
785 send = 1;
786 default:
787 if(ch != 0x04)
788 kbd.line[kbd.x++] = ch;
789 break;
790 }
791 }
792 if(send || kbd.x == sizeof kbd.line){
793 qwrite(lineq, kbd.line, kbd.x);
794 kbd.x = 0;
795 }
796 }
797 n = qread(lineq, buf, n);
798 qunlock(&kbd);
799 poperror();
800 return n;
801
802 case Qcputime:
803 k = offset;
804 if(k >= 6*NUMSIZE)
805 return 0;
806 if(k+n > 6*NUMSIZE)
807 n = 6*NUMSIZE - k;
808 /* easiest to format in a separate buffer and copy out */
809 for(i=0; i<6 && NUMSIZE*i<k+n; i++){
810 l = up->time[i];
811 if(i == TReal)
812 l = MACHP(0)->ticks - l;
813 l = TK2MS(l);
814 readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
815 }
816 memmove(buf, tmp+k, n);
817 return n;
818
819 case Qkmesg:
820 /*
821 * This is unlocked to avoid tying up a process
822 * that's writing to the buffer. kmesg.n never
823 * gets smaller, so worst case the reader will
824 * see a slurred buffer.
825 */
826 if(off >= kmesg.n)
827 n = 0;
828 else{
829 if(off+n > kmesg.n)
830 n = kmesg.n - off;
831 memmove(buf, kmesg.buf+off, n);
832 }
833 return n;
834
835 case Qkprint:
836 return qread(kprintoq, buf, n);
837
838 case Qpgrpid:
839 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
840
841 case Qpid:
842 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
843
844 case Qppid:
845 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
846
847 case Qtime:
848 return readtime((ulong)offset, buf, n);
849
850 case Qbintime:
851 return readbintime(buf, n);
852
853 case Qhostowner:
854 return readstr((ulong)offset, buf, n, eve);
855
856 case Qhostdomain:
857 return readstr((ulong)offset, buf, n, hostdomain);
858
859 case Quser:
860 return readstr((ulong)offset, buf, n, up->user);
861
862 case Qnull:
863 return 0;
864
865 case Qsysstat:
866 b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */
867 bp = b;
868 for(id = 0; id < 32; id++) {
869 if(active.machs & (1<<id)) {
870 mp = MACHP(id);
871 readnum(0, bp, NUMSIZE, id, NUMSIZE);
872 bp += NUMSIZE;
873 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
874 bp += NUMSIZE;
875 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
876 bp += NUMSIZE;
877 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
878 bp += NUMSIZE;
879 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
880 bp += NUMSIZE;
881 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
882 bp += NUMSIZE;
883 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
884 bp += NUMSIZE;
885 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
886 bp += NUMSIZE;
887 readnum(0, bp, NUMSIZE,
888 (mp->perf.avg_inidle*100)/mp->perf.period,
889 NUMSIZE);
890 bp += NUMSIZE;
891 readnum(0, bp, NUMSIZE,
892 (mp->perf.avg_inintr*100)/mp->perf.period,
893 NUMSIZE);
894 bp += NUMSIZE;
895 *bp++ = '\n';
896 }
897 }
898 if(waserror()){
899 free(b);
900 nexterror();
901 }
902 n = readstr((ulong)offset, buf, n, b);
903 free(b);
904 poperror();
905 return n;
906
907 case Qswap:
908 snprint(tmp, sizeof tmp,
909 "%lud memory\n"
910 "%d pagesize\n"
911 "%lud kernel\n"
912 "%lud/%lud user\n"
913 "%lud/%lud swap\n"
914 "%lud/%lud kernel malloc\n"
915 "%lud/%lud kernel draw\n",
916 conf.npage*BY2PG,
917 BY2PG,
918 conf.npage-conf.upages,
919 palloc.user-palloc.freecount, palloc.user,
920 conf.nswap-swapalloc.free, conf.nswap,
921 mainmem->cursize, mainmem->maxsize,
922 imagmem->cursize, imagmem->maxsize);
923
924 return readstr((ulong)offset, buf, n, tmp);
925
926 case Qsysname:
927 if(sysname == nil)
928 return 0;
929 return readstr((ulong)offset, buf, n, sysname);
930
931 case Qrandom:
932 return randomread(buf, n);
933
934 case Qdrivers:
935 b = malloc(READSTR);
936 if(b == nil)
937 error(Enomem);
938 n = 0;
939 for(i = 0; devtab[i] != nil; i++)
940 n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc, devtab[i]->name);
941 if(waserror()){
942 free(b);
943 nexterror();
944 }
945 n = readstr((ulong)offset, buf, n, b);
946 free(b);
947 poperror();
948 return n;
949
950 case Qzero:
951 memset(buf, 0, n);
952 return n;
953
954 case Qosversion:
955 snprint(tmp, sizeof tmp, "2000");
956 n = readstr((ulong)offset, buf, n, tmp);
957 return n;
958
959 default:
960 print("consread %#llux\n", c->qid.path);
961 error(Egreg);
962 }
963 return -1; /* never reached */
964 }
965
966 static long
967 conswrite(Chan *c, void *va, long n, vlong off)
968 {
969 char buf[256], ch;
970 long l, bp;
971 char *a;
972 Mach *mp;
973 int id, fd;
974 Chan *swc;
975 ulong offset;
976 Cmdbuf *cb;
977 Cmdtab *ct;
978
979 a = va;
980 offset = off;
981
982 switch((ulong)c->qid.path){
983 case Qcons:
984 /*
985 * Can't page fault in putstrn, so copy the data locally.
986 */
987 l = n;
988 while(l > 0){
989 bp = l;
990 if(bp > sizeof buf)
991 bp = sizeof buf;
992 memmove(buf, a, bp);
993 putstrn0(buf, bp, 1);
994 a += bp;
995 l -= bp;
996 }
997 break;
998
999 case Qconsctl:
1000 if(n >= sizeof(buf))
1001 n = sizeof(buf)-1;
1002 strncpy(buf, a, n);
1003 buf[n] = 0;
1004 for(a = buf; a;){
1005 if(strncmp(a, "rawon", 5) == 0){
1006 kbd.raw = 1;
1007 /* clumsy hack - wake up reader */
1008 ch = 0;
1009 qwrite(kbdq, &ch, 1);
1010 } else if(strncmp(a, "rawoff", 6) == 0){
1011 kbd.raw = 0;
1012 } else if(strncmp(a, "ctlpon", 6) == 0){
1013 kbd.ctlpoff = 0;
1014 } else if(strncmp(a, "ctlpoff", 7) == 0){
1015 kbd.ctlpoff = 1;
1016 }
1017 if(a = strchr(a, ' '))
1018 a++;
1019 }
1020 break;
1021
1022 case Qtime:
1023 if(!iseve())
1024 error(Eperm);
1025 return writetime(a, n);
1026
1027 case Qbintime:
1028 if(!iseve())
1029 error(Eperm);
1030 return writebintime(a, n);
1031
1032 case Qhostowner:
1033 return hostownerwrite(a, n);
1034
1035 case Qhostdomain:
1036 return hostdomainwrite(a, n);
1037
1038 case Quser:
1039 return userwrite(a, n);
1040
1041 case Qnull:
1042 break;
1043
1044 case Qreboot:
1045 if(!iseve())
1046 error(Eperm);
1047 cb = parsecmd(a, n);
1048
1049 if(waserror()) {
1050 free(cb);
1051 nexterror();
1052 }
1053 ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
1054 switch(ct->index) {
1055 case CMhalt:
1056 reboot(nil, 0, 0);
1057 break;
1058 case CMreboot:
1059 rebootcmd(cb->nf-1, cb->f+1);
1060 break;
1061 case CMpanic:
1062 *(ulong*)0=0;
1063 panic("/dev/reboot");
1064 }
1065 poperror();
1066 free(cb);
1067 break;
1068
1069 case Qsysstat:
1070 for(id = 0; id < 32; id++) {
1071 if(active.machs & (1<<id)) {
1072 mp = MACHP(id);
1073 mp->cs = 0;
1074 mp->intr = 0;
1075 mp->syscall = 0;
1076 mp->pfault = 0;
1077 mp->tlbfault = 0;
1078 mp->tlbpurge = 0;
1079 }
1080 }
1081 break;
1082
1083 case Qswap:
1084 if(n >= sizeof buf)
1085 error(Egreg);
1086 memmove(buf, va, n); /* so we can NUL-terminate */
1087 buf[n] = 0;
1088 /* start a pager if not already started */
1089 if(strncmp(buf, "start", 5) == 0){
1090 kickpager();
1091 break;
1092 }
1093 if(!iseve())
1094 error(Eperm);
1095 if(buf[0]<'' || '9'<buf[0])
1096 error(Ebadarg);
1097 fd = strtoul(buf, 0, 0);
1098 swc = fdtochan(fd, -1, 1, 1);
1099 setswapchan(swc);
1100 break;
1101
1102 case Qsysname:
1103 if(offset != 0)
1104 error(Ebadarg);
1105 if(n <= 0 || n >= sizeof buf)
1106 error(Ebadarg);
1107 strncpy(buf, a, n);
1108 buf[n] = 0;
1109 if(buf[n-1] == '\n')
1110 buf[n-1] = 0;
1111 kstrdup(&sysname, buf);
1112 break;
1113
1114 default:
1115 print("conswrite: %#llux\n", c->qid.path);
1116 error(Egreg);
1117 }
1118 return n;
1119 }
1120
1121 Dev consdevtab = {
1122 'c',
1123 "cons",
1124
1125 devreset,
1126 consinit,
1127 devshutdown,
1128 consattach,
1129 conswalk,
1130 consstat,
1131 consopen,
1132 devcreate,
1133 consclose,
1134 consread,
1135 devbread,
1136 conswrite,
1137 devbwrite,
1138 devremove,
1139 devwstat,
1140 };
1141
1142 static ulong randn;
1143
1144 static void
1145 seedrand(void)
1146 {
1147 if(!waserror()){
1148 randomread((void*)&randn, sizeof(randn));
1149 poperror();
1150 }
1151 }
1152
1153 int
1154 nrand(int n)
1155 {
1156 if(randn == 0)
1157 seedrand();
1158 randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
1159 return (randn>>16) % n;
1160 }
1161
1162 int
1163 rand(void)
1164 {
1165 nrand(1);
1166 return randn;
1167 }
1168
1169 static uvlong uvorder = 0x0001020304050607ULL;
1170
1171 static uchar*
1172 le2vlong(vlong *to, uchar *f)
1173 {
1174 uchar *t, *o;
1175 int i;
1176
1177 t = (uchar*)to;
1178 o = (uchar*)&uvorder;
1179 for(i = 0; i < sizeof(vlong); i++)
1180 t[o[i]] = f[i];
1181 return f+sizeof(vlong);
1182 }
1183
1184 static uchar*
1185 vlong2le(uchar *t, vlong from)
1186 {
1187 uchar *f, *o;
1188 int i;
1189
1190 f = (uchar*)&from;
1191 o = (uchar*)&uvorder;
1192 for(i = 0; i < sizeof(vlong); i++)
1193 t[i] = f[o[i]];
1194 return t+sizeof(vlong);
1195 }
1196
1197 static long order = 0x00010203;
1198
1199 static uchar*
1200 le2long(long *to, uchar *f)
1201 {
1202 uchar *t, *o;
1203 int i;
1204
1205 t = (uchar*)to;
1206 o = (uchar*)ℴ
1207 for(i = 0; i < sizeof(long); i++)
1208 t[o[i]] = f[i];
1209 return f+sizeof(long);
1210 }
1211
1212 static uchar*
1213 long2le(uchar *t, long from)
1214 {
1215 uchar *f, *o;
1216 int i;
1217
1218 f = (uchar*)&from;
1219 o = (uchar*)ℴ
1220 for(i = 0; i < sizeof(long); i++)
1221 t[i] = f[o[i]];
1222 return t+sizeof(long);
1223 }
1224
1225 char *Ebadtimectl = "bad time control";
1226
1227 /*
1228 * like the old #c/time but with added info. Return
1229 *
1230 * secs nanosecs fastticks fasthz
1231 */
1232 static int
1233 readtime(ulong off, char *buf, int n)
1234 {
1235 vlong nsec, ticks;
1236 long sec;
1237 char str[7*NUMSIZE];
1238
1239 nsec = todget(&ticks);
1240 if(fasthz == 0LL)
1241 fastticks((uvlong*)&fasthz);
1242 sec = nsec/1000000000ULL;
1243 snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
1244 NUMSIZE-1, sec,
1245 VLNUMSIZE-1, nsec,
1246 VLNUMSIZE-1, ticks,
1247 VLNUMSIZE-1, fasthz);
1248 return readstr(off, buf, n, str);
1249 }
1250
1251 /*
1252 * set the time in seconds
1253 */
1254 static int
1255 writetime(char *buf, int n)
1256 {
1257 char b[13];
1258 long i;
1259 vlong now;
1260
1261 if(n >= sizeof(b))
1262 error(Ebadtimectl);
1263 strncpy(b, buf, n);
1264 b[n] = 0;
1265 i = strtol(b, 0, 0);
1266 if(i <= 0)
1267 error(Ebadtimectl);
1268 now = i*1000000000LL;
1269 todset(now, 0, 0);
1270 return n;
1271 }
1272
1273 /*
1274 * read binary time info. all numbers are little endian.
1275 * ticks and nsec are syncronized.
1276 */
1277 static int
1278 readbintime(char *buf, int n)
1279 {
1280 int i;
1281 vlong nsec, ticks;
1282 uchar *b = (uchar*)buf;
1283
1284 i = 0;
1285 if(fasthz == 0LL)
1286 fastticks((uvlong*)&fasthz);
1287 nsec = todget(&ticks);
1288 if(n >= 3*sizeof(uvlong)){
1289 vlong2le(b+2*sizeof(uvlong), fasthz);
1290 i += sizeof(uvlong);
1291 }
1292 if(n >= 2*sizeof(uvlong)){
1293 vlong2le(b+sizeof(uvlong), ticks);
1294 i += sizeof(uvlong);
1295 }
1296 if(n >= 8){
1297 vlong2le(b, nsec);
1298 i += sizeof(vlong);
1299 }
1300 return i;
1301 }
1302
1303 /*
1304 * set any of the following
1305 * - time in nsec
1306 * - nsec trim applied over some seconds
1307 * - clock frequency
1308 */
1309 static int
1310 writebintime(char *buf, int n)
1311 {
1312 uchar *p;
1313 vlong delta;
1314 long period;
1315
1316 n--;
1317 p = (uchar*)buf + 1;
1318 switch(*buf){
1319 case 'n':
1320 if(n < sizeof(vlong))
1321 error(Ebadtimectl);
1322 le2vlong(&delta, p);
1323 todset(delta, 0, 0);
1324 break;
1325 case 'd':
1326 if(n < sizeof(vlong)+sizeof(long))
1327 error(Ebadtimectl);
1328 p = le2vlong(&delta, p);
1329 le2long(&period, p);
1330 todset(-1, delta, period);
1331 break;
1332 case 'f':
1333 if(n < sizeof(uvlong))
1334 error(Ebadtimectl);
1335 le2vlong(&fasthz, p);
1336 todsetfreq(fasthz);
1337 break;
1338 }
1339 return n;
1340 }
Cache object: eafb9c8fa2f45a93fdc0aab93140d8cb
|