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