Add the Inferno license to files we got from Inferno
[akaros.git] / kern / drivers / dev / cons.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <vfs.h>
30 #include <kfs.h>
31 #include <slab.h>
32 #include <kmalloc.h>
33 #include <kref.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <assert.h>
37 #include <error.h>
38 #include <cpio.h>
39 #include <pmap.h>
40 #include <smp.h>
41 #include <ip.h>
42
43 struct dev consdevtab;
44
45 static char *devname(void)
46 {
47         return consdevtab.name;
48 }
49
50 extern char *eve;
51 /* much stuff not ready yet. */
52
53 extern int cflag;
54
55 /* this would be good to have; when processes die, keep them around so we can
56  * debug them.
57  */
58 int keepbroken;
59
60 #if 0
61 void (*serwrite) (char *, int);
62
63 struct queue *kscanq;                   /* keyboard raw scancodes (when needed) */
64 char *kscanid;                                  /* name of raw scan format (if defined) */
65 struct queue *kbdq;                             /* unprocessed console input */
66 struct queue *lineq;                    /* processed console input */
67 struct queue *printq;                   /* console output */
68 struct queue *klogq;                    /* kernel print (log) output */
69 int iprintscreenputs;
70
71 static struct {
72         rwlock_t rwlock;
73         Queue *q;
74 } kprintq;
75
76 static struct {
77         qlock_t qlock;
78
79         int raw;                                        /* true if we shouldn't process input */
80         int ctl;                                        /* number of opens to the control file */
81         int kbdr;                                       /* number of open reads to the keyboard */
82         int scan;                                       /* true if reading raw scancodes */
83         int x;                                          /* index into line */
84         char line[1024];                        /* current input line */
85
86         char c;
87         int count;
88         int repeat;
89 } kbd;
90
91 #endif
92 char *sysname = "Your machine";
93 char *eve = "eve";
94
95 enum {
96         CMreboot,
97         CMhalt,
98         CMpanic,
99         CMbroken,
100         CMnobroken,
101         CMconsole,
102         CMV,
103 };
104
105 static struct cmdtab sysctlcmd[] = {
106         {CMreboot, "reboot", 0},
107         {CMhalt, "halt", 0},
108         {CMpanic, "panic", 0},
109         {CMconsole, "console", 1},
110         {CMbroken, "broken", 0},
111         {CMnobroken, "nobroken", 0},
112         {CMV, "V", 4},
113 };
114
115 void printinit(void)
116 {
117 #if 0
118         lineq = qopen(2 * 1024, 0, NULL, NULL);
119         if (lineq == NULL)
120                 panic("printinit");
121         qdropoverflow(lineq, 1);
122 #endif
123 }
124
125 /*
126  *  return true if current user is eve
127  */
128 int iseve(void)
129 {
130 #if 0
131         Osenv *o;
132
133         o = up->env;
134         return strcmp(eve, o->user) == 0;
135 #endif
136         return 1;
137 }
138
139 #if 0
140 static int consactive(void)
141 {
142         if (printq)
143                 return qlen(printq) > 0;
144         return 0;
145 }
146
147 static void prflush(void)
148 {
149         uint32_t now;
150
151         now = m->ticks;
152         while (serwrite == NULL && consactive())
153                 if (m->ticks - now >= HZ)
154                         break;
155 }
156
157 /*
158  *   Print a string on the console.  Convert \n to \r\n for serial
159  *   line consoles.  Locking of the queues is left up to the screen
160  *   or uart code.  Multi-line messages to serial consoles may get
161  *   interspersed with other messages.
162  */
163 static void putstrn0(char *str, int n, int usewrite)
164 {
165         int m;
166         char *t;
167         char buf[PRINTSIZE + 2];
168         ERRSTACK(1);
169
170         /*
171          *  if kprint is open, put the message there, otherwise
172          *  if there's an attached bit mapped display,
173          *  put the message there.
174          */
175         m = consoleprint;
176         if (canrlock(&(&kprintq)->rwlock)) {
177                 if (kprintq.q != NULL) {
178                         if (waserror()) {
179                                 runlock(&(&kprintq)->rwlock);
180                                 nexterror();
181                         }
182                         if (usewrite)
183                                 qwrite(kprintq.q, str, n);
184                         else
185                                 qiwrite(kprintq.q, str, n);
186                         poperror();
187                         m = 0;
188                 }
189                 runlock(&(&kprintq)->rwlock);
190         }
191         if (m && screenputs != NULL)
192                 screenputs(str, n);
193
194         /*
195          *  if there's a serial line being used as a console,
196          *  put the message there.
197          */
198         if (serwrite != NULL) {
199                 serwrite(str, n);
200                 return;
201         }
202
203         if (printq == 0)
204                 return;
205
206         while (n > 0) {
207                 t = memchr(str, '\n', n);
208                 if (t && !kbd.raw) {
209                         m = t - str;
210                         if (m > sizeof(buf) - 2)
211                                 m = sizeof(buf) - 2;
212                         memmove(buf, str, m);
213                         buf[m] = '\r';
214                         buf[m + 1] = '\n';
215                         if (usewrite)
216                                 qwrite(printq, buf, m + 2);
217                         else
218                                 qiwrite(printq, buf, m + 2);
219                         str = t + 1;
220                         n -= m + 1;
221                 } else {
222                         if (usewrite)
223                                 qwrite(printq, str, n);
224                         else
225                                 qiwrite(printq, str, n);
226                         break;
227                 }
228         }
229 }
230
231 /*
232  * mainly for libmp
233  */
234 void sysfatal(char *fmt, ...)
235 {
236         va_list arg;
237         char buf[64];
238
239         va_start(arg, fmt);
240         vsnprintf(buf, sizeof(buf), fmt, arg);
241         va_end(arg);
242         error(EFAIL, buf);
243 }
244
245 int pprint(char *fmt, ...)
246 {
247         ERRSTACK(1);
248         int n;
249         struct chan *c;
250         Osenv *o;
251         va_list arg;
252         char buf[2 * PRINTSIZE];
253
254         n = sprint(buf, "%s %ld: ", up->text, up->pid);
255         va_start(arg, fmt);
256         n = vseprintf(buf + n, buf + sizeof(buf), fmt, arg) - buf;
257         va_end(arg);
258
259         o = up->env;
260         if (o->fgrp == 0) {
261                 printd("%s", buf);
262                 return 0;
263         }
264         /* TODO: this is probably wrong (VFS hack) */
265         c = o->fgrp->fd[2];
266         if (c == 0 || (c->mode != OWRITE && c->mode != ORDWR)) {
267                 printd("%s", buf);
268                 return 0;
269         }
270
271         if (waserror()) {
272                 printd("%s", buf);
273                 poperror();
274                 return 0;
275         }
276         devtab[c->type].write(c, buf, n, c->offset);
277         poperror();
278
279         spin_lock(&c->lock);
280         c->offset += n;
281         spin_unlock(&c->lock);
282
283         return n;
284 }
285
286 void echo(Rune r, char *buf, int n)
287 {
288         if (kbd.raw)
289                 return;
290
291         if (r == '\n') {
292                 if (printq)
293                         qiwrite(printq, "\r", 1);
294         } else if (r == 0x15) {
295                 buf = "^U\n";
296                 n = 3;
297         }
298         if (consoleprint && screenputs != NULL)
299                 screenputs(buf, n);
300         if (printq)
301                 qiwrite(printq, buf, n);
302 }
303 #endif
304 #if 0
305 /*
306  *      Debug key support.  Allows other parts of the kernel to register debug
307  *      key handlers, instead of devcons.c having to know whatever's out there.
308  *      A kproc is used to invoke most handlers, rather than tying up the CPU at
309  *      splhi, which can choke some device drivers (eg softmodem).
310  */
311 typedef struct {
312         Rune r;
313         char *m;
314         void (*f) (Rune);
315         int i;                                          /* function called at interrupt time */
316 } Dbgkey;
317
318 static struct {
319         Rendez;
320         Dbgkey *work;
321         Dbgkey keys[50];
322         int nkeys;
323         int on;
324 } dbg;
325
326 static Dbgkey *finddbgkey(Rune r)
327 {
328         int i;
329         Dbgkey *dp;
330
331         for (dp = dbg.keys, i = 0; i < dbg.nkeys; i++, dp++)
332                 if (dp->r == r)
333                         return dp;
334         return NULL;
335 }
336
337 static int dbgwork(void *)
338 {
339         return dbg.work != 0;
340 }
341
342 static void dbgproc(void *)
343 {
344         Dbgkey *dp;
345
346         setpri(PriRealtime);
347         for (;;) {
348                 do {
349                         rendez_sleep(&dbg, dbgwork, 0);
350                         dp = dbg.work;
351                 } while (dp == NULL);
352                 dp->f(dp->r);
353                 dbg.work = NULL;
354         }
355 }
356
357 void debugkey(Rune r, char *msg, void (*fcn) (), int iflag)
358 {
359         Dbgkey *dp;
360
361         if (dbg.nkeys >= ARRAY_SIZE(dbg.keys))
362                 return;
363         if (finddbgkey(r) != NULL)
364                 return;
365         for (dp = &dbg.keys[dbg.nkeys++] - 1; dp >= dbg.keys; dp--) {
366                 if (strcmp(dp->m, msg) < 0)
367                         break;
368                 dp[1] = dp[0];
369         }
370         dp++;
371         dp->r = r;
372         dp->m = msg;
373         dp->f = fcn;
374         dp->i = iflag;
375 }
376
377 static int isdbgkey(Rune r)
378 {
379         static int ctrlt;
380         Dbgkey *dp;
381         int echoctrlt = ctrlt;
382
383         /*
384          * ^t hack BUG
385          */
386         if (dbg.on || (ctrlt >= 2)) {
387                 if (r == 0x14 || r == 0x05) {
388                         ctrlt++;
389                         return 0;
390                 }
391                 if (dp = finddbgkey(r)) {
392                         if (dp->i || ctrlt > 2)
393                                 dp->f(r);
394                         else {
395                                 dbg.work = dp;
396                                 rendez_wakeup(&dbg);
397                         }
398                         ctrlt = 0;
399                         return 1;
400                 }
401                 ctrlt = 0;
402         } else if (r == 0x14) {
403                 ctrlt++;
404                 return 1;
405         } else
406                 ctrlt = 0;
407         if (echoctrlt) {
408                 char buf[3];
409
410                 buf[0] = 0x14;
411                 while (--echoctrlt >= 0) {
412                         echo(buf[0], buf, 1);
413                         qproduce(kbdq, buf, 1);
414                 }
415         }
416         return 0;
417 }
418
419 static void dbgtoggle(Rune)
420 {
421         dbg.on = !dbg.on;
422         printd("Debug keys %s\n", dbg.on ? "HOT" : "COLD");
423 }
424
425 static void dbghelp(void)
426 {
427         int i;
428         Dbgkey *dp;
429         Dbgkey *dp2;
430         static char fmt[] = "%c: %-22s";
431
432         dp = dbg.keys;
433         dp2 = dp + (dbg.nkeys + 1) / 2;
434         for (i = dbg.nkeys; i > 1; i -= 2, dp++, dp2++) {
435                 printd(fmt, dp->r, dp->m);
436                 printd(fmt, dp2->r, dp2->m);
437                 printd("\n");
438         }
439         if (i)
440                 printd(fmt, dp->r, dp->m);
441         printd("\n");
442 }
443
444 static void debuginit(void)
445 {
446         ktask("consdbg", dbgproc, NULL);
447         debugkey('|', "HOT|COLD keys", dbgtoggle, 0);
448         debugkey('?', "help", dbghelp, 0);
449 }
450 #endif
451 #if 0
452 /*
453  *  Called by a uart interrupt for console input.
454  *
455  *  turn '\r' into '\n' before putting it into the queue.
456  */
457 int kbdcr2nl(struct queue *q, int ch)
458 {
459         if (ch == '\r')
460                 ch = '\n';
461         return kbdputc(q, ch);
462 }
463
464 /*
465  *  Put character, possibly a rune, into read queue at interrupt time.
466  *  Performs translation for compose sequences
467  *  Called at interrupt time to process a character.
468  */
469 int kbdputc(struct queue *q, int ch)
470 {
471         int n;
472         char buf[3];
473         Rune r;
474         static Rune kc[15];
475         static int nk, collecting = 0;
476
477         r = ch;
478         if (r == Latin) {
479                 collecting = 1;
480                 nk = 0;
481                 return 0;
482         }
483         if (collecting) {
484                 int c;
485                 nk += runetochar((char *unused_char_p_t)&kc[nk], &r);
486                 c = latin1(kc, nk);
487                 if (c < -1)     /* need more keystrokes */
488                         return 0;
489                 collecting = 0;
490                 if (c == -1) {  /* invalid sequence */
491                         echo(kc[0], (char *unused_char_p_t)kc, nk);
492                         qproduce(q, kc, nk);
493                         return 0;
494                 }
495                 r = (Rune) c;
496         }
497         kbd.c = r;
498         n = runetochar(buf, &r);
499         if (n == 0)
500                 return 0;
501         if (!isdbgkey(r)) {
502                 echo(r, buf, n);
503                 qproduce(q, buf, n);
504         }
505         return 0;
506 }
507
508 void kbdrepeat(int rep)
509 {
510         kbd.repeat = rep;
511         kbd.count = 0;
512 }
513
514 void kbdclock(void)
515 {
516         if (kbd.repeat == 0)
517                 return;
518         if (kbd.repeat == 1 && ++kbd.count > HZ) {
519                 kbd.repeat = 2;
520                 kbd.count = 0;
521                 return;
522         }
523         if (++kbd.count & 1)
524                 kbdputc(kbdq, kbd.c);
525 }
526 #endif
527
528 enum {
529         Qdir,
530         Qcons,
531         Qsysctl,
532         Qconsctl,
533         Qdrivers,
534         Qhostowner,
535         Qkeyboard,
536         Qklog,
537         Qkprint,
538         Qscancode,
539         Qmemory,
540         Qmsec,
541         Qnull,
542         Qrandom,
543         Qsysname,
544         Qtime,
545         Qurandom,
546         Quser,
547         Qjit,
548 };
549
550 static struct dirtab consdir[] = {
551         {".", {Qdir, 0, QTDIR}, 0, DMDIR | 0555},
552         {"cons", {Qcons}, 0, 0660},
553         {"consctl", {Qconsctl}, 0, 0220},
554         {"sysctl", {Qsysctl}, 0, 0666},
555         {"drivers", {Qdrivers}, 0, 0444},
556         {"hostowner", {Qhostowner}, 0, 0644},
557         {"keyboard", {Qkeyboard}, 0, 0666},
558         {"klog", {Qklog}, 0, 0444},
559         {"kprint", {Qkprint}, 0, 0444},
560         {"scancode", {Qscancode}, 0, 0444},
561         {"memory", {Qmemory}, 0, 0444},
562         {"msec", {Qmsec}, NUMSIZE, 0444},
563         {"null", {Qnull}, 0, 0666},
564         {"random", {Qrandom}, 0, 0444},
565         {"sysname", {Qsysname}, 0, 0664},
566         {"time", {Qtime}, 0, 0664},
567         {"user", {Quser}, 0, 0644},
568         {"urandom", {Qurandom}, 0, 0444},
569         {"jit", {Qjit}, 0, 0666},
570 };
571
572 uint32_t boottime;                              /* seconds since epoch at boot */
573
574 #if 0
575 void fddump()
576 {
577         struct proc *p;
578         Osenv *o;
579         int i;
580         struct chan *c;
581
582         p = proctab(6);
583         o = p->env;
584         for (i = 0; i <= o->fgrp->maxfd; i++) {
585                 if ((c = o->fgrp->fd[i]) == NULL)
586                         continue;
587                 printd("%d: %s\n", i, c->name == NULL ? "???" : c->name->s);
588         }
589 }
590 #endif
591
592 static void consinit(void)
593 {
594         randominit();
595 #if 0
596         debuginit();
597         debugkey('f', "files/6", fddump, 0);
598         debugkey('q', "panic", qpanic, 1);
599         debugkey('r', "exit", rexit, 1);
600         klogq = qopen(128 * 1024, 0, 0, 0);
601 #endif
602 }
603
604 static struct chan *consattach(char *spec)
605 {
606         return devattach(devname(), spec);
607 }
608
609 static struct walkqid *conswalk(struct chan *c, struct chan *nc, char **name,
610                                                                 int nname)
611 {
612         return devwalk(c, nc, name, nname, consdir, ARRAY_SIZE(consdir), devgen);
613 }
614
615 static int consstat(struct chan *c, uint8_t * dp, int n)
616 {
617         return devstat(c, dp, n, consdir, ARRAY_SIZE(consdir), devgen);
618 }
619
620 #if 0
621 static void flushkbdline(struct queue *q)
622 {
623         if (kbd.x) {
624                 qwrite(q, kbd.line, kbd.x);
625                 kbd.x = 0;
626         }
627 }
628 #endif
629
630 static struct chan *consopen(struct chan *c, int omode)
631 {
632         c->aux = 0;
633 #if 0
634         switch ((uint32_t) c->qid.path) {
635                 case Qconsctl:
636                         if (!iseve())
637                                 error(EPERM, NULL);
638                         qlock(&(&kbd)->qlock);
639                         kbd.ctl++;
640                         qunlock(&(&kbd)->qlock);
641                         break;
642
643                 case Qkeyboard:
644                         if ((omode & 3) != OWRITE) {
645                                 qlock(&(&kbd)->qlock);
646                                 kbd.kbdr++;
647                                 flushkbdline(kbdq);
648                                 kbd.raw = 1;
649                                 qunlock(&(&kbd)->qlock);
650                         }
651                         break;
652
653                 case Qscancode:
654                         qlock(&(&kbd)->qlock);
655                         if (kscanq || !kscanid) {
656                                 qunlock(&(&kbd)->qlock);
657                                 c->flag &= ~COPEN;
658                                 if (kscanq)
659                                         error(EBUSY, NULL);
660                                 else
661                                         error(EINVAL, NULL);
662                         }
663                         kscanq = qopen(256, 0, NULL, NULL);
664                         qunlock(&(&kbd)->qlock);
665                         break;
666
667                 case Qkprint:
668                         if ((omode & 3) != OWRITE) {
669                                 wlock(&(&kprintq)->rwlock);
670                                 if (kprintq.q != NULL) {
671                                         wunlock(&(&kprintq)->rwlock);
672                                         error(EBUSY, NULL);
673                                 }
674                                 kprintq.q = qopen(32 * 1024, Qcoalesce, NULL, NULL);
675                                 if (kprintq.q == NULL) {
676                                         wunlock(&(&kprintq)->rwlock);
677                                         error(ENOMEM, NULL);
678                                 }
679                                 qdropoverflow(kprintq.q, 1);
680                                 wunlock(&(&kprintq)->rwlock);
681                                 c->iounit = qiomaxatomic;
682                         }
683                         break;
684         }
685 #endif
686         return devopen(c, omode, consdir, ARRAY_SIZE(consdir), devgen);
687 }
688
689 static void consclose(struct chan *c)
690 {
691         if ((c->flag & COPEN) == 0)
692                 return;
693
694         switch ((uint32_t) c->qid.path) {
695 #if 0
696                 case Qconsctl:
697                         /* last close of control file turns off raw */
698                         qlock(&(&kbd)->qlock);
699                         if (--kbd.ctl == 0)
700                                 kbd.raw = 0;
701                         qunlock(&(&kbd)->qlock);
702                         break;
703
704                 case Qkeyboard:
705                         if (c->mode != OWRITE) {
706                                 qlock(&(&kbd)->qlock);
707                                 --kbd.kbdr;
708                                 qunlock(&(&kbd)->qlock);
709                         }
710                         break;
711
712                 case Qscancode:
713                         qlock(&(&kbd)->qlock);
714                         if (kscanq) {
715                                 qfree(kscanq);
716                                 kscanq = 0;
717                         }
718                         qunlock(&(&kbd)->qlock);
719                         break;
720
721                 case Qkprint:
722                         wlock(&(&kprintq)->rwlock);
723                         qfree(kprintq.q);
724                         kprintq.q = NULL;
725                         wunlock(&(&kprintq)->rwlock);
726                         break;
727 #endif
728                 default:
729                         break;
730         }
731 }
732
733 /* we do it this way to avoid the many fun deadlock opportunities
734  * we keep hitting. And, if you don't suck it
735  * out soon enough, you lost it. No real effort to ensure goodness
736  * here as it can get called anywhere. Barret will fix it.
737  */
738 static uint8_t logbuffer[1 << 20];
739 static int index = 0;
740 static struct queue *logqueue = NULL;
741 static int reading_kmesg = 0;
742 void logbuf(int c)
743 {
744         if (reading_kmesg)
745                 return;
746         if (index > 1 << 20)
747                 return;
748         logbuffer[index++] = c;
749 }
750
751 static long consread(struct chan *c, void *buf, long n, int64_t offset)
752 {
753         ERRSTACK(1);
754         int l;
755
756         int ch, eol, i;
757         char *p, tmp[128];
758         char *cbuf = buf;
759
760         if (n <= 0)
761                 return n;
762
763         switch ((uint32_t) c->qid.path) {
764                 case Qdir:
765                         return devdirread(c, buf, n, consdir, ARRAY_SIZE(consdir), devgen);
766                 case Qsysctl:
767                         return readstr(offset, buf, n, "akaros");
768 #if 0
769                 case Qcons:
770                 case Qkeyboard:
771                         qlock(&(&kbd)->qlock);
772                         if (waserror()) {
773                                 qunlock(&(&kbd)->qlock);
774                                 nexterror();
775                         }
776                         if (kbd.raw || kbd.kbdr) {
777                                 if (qcanread(lineq))
778                                         n = qread(lineq, buf, n);
779                                 else {
780                                         /* read as much as possible */
781                                         do {
782                                                 i = qread(kbdq, cbuf, n);
783                                                 cbuf += i;
784                                                 n -= i;
785                                         } while (n > 0 && qcanread(kbdq));
786                                         n = cbuf - (char *unused_char_p_t)buf;
787                                 }
788                         } else {
789                                 while (!qcanread(lineq)) {
790                                         qread(kbdq, &kbd.line[kbd.x], 1);
791                                         ch = kbd.line[kbd.x];
792                                         eol = 0;
793                                         switch (ch) {
794                                                 case '\b':
795                                                         if (kbd.x)
796                                                                 kbd.x--;
797                                                         break;
798                                                 case 0x15:
799                                                         kbd.x = 0;
800                                                         break;
801                                                 case '\n':
802                                                 case 0x04:
803                                                         eol = 1;
804                                                 default:
805                                                         kbd.line[kbd.x++] = ch;
806                                                         break;
807                                         }
808                                         if (kbd.x == sizeof(kbd.line) || eol) {
809                                                 if (ch == 0x04)
810                                                         kbd.x--;
811                                                 qwrite(lineq, kbd.line, kbd.x);
812                                                 kbd.x = 0;
813                                         }
814                                 }
815                                 n = qread(lineq, buf, n);
816                         }
817                         qunlock(&(&kbd)->qlock);
818                         poperror();
819                         return n;
820
821                 case Qscancode:
822                         if (offset == 0)
823                                 return readstr(0, buf, n, kscanid);
824                         else
825                                 return qread(kscanq, buf, n);
826
827                 case Qtime:
828                         snprintf(tmp, sizeof(tmp), "%.lld", (int64_t) mseconds() * 1000);
829                         return readstr(offset, buf, n, tmp);
830
831                 case Qhostowner:
832                         return readstr(offset, buf, n, eve);
833
834                 case Quser:
835                         return readstr(offset, buf, n, o->user);
836
837                 case Qjit:
838                         snprintf(tmp, sizeof(tmp), "%d", cflag);
839                         return readstr(offset, buf, n, tmp);
840 #endif
841                 case Qnull:
842                         return 0;
843 #if 0
844                 case Qmsec:
845                         return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
846 #endif
847                 case Qsysname:
848                         if (sysname == NULL)
849                                 return 0;
850                         return readstr(offset, buf, n, "Akaros");
851
852                 case Qrandom:
853                 case Qurandom:
854                         return randomread(buf, n);
855 #if 0
856                 case Qmemory:
857                         return poolread(buf, n, offset);
858 #endif
859                 case Qdrivers:
860                         p = kzmalloc(READSTR, 0);
861                         if (p == NULL)
862                                 error(ENOMEM, NULL);
863                         l = 0;
864                         for (i = 0; &devtab[i] < __devtabend; i++)
865                                 l += snprintf(p + l, READSTR - l, "#%s\n", devtab[i].name);
866                         if (waserror()) {
867                                 kfree(p);
868                                 nexterror();
869                         }
870                         n = readstr(offset, buf, n, p);
871                         kfree(p);
872                         poperror();
873                         return n;
874                 case Qklog:
875                         //return qread(klogq, buf, n);  
876                         /* the queue gives us some elasticity for log reading. */
877                         if (!logqueue)
878                                 logqueue = qopen(1 << 20, 0, 0, 0);
879                         if (logqueue) {
880                                 int ret;
881                                 /* atomic sets/gets are not that important in this case. */
882                                 reading_kmesg = 1;
883                                 qwrite(logqueue, logbuffer, index);
884                                 index = 0;
885                                 ret = qread(logqueue, buf, n);
886                                 reading_kmesg = 0;
887                                 return ret;
888                         }
889                         break;
890 #if 0
891                 case Qkprint:
892                         rlock(&(&kprintq)->rwlock);
893                         if (waserror()) {
894                                 runlock(&(&kprintq)->rwlock);
895                                 nexterror();
896                         }
897                         n = qread(kprintq.q, buf, n);
898                         poperror();
899                         runlock(&(&kprintq)->rwlock);
900                         return n;
901 #endif
902                 default:
903                         printd("consread %llu\n", c->qid.path);
904                         error(EINVAL, NULL);
905         }
906         return -1;      /* never reached */
907 }
908
909 static long conswrite(struct chan *c, void *va, long n, int64_t offset)
910 {
911         ERRSTACK(1);
912         int64_t t;
913         uint64_t ip;
914         long l, bp;
915         char *a = va;
916         struct cmdbuf *cb;
917         struct cmdtab *ct;
918         char buf[256];
919         int x;
920         uint64_t rip, rsp, cr3, flags, vcpu;
921         int ret;
922
923         switch ((uint32_t) c->qid.path) {
924 #if 0
925                 case Qcons:
926                         /*
927                          * Can't page fault in putstrn, so copy the data locally.
928                          */
929                         l = n;
930                         while (l > 0) {
931                                 bp = l;
932                                 if (bp > sizeof buf)
933                                         bp = sizeof buf;
934                                 memmove(buf, a, bp);
935                                 putstrn0(a, bp, 1);
936                                 a += bp;
937                                 l -= bp;
938                         }
939                         break;
940
941                 case Qconsctl:
942                         if (n >= sizeof(buf))
943                                 n = sizeof(buf) - 1;
944                         strncpy(buf, a, n);
945                         buf[n] = 0;
946                         for (a = buf; a;) {
947                                 if (strncmp(a, "rawon", 5) == 0) {
948                                         qlock(&(&kbd)->qlock);
949                                         flushkbdline(kbdq);
950                                         kbd.raw = 1;
951                                         qunlock(&(&kbd)->qlock);
952                                 } else if (strncmp(a, "rawoff", 6) == 0) {
953                                         qlock(&(&kbd)->qlock);
954                                         kbd.raw = 0;
955                                         kbd.x = 0;
956                                         qunlock(&(&kbd)->qlock);
957                                 }
958                                 if (a = strchr(a, ' '))
959                                         a++;
960                         }
961                         break;
962
963                 case Qkeyboard:
964                         for (x = 0; x < n;) {
965                                 Rune r;
966                                 x += chartorune(&r, &a[x]);
967                                 kbdputc(kbdq, r);
968                         }
969                         break;
970
971                 case Qtime:
972                         if (n >= sizeof(buf))
973                                 n = sizeof(buf) - 1;
974                         strncpy(buf, a, n);
975                         buf[n] = 0;
976                         t = strtoll(buf, 0, 0) / 1000000;
977                         boottime = t - TK2SEC(MACHP(0)->ticks);
978                         break;
979
980                 case Qhostowner:
981                         if (!iseve())
982                                 error(EPERM, NULL);
983                         if (offset != 0 || n >= sizeof(buf))
984                                 error(EINVAL, NULL);
985                         memmove(buf, a, n);
986                         buf[n] = '\0';
987                         if (n > 0 && buf[n - 1] == '\n')
988                                 buf[--n] = 0;
989                         if (n <= 0)
990                                 error(EINVAL, NULL);
991                         renameuser(eve, buf);
992                         renameproguser(eve, buf);
993                         kstrdup(&eve, buf);
994                         kstrdup(&up->env->user, buf);
995                         break;
996
997                 case Quser:
998                         if (!iseve())
999                                 error(EPERM, NULL);
1000                         if (offset != 0)
1001                                 error(EINVAL, NULL);
1002                         if (n <= 0 || n >= sizeof(buf))
1003                                 error(EINVAL, NULL);
1004                         strncpy(buf, a, n);
1005                         buf[n] = 0;
1006                         if (buf[n - 1] == '\n')
1007                                 buf[n - 1] = 0;
1008                         kstrdup(&up->env->user, buf);
1009                         break;
1010
1011                 case Qjit:
1012                         if (n >= sizeof(buf))
1013                                 n = sizeof(buf) - 1;
1014                         strncpy(buf, va, n);
1015                         buf[n] = '\0';
1016                         x = atoi(buf);
1017                         if (x < 0 || x > 9)
1018                                 error(EINVAL, NULL);
1019                         cflag = x;
1020                         return n;
1021
1022                 case Qnull:
1023                         break;
1024
1025                 case Qsysname:
1026                         if (offset != 0)
1027                                 error(EINVAL, NULL);
1028                         if (n <= 0 || n >= sizeof(buf))
1029                                 error(EINVAL, NULL);
1030                         strncpy(buf, a, n);
1031                         buf[n] = 0;
1032                         if (buf[n - 1] == '\n')
1033                                 buf[n - 1] = 0;
1034                         kstrdup(&sysname, buf);
1035                         break;
1036 #endif
1037                 case Qsysctl:
1038                         //if (!iseve()) error(EPERM, NULL);
1039                         cb = parsecmd(a, n);
1040                         if (cb->nf > 1) 
1041                         printd("cons sysctl cmd %s\n", cb->f[0]);
1042                         if (waserror()) {
1043                                 kfree(cb);
1044                                 nexterror();
1045                         }
1046                         ct = lookupcmd(cb, sysctlcmd, ARRAY_SIZE(sysctlcmd));
1047                         switch (ct->index) {
1048                                 case CMreboot:
1049                                         reboot();
1050                                         break;
1051                                 case CMhalt:
1052                                         cpu_halt();
1053                                         break;
1054                                 case CMpanic:
1055                                         panic("sysctl");
1056                                         //case CMconsole:
1057                                         //consoleprint = strcmp(cb->f[1], "off") != 0;
1058                                         break;
1059                                 case CMbroken:
1060                                         keepbroken = 1;
1061                                         break;
1062                                 case CMnobroken:
1063                                         keepbroken = 0;
1064                                         break;
1065                                 case CMV:
1066                                         rip =  strtoul(cb->f[1], NULL, 0);
1067                                         rsp =  strtoul(cb->f[2], NULL, 0);
1068                                         cr3 =  strtoul(cb->f[3], NULL, 0);
1069                                         ret = vm_run(rip, rsp, cr3);
1070                                         printd("vm_run returns %d\n", ret);
1071                                         n = ret;
1072                                         break;
1073                         }
1074                         poperror();
1075                         kfree(cb);
1076                         break;
1077                 default:
1078                         printd("conswrite: %llu\n", c->qid.path);
1079                         error(EINVAL, NULL);
1080         }
1081         return n;
1082 }
1083
1084 struct dev consdevtab __devtab = {
1085         "cons",
1086
1087         devreset,
1088         consinit,
1089         devshutdown,
1090         consattach,
1091         conswalk,
1092         consstat,
1093         consopen,
1094         devcreate,
1095         consclose,
1096         consread,
1097         devbread,
1098         conswrite,
1099         devbwrite,
1100         devremove,
1101         devwstat,
1102         devpower,
1103         devchaninfo,
1104 };
1105
1106 static uint32_t randn;
1107
1108 static void seedrand(void)
1109 {
1110         randomread((void *)&randn, sizeof(randn));
1111 }
1112
1113 int nrand(int n)
1114 {
1115         if (randn == 0)
1116                 seedrand();
1117         randn = randn * 1103515245 + 12345 + read_tsc();
1118         return (randn >> 16) % n;
1119 }
1120
1121 int rand(void)
1122 {
1123         nrand(1);
1124         return randn;
1125 }
1126
1127 uint32_t truerand(void)
1128 {
1129         uint32_t x;
1130
1131         randomread(&x, sizeof(x));
1132         return x;
1133 }
1134
1135 /* TODO: qlock_init this, if you ever use this */
1136 qlock_t grandomlk;
1137
1138 void _genrandomqlock(void)
1139 {
1140         qlock(&grandomlk);
1141 }
1142
1143 void _genrandomqunlock(void)
1144 {
1145         qunlock(&grandomlk);
1146 }