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