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