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