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