Use the new RNG for the networking stack
[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         Qvmctl,
609         Qzero,
610 };
611
612 enum {
613         VLNUMSIZE = 22,
614         DOMLEN = 256,
615 };
616
617 static struct dirtab consdir[] = {
618         {".", {Qdir, 0, QTDIR}, 0, DMDIR | 0555},
619         {"bintime", {Qbintime}, 24, 0664},
620         {"config", {Qconfig}, 0, 0444},
621         {"cons", {Qcons}, 0, 0660},
622         {"consctl", {Qconsctl}, 0, 0220},
623         {"cputime", {Qcputime}, 6 * NUMSIZE, 0444},
624         {"drivers", {Qdrivers}, 0, 0444},
625         {"hostdomain", {Qhostdomain}, DOMLEN, 0664},
626         {"hostowner", {Qhostowner}, 0, 0664},
627         {"klog", {Qklog}, 0, 0440},
628         {"kmesg", {Qkmesg}, 0, 0440},
629         {"kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL | 0440},
630         {"null", {Qnull}, 0, 0666},
631         {"osversion", {Qosversion}, 0, 0444},
632         {"pgrpid", {Qpgrpid}, NUMSIZE, 0444},
633         {"pid", {Qpid}, NUMSIZE, 0444},
634         {"ppid", {Qppid}, NUMSIZE, 0444},
635         {"reboot", {Qreboot}, 0, 0660},
636         {"swap", {Qswap}, 0, 0664},
637         {"sysctl", {Qsysctl}, 0, 0666},
638         {"sysname", {Qsysname}, 0, 0664},
639         {"sysstat", {Qsysstat}, 0, 0666},
640         {"time", {Qtime}, NUMSIZE + 3 * VLNUMSIZE, 0664},
641         {"user", {Quser}, 0, 0666},
642         {"vmctl", {Qvmctl}, 0, 0666},
643         {"zero", {Qzero}, 0, 0444},
644 };
645
646 int consreadnum(uint32_t off, char *buf, uint32_t n, uint32_t val, int size)
647 {
648         char tmp[64];
649
650         snprintf(tmp, sizeof(tmp), "%*lud", size - 1, val);
651         tmp[size - 1] = ' ';
652         if (off >= size)
653                 return 0;
654         if (off + n > size)
655                 n = size - off;
656         memmove(buf, tmp + off, n);
657         return n;
658 }
659
660 int consreadstr(uint32_t off, char *buf, uint32_t n, char *str)
661 {
662         int size;
663
664         size = strlen(str);
665         if (off >= size)
666                 return 0;
667         if (off + n > size)
668                 n = size - off;
669         memmove(buf, str + off, n);
670         return n;
671 }
672
673 static void consinit(void)
674 {
675 #if 0
676         todinit();
677 #endif
678         /*
679          * at 115200 baud, the 1024 char buffer takes 56 ms to process,
680          * processing it every 22 ms should be fine
681          */
682 #if 0
683         addclock0link(kbdputcclock, 22);
684 #endif
685 }
686
687 static char *devname(void);
688
689 static struct chan *consattach(char *spec)
690 {
691         return devattach(devname(), spec);
692 }
693
694 static struct walkqid *conswalk(struct chan *c, struct chan *nc, char **name,
695                                                                 int nname)
696 {
697         return devwalk(c, nc, name, nname, consdir, ARRAY_SIZE(consdir), devgen);
698 }
699
700 static int consstat(struct chan *c, uint8_t * dp, int n)
701 {
702         return devstat(c, dp, n, consdir, ARRAY_SIZE(consdir), devgen);
703 }
704
705 static struct chan *consopen(struct chan *c, int omode)
706 {
707         c->aux = NULL;
708         c = devopen(c, omode, consdir, ARRAY_SIZE(consdir), devgen);
709         switch ((uint32_t) c->qid.path) {
710                 case Qconsctl:
711                         kref_get(&kbd.ctl, 1);
712                         break;
713
714                 case Qkprint:
715                         if (atomic_swap(&kprintinuse, 1) != 0) {
716                                 c->flag &= ~COPEN;
717                                 error(EADDRINUSE, "kprintinuse lock failed");
718                         }
719                         if (kprintoq == NULL) {
720                                 kprintoq = qopen(8 * 1024, Qcoalesce, 0, 0);
721                                 if (kprintoq == NULL) {
722                                         c->flag &= ~COPEN;
723                                         error(ENOMEM, "Can't allocate kprintoq");
724                                 }
725                                 qdropoverflow(kprintoq, 1);
726                         } else
727                                 qreopen(kprintoq);
728                         c->iounit = qiomaxatomic;
729                         break;
730         }
731         return c;
732 }
733
734 static void consclose(struct chan *c)
735 {
736         switch ((uint32_t) c->qid.path) {
737                         /* last close of control file turns off raw */
738                 case Qconsctl:
739                         if (c->flag & COPEN) {
740                                 if (kref_put(&kbd.ctl) == 0)
741                                         kbd.raw = 0;
742                         }
743                         break;
744
745                         /* close of kprint allows other opens */
746                 case Qkprint:
747                         if (c->flag & COPEN) {
748                                 kprintinuse = 0;
749                                 qhangup(kprintoq, NULL);
750                         }
751                         break;
752         }
753 }
754
755 static long consread(struct chan *c, void *buf, long n, int64_t off)
756 {
757         ERRSTACK(1);
758         uint32_t l;
759 #if 0
760         Mach *mp;
761 #endif
762         char *b, *bp, ch;
763         char tmp[256];                          /* must be >= 18*NUMSIZE (Qswap) */
764         int i, k, id, send;
765         int64_t offset = off;
766 #if 0
767         extern char configfile[];
768 #endif
769
770         if (n <= 0)
771                 return n;
772
773         switch ((uint32_t) c->qid.path) {
774                 case Qdir:
775                         return devdirread(c, buf, n, consdir, ARRAY_SIZE(consdir), devgen);
776
777                 case Qcons:
778                         qlock(&(&kbd)->qlock);
779                         if (waserror()) {
780                                 qunlock(&(&kbd)->qlock);
781                                 nexterror();
782                         }
783                         while (!qcanread(lineq)) {
784                                 if (qread(kbdq, &ch, 1) == 0)
785                                         continue;
786                                 send = 0;
787                                 if (ch == 0) {
788                                         /* flush output on rawoff -> rawon */
789                                         if (kbd.x > 0)
790                                                 send = !qcanread(kbdq);
791                                 } else if (kbd.raw) {
792                                         kbd.line[kbd.x++] = ch;
793                                         send = !qcanread(kbdq);
794                                 } else {
795                                         switch (ch) {
796                                                 case '\b':
797                                                         if (kbd.x > 0)
798                                                                 kbd.x--;
799                                                         break;
800                                                 case 0x15:      /* ^U */
801                                                         kbd.x = 0;
802                                                         break;
803                                                 case '\n':
804                                                 case 0x04:      /* ^D */
805                                                         send = 1;
806                                                 default:
807                                                         if (ch != 0x04)
808                                                                 kbd.line[kbd.x++] = ch;
809                                                         break;
810                                         }
811                                 }
812                                 if (send || kbd.x == sizeof kbd.line) {
813                                         qwrite(lineq, kbd.line, kbd.x);
814                                         kbd.x = 0;
815                                 }
816                         }
817                         n = qread(lineq, buf, n);
818                         qunlock(&(&kbd)->qlock);
819                         poperror();
820                         return n;
821
822 #if 0
823                 case Qcputime:
824                         k = offset;
825                         if (k >= 6 * NUMSIZE)
826                                 return 0;
827                         if (k + n > 6 * NUMSIZE)
828                                 n = 6 * NUMSIZE - k;
829                         /* easiest to format in a separate buffer and copy out */
830                         for (i = 0; i < 6 && NUMSIZE * i < k + n; i++) {
831                                 l = current->time[i];
832                                 if (i == TReal)
833                                         l = MACHP(0)->ticks - l;
834                                 l = TK2MS(l);
835                                 consreadnum(0, tmp + NUMSIZE * i, NUMSIZE, l, NUMSIZE);
836                         }
837                         memmove(buf, tmp + k, n);
838                         return n;
839 #endif
840
841                 case Qkmesg:
842                         /*
843                          * This is unlocked to avoid tying up a process
844                          * that's writing to the buffer.  kmesg.n never
845                          * gets smaller, so worst case the reader will
846                          * see a slurred buffer.
847                          */
848                         if (off >= kmesg.n)
849                                 n = 0;
850                         else {
851                                 if (off + n > kmesg.n)
852                                         n = kmesg.n - off;
853                                 memmove(buf, kmesg.buf + off, n);
854                         }
855                         return n;
856
857                 case Qkprint:
858                         return qread(kprintoq, buf, n);
859
860                 case Qpgrpid:
861                         return consreadnum((uint32_t) offset, buf, n, current->pgrp->pgrpid,
862                                                            NUMSIZE);
863
864                 case Qpid:
865                         return consreadnum((uint32_t) offset, buf, n, current->pid,
866                                                            NUMSIZE);
867
868                 case Qppid:
869                         return consreadnum((uint32_t) offset, buf, n, current->ppid,
870                                                            NUMSIZE);
871
872                 case Qtime:
873                         return readtime((uint32_t) offset, buf, n);
874
875                 case Qbintime:
876                         return readbintime(buf, n);
877
878                 case Qhostowner:
879                         return consreadstr((uint32_t) offset, buf, n, eve);
880
881                 case Qhostdomain:
882                         return consreadstr((uint32_t) offset, buf, n, hostdomain);
883
884                 case Quser:
885                         return consreadstr((uint32_t) offset, buf, n, current->user);
886
887                 case Qnull:
888                         return 0;
889
890 #if 0
891                 case Qconfig:
892                         return consreadstr((uint32_t) offset, buf, n, configfile);
893
894                 case Qsysstat:
895                         b = kzmalloc(conf.nmach * (NUMSIZE * 11 + 1) + 1, 0);   /* +1 for NUL */
896                         bp = b;
897                         for (id = 0; id < 32; id++) {
898                                 if (active.machs & (1 << id)) {
899                                         mp = MACHP(id);
900                                         consreadnum(0, bp, NUMSIZE, id, NUMSIZE);
901                                         bp += NUMSIZE;
902                                         consreadnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
903                                         bp += NUMSIZE;
904                                         consreadnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
905                                         bp += NUMSIZE;
906                                         consreadnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
907                                         bp += NUMSIZE;
908                                         consreadnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
909                                         bp += NUMSIZE;
910                                         consreadnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
911                                         bp += NUMSIZE;
912                                         consreadnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
913                                         bp += NUMSIZE;
914                                         consreadnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
915                                         bp += NUMSIZE;
916                                         consreadnum(0, bp, NUMSIZE,
917                                                                 (mp->perf.avg_inidle * 100) / mp->perf.period,
918                                                                 NUMSIZE);
919                                         bp += NUMSIZE;
920                                         consreadnum(0, bp, NUMSIZE,
921                                                                 (mp->perf.avg_inintr * 100) / mp->perf.period,
922                                                                 NUMSIZE);
923                                         bp += NUMSIZE;
924                                         *bp++ = '\n';
925                                 }
926                         }
927                         if (waserror()) {
928                                 kfree(b);
929                                 nexterror();
930                         }
931                         n = consreadstr((uint32_t) offset, buf, n, b);
932                         kfree(b);
933                         poperror();
934                         return n;
935
936                 case Qswap:
937                         snprintf(tmp, sizeof tmp,
938                                          "%lud memory\n"
939                                          "%d pagesize\n"
940                                          "%lud kernel\n"
941                                          "%lud/%lud user\n"
942                                          "%lud/%lud swap\n"
943                                          "%lud/%lud kernel malloc\n"
944                                          "%lud/%lud kernel draw\n",
945                                          conf.npage * BY2PG,
946                                          BY2PG,
947                                          conf.npage - conf.upages,
948                                          palloc.user - palloc.freecount, palloc.user,
949                                          conf.nswap - swapalloc.free, conf.nswap,
950                                          mainmem->cursize, mainmem->maxsize,
951                                          imagmem->cursize, imagmem->maxsize);
952
953                         return consreadstr((uint32_t) offset, buf, n, tmp);
954 #endif
955
956                 case Qsysname:
957                         if (sysname == NULL)
958                                 return 0;
959                         return consreadstr((uint32_t) offset, buf, n, sysname);
960
961                 case Qdrivers:
962                         b = kzmalloc(READSTR, 0);
963                         if (b == NULL)
964                                 error(ENOMEM, "allocation for /dev/drivers read failed");
965                         k = 0;
966                         for (int i = 0; &devtab[i] < __devtabend; i++)
967                                 k += snprintf(b + k, READSTR - k, "#%s\n", devtab[i].name);
968                         if (waserror()) {
969                                 kfree(b);
970                                 nexterror();
971                         }
972                         n = consreadstr((uint32_t) offset, buf, n, b);
973                         kfree(b);
974                         poperror();
975                         return n;
976
977                 case Qklog:
978                         //return qread(klogq, buf, n);
979                         /* the queue gives us some elasticity for log reading. */
980                         if (!logqueue)
981                                 logqueue = qopen(1 << 20, 0, 0, 0);
982                         if (logqueue) {
983                                 int ret;
984                                 /* atomic sets/gets are not that important in this case. */
985                                 reading_kmesg = 1;
986                                 qwrite(logqueue, logbuffer, index);
987                                 index = 0;
988                                 ret = qread(logqueue, buf, n);
989                                 reading_kmesg = 0;
990                                 return ret;
991                         }
992                         break;
993
994                 case Qzero:
995                         memset(buf, 0, n);
996                         return n;
997
998                 case Qosversion:
999                         snprintf(tmp, sizeof tmp, "2000");
1000                         n = consreadstr((uint32_t) offset, buf, n, tmp);
1001                         return n;
1002
1003                 default:
1004                         printd("consread %#llux\n", c->qid.path);
1005                         error(EINVAL, "bad QID in consread");
1006         }
1007         return -1;      /* never reached */
1008 }
1009
1010 static long conswrite(struct chan *c, void *va, long n, int64_t off)
1011 {
1012         ERRSTACK(1);
1013         char buf[256], ch;
1014         long l, bp;
1015         char *a;
1016         //Mach *mp;
1017         int id, fd;
1018         struct chan *swc;
1019         uint32_t offset;
1020         struct cmdbuf *cb;
1021         struct cmdtab *ct;
1022         int x;
1023         uint64_t rip, rsp, cr3, flags, vcpu;
1024         int ret;
1025         struct vmctl vmctl;
1026
1027         a = va;
1028         offset = off;
1029
1030         switch ((uint32_t) c->qid.path) {
1031                 case Qcons:
1032                         /*
1033                          * Can't page fault in putstrn, so copy the data locally.
1034                          */
1035                         l = n;
1036                         while (l > 0) {
1037                                 bp = l;
1038                                 if (bp > sizeof buf)
1039                                         bp = sizeof buf;
1040                                 memmove(buf, a, bp);
1041                                 putstrn0(buf, bp, 1);
1042                                 a += bp;
1043                                 l -= bp;
1044                         }
1045                         break;
1046
1047                 case Qconsctl:
1048                         if (n >= sizeof(buf))
1049                                 n = sizeof(buf) - 1;
1050                         strncpy(buf, a, n);
1051                         buf[n] = 0;
1052                         for (a = buf; a;) {
1053                                 if (strncmp(a, "rawon", 5) == 0) {
1054                                         kbd.raw = 1;
1055                                         /* clumsy hack - wake up reader */
1056                                         ch = 0;
1057                                         qwrite(kbdq, &ch, 1);
1058                                 } else if (strncmp(a, "rawoff", 6) == 0) {
1059                                         kbd.raw = 0;
1060                                 } else if (strncmp(a, "ctlpon", 6) == 0) {
1061                                         kbd.ctlpoff = 0;
1062                                 } else if (strncmp(a, "ctlpoff", 7) == 0) {
1063                                         kbd.ctlpoff = 1;
1064                                 }
1065                                 if ((a = strchr(a, ' ')) != NULL)
1066                                         a++;
1067                         }
1068                         break;
1069
1070                 case Qtime:
1071                         if (!iseve())
1072                                 error(EPERM, "Hodie Natus Est Radici Frater");
1073                         return writetime(a, n);
1074
1075                 case Qbintime:
1076                         if (!iseve())
1077                                 error(EPERM, ERROR_FIXME);
1078                         return writebintime(a, n);
1079
1080 #if 0
1081                 case Qhostowner:
1082                         return hostownerwrite(a, n);
1083
1084                 case Qhostdomain:
1085                         return hostdomainwrite(a, n);
1086
1087                 case Quser:
1088                         return userwrite(a, n);
1089 #endif
1090
1091                 case Qnull:
1092                         break;
1093
1094                 case Qconfig:
1095                         error(EPERM, "Cannot write to config QID");
1096                         break;
1097
1098                 case Qvmctl:
1099                         memmove(&vmctl, a, sizeof(vmctl));
1100                         if ((offset >> 12) ==1) {
1101                                 ret = vm_post_interrupt(&vmctl);
1102                                 n = ret;
1103                                 //printk("vm_interrupt_notify returns %d\n", ret);
1104                         } else {
1105                                 error(EINVAL, "Bad vmctl command");
1106                         }
1107                         break;
1108                 case Qsysctl:
1109                         //if (!iseve()) error(EPERM, ERROR_FIXME);
1110                         cb = parsecmd(a, n);
1111                         if (cb->nf > 1)
1112                         printd("cons sysctl cmd %s\n", cb->f[0]);
1113
1114                 case Qreboot:
1115                         if (!iseve())
1116                                 error(EPERM, ERROR_FIXME);
1117                         cb = parsecmd(a, n);
1118
1119                         if (waserror()) {
1120                                 kfree(cb);
1121                                 nexterror();
1122                         }
1123                         ct = lookupcmd(cb, rebootmsg, ARRAY_SIZE(rebootmsg));
1124                         switch (ct->index) {
1125                                 case CMhalt:
1126                                         cpu_halt();
1127                                         break;
1128                                 case CMbroken:
1129                                         keepbroken = 1;
1130                                         break;
1131                                 case CMnobroken:
1132                                         keepbroken = 0;
1133                                         break;
1134                                 case CMreboot:
1135                                         reboot();
1136                                         break;
1137                                 case CMpanic:
1138                                         *(uint32_t *) 0 = 0;
1139                                         panic("/dev/reboot");
1140                         }
1141                         poperror();
1142                         kfree(cb);
1143                         break;
1144
1145 #if 0
1146                 case Qsysstat:
1147                         for (id = 0; id < 32; id++) {
1148                                 if (active.machs & (1 << id)) {
1149                                         mp = MACHP(id);
1150                                         mp->cs = 0;
1151                                         mp->intr = 0;
1152                                         mp->syscall = 0;
1153                                         mp->pfault = 0;
1154                                         mp->tlbfault = 0;
1155                                         mp->tlbpurge = 0;
1156                                 }
1157                         }
1158                         break;
1159
1160                 case Qswap:
1161                         if (n >= sizeof buf)
1162                                 error(EINVAL, "n is bigger than sizeof buf for Qswap");
1163                         memmove(buf, va, n);    /* so we can NUL-terminate */
1164                         buf[n] = 0;
1165                         /* start a pager if not already started */
1166                         if (strncmp(buf, "start", 5) == 0) {
1167                                 kickpager();
1168                                 break;
1169                         }
1170                         if (!iseve())
1171                                 error(EPERM, ERROR_FIXME);
1172                         if (buf[0] < '0' || '9' < buf[0])
1173                                 error(EINVAL, ERROR_FIXME);
1174                         fd = strtoul(buf, 0, 0);
1175                         swc = fdtochan(fd, -1, 1, 1);
1176                         setswapchan(swc);
1177                         break;
1178 #endif
1179
1180                 case Qsysname:
1181                         if (offset != 0)
1182                                 error(EINVAL, ERROR_FIXME);
1183                         if (n <= 0 || n >= sizeof buf)
1184                                 error(EINVAL, ERROR_FIXME);
1185                         strncpy(buf, a, n);
1186                         buf[n] = 0;
1187                         if (buf[n - 1] == '\n')
1188                                 buf[n - 1] = 0;
1189                         kstrdup(&sysname, buf);
1190                         break;
1191
1192                 default:
1193                         printd("conswrite: %#llux\n", c->qid.path);
1194                         error(EINVAL, "bad QID in conswrite");
1195         }
1196         return n;
1197 }
1198
1199 struct dev consdevtab __devtab = {
1200         .name = "cons",
1201
1202         .reset = devreset,
1203         .init = consinit,
1204         .shutdown = devshutdown,
1205         .attach = consattach,
1206         .walk = conswalk,
1207         .stat = consstat,
1208         .open = consopen,
1209         .create = devcreate,
1210         .close = consclose,
1211         .read = consread,
1212         .bread = devbread,
1213         .write = conswrite,
1214         .bwrite = devbwrite,
1215         .remove = devremove,
1216         .wstat = devwstat,
1217         .power = devpower,
1218         .chaninfo = devchaninfo,
1219 };
1220
1221 static char *devname(void)
1222 {
1223         return consdevtab.name;
1224 }
1225
1226 static uint64_t uvorder = 0x0001020304050607ULL;
1227
1228 static uint8_t *le2int64_t(int64_t * to, uint8_t * f)
1229 {
1230         uint8_t *t, *o;
1231         int i;
1232
1233         t = (uint8_t *) to;
1234         o = (uint8_t *) & uvorder;
1235         for (i = 0; i < sizeof(int64_t); i++)
1236                 t[o[i]] = f[i];
1237         return f + sizeof(int64_t);
1238 }
1239
1240 static uint8_t *int64_t2le(uint8_t * t, int64_t from)
1241 {
1242         uint8_t *f, *o;
1243         int i;
1244
1245         f = (uint8_t *) & from;
1246         o = (uint8_t *) & uvorder;
1247         for (i = 0; i < sizeof(int64_t); i++)
1248                 t[i] = f[o[i]];
1249         return t + sizeof(int64_t);
1250 }
1251
1252 static long order = 0x00010203;
1253
1254 static uint8_t *le2long(long *to, uint8_t * f)
1255 {
1256         uint8_t *t, *o;
1257         int i;
1258
1259         t = (uint8_t *) & to;
1260         o = (uint8_t *) & order;
1261         for (i = 0; i < sizeof(long); i++)
1262                 t[o[i]] = f[i];
1263         return f + sizeof(long);
1264 }
1265
1266 static uint8_t *long2le(uint8_t * t, long from)
1267 {
1268         uint8_t *f, *o;
1269         int i;
1270
1271         f = (uint8_t *) & from;
1272         o = (uint8_t *) & order;
1273         for (i = 0; i < sizeof(long); i++)
1274                 t[i] = f[o[i]];
1275         return t + sizeof(long);
1276 }
1277
1278 char *Ebadtimectl = "bad time control";
1279
1280 /*
1281  *  like the old #c/time but with added info.  Return
1282  *
1283  *      secs    nanosecs        fastticks       fasthz
1284  */
1285 static int readtime(uint32_t off, char *buf, int n)
1286 {
1287         int64_t nsec, ticks;
1288         long sec;
1289         char str[7 * NUMSIZE];
1290
1291         if (fasthz == 0LL)
1292                 fasthz = system_timing.tsc_freq;
1293 #if 0
1294         fastticks((uint64_t *) & fasthz);
1295         nsec = todget(&ticks);
1296 #endif
1297         ticks = read_tsc();
1298         nsec = tsc2nsec(ticks);
1299         sec = nsec / 1000000000ULL;
1300         snprintf(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
1301                          NUMSIZE - 1, sec,
1302                          VLNUMSIZE - 1, nsec, VLNUMSIZE - 1, ticks, VLNUMSIZE - 1, fasthz);
1303         return consreadstr(off, buf, n, str);
1304 }
1305
1306 /*
1307  *  set the time in seconds
1308  */
1309 static int writetime(char *buf, int n)
1310 {
1311         char b[13];
1312         long i;
1313         int64_t now;
1314
1315         if (n >= sizeof(b))
1316                 error(EINVAL, "bad size in writetime");
1317         strncpy(b, buf, n);
1318         b[n] = 0;
1319         i = strtol(b, 0, 0);
1320         if (i <= 0)
1321                 error(EINVAL, "Bad time in write");
1322         now = i * 1000000000LL;
1323 #if 0
1324         todset(now, 0, 0);
1325 #endif
1326         return n;
1327 }
1328
1329 /*
1330  *  read binary time info.  all numbers are little endian.
1331  *  ticks and nsec are syncronized.
1332  */
1333 static int readbintime(char *buf, int n)
1334 {
1335         int i;
1336         int64_t nsec, ticks;
1337         uint8_t *b = (uint8_t *) buf;
1338
1339         i = 0;
1340         if (fasthz == 0LL)
1341                 fasthz = system_timing.tsc_freq;
1342 #if 0
1343         fastticks((uint64_t *) & fasthz);
1344         nsec = todget(&ticks);
1345 #endif
1346         ticks = read_tsc();
1347         nsec = tsc2nsec(ticks);
1348         if (n >= 3 * sizeof(uint64_t)) {
1349                 int64_t2le(b + 2 * sizeof(uint64_t), fasthz);
1350                 i += sizeof(uint64_t);
1351         }
1352         if (n >= 2 * sizeof(uint64_t)) {
1353                 int64_t2le(b + sizeof(uint64_t), ticks);
1354                 i += sizeof(uint64_t);
1355         }
1356         if (n >= 8) {
1357                 int64_t2le(b, nsec);
1358                 i += sizeof(int64_t);
1359         }
1360         return i;
1361 }
1362
1363 /*
1364  *  set any of the following
1365  *      - time in nsec
1366  *      - nsec trim applied over some seconds
1367  *      - clock frequency
1368  */
1369 static int writebintime(char *buf, int n)
1370 {
1371         uint8_t *p;
1372         int64_t delta = 0;
1373         long period = 0;
1374
1375         n--;
1376         p = (uint8_t *) buf + 1;
1377         switch (*buf) {
1378                 case 'n':
1379                         if (n < sizeof(int64_t))
1380                                 error(EINVAL, ERROR_FIXME);
1381                         le2int64_t(&delta, p);
1382 #if 0
1383                         todset(delta, 0, 0);
1384 #endif
1385                         break;
1386                 case 'd':
1387                         if (n < sizeof(int64_t) + sizeof(long))
1388                                 error(EINVAL, ERROR_FIXME);
1389                         p = le2int64_t(&delta, p);
1390                         le2long(&period, p);
1391 #if 0
1392                         todset(-1, delta, period);
1393 #endif
1394                         break;
1395                 case 'f':
1396                         if (n < sizeof(uint64_t))
1397                                 error(EINVAL, ERROR_FIXME);
1398                         le2int64_t(&fasthz, p);
1399                         if (fasthz <= 0)
1400                                 error(EINVAL, ERROR_FIXME);
1401 #if 0
1402                         todsetfreq(fasthz);
1403 #endif
1404                         break;
1405         }
1406         return n;
1407 }