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