2578b494153d90e4361e28b2f2028e2ac858573b
[akaros.git] / kern / drivers / dev / cons.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9
10 #include <arch/arch.h>
11 #include <ros/fs.h>
12 #include <ns.h>
13 #include <kmalloc.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <time.h>
17 #include <atomic.h>
18 #include <smp.h>
19 #include <error.h>
20 #include <sys/queue.h>
21 #include <event.h>
22 #include <ros/procinfo.h>
23
24 #if 0
25 void (*consdebug) (void) = NULL;
26 #endif
27 void (*screenputs) (const char *, int) = cputbuf;
28
29 struct queue *kbdq;                             /* unprocessed console input */
30 struct queue *lineq;                    /* processed console input */
31 struct queue *serialoq;                 /* serial console output */
32 struct queue *kprintoq;                 /* console output, for /dev/kprint */
33 atomic_t kprintinuse = 0;               /* test and set whether /dev/kprint is open */
34 int iprintscreenputs = 1;
35 int keepbroken = 1;
36
37 struct queue *cons_q;                   /* Akaros cons input: keyboard, serial, etc */
38
39 static uint8_t logbuffer[1 << 20];
40 static int index = 0;
41 static struct queue *logqueue = NULL;
42 static int reading_kmesg = 0;
43
44 typedef unsigned char uint8_t;
45
46 void logbuf(int c)
47 {
48         if (reading_kmesg)
49                 return;
50         if (index > 1 << 20)
51                 return;
52         logbuffer[index++] = c;
53 }
54
55 /*
56  *  return true if current user is eve
57  */
58 int iseve(void)
59 {
60 #if 0
61         return strcmp(eve, o->user) == 0;
62 #endif
63         return 1;
64 }
65
66 char *eve = "eve";
67 char hostdomain[256] = "akaros.org";
68
69 static struct {
70         qlock_t qlock;
71
72         int raw;                                        /* true if we shouldn't process input */
73         struct kref ctl;                        /* number of opens to the control file */
74         int x;                                          /* index into line */
75         char line[1024];                        /* current input line */
76
77         int count;
78         int ctlpoff;
79
80         /* a place to save up characters at interrupt time before dumping them in the queue */
81         spinlock_t lockputc;
82         char istage[1024];
83         char *iw;
84         char *ir;
85         char *ie;
86 } kbd = {
87 .iw = kbd.istage,.ir = kbd.istage,.ie = kbd.istage + sizeof(kbd.istage),};
88
89 char *sysname;
90 int64_t fasthz;
91
92 static int readtime(uint32_t, char *, int);
93 static int readbintime(char *, int);
94 static int writetime(char *, int);
95 static int writebintime(char *, int);
96 static void killkid(void);
97
98 enum {
99         CMbroken,
100         CMconsole,
101         CMhalt,
102         CMnobroken,
103         CMpanic,
104         CMreboot,
105 };
106
107
108 struct cmdtab rebootmsg[] = {
109         {CMbroken, "broken", 0},
110         {CMconsole, "console", 1},
111         {CMhalt, "halt", 1},
112         {CMnobroken, "nobroken", 0},
113         {CMpanic, "panic", 0},
114         {CMreboot, "reboot", 0},
115 };
116
117 void printinit(void)
118 {
119         lineq = qopen(2 * 1024, 0, NULL, NULL);
120         if (lineq == NULL)
121                 panic("printinit");
122         qdropoverflow(lineq, 1);
123 }
124
125 int consactive(void)
126 {
127         if (serialoq)
128                 return qlen(serialoq) > 0;
129         return 0;
130 }
131
132 void prflush(void)
133 {
134         long times = 0;
135
136         while (consactive())
137                 if (times++ > 1000)
138                         break;
139 }
140
141 /*
142  * Log console output so it can be retrieved via /dev/kmesg.
143  * This is good for catching boot-time messages after the fact.
144  */
145 struct {
146         spinlock_t lk;
147         char buf[1 << 20];
148         unsigned int n;
149 } kmesg;
150
151 static void kmesgputs(char *str, int n)
152 {
153         unsigned int nn, d;
154
155         spin_lock_irqsave(&kmesg.lk);
156         /* take the tail of huge writes */
157         if (n > sizeof kmesg.buf) {
158                 d = n - sizeof kmesg.buf;
159                 str += d;
160                 n -= d;
161         }
162
163         /* slide the buffer down to make room */
164         nn = kmesg.n;
165         if (nn + n >= sizeof kmesg.buf) {
166                 d = nn + n - sizeof kmesg.buf;
167                 if (d)
168                         memmove(kmesg.buf, kmesg.buf + d, sizeof kmesg.buf - d);
169                 nn -= d;
170         }
171
172         /* copy the data in */
173         memmove(kmesg.buf + nn, str, n);
174         nn += n;
175         kmesg.n = nn;
176         spin_unlock_irqsave(&kmesg.lk);
177 }
178
179 /*
180  *   Print a string on the console.  Convert \n to \r\n for serial
181  *   line consoles.  Locking of the queues is left up to the screen
182  *   or uart code.  Multi-line messages to serial consoles may get
183  *   interspersed with other messages.
184  */
185 static void putstrn0(char *str, int n, int usewrite)
186 {
187         int m;
188         char *t;
189
190 #if 0
191         if (!islo())
192                 usewrite = 0;
193 #endif
194
195         /*
196          *  how many different output devices do we need?
197          */
198         kmesgputs(str, n);
199
200         /*
201          *  if someone is reading /dev/kprint
202          *  put the message there.
203          *  if not and there's an attached bit mapped display,
204          *  put the message there.
205          *
206          *  if there's a serial line being used as a console,
207          *  put the message there.
208          */
209         if (kprintoq != NULL && !qisclosed(kprintoq)) {
210                 if (usewrite)
211                         qwrite(kprintoq, str, n);
212                 else
213                         qiwrite(kprintoq, str, n);
214         } else if (screenputs != NULL)
215                 screenputs(str, n);
216
217         if (serialoq == NULL) {
218 #if 0
219                 uartputs(str, n);
220 #endif
221                 return;
222         }
223
224         while (n > 0) {
225                 t = memchr(str, '\n', n);
226                 if (t && !kbd.raw) {
227                         m = t - str;
228                         if (usewrite) {
229                                 qwrite(serialoq, str, m);
230                                 qwrite(serialoq, "\r\n", 2);
231                         } else {
232                                 qiwrite(serialoq, str, m);
233                                 qiwrite(serialoq, "\r\n", 2);
234                         }
235                         n -= m + 1;
236                         str = t + 1;
237                 } else {
238                         if (usewrite)
239                                 qwrite(serialoq, str, n);
240                         else
241                                 qiwrite(serialoq, str, n);
242                         break;
243                 }
244         }
245 }
246
247 void putstrn(char *str, int n)
248 {
249         putstrn0(str, n, 0);
250 }
251
252 int noprint;
253
254 int print(char *fmt, ...)
255 {
256         int n;
257         va_list arg;
258         char buf[PRINTSIZE];
259
260         if (noprint)
261                 return -1;
262
263         va_start(arg, fmt);
264         n = vsnprintf(buf, sizeof(buf), fmt, arg);
265         va_end(arg);
266         putstrn(buf, n);
267
268         return n;
269 }
270
271 /*
272  * Want to interlock iprints to avoid interlaced output on
273  * multiprocessor, but don't want to deadlock if one processor
274  * dies during print and another has something important to say.
275  * Make a good faith effort.
276  */
277 static spinlock_t iprintlock;
278 static int iprintcanlock(spinlock_t * l)
279 {
280         int i;
281
282         for (i = 0; i < 1000; i++) {
283                 if (spin_trylock(l))
284                         return 1;
285         }
286         return 0;
287 }
288
289 int iprint(char *fmt, ...)
290 {
291         int8_t s = 0;
292         int n, locked;
293         va_list arg;
294         char buf[PRINTSIZE];
295
296         disable_irqsave(&s);
297         va_start(arg, fmt);
298         n = vsnprintf(buf, sizeof(buf), fmt, arg);
299         va_end(arg);
300         locked = iprintcanlock(&iprintlock);
301         if (screenputs != NULL && iprintscreenputs)
302                 screenputs(buf, n);
303 #if 0
304         uartputs(buf, n);
305 #endif
306         if (locked)
307                 spin_unlock(&iprintlock);
308         enable_irqsave(&s);
309
310         return n;
311 }
312
313 /* libmp at least contains a few calls to sysfatal; simulate with panic */
314 void sysfatal(char *fmt, ...)
315 {
316         char err[256];
317         va_list arg;
318
319         va_start(arg, fmt);
320         vsnprintf(err, sizeof err, fmt, arg);
321         va_end(arg);
322         panic("sysfatal: %s", err);
323 }
324
325 void _assert(char *fmt)
326 {
327         panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
328 }
329
330 #if 0
331 int pprint(char *fmt, ...)
332 {
333         ERRSTACK(2);
334         int n;
335         struct chan *c;
336         va_list arg;
337         char buf[2 * PRINTSIZE];
338
339         if (up == NULL || current->fgrp == NULL)
340                 return 0;
341
342         c = current->fgrp->fd[2];
343         if (c == 0 || (c->mode != O_WRITE && c->mode != O_RDWR))
344                 return 0;
345         n = snprintf(buf, sizeof buf, "%s %lud: ", current->text, current->pid);
346         va_start(arg, fmt);
347         n = vsnprintf(buf + n, sizeof(buf), fmt, arg);
348         va_end(arg);
349
350         if (waserror())
351                 return 0;
352         devtab[c->type]->write(c, buf, n, c->offset);
353         poperror();
354
355         spin_lock(&c->lock);
356         c->offset += n;
357         spin_unlock(&c->lock);
358
359         return n;
360 }
361 #endif
362
363 static void echoscreen(char *buf, int n)
364 {
365         char *e, *p;
366         char ebuf[128];
367         int x;
368
369         p = ebuf;
370         e = ebuf + sizeof(ebuf) - 4;
371         while (n-- > 0) {
372                 if (p >= e) {
373                         screenputs(ebuf, p - ebuf);
374                         p = ebuf;
375                 }
376                 x = *buf++;
377                 if (x == 0x15) {
378                         *p++ = '^';
379                         *p++ = 'U';
380                         *p++ = '\n';
381                 } else
382                         *p++ = x;
383         }
384         if (p != ebuf)
385                 screenputs(ebuf, p - ebuf);
386 }
387
388 static void echoserialoq(char *buf, int n)
389 {
390         char *e, *p;
391         char ebuf[128];
392         int x;
393
394         p = ebuf;
395         e = ebuf + sizeof(ebuf) - 4;
396         while (n-- > 0) {
397                 if (p >= e) {
398                         qiwrite(serialoq, ebuf, p - ebuf);
399                         p = ebuf;
400                 }
401                 x = *buf++;
402                 if (x == '\n') {
403                         *p++ = '\r';
404                         *p++ = '\n';
405                 } else if (x == 0x15) {
406                         *p++ = '^';
407                         *p++ = 'U';
408                         *p++ = '\n';
409                 } else
410                         *p++ = x;
411         }
412         if (p != ebuf)
413                 qiwrite(serialoq, ebuf, p - ebuf);
414 }
415
416 static void echo(char *buf, int n)
417 {
418         static int ctrlt, pid;
419         char *e, *p;
420
421         if (n == 0)
422                 return;
423
424         e = buf + n;
425         for (p = buf; p < e; p++) {
426                 switch (*p) {
427 #if 0
428                         case 0x10:      /* ^P */
429                                 if (cpuserver && !kbd.ctlpoff) {
430                                         active.exiting = 1;
431                                         return;
432                                 }
433                                 break;
434 #endif
435                         case 0x14:      /* ^T */
436                                 ctrlt++;
437                                 if (ctrlt > 2)
438                                         ctrlt = 2;
439                                 continue;
440                 }
441
442                 if (ctrlt != 2)
443                         continue;
444
445                 /* ^T escapes */
446                 ctrlt = 0;
447                 switch (*p) {
448 #if 0
449                         case 'S':{
450                                         int8_t x = 0;
451                                         disable_irqsave(&x);
452                                         dumpstack();
453                                         procdump();
454                                         enable_irqsave(&x);
455                                         return;
456                                 }
457 #endif
458                         case 's':
459                                 dumpstack();
460                                 return;
461 #if 0
462                         case 'x':
463                                 xsummary();
464                                 ixsummary();
465                                 mallocsummary();
466                                 memorysummary();
467                                 pagersummary();
468                                 return;
469                         case 'd':
470                                 if (consdebug == NULL)
471                                         consdebug = rdb;
472                                 else
473                                         consdebug = NULL;
474                                 printd("consdebug now %#p\n", consdebug);
475                                 return;
476                         case 'D':
477                                 if (consdebug == NULL)
478                                         consdebug = rdb;
479                                 consdebug();
480                                 return;
481                         case 'p':
482                                 x = spllo();
483                                 procdump();
484                                 splx(x);
485                                 return;
486                         case 'q':
487                                 scheddump();
488                                 return;
489                         case 'k':
490                                 killbig("^t ^t k");
491                                 return;
492 #endif
493                         case 'r':
494                                 exit(0);
495                                 return;
496                 }
497         }
498
499         qwrite(kbdq, buf, n);   /* was once qproduce, YMMV */
500         if (kbd.raw)
501                 return;
502         kmesgputs(buf, n);
503         if (screenputs != NULL)
504                 echoscreen(buf, n);
505         if (serialoq)
506                 echoserialoq(buf, n);
507 }
508
509 /*
510  *  Called by a uart interrupt for console input.
511  *
512  *  turn '\r' into '\n' before putting it into the queue.
513  */
514 int kbdcr2nl(struct queue *ignored_queue, int ch)
515 {
516         char *next;
517
518         spin_lock_irqsave(&kbd.lockputc);       /* just a mutex */
519         if (ch == '\r' && !kbd.raw)
520                 ch = '\n';
521         next = kbd.iw + 1;
522         if (next >= kbd.ie)
523                 next = kbd.istage;
524         if (next != kbd.ir) {
525                 *kbd.iw = ch;
526                 kbd.iw = next;
527         }
528         spin_unlock_irqsave(&kbd.lockputc);
529         return 0;
530 }
531
532 /*
533  *  Put character, possibly a rune, into read queue at interrupt time.
534  *  Called at interrupt time to process a character.
535  */
536 int kbdputc(struct queue *unused_queue, int ch)
537 {
538         int i, n;
539         char buf[3];
540         // Akaros does not use Rune et al.
541         //Rune r;
542         int r;
543         char *next;
544
545         if (kbd.ir == NULL)
546                 return 0;       /* in case we're not inited yet */
547
548         spin_lock_irqsave(&kbd.lockputc);       /* just a mutex */
549         r = ch;
550         //n = runetochar(buf, &r);
551         // Fake Rune support.
552         n = 1;
553         buf[0] = r;
554         for (i = 0; i < n; i++) {
555                 next = kbd.iw + 1;
556                 if (next >= kbd.ie)
557                         next = kbd.istage;
558                 if (next == kbd.ir)
559                         break;
560                 *kbd.iw = buf[i];
561                 kbd.iw = next;
562         }
563         spin_unlock_irqsave(&kbd.lockputc);
564         return 0;
565 }
566
567 /*
568  *  we save up input characters till clock time to reduce
569  *  per character interrupt overhead.
570  */
571 static void kbdputcclock(void)
572 {
573         char *iw;
574
575         /* this amortizes cost of qproduce */
576         if (kbd.iw != kbd.ir) {
577                 iw = kbd.iw;
578                 if (iw < kbd.ir) {
579                         echo(kbd.ir, kbd.ie - kbd.ir);
580                         kbd.ir = kbd.istage;
581                 }
582                 if (kbd.ir != iw) {
583                         echo(kbd.ir, iw - kbd.ir);
584                         kbd.ir = iw;
585                 }
586         }
587 }
588
589 enum {
590         Qdir,
591         Qbintime,
592         Qconfig,
593         Qcons,
594         Qconsctl,
595         Qcputime,
596         Qdrivers,
597         Qhostdomain,
598         Qhostowner,
599         Qklog,
600         Qkmesg,
601         Qkprint,
602         Qnull,
603         Qosversion,
604         Qpgrpid,
605         Qpid,
606         Qppid,
607         Qreboot,
608         Qswap,
609         Qsysctl,
610         Qsysname,
611         Qsysstat,
612         Qtime,
613         Quser,
614         Qzero,
615         Qkillkid,
616 };
617
618 enum {
619         VLNUMSIZE = 22,
620         DOMLEN = 256,
621 };
622
623 static struct dirtab consdir[] = {
624         {".", {Qdir, 0, QTDIR}, 0, DMDIR | 0555},
625         {"bintime", {Qbintime}, 24, 0664},
626         {"config", {Qconfig}, 0, 0444},
627         {"cons", {Qcons}, 0, 0660},
628         {"consctl", {Qconsctl}, 0, 0220},
629         // FIXME -- we don't have real permissions yet so we set it to 222, not 220
630         {"killkid", {Qkillkid}, 0, 0220 | /* BOGUS */ 2},
631         {"cputime", {Qcputime}, 6 * NUMSIZE, 0444},
632         {"drivers", {Qdrivers}, 0, 0444},
633         {"hostdomain", {Qhostdomain}, DOMLEN, 0664},
634         {"hostowner", {Qhostowner}, 0, 0664},
635         {"klog", {Qklog}, 0, 0440},
636         {"kmesg", {Qkmesg}, 0, 0440},
637         {"kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL | 0440},
638         {"null", {Qnull}, 0, 0666},
639         {"osversion", {Qosversion}, 0, 0444},
640         {"pgrpid", {Qpgrpid}, NUMSIZE, 0444},
641         {"pid", {Qpid}, NUMSIZE, 0444},
642         {"ppid", {Qppid}, NUMSIZE, 0444},
643         {"reboot", {Qreboot}, 0, 0660},
644         {"swap", {Qswap}, 0, 0664},
645         {"sysctl", {Qsysctl}, 0, 0666},
646         {"sysname", {Qsysname}, 0, 0664},
647         {"sysstat", {Qsysstat}, 0, 0666},
648         {"time", {Qtime}, NUMSIZE + 3 * VLNUMSIZE, 0664},
649         {"user", {Quser}, 0, 0666},
650         {"zero", {Qzero}, 0, 0444},
651 };
652
653 int consreadnum(uint32_t off, char *buf, uint32_t n, uint32_t val, int size)
654 {
655         char tmp[64];
656
657         snprintf(tmp, sizeof(tmp), "%*lud", size - 1, val);
658         tmp[size - 1] = ' ';
659         if (off >= size)
660                 return 0;
661         if (off + n > size)
662                 n = size - off;
663         memmove(buf, tmp + off, n);
664         return n;
665 }
666
667 int consreadstr(uint32_t off, char *buf, uint32_t n, char *str)
668 {
669         int size;
670
671         size = strlen(str);
672         if (off >= size)
673                 return 0;
674         if (off + n > size)
675                 n = size - off;
676         memmove(buf, str + off, n);
677         return n;
678 }
679
680 static void consinit(void)
681 {
682         kstrdup(&sysname, "nanwan");
683         cons_q = qopen(256, 0, 0, 0);
684 #if 0
685         todinit();
686 #endif
687         /*
688          * at 115200 baud, the 1024 char buffer takes 56 ms to process,
689          * processing it every 22 ms should be fine
690          */
691 #if 0
692         addclock0link(kbdputcclock, 22);
693 #endif
694 }
695
696 static char *devname(void);
697
698 static struct chan *consattach(char *spec)
699 {
700         return devattach(devname(), spec);
701 }
702
703 static struct walkqid *conswalk(struct chan *c, struct chan *nc, char **name,
704                                                                 int nname)
705 {
706         return devwalk(c, nc, name, nname, consdir, ARRAY_SIZE(consdir), devgen);
707 }
708
709 static int consstat(struct chan *c, uint8_t * dp, int n)
710 {
711         return devstat(c, dp, n, consdir, ARRAY_SIZE(consdir), devgen);
712 }
713
714 static struct chan *consopen(struct chan *c, int omode)
715 {
716         c->aux = NULL;
717         c = devopen(c, omode, consdir, ARRAY_SIZE(consdir), devgen);
718         switch ((uint32_t) c->qid.path) {
719                 case Qconsctl:
720                         kref_get(&kbd.ctl, 1);
721                         break;
722
723                 case Qkprint:
724                         if (atomic_swap(&kprintinuse, 1) != 0) {
725                                 c->flag &= ~COPEN;
726                                 error(EADDRINUSE, "kprintinuse lock failed");
727                         }
728                         if (kprintoq == NULL) {
729                                 kprintoq = qopen(8 * 1024, Qcoalesce, 0, 0);
730                                 if (kprintoq == NULL) {
731                                         c->flag &= ~COPEN;
732                                         error(ENOMEM, "Can't allocate kprintoq");
733                                 }
734                                 qdropoverflow(kprintoq, 1);
735                         } else
736                                 qreopen(kprintoq);
737                         c->iounit = qiomaxatomic;
738                         break;
739         }
740         return c;
741 }
742
743 static void consclose(struct chan *c)
744 {
745         switch ((uint32_t) c->qid.path) {
746                         /* last close of control file turns off raw */
747                 case Qconsctl:
748                         if (c->flag & COPEN) {
749                                 if (kref_put(&kbd.ctl) == 0)
750                                         kbd.raw = 0;
751                         }
752                         break;
753
754                         /* close of kprint allows other opens */
755                 case Qkprint:
756                         if (c->flag & COPEN) {
757                                 kprintinuse = 0;
758                                 qhangup(kprintoq, NULL);
759                         }
760                         break;
761         }
762 }
763
764 static long consread(struct chan *c, void *buf, long n, int64_t off)
765 {
766         ERRSTACK(1);
767         uint32_t l;
768 #if 0
769         Mach *mp;
770 #endif
771         char *b, *bp, ch;
772         char tmp[256];                          /* must be >= 18*NUMSIZE (Qswap) */
773         int i, k, id, send;
774         int64_t offset = off;
775 #if 0
776         extern char configfile[];
777 #endif
778
779         if (n <= 0)
780                 return n;
781
782         switch ((uint32_t) c->qid.path) {
783                 case Qdir:
784                         return devdirread(c, buf, n, consdir, ARRAY_SIZE(consdir), devgen);
785
786                 case Qcons:
787                         qlock(&(&kbd)->qlock);
788                         if (waserror()) {
789                                 qunlock(&(&kbd)->qlock);
790                                 nexterror();
791                         }
792                         while (!qcanread(lineq)) {
793                                 if (qread(kbdq, &ch, 1) == 0)
794                                         continue;
795                                 send = 0;
796                                 if (ch == 0) {
797                                         /* flush output on rawoff -> rawon */
798                                         if (kbd.x > 0)
799                                                 send = !qcanread(kbdq);
800                                 } else if (kbd.raw) {
801                                         kbd.line[kbd.x++] = ch;
802                                         send = !qcanread(kbdq);
803                                 } else {
804                                         switch (ch) {
805                                                 case '\b':
806                                                         if (kbd.x > 0)
807                                                                 kbd.x--;
808                                                         break;
809                                                 case 0x15:      /* ^U */
810                                                         kbd.x = 0;
811                                                         break;
812                                                 case '\n':
813                                                 case 0x04:      /* ^D */
814                                                         send = 1;
815                                                 default:
816                                                         if (ch != 0x04)
817                                                                 kbd.line[kbd.x++] = ch;
818                                                         break;
819                                         }
820                                 }
821                                 if (send || kbd.x == sizeof kbd.line) {
822                                         qwrite(lineq, kbd.line, kbd.x);
823                                         kbd.x = 0;
824                                 }
825                         }
826                         n = qread(lineq, buf, n);
827                         qunlock(&(&kbd)->qlock);
828                         poperror();
829                         return n;
830
831 #if 0
832                 case Qcputime:
833                         k = offset;
834                         if (k >= 6 * NUMSIZE)
835                                 return 0;
836                         if (k + n > 6 * NUMSIZE)
837                                 n = 6 * NUMSIZE - k;
838                         /* easiest to format in a separate buffer and copy out */
839                         for (i = 0; i < 6 && NUMSIZE * i < k + n; i++) {
840                                 l = current->time[i];
841                                 if (i == TReal)
842                                         l = MACHP(0)->ticks - l;
843                                 l = TK2MS(l);
844                                 consreadnum(0, tmp + NUMSIZE * i, NUMSIZE, l, NUMSIZE);
845                         }
846                         memmove(buf, tmp + k, n);
847                         return n;
848 #endif
849
850                 case Qkmesg:
851                         /*
852                          * This is unlocked to avoid tying up a process
853                          * that's writing to the buffer.  kmesg.n never
854                          * gets smaller, so worst case the reader will
855                          * see a slurred buffer.
856                          */
857                         if (off >= kmesg.n)
858                                 n = 0;
859                         else {
860                                 if (off + n > kmesg.n)
861                                         n = kmesg.n - off;
862                                 memmove(buf, kmesg.buf + off, n);
863                         }
864                         return n;
865
866                 case Qkprint:
867                         return qread(kprintoq, buf, n);
868
869                 case Qpgrpid:
870                         return consreadnum((uint32_t) offset, buf, n, current->pgrp->pgrpid,
871                                                            NUMSIZE);
872
873                 case Qpid:
874                         return consreadnum((uint32_t) offset, buf, n, current->pid,
875                                                            NUMSIZE);
876
877                 case Qppid:
878                         return consreadnum((uint32_t) offset, buf, n, current->ppid,
879                                                            NUMSIZE);
880
881                 case Qtime:
882                         return readtime((uint32_t) offset, buf, n);
883
884                 case Qbintime:
885                         return readbintime(buf, n);
886
887                 case Qhostowner:
888                         return consreadstr((uint32_t) offset, buf, n, eve);
889
890                 case Qhostdomain:
891                         return consreadstr((uint32_t) offset, buf, n, hostdomain);
892
893                 case Quser:
894                         return consreadstr((uint32_t) offset, buf, n, current->user);
895
896                 case Qnull:
897                         return 0;
898
899 #if 0
900                 case Qconfig:
901                         return consreadstr((uint32_t) offset, buf, n, configfile);
902
903                 case Qsysstat:
904                         b = kzmalloc(conf.nmach * (NUMSIZE * 11 + 1) + 1, 0);   /* +1 for NUL */
905                         bp = b;
906                         for (id = 0; id < 32; id++) {
907                                 if (active.machs & (1 << id)) {
908                                         mp = MACHP(id);
909                                         consreadnum(0, bp, NUMSIZE, id, NUMSIZE);
910                                         bp += NUMSIZE;
911                                         consreadnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
912                                         bp += NUMSIZE;
913                                         consreadnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
914                                         bp += NUMSIZE;
915                                         consreadnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
916                                         bp += NUMSIZE;
917                                         consreadnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
918                                         bp += NUMSIZE;
919                                         consreadnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
920                                         bp += NUMSIZE;
921                                         consreadnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
922                                         bp += NUMSIZE;
923                                         consreadnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
924                                         bp += NUMSIZE;
925                                         consreadnum(0, bp, NUMSIZE,
926                                                                 (mp->perf.avg_inidle * 100) / mp->perf.period,
927                                                                 NUMSIZE);
928                                         bp += NUMSIZE;
929                                         consreadnum(0, bp, NUMSIZE,
930                                                                 (mp->perf.avg_inintr * 100) / mp->perf.period,
931                                                                 NUMSIZE);
932                                         bp += NUMSIZE;
933                                         *bp++ = '\n';
934                                 }
935                         }
936                         if (waserror()) {
937                                 kfree(b);
938                                 nexterror();
939                         }
940                         n = consreadstr((uint32_t) offset, buf, n, b);
941                         kfree(b);
942                         poperror();
943                         return n;
944
945                 case Qswap:
946                         snprintf(tmp, sizeof tmp,
947                                          "%lud memory\n"
948                                          "%d pagesize\n"
949                                          "%lud kernel\n"
950                                          "%lud/%lud user\n"
951                                          "%lud/%lud swap\n"
952                                          "%lud/%lud kernel malloc\n"
953                                          "%lud/%lud kernel draw\n",
954                                          conf.npage * BY2PG,
955                                          BY2PG,
956                                          conf.npage - conf.upages,
957                                          palloc.user - palloc.freecount, palloc.user,
958                                          conf.nswap - swapalloc.free, conf.nswap,
959                                          mainmem->cursize, mainmem->maxsize,
960                                          imagmem->cursize, imagmem->maxsize);
961
962                         return consreadstr((uint32_t) offset, buf, n, tmp);
963 #endif
964
965                 case Qsysname:
966                         /* TODO: this is racy */
967                         if (sysname == NULL)
968                                 return 0;
969                         return consreadstr((uint32_t) offset, buf, n, sysname);
970
971                 case Qdrivers:
972                         b = kzmalloc(READSTR, 0);
973                         if (b == NULL)
974                                 error(ENOMEM, "allocation for /dev/drivers read failed");
975                         k = 0;
976                         for (int i = 0; &devtab[i] < __devtabend; i++)
977                                 k += snprintf(b + k, READSTR - k, "#%s\n", devtab[i].name);
978                         if (waserror()) {
979                                 kfree(b);
980                                 nexterror();
981                         }
982                         n = consreadstr((uint32_t) offset, buf, n, b);
983                         kfree(b);
984                         poperror();
985                         return n;
986
987                 case Qklog:
988                         //return qread(klogq, buf, n);
989                         /* the queue gives us some elasticity for log reading. */
990                         if (!logqueue)
991                                 logqueue = qopen(1 << 20, 0, 0, 0);
992                         if (logqueue) {
993                                 int ret;
994                                 /* atomic sets/gets are not that important in this case. */
995                                 reading_kmesg = 1;
996                                 qwrite(logqueue, logbuffer, index);
997                                 index = 0;
998                                 ret = qread(logqueue, buf, n);
999                                 reading_kmesg = 0;
1000                                 return ret;
1001                         }
1002                         break;
1003
1004                 case Qzero:
1005                         memset(buf, 0, n);
1006                         return n;
1007
1008                 case Qosversion:
1009                         snprintf(tmp, sizeof tmp, "2000");
1010                         n = consreadstr((uint32_t) offset, buf, n, tmp);
1011                         return n;
1012
1013                 default:
1014                         printd("consread %#llux\n", c->qid.path);
1015                         error(EINVAL, "bad QID in consread");
1016         }
1017         return -1;      /* never reached */
1018 }
1019
1020 static long conswrite(struct chan *c, void *va, long n, int64_t off)
1021 {
1022         ERRSTACK(1);
1023         char buf[256], ch;
1024         long l, bp;
1025         char *a;
1026         //Mach *mp;
1027         int id, fd;
1028         struct chan *swc;
1029         uint32_t offset;
1030         struct cmdbuf *cb;
1031         struct cmdtab *ct;
1032         int x;
1033         uint64_t rip, rsp, cr3, flags, vcpu;
1034         int ret;
1035
1036         a = va;
1037         offset = off;
1038
1039         switch ((uint32_t) c->qid.path) {
1040                 case Qcons:
1041                         /*
1042                          * Can't page fault in putstrn, so copy the data locally.
1043                          */
1044                         l = n;
1045                         while (l > 0) {
1046                                 bp = l;
1047                                 if (bp > sizeof buf)
1048                                         bp = sizeof buf;
1049                                 memmove(buf, a, bp);
1050                                 putstrn0(buf, bp, 1);
1051                                 a += bp;
1052                                 l -= bp;
1053                         }
1054                         break;
1055
1056                 /* TODO: have it take a command about just *how* to kill the kid? */
1057                 case Qkillkid:
1058                         killkid();
1059                         break;
1060
1061                 case Qconsctl:
1062                         if (n >= sizeof(buf))
1063                                 n = sizeof(buf) - 1;
1064                         strncpy(buf, a, n);
1065                         buf[n] = 0;
1066                         for (a = buf; a;) {
1067                                 if (strncmp(a, "rawon", 5) == 0) {
1068                                         kbd.raw = 1;
1069                                         /* clumsy hack - wake up reader */
1070                                         ch = 0;
1071                                         qwrite(kbdq, &ch, 1);
1072                                 } else if (strncmp(a, "rawoff", 6) == 0) {
1073                                         kbd.raw = 0;
1074                                 } else if (strncmp(a, "ctlpon", 6) == 0) {
1075                                         kbd.ctlpoff = 0;
1076                                 } else if (strncmp(a, "ctlpoff", 7) == 0) {
1077                                         kbd.ctlpoff = 1;
1078                                 }
1079                                 if ((a = strchr(a, ' ')) != NULL)
1080                                         a++;
1081                         }
1082                         break;
1083
1084                 case Qtime:
1085                         if (!iseve())
1086                                 error(EPERM, "Hodie Natus Est Radici Frater");
1087                         return writetime(a, n);
1088
1089                 case Qbintime:
1090                         if (!iseve())
1091                                 error(EPERM, ERROR_FIXME);
1092                         return writebintime(a, n);
1093
1094 #if 0
1095                 case Qhostowner:
1096                         return hostownerwrite(a, n);
1097
1098                 case Qhostdomain:
1099                         return hostdomainwrite(a, n);
1100
1101                 case Quser:
1102                         return userwrite(a, n);
1103 #endif
1104
1105                 case Qnull:
1106                         break;
1107
1108                 case Qconfig:
1109                         error(EPERM, "Cannot write to config QID");
1110                         break;
1111
1112                 case Qsysctl:
1113                         //if (!iseve()) error(EPERM, ERROR_FIXME);
1114                         cb = parsecmd(a, n);
1115                         if (cb->nf > 1)
1116                         printd("cons sysctl cmd %s\n", cb->f[0]);
1117
1118                 case Qreboot:
1119                         if (!iseve())
1120                                 error(EPERM, ERROR_FIXME);
1121                         cb = parsecmd(a, n);
1122
1123                         if (waserror()) {
1124                                 kfree(cb);
1125                                 nexterror();
1126                         }
1127                         ct = lookupcmd(cb, rebootmsg, ARRAY_SIZE(rebootmsg));
1128                         switch (ct->index) {
1129                                 case CMhalt:
1130                                         cpu_halt();
1131                                         break;
1132                                 case CMbroken:
1133                                         keepbroken = 1;
1134                                         break;
1135                                 case CMnobroken:
1136                                         keepbroken = 0;
1137                                         break;
1138                                 case CMreboot:
1139                                         reboot();
1140                                         break;
1141                                 case CMpanic:
1142                                         *(uint32_t *) 0 = 0;
1143                                         panic("/dev/reboot");
1144                                         break;
1145                         }
1146                         poperror();
1147                         kfree(cb);
1148                         break;
1149
1150 #if 0
1151                 case Qsysstat:
1152                         for (id = 0; id < 32; id++) {
1153                                 if (active.machs & (1 << id)) {
1154                                         mp = MACHP(id);
1155                                         mp->cs = 0;
1156                                         mp->intr = 0;
1157                                         mp->syscall = 0;
1158                                         mp->pfault = 0;
1159                                         mp->tlbfault = 0;
1160                                         mp->tlbpurge = 0;
1161                                 }
1162                         }
1163                         break;
1164
1165                 case Qswap:
1166                         if (n >= sizeof buf)
1167                                 error(EINVAL, "n is bigger than sizeof buf for Qswap");
1168                         memmove(buf, va, n);    /* so we can NUL-terminate */
1169                         buf[n] = 0;
1170                         /* start a pager if not already started */
1171                         if (strncmp(buf, "start", 5) == 0) {
1172                                 kickpager();
1173                                 break;
1174                         }
1175                         if (!iseve())
1176                                 error(EPERM, ERROR_FIXME);
1177                         if (buf[0] < '0' || '9' < buf[0])
1178                                 error(EINVAL, ERROR_FIXME);
1179                         fd = strtoul(buf, 0, 0);
1180                         swc = fdtochan(fd, -1, 1, 1);
1181                         setswapchan(swc);
1182                         break;
1183 #endif
1184
1185                 case Qsysname:
1186                         /* TODO: this is racy */
1187                         if (offset != 0)
1188                                 error(EINVAL, ERROR_FIXME);
1189                         if (n <= 0 || n >= sizeof buf)
1190                                 error(EINVAL, ERROR_FIXME);
1191                         strncpy(buf, a, n);
1192                         buf[n] = 0;
1193                         if (buf[n - 1] == '\n')
1194                                 buf[n - 1] = 0;
1195                         kstrdup(&sysname, buf);
1196                         break;
1197
1198                 default:
1199                         printd("conswrite: %#llux\n", c->qid.path);
1200                         error(EINVAL, "bad QID in conswrite");
1201         }
1202         return n;
1203 }
1204
1205 struct dev consdevtab __devtab = {
1206         .name = "cons",
1207
1208         .reset = devreset,
1209         .init = consinit,
1210         .shutdown = devshutdown,
1211         .attach = consattach,
1212         .walk = conswalk,
1213         .stat = consstat,
1214         .open = consopen,
1215         .create = devcreate,
1216         .close = consclose,
1217         .read = consread,
1218         .bread = devbread,
1219         .write = conswrite,
1220         .bwrite = devbwrite,
1221         .remove = devremove,
1222         .wstat = devwstat,
1223         .power = devpower,
1224         .chaninfo = devchaninfo,
1225 };
1226
1227 static char *devname(void)
1228 {
1229         return consdevtab.name;
1230 }
1231
1232 static uint64_t uvorder = 0x0001020304050607ULL;
1233
1234 static uint8_t *le2int64_t(int64_t * to, uint8_t * f)
1235 {
1236         uint8_t *t, *o;
1237         int i;
1238
1239         t = (uint8_t *) to;
1240         o = (uint8_t *) & uvorder;
1241         for (i = 0; i < sizeof(int64_t); i++)
1242                 t[o[i]] = f[i];
1243         return f + sizeof(int64_t);
1244 }
1245
1246 static uint8_t *int64_t2le(uint8_t * t, int64_t from)
1247 {
1248         uint8_t *f, *o;
1249         int i;
1250
1251         f = (uint8_t *) & from;
1252         o = (uint8_t *) & uvorder;
1253         for (i = 0; i < sizeof(int64_t); i++)
1254                 t[i] = f[o[i]];
1255         return t + sizeof(int64_t);
1256 }
1257
1258 static long order = 0x00010203;
1259
1260 static uint8_t *le2long(long *to, uint8_t * f)
1261 {
1262         uint8_t *t, *o;
1263         int i;
1264
1265         t = (uint8_t *) & to;
1266         o = (uint8_t *) & order;
1267         for (i = 0; i < sizeof(long); i++)
1268                 t[o[i]] = f[i];
1269         return f + sizeof(long);
1270 }
1271
1272 static uint8_t *long2le(uint8_t * t, long from)
1273 {
1274         uint8_t *f, *o;
1275         int i;
1276
1277         f = (uint8_t *) & from;
1278         o = (uint8_t *) & order;
1279         for (i = 0; i < sizeof(long); i++)
1280                 t[i] = f[o[i]];
1281         return t + sizeof(long);
1282 }
1283
1284 char *Ebadtimectl = "bad time control";
1285
1286 /*
1287  *  like the old #c/time but with added info.  Return
1288  *
1289  *      secs    nanosecs        fastticks       fasthz
1290  */
1291 static int readtime(uint32_t off, char *buf, int n)
1292 {
1293         int64_t nsec, ticks;
1294         long sec;
1295         char str[7 * NUMSIZE];
1296
1297         if (fasthz == 0LL)
1298                 fasthz = __proc_global_info.tsc_freq;
1299 #if 0
1300         fastticks((uint64_t *) & fasthz);
1301         nsec = todget(&ticks);
1302 #endif
1303         ticks = read_tsc();
1304         nsec = tsc2nsec(ticks);
1305         sec = nsec / 1000000000ULL;
1306         snprintf(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
1307                          NUMSIZE - 1, sec,
1308                          VLNUMSIZE - 1, nsec, VLNUMSIZE - 1, ticks, VLNUMSIZE - 1, fasthz);
1309         return consreadstr(off, buf, n, str);
1310 }
1311
1312 /*
1313  *  set the time in seconds
1314  */
1315 static int writetime(char *buf, int n)
1316 {
1317         char b[13];
1318         long i;
1319         int64_t now;
1320
1321         if (n >= sizeof(b))
1322                 error(EINVAL, "bad size in writetime");
1323         strncpy(b, buf, n);
1324         b[n] = 0;
1325         i = strtol(b, 0, 0);
1326         if (i <= 0)
1327                 error(EINVAL, "Bad time in write");
1328         now = i * 1000000000LL;
1329 #if 0
1330         todset(now, 0, 0);
1331 #endif
1332         return n;
1333 }
1334
1335 /*
1336  *  read binary time info.  all numbers are little endian.
1337  *  ticks and nsec are syncronized.
1338  */
1339 static int readbintime(char *buf, int n)
1340 {
1341         int i;
1342         int64_t nsec, ticks;
1343         uint8_t *b = (uint8_t *) buf;
1344
1345         i = 0;
1346         if (fasthz == 0LL)
1347                 fasthz = __proc_global_info.tsc_freq;
1348 #if 0
1349         fastticks((uint64_t *) & fasthz);
1350         nsec = todget(&ticks);
1351 #endif
1352         ticks = read_tsc();
1353         nsec = tsc2nsec(ticks);
1354         if (n >= 3 * sizeof(uint64_t)) {
1355                 int64_t2le(b + 2 * sizeof(uint64_t), fasthz);
1356                 i += sizeof(uint64_t);
1357         }
1358         if (n >= 2 * sizeof(uint64_t)) {
1359                 int64_t2le(b + sizeof(uint64_t), ticks);
1360                 i += sizeof(uint64_t);
1361         }
1362         if (n >= 8) {
1363                 int64_t2le(b, nsec);
1364                 i += sizeof(int64_t);
1365         }
1366         return i;
1367 }
1368
1369 /*
1370  *  set any of the following
1371  *      - time in nsec
1372  *      - nsec trim applied over some seconds
1373  *      - clock frequency
1374  */
1375 static int writebintime(char *buf, int n)
1376 {
1377         uint8_t *p;
1378         int64_t delta = 0;
1379         long period = 0;
1380
1381         n--;
1382         p = (uint8_t *) buf + 1;
1383         switch (*buf) {
1384                 case 'n':
1385                         if (n < sizeof(int64_t))
1386                                 error(EINVAL, ERROR_FIXME);
1387                         le2int64_t(&delta, p);
1388 #if 0
1389                         todset(delta, 0, 0);
1390 #endif
1391                         break;
1392                 case 'd':
1393                         if (n < sizeof(int64_t) + sizeof(long))
1394                                 error(EINVAL, ERROR_FIXME);
1395                         p = le2int64_t(&delta, p);
1396                         le2long(&period, p);
1397 #if 0
1398                         todset(-1, delta, period);
1399 #endif
1400                         break;
1401                 case 'f':
1402                         if (n < sizeof(uint64_t))
1403                                 error(EINVAL, ERROR_FIXME);
1404                         le2int64_t(&fasthz, p);
1405                         if (fasthz <= 0)
1406                                 error(EINVAL, ERROR_FIXME);
1407 #if 0
1408                         todsetfreq(fasthz);
1409 #endif
1410                         break;
1411         }
1412         return n;
1413 }
1414
1415 /*
1416  * find_first_kid finds your immediate descendant. Not because we're
1417  * trying to give it a check from the estate, mind you. We're here on
1418  * much more unpleasant business. To make it easy to call this
1419  * multiple times without lots of fussy checking, we allow it to be
1420  * called with NULL pointers; hence find_first_kid(find_first_kid(x))
1421  * works even if x is chaste and will return NULL.
1422  */
1423 static struct proc *find_first_kid(struct proc *p)
1424 {
1425         struct proc *kid;
1426
1427         cv_lock(&p->child_wait);
1428         kid = TAILQ_FIRST(&p->children);
1429         if (kid) {
1430                 proc_incref(kid, 1);
1431                 proc_decref(p);
1432         }
1433         cv_unlock(&p->child_wait);
1434         return kid;
1435 }
1436
1437 /*
1438  * killkid manages population issues by killing your kids.  This is a
1439  * particular temporary (we think) function for ssh. As such, we are
1440  * going to make a Command Decision to never kill the top level
1441  * kid. We start on grandkids, in other words.  Hey, the parent/child
1442  * terminology was Ken's idea; go yell at him.  If you want, we can
1443  * rename this to DrownCuteKittens.
1444  *
1445  * This was hard to get right so it's way more verbose than you might think we need.
1446  * Sorry.
1447  */
1448 void killkid(void)
1449 {
1450         struct proc *check, *kid, *grandkid, *victim;
1451
1452         /* find first grandkid */
1453         proc_incref(current, 1);
1454         kid = find_first_kid(current);
1455         if (!kid) {
1456                 proc_decref(current);
1457                 return;
1458         }
1459         grandkid = find_first_kid(kid);
1460         if (!grandkid) {
1461                 proc_decref(kid);
1462                 return;
1463         }
1464         victim = grandkid;
1465         while (1) {
1466                 check = find_first_kid(victim);
1467                 if (!check)
1468                         break;
1469                 victim = check;
1470         }
1471         send_posix_signal(victim, SIGINT);
1472         proc_decref(victim);
1473 }
1474
1475 void cons_add_char(char c)
1476 {
1477         qiwrite(cons_q, &c, sizeof(char));
1478 }