]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devcons.c
merge
[plan9front.git] / sys / src / 9 / port / devcons.c
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
8 #include        <pool.h>
9 #include        <authsrv.h>
10
11 void    (*consdebug)(void) = nil;
12 void    (*screenputs)(char*, int) = nil;
13
14 Queue*  serialoq;               /* serial console output */
15 Queue*  kprintoq;               /* console output, for /dev/kprint */
16 ulong   kprintinuse;            /* test and set whether /dev/kprint is open */
17 int     iprintscreenputs = 1;
18
19 int     panicking;
20
21 char    *sysname;
22 vlong   fasthz;
23
24 static int      readtime(ulong, char*, int);
25 static int      readbintime(char*, int);
26 static int      writetime(char*, int);
27 static int      writebintime(char*, int);
28
29 enum
30 {
31         CMhalt,
32         CMreboot,
33         CMpanic,
34         CMrdb,
35 };
36
37 Cmdtab rebootmsg[] =
38 {
39         CMhalt,         "halt",         1,
40         CMreboot,       "reboot",       0,
41         CMpanic,        "panic",        0,
42         CMrdb,          "rdb",          0,
43 };
44
45 void
46 printinit(void)
47 {
48 }
49
50 int
51 consactive(void)
52 {
53         if(serialoq)
54                 return qlen(serialoq) > 0;
55         return 0;
56 }
57
58 void
59 prflush(void)
60 {
61         ulong now;
62
63         now = m->ticks;
64         while(consactive())
65                 if(m->ticks - now >= HZ)
66                         break;
67 }
68
69 /*
70  * Log console output so it can be retrieved via /dev/kmesg.
71  * This is good for catching boot-time messages after the fact.
72  */
73 struct {
74         Lock lk;
75         char buf[16384];
76         uint n;
77 } kmesg;
78
79 static void
80 kmesgputs(char *str, int n)
81 {
82         uint nn, d;
83
84         ilock(&kmesg.lk);
85         /* take the tail of huge writes */
86         if(n > sizeof kmesg.buf){
87                 d = n - sizeof kmesg.buf;
88                 str += d;
89                 n -= d;
90         }
91
92         /* slide the buffer down to make room */
93         nn = kmesg.n;
94         if(nn + n >= sizeof kmesg.buf){
95                 d = nn + n - sizeof kmesg.buf;
96                 if(d)
97                         memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
98                 nn -= d;
99         }
100
101         /* copy the data in */
102         memmove(kmesg.buf+nn, str, n);
103         nn += n;
104         kmesg.n = nn;
105         iunlock(&kmesg.lk);
106 }
107
108 /*
109  *   Print a string on the console.  Convert \n to \r\n for serial
110  *   line consoles.  Locking of the queues is left up to the screen
111  *   or uart code.  Multi-line messages to serial consoles may get
112  *   interspersed with other messages.
113  */
114 static void
115 putstrn0(char *str, int n, int usewrite)
116 {
117         int m;
118         char *t;
119
120         if(!islo())
121                 usewrite = 0;
122
123         /*
124          *  how many different output devices do we need?
125          */
126         kmesgputs(str, n);
127
128         /*
129          *  if someone is reading /dev/kprint,
130          *  put the message there.
131          *  if not and there's an attached bit mapped display,
132          *  put the message there.
133          *
134          *  if there's a serial line being used as a console,
135          *  put the message there.
136          */
137         if(kprintoq != nil && !qisclosed(kprintoq)){
138                 if(usewrite)
139                         qwrite(kprintoq, str, n);
140                 else
141                         qiwrite(kprintoq, str, n);
142         }else if(screenputs != nil)
143                 screenputs(str, n);
144
145         if(serialoq == nil){
146                 uartputs(str, n);
147                 return;
148         }
149
150         while(n > 0) {
151                 t = memchr(str, '\n', n);
152                 if(t != nil) {
153                         m = t-str;
154                         if(usewrite){
155                                 qwrite(serialoq, str, m);
156                                 qwrite(serialoq, "\r\n", 2);
157                         } else {
158                                 qiwrite(serialoq, str, m);
159                                 qiwrite(serialoq, "\r\n", 2);
160                         }
161                         n -= m+1;
162                         str = t+1;
163                 } else {
164                         if(usewrite)
165                                 qwrite(serialoq, str, n);
166                         else
167                                 qiwrite(serialoq, str, n);
168                         break;
169                 }
170         }
171 }
172
173 void
174 putstrn(char *str, int n)
175 {
176         putstrn0(str, n, 0);
177 }
178
179 int
180 print(char *fmt, ...)
181 {
182         int n;
183         va_list arg;
184         char buf[PRINTSIZE];
185
186         va_start(arg, fmt);
187         n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
188         va_end(arg);
189         putstrn(buf, n);
190
191         return n;
192 }
193
194 /*
195  * Want to interlock iprints to avoid interlaced output on 
196  * multiprocessor, but don't want to deadlock if one processor
197  * dies during print and another has something important to say.
198  * Make a good faith effort.
199  */
200 static Lock iprintlock;
201 static int
202 iprintcanlock(Lock *l)
203 {
204         int i;
205         
206         for(i=0; i<1000; i++){
207                 if(canlock(l))
208                         return 1;
209                 if(l->m == MACHP(m->machno))
210                         return 0;
211                 microdelay(100);
212         }
213         return 0;
214 }
215
216 int
217 iprint(char *fmt, ...)
218 {
219         int n, s, locked;
220         va_list arg;
221         char buf[PRINTSIZE];
222
223         s = splhi();
224         va_start(arg, fmt);
225         n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
226         va_end(arg);
227         locked = iprintcanlock(&iprintlock);
228         if(screenputs != nil && iprintscreenputs)
229                 screenputs(buf, n);
230         uartputs(buf, n);
231         if(locked)
232                 unlock(&iprintlock);
233         splx(s);
234
235         return n;
236 }
237
238 void
239 panic(char *fmt, ...)
240 {
241         int s;
242         va_list arg;
243         char buf[PRINTSIZE];
244
245         kprintoq = nil; /* don't try to write to /dev/kprint */
246
247         if(panicking)
248                 for(;;);
249         panicking = 1;
250
251         s = splhi();
252         strcpy(buf, "panic: ");
253         va_start(arg, fmt);
254         vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
255         va_end(arg);
256         iprint("%s\n", buf);
257         if(consdebug)
258                 (*consdebug)();
259         splx(s);
260         prflush();
261         dumpstack();
262
263         /* reboot cpu servers and headless machines when not debugging */
264         if(getconf("*debug") == nil)
265         if(cpuserver || !conf.monitor)
266                 exit(1);
267
268         /* otherwise, just hang */
269         while(islo()) idlehands();
270         for(;;);
271 }
272
273 /* libmp at least contains a few calls to sysfatal; simulate with panic */
274 void
275 sysfatal(char *fmt, ...)
276 {
277         char err[256];
278         va_list arg;
279
280         va_start(arg, fmt);
281         vseprint(err, err + sizeof err, fmt, arg);
282         va_end(arg);
283         panic("sysfatal: %s", err);
284 }
285
286 void
287 _assert(char *fmt)
288 {
289         panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
290 }
291
292 int
293 pprint(char *fmt, ...)
294 {
295         int n;
296         Chan *c;
297         va_list arg;
298         char buf[2*PRINTSIZE];
299
300         if(up == nil || up->fgrp == nil)
301                 return 0;
302
303         c = up->fgrp->fd[2];
304         if(c==nil || (c->flag&CMSG)!=0 || (c->mode!=OWRITE && c->mode!=ORDWR))
305                 return 0;
306         n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
307         va_start(arg, fmt);
308         n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
309         va_end(arg);
310
311         if(waserror())
312                 return 0;
313         devtab[c->type]->write(c, buf, n, c->offset);
314         poperror();
315
316         lock(c);
317         c->offset += n;
318         unlock(c);
319
320         return n;
321 }
322
323 enum{
324         Qdir,
325         Qbintime,
326         Qcons,
327         Qconsctl,
328         Qcputime,
329         Qdrivers,
330         Qkmesg,
331         Qkprint,
332         Qhostdomain,
333         Qhostowner,
334         Qnull,
335         Qosversion,
336         Qpgrpid,
337         Qpid,
338         Qppid,
339         Qrandom,
340         Qreboot,
341         Qswap,
342         Qsysname,
343         Qsysstat,
344         Qtime,
345         Quser,
346         Qzero,
347         Qmordor,
348         Qconfig,
349 };
350
351 enum
352 {
353         VLNUMSIZE=      22,
354 };
355
356 static Dirtab consdir[]={
357         ".",    {Qdir, 0, QTDIR},       0,              DMDIR|0555,
358         "bintime",      {Qbintime},     24,             0664,
359         "cons",         {Qcons},        0,              0660,
360         "consctl",      {Qconsctl},     0,              0220,
361         "cputime",      {Qcputime},     6*NUMSIZE,      0444,
362         "drivers",      {Qdrivers},     0,              0444,
363         "hostdomain",   {Qhostdomain},  DOMLEN,         0664,
364         "hostowner",    {Qhostowner},   0,              0664,
365         "kmesg",        {Qkmesg},       0,              0440,
366         "kprint",       {Qkprint, 0, QTEXCL},   0,      DMEXCL|0440,
367         "null",         {Qnull},        0,              0666,
368         "osversion",    {Qosversion},   0,              0444,
369         "pgrpid",       {Qpgrpid},      NUMSIZE,        0444,
370         "pid",          {Qpid},         NUMSIZE,        0444,
371         "ppid",         {Qppid},        NUMSIZE,        0444,
372         "random",       {Qrandom},      0,              0444,
373         "reboot",       {Qreboot},      0,              0664,
374         "swap",         {Qswap},        0,              0664,
375         "sysname",      {Qsysname},     0,              0664,
376         "sysstat",      {Qsysstat},     0,              0666,
377         "time",         {Qtime},        NUMSIZE+3*VLNUMSIZE,    0664,
378         "user",         {Quser},        0,              0666,
379         "zero",         {Qzero},        0,              0444,
380         "config",       {Qconfig},      0,              0444,
381         "mordor",       {Qmordor},      0,              0666,
382 };
383
384 int
385 readnum(ulong off, char *buf, ulong n, ulong val, int size)
386 {
387         char tmp[64];
388
389         snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
390         tmp[size-1] = ' ';
391         if(off >= size)
392                 return 0;
393         if(off+n > size)
394                 n = size-off;
395         memmove(buf, tmp+off, n);
396         return n;
397 }
398
399 int
400 readstr(ulong off, char *buf, ulong n, char *str)
401 {
402         int size;
403
404         size = strlen(str);
405         if(off >= size)
406                 return 0;
407         if(off+n > size)
408                 n = size-off;
409         memmove(buf, str+off, n);
410         return n;
411 }
412
413 static void
414 consinit(void)
415 {
416         todinit();
417         randominit();
418 }
419
420 static Chan*
421 consattach(char *spec)
422 {
423         return devattach('c', spec);
424 }
425
426 static Walkqid*
427 conswalk(Chan *c, Chan *nc, char **name, int nname)
428 {
429         return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
430 }
431
432 static int
433 consstat(Chan *c, uchar *dp, int n)
434 {
435         return devstat(c, dp, n, consdir, nelem(consdir), devgen);
436 }
437
438 static Chan*
439 consopen(Chan *c, int omode)
440 {
441         c->aux = nil;
442         c = devopen(c, omode, consdir, nelem(consdir), devgen);
443         switch((ulong)c->qid.path){
444         case Qkprint:
445                 if(tas(&kprintinuse) != 0){
446                         c->flag &= ~COPEN;
447                         error(Einuse);
448                 }
449                 if(kprintoq == nil){
450                         kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
451                         if(kprintoq == nil){
452                                 c->flag &= ~COPEN;
453                                 error(Enomem);
454                         }
455                         qnoblock(kprintoq, 1);
456                 }else
457                         qreopen(kprintoq);
458                 c->iounit = qiomaxatomic;
459                 break;
460         }
461         return c;
462 }
463
464 static void
465 consclose(Chan *c)
466 {
467         switch((ulong)c->qid.path){
468         /* close of kprint allows other opens */
469         case Qkprint:
470                 if(c->flag & COPEN){
471                         kprintinuse = 0;
472                         qhangup(kprintoq, nil);
473                 }
474                 break;
475         }
476 }
477
478 static long
479 consread(Chan *c, void *buf, long n, vlong off)
480 {
481         ulong l;
482         Mach *mp;
483         char *b, *bp;
484         char tmp[256];          /* must be >= 18*NUMSIZE (Qswap) */
485         int i, k, id;
486         vlong offset = off;
487         extern char configfile[];
488         extern Image fscache;
489         extern Image swapimage;
490
491         if(n <= 0)
492                 return n;
493
494         switch((ulong)c->qid.path){
495         case Qdir:
496                 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
497
498         case Qcons:
499                 error(Egreg);
500
501         case Qcputime:
502                 k = offset;
503                 if(k >= 6*NUMSIZE)
504                         return 0;
505                 if(k+n > 6*NUMSIZE)
506                         n = 6*NUMSIZE - k;
507                 /* easiest to format in a separate buffer and copy out */
508                 for(i=0; i<6 && NUMSIZE*i<k+n; i++){
509                         l = up->time[i];
510                         if(i == TReal)
511                                 l = MACHP(0)->ticks - l;
512                         l = TK2MS(l);
513                         readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
514                 }
515                 memmove(buf, tmp+k, n);
516                 return n;
517
518         case Qkmesg:
519                 /*
520                  * This is unlocked to avoid tying up a process
521                  * that's writing to the buffer.  kmesg.n never 
522                  * gets smaller, so worst case the reader will
523                  * see a slurred buffer.
524                  */
525                 if(off >= kmesg.n)
526                         n = 0;
527                 else{
528                         if(off+n > kmesg.n)
529                                 n = kmesg.n - off;
530                         memmove(buf, kmesg.buf+off, n);
531                 }
532                 return n;
533                 
534         case Qkprint:
535                 return qread(kprintoq, buf, n);
536
537         case Qpgrpid:
538                 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
539
540         case Qpid:
541                 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
542
543         case Qppid:
544                 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
545
546         case Qtime:
547                 return readtime((ulong)offset, buf, n);
548
549         case Qbintime:
550                 return readbintime(buf, n);
551
552         case Qhostowner:
553                 return readstr((ulong)offset, buf, n, eve);
554
555         case Qhostdomain:
556                 return readstr((ulong)offset, buf, n, hostdomain);
557
558         case Quser:
559                 return readstr((ulong)offset, buf, n, up->user);
560
561         case Qnull:
562                 return 0;
563
564         case Qconfig:
565                 return readstr((ulong)offset, buf, n, configfile);
566
567         case Qsysstat:
568                 b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1);     /* +1 for NUL */
569                 bp = b;
570                 for(id = 0; id < MAXMACH; id++) {
571                         if(active.machs[id]) {
572                                 mp = MACHP(id);
573                                 readnum(0, bp, NUMSIZE, id, NUMSIZE);
574                                 bp += NUMSIZE;
575                                 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
576                                 bp += NUMSIZE;
577                                 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
578                                 bp += NUMSIZE;
579                                 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
580                                 bp += NUMSIZE;
581                                 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
582                                 bp += NUMSIZE;
583                                 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
584                                 bp += NUMSIZE;
585                                 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
586                                 bp += NUMSIZE;
587                                 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
588                                 bp += NUMSIZE;
589                                 l = mp->perf.period;
590                                 if(l == 0)
591                                         l = 1;
592                                 readnum(0, bp, NUMSIZE,
593                                         (mp->perf.avg_inidle*100)/l, NUMSIZE);
594                                 bp += NUMSIZE;
595                                 readnum(0, bp, NUMSIZE,
596                                         (mp->perf.avg_inintr*100)/l, NUMSIZE);
597                                 bp += NUMSIZE;
598                                 *bp++ = '\n';
599                         }
600                 }
601                 if(waserror()){
602                         free(b);
603                         nexterror();
604                 }
605                 n = readstr((ulong)offset, buf, n, b);
606                 free(b);
607                 poperror();
608                 return n;
609
610         case Qswap:
611                 snprint(tmp, sizeof tmp,
612                         "%llud memory\n"
613                         "%llud pagesize\n"
614                         "%lud kernel\n"
615                         "%lud/%lud user\n"
616                         "%lud/%lud swap\n"
617                         "%llud/%llud/%llud kernel malloc\n"
618                         "%llud/%llud/%llud kernel draw\n"
619                         "%llud/%llud/%llud kernel secret\n",
620                         (uvlong)conf.npage*BY2PG,
621                         (uvlong)BY2PG,
622                         conf.npage-conf.upages,
623                         palloc.user-palloc.freecount-fscache.pgref-swapimage.pgref, palloc.user,
624                         conf.nswap-swapalloc.free, conf.nswap,
625                         (uvlong)mainmem->curalloc,
626                         (uvlong)mainmem->cursize,
627                         (uvlong)mainmem->maxsize,
628                         (uvlong)imagmem->curalloc,
629                         (uvlong)imagmem->cursize,
630                         (uvlong)imagmem->maxsize,
631                         (uvlong)secrmem->curalloc,
632                         (uvlong)secrmem->cursize,
633                         (uvlong)secrmem->maxsize);
634
635                 return readstr((ulong)offset, buf, n, tmp);
636
637         case Qsysname:
638                 if(sysname == nil)
639                         return 0;
640                 return readstr((ulong)offset, buf, n, sysname);
641
642         case Qrandom:
643                 return randomread(buf, n);
644
645         case Qdrivers:
646                 b = smalloc(READSTR);
647                 k = 0;
648                 for(i = 0; devtab[i] != nil; i++)
649                         k += snprint(b+k, READSTR-k, "#%C %s\n",
650                                 devtab[i]->dc, devtab[i]->name);
651                 if(waserror()){
652                         free(b);
653                         nexterror();
654                 }
655                 n = readstr((ulong)offset, buf, n, b);
656                 poperror();
657                 free(b);
658                 return n;
659
660         case Qzero:
661                 memset(buf, 0, n);
662                 return n;
663         
664         case Qmordor:
665                 error("one does not simply read from mordor");
666                 return 0;
667
668         case Qosversion:
669                 snprint(tmp, sizeof tmp, "2000");
670                 n = readstr((ulong)offset, buf, n, tmp);
671                 return n;
672
673         default:
674                 print("consread %#llux\n", c->qid.path);
675                 error(Egreg);
676         }
677         return -1;              /* never reached */
678 }
679
680 static long
681 conswrite(Chan *c, void *va, long n, vlong off)
682 {
683         char buf[256];
684         long l, bp;
685         char *a;
686         Mach *mp;
687         int id, fd;
688         Chan *swc;
689         ulong offset;
690         Cmdbuf *cb;
691         Cmdtab *ct;
692
693         a = va;
694         offset = off;
695
696         switch((ulong)c->qid.path){
697         case Qcons:
698                 /*
699                  * Can't page fault in putstrn, so copy the data locally.
700                  */
701                 l = n;
702                 while(l > 0){
703                         bp = l;
704                         if(bp > sizeof buf)
705                                 bp = sizeof buf;
706                         memmove(buf, a, bp);
707                         putstrn0(buf, bp, 1);
708                         a += bp;
709                         l -= bp;
710                 }
711                 break;
712
713         case Qconsctl:
714                 error(Egreg);
715
716         case Qtime:
717                 if(!iseve())
718                         error(Eperm);
719                 return writetime(a, n);
720
721         case Qbintime:
722                 if(!iseve())
723                         error(Eperm);
724                 return writebintime(a, n);
725
726         case Qhostowner:
727                 return hostownerwrite(a, n);
728
729         case Qhostdomain:
730                 return hostdomainwrite(a, n);
731
732         case Quser:
733                 return userwrite(a, n);
734
735         case Qnull:
736                 break;
737
738         case Qconfig:
739                 error(Eperm);
740                 break;
741
742         case Qreboot:
743                 if(!iseve())
744                         error(Eperm);
745                 cb = parsecmd(a, n);
746
747                 if(waserror()) {
748                         free(cb);
749                         nexterror();
750                 }
751                 ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
752                 switch(ct->index) {
753                 case CMhalt:
754                         reboot(nil, 0, 0);
755                         break;
756                 case CMreboot:
757                         rebootcmd(cb->nf-1, cb->f+1);
758                         break;
759                 case CMpanic:
760                         *(ulong*)0=0;
761                         panic("/dev/reboot");
762                 case CMrdb:
763                         if(consdebug == nil)
764                                 consdebug = rdb;
765                         consdebug();
766                         break;
767                 }
768                 poperror();
769                 free(cb);
770                 break;
771
772         case Qsysstat:
773                 for(id = 0; id < MAXMACH; id++) {
774                         if(active.machs[id]) {
775                                 mp = MACHP(id);
776                                 mp->cs = 0;
777                                 mp->intr = 0;
778                                 mp->syscall = 0;
779                                 mp->pfault = 0;
780                                 mp->tlbfault = 0;
781                                 mp->tlbpurge = 0;
782                         }
783                 }
784                 break;
785
786         case Qswap:
787                 if(n >= sizeof buf)
788                         error(Egreg);
789                 memmove(buf, va, n);    /* so we can NUL-terminate */
790                 buf[n] = 0;
791                 /* start a pager if not already started */
792                 if(strncmp(buf, "start", 5) == 0){
793                         kickpager();
794                         break;
795                 }
796                 if(!iseve())
797                         error(Eperm);
798                 if(buf[0]<'0' || '9'<buf[0])
799                         error(Ebadarg);
800                 fd = strtoul(buf, 0, 0);
801                 swc = fdtochan(fd, ORDWR, 1, 1);
802                 setswapchan(swc);
803                 break;
804
805         case Qsysname:
806                 if(offset != 0)
807                         error(Ebadarg);
808                 if(n <= 0 || n >= sizeof buf)
809                         error(Ebadarg);
810                 strncpy(buf, a, n);
811                 buf[n] = 0;
812                 if(buf[n-1] == '\n')
813                         buf[n-1] = 0;
814                 kstrdup(&sysname, buf);
815                 break;
816         
817         case Qmordor:
818                 error("one does not simply write into mordor");
819                 return 0;
820
821         default:
822                 print("conswrite: %#llux\n", c->qid.path);
823                 error(Egreg);
824         }
825         return n;
826 }
827
828 Dev consdevtab = {
829         'c',
830         "cons",
831
832         devreset,
833         consinit,
834         devshutdown,
835         consattach,
836         conswalk,
837         consstat,
838         consopen,
839         devcreate,
840         consclose,
841         consread,
842         devbread,
843         conswrite,
844         devbwrite,
845         devremove,
846         devwstat,
847 };
848
849 static  ulong   randn;
850
851 int
852 rand(void)
853 {
854         if(randn == 0)
855                 randomread((void*)&randn, sizeof(randn));
856         randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
857         return randn;
858 }
859
860 int
861 nrand(int n)
862 {
863         rand();
864         return (randn>>16) % n;
865 }
866
867 static uvlong uvorder = 0x0001020304050607ULL;
868
869 static uchar*
870 le2vlong(vlong *to, uchar *f)
871 {
872         uchar *t, *o;
873         int i;
874
875         t = (uchar*)to;
876         o = (uchar*)&uvorder;
877         for(i = 0; i < sizeof(vlong); i++)
878                 t[o[i]] = f[i];
879         return f+sizeof(vlong);
880 }
881
882 static uchar*
883 vlong2le(uchar *t, vlong from)
884 {
885         uchar *f, *o;
886         int i;
887
888         f = (uchar*)&from;
889         o = (uchar*)&uvorder;
890         for(i = 0; i < sizeof(vlong); i++)
891                 t[i] = f[o[i]];
892         return t+sizeof(vlong);
893 }
894
895 static long order = 0x00010203;
896
897 static uchar*
898 le2long(long *to, uchar *f)
899 {
900         uchar *t, *o;
901         int i;
902
903         t = (uchar*)to;
904         o = (uchar*)&order;
905         for(i = 0; i < sizeof(long); i++)
906                 t[o[i]] = f[i];
907         return f+sizeof(long);
908 }
909
910 static uchar*
911 long2le(uchar *t, long from)
912 {
913         uchar *f, *o;
914         int i;
915
916         f = (uchar*)&from;
917         o = (uchar*)&order;
918         for(i = 0; i < sizeof(long); i++)
919                 t[i] = f[o[i]];
920         return t+sizeof(long);
921 }
922
923 char *Ebadtimectl = "bad time control";
924
925 /*
926  *  like the old #c/time but with added info.  Return
927  *
928  *      secs    nanosecs        fastticks       fasthz
929  */
930 static int
931 readtime(ulong off, char *buf, int n)
932 {
933         vlong   nsec, ticks;
934         long sec;
935         char str[7*NUMSIZE];
936
937         nsec = todget(&ticks);
938         if(fasthz == 0LL)
939                 fastticks((uvlong*)&fasthz);
940         sec = nsec/1000000000ULL;
941         snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
942                 NUMSIZE-1, sec,
943                 VLNUMSIZE-1, nsec,
944                 VLNUMSIZE-1, ticks,
945                 VLNUMSIZE-1, fasthz);
946         return readstr(off, buf, n, str);
947 }
948
949 /*
950  *  set the time in seconds
951  */
952 static int
953 writetime(char *buf, int n)
954 {
955         char b[13];
956         long i;
957         vlong now;
958
959         if(n >= sizeof(b))
960                 error(Ebadtimectl);
961         strncpy(b, buf, n);
962         b[n] = 0;
963         i = strtol(b, 0, 0);
964         if(i <= 0)
965                 error(Ebadtimectl);
966         now = i*1000000000LL;
967         todset(now, 0, 0);
968         return n;
969 }
970
971 /*
972  *  read binary time info.  all numbers are little endian.
973  *  ticks and nsec are syncronized.
974  */
975 static int
976 readbintime(char *buf, int n)
977 {
978         int i;
979         vlong nsec, ticks;
980         uchar *b = (uchar*)buf;
981
982         i = 0;
983         if(fasthz == 0LL)
984                 fastticks((uvlong*)&fasthz);
985         nsec = todget(&ticks);
986         if(n >= 3*sizeof(uvlong)){
987                 vlong2le(b+2*sizeof(uvlong), fasthz);
988                 i += sizeof(uvlong);
989         }
990         if(n >= 2*sizeof(uvlong)){
991                 vlong2le(b+sizeof(uvlong), ticks);
992                 i += sizeof(uvlong);
993         }
994         if(n >= 8){
995                 vlong2le(b, nsec);
996                 i += sizeof(vlong);
997         }
998         return i;
999 }
1000
1001 /*
1002  *  set any of the following
1003  *      - time in nsec
1004  *      - nsec trim applied over some seconds
1005  *      - clock frequency
1006  */
1007 static int
1008 writebintime(char *buf, int n)
1009 {
1010         uchar *p;
1011         vlong delta;
1012         long period;
1013
1014         n--;
1015         p = (uchar*)buf + 1;
1016         switch(*buf){
1017         case 'n':
1018                 if(n < sizeof(vlong))
1019                         error(Ebadtimectl);
1020                 le2vlong(&delta, p);
1021                 todset(delta, 0, 0);
1022                 break;
1023         case 'd':
1024                 if(n < sizeof(vlong)+sizeof(long))
1025                         error(Ebadtimectl);
1026                 p = le2vlong(&delta, p);
1027                 le2long(&period, p);
1028                 todset(-1, delta, period);
1029                 break;
1030         case 'f':
1031                 if(n < sizeof(uvlong))
1032                         error(Ebadtimectl);
1033                 le2vlong(&fasthz, p);
1034                 if(fasthz <= 0)
1035                         error(Ebadtimectl);
1036                 todsetfreq(fasthz);
1037                 break;
1038         }
1039         return n;
1040 }
1041
1042 void
1043 cpushutdown(void)
1044 {
1045         int ms, once;
1046
1047         lock(&active);
1048         once = active.machs[m->machno];
1049         active.machs[m->machno] = 0;
1050         active.exiting = 1;
1051         unlock(&active);
1052
1053         if(once)
1054                 iprint("cpu%d: exiting\n", m->machno);
1055
1056         /* wait for any other processors to shutdown */
1057         spllo();
1058         for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
1059                 delay(TK2MS(2));
1060                 if(memchr(active.machs, 1, MAXMACH) == nil && consactive() == 0)
1061                         break;
1062         }
1063 }