The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/devcons.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: eafb9c8fa2f45a93fdc0aab93140d8cb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.