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