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