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