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