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