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