Add in minimal code for freeing a vm
[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 static long
846 consread(struct chan *c, void *buf, long n, int64_t offset)
847 {
848         ERRSTACK(2);
849         int l;
850
851         int ch, eol, i;
852         char *p, tmp[128];
853         char *cbuf = buf;
854
855         if(n <= 0)
856                 return n;
857
858         switch((uint32_t)c->qid.path){
859         case Qdir:
860                 return devdirread(c, buf, n, consdir, ARRAY_SIZE(consdir), devgen);
861         case Qsysctl:
862                 return readstr(offset, buf, n, "akaros");
863 #if 0
864         case Qcons:
865         case Qkeyboard:
866                 qlock(&(&kbd)->qlock);
867                 if(waserror()) {
868                         qunlock(&(&kbd)->qlock);
869                         nexterror();
870                 }
871                 if(kbd.raw || kbd.kbdr) {
872                         if(qcanread(lineq))
873                                 n = qread(lineq, buf, n);
874                         else {
875                                 /* read as much as possible */
876                                 do {
877                                         i = qread(kbdq, cbuf, n);
878                                         cbuf += i;
879                                         n -= i;
880                                 } while(n>0 && qcanread(kbdq));
881                                 n = cbuf - ( char *unused_char_p_t)buf;
882                         }
883                 } else {
884                         while(!qcanread(lineq)) {
885                                 qread(kbdq, &kbd.line[kbd.x], 1);
886                                 ch = kbd.line[kbd.x];
887                                 eol = 0;
888                                 switch(ch){
889                                 case '\b':
890                                         if(kbd.x)
891                                                 kbd.x--;
892                                         break;
893                                 case 0x15:
894                                         kbd.x = 0;
895                                         break;
896                                 case '\n':
897                                 case 0x04:
898                                         eol = 1;
899                                 default:
900                                         kbd.line[kbd.x++] = ch;
901                                         break;
902                                 }
903                                 if(kbd.x == sizeof(kbd.line) || eol) {
904                                         if(ch == 0x04)
905                                                 kbd.x--;
906                                         qwrite(lineq, kbd.line, kbd.x);
907                                         kbd.x = 0;
908                                 }
909                         }
910                         n = qread(lineq, buf, n);
911                 }
912                 qunlock(&(&kbd)->qlock);
913                 poperror();
914                 return n;
915
916         case Qscancode:
917                 if(offset == 0)
918                         return readstr(0, buf, n, kscanid);
919                 else
920                         return qread(kscanq, buf, n);
921
922         case Qtime:
923                 snprintf(tmp, sizeof(tmp), "%.lld", (int64_t)mseconds()*1000);
924                 return readstr(offset, buf, n, tmp);
925
926         case Qhostowner:
927                 return readstr(offset, buf, n, eve);
928
929         case Quser:
930                 return readstr(offset, buf, n, o->user);
931
932         case Qjit:
933                 snprintf(tmp, sizeof(tmp), "%d", cflag);
934                 return readstr(offset, buf, n, tmp);
935 #endif
936         case Qnull:
937                 return 0;
938 #if 0
939         case Qmsec:
940                 return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
941 #endif
942         case Qsysname:
943                 if(sysname == NULL)
944                         return 0;
945                 return readstr(offset, buf, n, "Windows 95");
946
947 /* not in akaros, inferno was a special case. 
948         case Qnotquiterandom:
949                 genrandom(buf, n);
950                 return n;
951 */
952
953         case Qrandom:
954                 return randomread(buf, n);
955 #if 0
956         case Qmemory:
957                 return poolread(buf, n, offset);
958 #endif
959         case Qdrivers:
960                 p = kzmalloc(READSTR, 0);
961                 if(p == NULL)
962                         error(Enomem);
963                 l = 0;
964                 for(i = 0; devtab[i] != NULL; i++)
965                         l += snprintf(p+l, READSTR-l, "#%C %s\n", devtab[i]->dc,  devtab[i]->name);
966                 if(waserror()){
967                         kfree(p);
968                         nexterror();
969                 }
970                 n = readstr(offset, buf, n, p);
971                 kfree(p);
972                 poperror();
973                 return n;
974 #if 0
975         case Qklog:
976                 return qread(klogq, buf, n);
977
978         case Qkprint:
979                 rlock(&(&kprintq)->rwlock);
980                 if(waserror()){
981                         runlock(&(&kprintq)->rwlock);
982                         nexterror();
983                 }
984                 n = qread(kprintq.q, buf, n);
985                 poperror();
986                 runlock(&(&kprintq)->rwlock);
987                 return n;
988 #endif
989         default:
990                 printd("consread %llud\n", c->qid.path);
991                 error(Egreg);
992         }
993         return -1;              /* never reached */
994 }
995
996 static long
997 conswrite(struct chan *c, void *va, long n, int64_t offset)
998 {
999         int64_t t;
1000         long l, bp;
1001         char *a = va;
1002         struct cmdbuf *cb;
1003         struct cmdtab *ct;
1004         char buf[256];
1005         int x;
1006
1007         switch((uint32_t)c->qid.path){
1008 #if 0
1009         case Qcons:
1010                 /*
1011                  * Can't page fault in putstrn, so copy the data locally.
1012                  */
1013                 l = n;
1014                 while(l > 0){
1015                         bp = l;
1016                         if(bp > sizeof buf)
1017                                 bp = sizeof buf;
1018                         memmove(buf, a, bp);
1019                         putstrn0(a, bp, 1);
1020                         a += bp;
1021                         l -= bp;
1022                 }
1023                 break;
1024
1025         case Qconsctl:
1026                 if(n >= sizeof(buf))
1027                         n = sizeof(buf)-1;
1028                 strncpy(buf, a, n);
1029                 buf[n] = 0;
1030                 for(a = buf; a;){
1031                         if(strncmp(a, "rawon", 5) == 0){
1032                                 qlock(&(&kbd)->qlock);
1033                                 flushkbdline(kbdq);
1034                                 kbd.raw = 1;
1035                                 qunlock(&(&kbd)->qlock);
1036                         } else if(strncmp(a, "rawoff", 6) == 0){
1037                                 qlock(&(&kbd)->qlock);
1038                                 kbd.raw = 0;
1039                                 kbd.x = 0;
1040                                 qunlock(&(&kbd)->qlock);
1041                         }
1042                         if(a = strchr(a, ' '))
1043                                 a++;
1044                 }
1045                 break;
1046
1047         case Qkeyboard:
1048                 for(x=0; x<n; ) {
1049                         Rune r;
1050                         x += chartorune(&r, &a[x]);
1051                         kbdputc(kbdq, r);
1052                 }
1053                 break;
1054         
1055         case Qtime:
1056                 if(n >= sizeof(buf))
1057                         n = sizeof(buf)-1;
1058                 strncpy(buf, a, n);
1059                 buf[n] = 0;
1060                 t = strtoll(buf, 0, 0)/1000000;
1061                 boottime = t - TK2SEC(MACHP(0)->ticks);
1062                 break;
1063
1064         case Qhostowner:
1065                 if(!iseve())
1066                         error(Eperm);
1067                 if(offset != 0 || n >= sizeof(buf))
1068                         error(Ebadarg);
1069                 memmove(buf, a, n);
1070                 buf[n] = '\0';
1071                 if(n > 0 && buf[n-1] == '\n')
1072                         buf[--n] = 0;
1073                 if(n <= 0)
1074                         error(Ebadarg);
1075                 renameuser(eve, buf);
1076                 renameproguser(eve, buf);
1077                 kstrdup(&eve, buf);
1078                 kstrdup(&up->env->user, buf);
1079                 break;
1080
1081         case Quser:
1082                 if(!iseve())
1083                         error(Eperm);
1084                 if(offset != 0)
1085                         error(Ebadarg);
1086                 if(n <= 0 || n >= sizeof(buf))
1087                         error(Ebadarg);
1088                 strncpy(buf, a, n);
1089                 buf[n] = 0;
1090                 if(buf[n-1] == '\n')
1091                         buf[n-1] = 0;
1092                 kstrdup(&up->env->user, buf);
1093                 break;
1094
1095         case Qjit:
1096                 if(n >= sizeof(buf))
1097                         n = sizeof(buf)-1;
1098                 strncpy(buf, va, n);
1099                 buf[n] = '\0';
1100                 x = atoi(buf);
1101                 if(x < 0 || x > 9)
1102                         error(Ebadarg);
1103                 cflag = x;
1104                 return n;
1105
1106         case Qnull:
1107                 break;
1108
1109         case Qsysname:
1110                 if(offset != 0)
1111                         error(Ebadarg);
1112                 if(n <= 0 || n >= sizeof(buf))
1113                         error(Ebadarg);
1114                 strncpy(buf, a, n);
1115                 buf[n] = 0;
1116                 if(buf[n-1] == '\n')
1117                         buf[n-1] = 0;
1118                 kstrdup(&sysname, buf);
1119                 break;
1120
1121         case Qsysctl:
1122                 if(!iseve())
1123                         error(Eperm);
1124                 cb = parsecmd(a, n);
1125                 if(waserror()){
1126                         kfree(cb);
1127                         nexterror();
1128                 }
1129                 ct = lookupcmd(cb, sysctlcmd, ARRAY_SIZE(sysctlcmd));
1130                 switch(ct->index){
1131                 case CMreboot:
1132                         reboot();
1133                         break;
1134                 case CMhalt:
1135                         halt();
1136                         break;
1137                 case CMpanic:
1138                         panic("sysctl");
1139                 case CMconsole:
1140                         consoleprint = strcmp(cb->f[1], "off") != 0;
1141                         break;
1142                 case CMbroken:
1143                         keepbroken = 1;
1144                         break;
1145                 case CMnobroken:
1146                         keepbroken = 0;
1147                         break;
1148                 }
1149                 poperror();
1150                 kfree(cb);
1151                 break;
1152 #endif
1153         default:
1154                 printd("conswrite: %llud\n", c->qid.path);
1155                 error(Egreg);
1156         }
1157         return n;
1158 }
1159
1160 struct dev consdevtab = {
1161         'c',
1162         "cons",
1163
1164         devreset,
1165         consinit,
1166         devshutdown,
1167         consattach,
1168         conswalk,
1169         consstat,
1170         consopen,
1171         devcreate,
1172         consclose,
1173         consread,
1174         devbread,
1175         conswrite,
1176         devbwrite,
1177         devremove,
1178         devwstat,
1179 };
1180
1181 static  uint32_t        randn;
1182
1183 static void
1184 seedrand(void)
1185 {
1186         randomread((void*)&randn, sizeof(randn));
1187 }
1188
1189 int
1190 nrand(int n)
1191 {
1192         if(randn == 0)
1193                 seedrand();
1194         randn = randn*1103515245 + 12345 + read_tsc();
1195         return (randn>>16) % n;
1196 }
1197
1198 int
1199 rand(void)
1200 {
1201         nrand(1);
1202         return randn;
1203 }
1204
1205 uint32_t
1206 truerand(void)
1207 {
1208         uint32_t x;
1209
1210         randomread(&x, sizeof(x));
1211         return x;
1212 }
1213
1214 qlock_t grandomlk;
1215
1216 void
1217 _genrandomqlock(void)
1218 {
1219         qlock(&grandomlk);
1220 }
1221
1222
1223 void
1224 _genrandomqunlock(void)
1225 {
1226         qunlock(&grandomlk);
1227 }