xref: /plan9/sys/src/9/port/devcons.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
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 void
303 _assert(char *fmt)
304 {
305 	panic("assert failed at 0x%lux: %s", getcallerpc(&fmt), fmt);
306 }
307 
308 int
309 pprint(char *fmt, ...)
310 {
311 	int n;
312 	Chan *c;
313 	va_list arg;
314 	char buf[2*PRINTSIZE];
315 
316 	if(up == nil || up->fgrp == nil)
317 		return 0;
318 
319 	c = up->fgrp->fd[2];
320 	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
321 		return 0;
322 	n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
323 	va_start(arg, fmt);
324 	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
325 	va_end(arg);
326 
327 	if(waserror())
328 		return 0;
329 	devtab[c->type]->write(c, buf, n, c->offset);
330 	poperror();
331 
332 	lock(c);
333 	c->offset += n;
334 	unlock(c);
335 
336 	return n;
337 }
338 
339 static void
340 echoscreen(char *buf, int n)
341 {
342 	char *e, *p;
343 	char ebuf[128];
344 	int x;
345 
346 	p = ebuf;
347 	e = ebuf + sizeof(ebuf) - 4;
348 	while(n-- > 0){
349 		if(p >= e){
350 			screenputs(ebuf, p - ebuf);
351 			p = ebuf;
352 		}
353 		x = *buf++;
354 		if(x == 0x15){
355 			*p++ = '^';
356 			*p++ = 'U';
357 			*p++ = '\n';
358 		} else
359 			*p++ = x;
360 	}
361 	if(p != ebuf)
362 		screenputs(ebuf, p - ebuf);
363 }
364 
365 static void
366 echoserialoq(char *buf, int n)
367 {
368 	char *e, *p;
369 	char ebuf[128];
370 	int x;
371 
372 	p = ebuf;
373 	e = ebuf + sizeof(ebuf) - 4;
374 	while(n-- > 0){
375 		if(p >= e){
376 			qiwrite(serialoq, ebuf, p - ebuf);
377 			p = ebuf;
378 		}
379 		x = *buf++;
380 		if(x == '\n'){
381 			*p++ = '\r';
382 			*p++ = '\n';
383 		} else if(x == 0x15){
384 			*p++ = '^';
385 			*p++ = 'U';
386 			*p++ = '\n';
387 		} else
388 			*p++ = x;
389 	}
390 	if(p != ebuf)
391 		qiwrite(serialoq, ebuf, p - ebuf);
392 }
393 
394 static void
395 echo(char *buf, int n)
396 {
397 	static int ctrlt, pid;
398 	int x;
399 	char *e, *p;
400 
401 	if(n == 0)
402 		return;
403 
404 	e = buf+n;
405 	for(p = buf; p < e; p++){
406 		switch(*p){
407 		case 0x10:	/* ^P */
408 			if(cpuserver && !kbd.ctlpoff){
409 				active.exiting = 1;
410 				return;
411 			}
412 			break;
413 		case 0x14:	/* ^T */
414 			ctrlt++;
415 			if(ctrlt > 2)
416 				ctrlt = 2;
417 			continue;
418 		}
419 
420 		if(ctrlt != 2)
421 			continue;
422 
423 		/* ^T escapes */
424 		ctrlt = 0;
425 		switch(*p){
426 		case 'S':
427 			x = splhi();
428 			dumpstack();
429 			procdump();
430 			splx(x);
431 			return;
432 		case 's':
433 			dumpstack();
434 			return;
435 		case 'x':
436 			xsummary();
437 			ixsummary();
438 			mallocsummary();
439 		//	memorysummary();
440 			pagersummary();
441 			return;
442 		case 'd':
443 			if(consdebug == nil)
444 				consdebug = rdb;
445 			else
446 				consdebug = nil;
447 			print("consdebug now 0x%p\n", consdebug);
448 			return;
449 		case 'D':
450 			if(consdebug == nil)
451 				consdebug = rdb;
452 			consdebug();
453 			return;
454 		case 'p':
455 			x = spllo();
456 			procdump();
457 			splx(x);
458 			return;
459 		case 'q':
460 			scheddump();
461 			return;
462 		case 'k':
463 			killbig("^t ^t k");
464 			return;
465 		case 'r':
466 			exit(0);
467 			return;
468 		}
469 	}
470 
471 	qproduce(kbdq, buf, n);
472 	if(kbd.raw)
473 		return;
474 	kmesgputs(buf, n);
475 	if(screenputs != nil)
476 		echoscreen(buf, n);
477 	if(serialoq)
478 		echoserialoq(buf, n);
479 }
480 
481 /*
482  *  Called by a uart interrupt for console input.
483  *
484  *  turn '\r' into '\n' before putting it into the queue.
485  */
486 int
487 kbdcr2nl(Queue*, int ch)
488 {
489 	char *next;
490 
491 	ilock(&kbd.lockputc);		/* just a mutex */
492 	if(ch == '\r' && !kbd.raw)
493 		ch = '\n';
494 	next = kbd.iw+1;
495 	if(next >= kbd.ie)
496 		next = kbd.istage;
497 	if(next != kbd.ir){
498 		*kbd.iw = ch;
499 		kbd.iw = next;
500 	}
501 	iunlock(&kbd.lockputc);
502 	return 0;
503 }
504 
505 /*
506  *  Put character, possibly a rune, into read queue at interrupt time.
507  *  Called at interrupt time to process a character.
508  */
509 int
510 kbdputc(Queue*, int ch)
511 {
512 	int i, n;
513 	char buf[3];
514 	Rune r;
515 	char *next;
516 
517 	if(kbd.ir == nil)
518 		return 0;		/* in case we're not inited yet */
519 
520 	ilock(&kbd.lockputc);		/* just a mutex */
521 	r = ch;
522 	n = runetochar(buf, &r);
523 	for(i = 0; i < n; i++){
524 		next = kbd.iw+1;
525 		if(next >= kbd.ie)
526 			next = kbd.istage;
527 		if(next == kbd.ir)
528 			break;
529 		*kbd.iw = buf[i];
530 		kbd.iw = next;
531 	}
532 	iunlock(&kbd.lockputc);
533 	return 0;
534 }
535 
536 /*
537  *  we save up input characters till clock time to reduce
538  *  per character interrupt overhead.
539  */
540 static void
541 kbdputcclock(void)
542 {
543 	char *iw;
544 
545 	/* this amortizes cost of qproduce */
546 	if(kbd.iw != kbd.ir){
547 		iw = kbd.iw;
548 		if(iw < kbd.ir){
549 			echo(kbd.ir, kbd.ie-kbd.ir);
550 			kbd.ir = kbd.istage;
551 		}
552 		if(kbd.ir != iw){
553 			echo(kbd.ir, iw-kbd.ir);
554 			kbd.ir = iw;
555 		}
556 	}
557 }
558 
559 enum{
560 	Qdir,
561 	Qbintime,
562 	Qcons,
563 	Qconsctl,
564 	Qcputime,
565 	Qdrivers,
566 	Qkmesg,
567 	Qkprint,
568 	Qhostdomain,
569 	Qhostowner,
570 	Qnull,
571 	Qosversion,
572 	Qpgrpid,
573 	Qpid,
574 	Qppid,
575 	Qrandom,
576 	Qreboot,
577 	Qswap,
578 	Qsysname,
579 	Qsysstat,
580 	Qtime,
581 	Quser,
582 	Qzero,
583 };
584 
585 enum
586 {
587 	VLNUMSIZE=	22,
588 };
589 
590 static Dirtab consdir[]={
591 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
592 	"bintime",	{Qbintime},	24,		0664,
593 	"cons",		{Qcons},	0,		0660,
594 	"consctl",	{Qconsctl},	0,		0220,
595 	"cputime",	{Qcputime},	6*NUMSIZE,	0444,
596 	"drivers",	{Qdrivers},	0,		0444,
597 	"hostdomain",	{Qhostdomain},	DOMLEN,		0664,
598 	"hostowner",	{Qhostowner},	0,		0664,
599 	"kmesg",	{Qkmesg},	0,		0440,
600 	"kprint",	{Qkprint, 0, QTEXCL},	0,	DMEXCL|0440,
601 	"null",		{Qnull},	0,		0666,
602 	"osversion",	{Qosversion},	0,		0444,
603 	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444,
604 	"pid",		{Qpid},		NUMSIZE,	0444,
605 	"ppid",		{Qppid},	NUMSIZE,	0444,
606 	"random",	{Qrandom},	0,		0444,
607 	"reboot",	{Qreboot},	0,		0664,
608 	"swap",		{Qswap},	0,		0664,
609 	"sysname",	{Qsysname},	0,		0664,
610 	"sysstat",	{Qsysstat},	0,		0666,
611 	"time",		{Qtime},	NUMSIZE+3*VLNUMSIZE,	0664,
612 	"user",		{Quser},	0,		0666,
613 	"zero",		{Qzero},	0,		0444,
614 };
615 
616 int
617 readnum(ulong off, char *buf, ulong n, ulong val, int size)
618 {
619 	char tmp[64];
620 
621 	snprint(tmp, sizeof(tmp), "%*.0lud", size-1, val);
622 	tmp[size-1] = ' ';
623 	if(off >= size)
624 		return 0;
625 	if(off+n > size)
626 		n = size-off;
627 	memmove(buf, tmp+off, n);
628 	return n;
629 }
630 
631 int
632 readstr(ulong off, char *buf, ulong n, char *str)
633 {
634 	int size;
635 
636 	size = strlen(str);
637 	if(off >= size)
638 		return 0;
639 	if(off+n > size)
640 		n = size-off;
641 	memmove(buf, str+off, n);
642 	return n;
643 }
644 
645 static void
646 consinit(void)
647 {
648 	todinit();
649 	randominit();
650 	/*
651 	 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
652 	 * processing it every 22 ms should be fine
653 	 */
654 	addclock0link(kbdputcclock, 22);
655 }
656 
657 static Chan*
658 consattach(char *spec)
659 {
660 	return devattach('c', spec);
661 }
662 
663 static Walkqid*
664 conswalk(Chan *c, Chan *nc, char **name, int nname)
665 {
666 	return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
667 }
668 
669 static int
670 consstat(Chan *c, uchar *dp, int n)
671 {
672 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
673 }
674 
675 static Chan*
676 consopen(Chan *c, int omode)
677 {
678 	c->aux = nil;
679 	c = devopen(c, omode, consdir, nelem(consdir), devgen);
680 	switch((ulong)c->qid.path){
681 	case Qconsctl:
682 		incref(&kbd.ctl);
683 		break;
684 
685 	case Qkprint:
686 		if(tas(&kprintinuse) != 0){
687 			c->flag &= ~COPEN;
688 			error(Einuse);
689 		}
690 		if(kprintoq == nil){
691 			kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
692 			if(kprintoq == nil){
693 				c->flag &= ~COPEN;
694 				error(Enomem);
695 			}
696 			qnoblock(kprintoq, 1);
697 		}else
698 			qreopen(kprintoq);
699 		c->iounit = qiomaxatomic;
700 		break;
701 	}
702 	return c;
703 }
704 
705 static void
706 consclose(Chan *c)
707 {
708 	switch((ulong)c->qid.path){
709 	/* last close of control file turns off raw */
710 	case Qconsctl:
711 		if(c->flag&COPEN){
712 			if(decref(&kbd.ctl) == 0)
713 				kbd.raw = 0;
714 		}
715 		break;
716 
717 	/* close of kprint allows other opens */
718 	case Qkprint:
719 		if(c->flag & COPEN){
720 			kprintinuse = 0;
721 			qhangup(kprintoq, nil);
722 		}
723 		break;
724 	}
725 }
726 
727 static long
728 consread(Chan *c, void *buf, long n, vlong off)
729 {
730 	ulong l;
731 	Mach *mp;
732 	char *b, *bp, ch;
733 	char tmp[256];		/* must be >= 18*NUMSIZE (Qswap) */
734 	int i, k, id, send;
735 	vlong offset = off;
736 
737 	if(n <= 0)
738 		return n;
739 
740 	switch((ulong)c->qid.path){
741 	case Qdir:
742 		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
743 
744 	case Qcons:
745 		qlock(&kbd);
746 		if(waserror()) {
747 			qunlock(&kbd);
748 			nexterror();
749 		}
750 		while(!qcanread(lineq)){
751 			if(qread(kbdq, &ch, 1) == 0)
752 				continue;
753 			send = 0;
754 			if(ch == 0){
755 				/* flush output on rawoff -> rawon */
756 				if(kbd.x > 0)
757 					send = !qcanread(kbdq);
758 			}else if(kbd.raw){
759 				kbd.line[kbd.x++] = ch;
760 				send = !qcanread(kbdq);
761 			}else{
762 				switch(ch){
763 				case '\b':
764 					if(kbd.x > 0)
765 						kbd.x--;
766 					break;
767 				case 0x15:	/* ^U */
768 					kbd.x = 0;
769 					break;
770 				case '\n':
771 				case 0x04:	/* ^D */
772 					send = 1;
773 				default:
774 					if(ch != 0x04)
775 						kbd.line[kbd.x++] = ch;
776 					break;
777 				}
778 			}
779 			if(send || kbd.x == sizeof kbd.line){
780 				qwrite(lineq, kbd.line, kbd.x);
781 				kbd.x = 0;
782 			}
783 		}
784 		n = qread(lineq, buf, n);
785 		qunlock(&kbd);
786 		poperror();
787 		return n;
788 
789 	case Qcputime:
790 		k = offset;
791 		if(k >= 6*NUMSIZE)
792 			return 0;
793 		if(k+n > 6*NUMSIZE)
794 			n = 6*NUMSIZE - k;
795 		/* easiest to format in a separate buffer and copy out */
796 		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
797 			l = up->time[i];
798 			if(i == TReal)
799 				l = MACHP(0)->ticks - l;
800 			l = TK2MS(l);
801 			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
802 		}
803 		memmove(buf, tmp+k, n);
804 		return n;
805 
806 	case Qkmesg:
807 		/*
808 		 * This is unlocked to avoid tying up a process
809 		 * that's writing to the buffer.  kmesg.n never
810 		 * gets smaller, so worst case the reader will
811 		 * see a slurred buffer.
812 		 */
813 		if(off >= kmesg.n)
814 			n = 0;
815 		else{
816 			if(off+n > kmesg.n)
817 				n = kmesg.n - off;
818 			memmove(buf, kmesg.buf+off, n);
819 		}
820 		return n;
821 
822 	case Qkprint:
823 		return qread(kprintoq, buf, n);
824 
825 	case Qpgrpid:
826 		return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
827 
828 	case Qpid:
829 		return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
830 
831 	case Qppid:
832 		return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
833 
834 	case Qtime:
835 		return readtime((ulong)offset, buf, n);
836 
837 	case Qbintime:
838 		return readbintime(buf, n);
839 
840 	case Qhostowner:
841 		return readstr((ulong)offset, buf, n, eve);
842 
843 	case Qhostdomain:
844 		return readstr((ulong)offset, buf, n, hostdomain);
845 
846 	case Quser:
847 		return readstr((ulong)offset, buf, n, up->user);
848 
849 	case Qnull:
850 		return 0;
851 
852 	case Qsysstat:
853 		b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1);	/* +1 for NUL */
854 		bp = b;
855 		for(id = 0; id < 32; id++) {
856 			if(active.machs & (1<<id)) {
857 				mp = MACHP(id);
858 				readnum(0, bp, NUMSIZE, id, NUMSIZE);
859 				bp += NUMSIZE;
860 				readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
861 				bp += NUMSIZE;
862 				readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
863 				bp += NUMSIZE;
864 				readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
865 				bp += NUMSIZE;
866 				readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
867 				bp += NUMSIZE;
868 				readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
869 				bp += NUMSIZE;
870 				readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
871 				bp += NUMSIZE;
872 				readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
873 				bp += NUMSIZE;
874 				readnum(0, bp, NUMSIZE,
875 					(mp->perf.avg_inidle*100)/mp->perf.period,
876 					NUMSIZE);
877 				bp += NUMSIZE;
878 				readnum(0, bp, NUMSIZE,
879 					(mp->perf.avg_inintr*100)/mp->perf.period,
880 					NUMSIZE);
881 				bp += NUMSIZE;
882 				*bp++ = '\n';
883 			}
884 		}
885 		if(waserror()){
886 			free(b);
887 			nexterror();
888 		}
889 		n = readstr((ulong)offset, buf, n, b);
890 		free(b);
891 		poperror();
892 		return n;
893 
894 	case Qswap:
895 		snprint(tmp, sizeof tmp,
896 			"%lud memory\n"
897 			"%d pagesize\n"
898 			"%lud kernel\n"
899 			"%lud/%lud user\n"
900 			"%lud/%lud swap\n"
901 			"%lud/%lud kernel malloc\n"
902 			"%lud/%lud kernel draw\n",
903 			conf.npage*BY2PG,
904 			BY2PG,
905 			conf.npage-conf.upages,
906 			palloc.user-palloc.freecount, palloc.user,
907 			conf.nswap-swapalloc.free, conf.nswap,
908 			mainmem->cursize, mainmem->maxsize,
909 			imagmem->cursize, imagmem->maxsize);
910 
911 		return readstr((ulong)offset, buf, n, tmp);
912 
913 	case Qsysname:
914 		if(sysname == nil)
915 			return 0;
916 		return readstr((ulong)offset, buf, n, sysname);
917 
918 	case Qrandom:
919 		return randomread(buf, n);
920 
921 	case Qdrivers:
922 		b = malloc(READSTR);
923 		if(b == nil)
924 			error(Enomem);
925 		n = 0;
926 		for(i = 0; devtab[i] != nil; i++)
927 			n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc,  devtab[i]->name);
928 		if(waserror()){
929 			free(b);
930 			nexterror();
931 		}
932 		n = readstr((ulong)offset, buf, n, b);
933 		free(b);
934 		poperror();
935 		return n;
936 
937 	case Qzero:
938 		memset(buf, 0, n);
939 		return n;
940 
941 	case Qosversion:
942 		snprint(tmp, sizeof tmp, "2000");
943 		n = readstr((ulong)offset, buf, n, tmp);
944 		return n;
945 
946 	default:
947 		print("consread 0x%llux\n", c->qid.path);
948 		error(Egreg);
949 	}
950 	return -1;		/* never reached */
951 }
952 
953 static long
954 conswrite(Chan *c, void *va, long n, vlong off)
955 {
956 	char buf[256], ch;
957 	long l, bp;
958 	char *a;
959 	Mach *mp;
960 	int id, fd;
961 	Chan *swc;
962 	ulong offset;
963 	Cmdbuf *cb;
964 	Cmdtab *ct;
965 
966 	a = va;
967 	offset = off;
968 
969 	switch((ulong)c->qid.path){
970 	case Qcons:
971 		/*
972 		 * Can't page fault in putstrn, so copy the data locally.
973 		 */
974 		l = n;
975 		while(l > 0){
976 			bp = l;
977 			if(bp > sizeof buf)
978 				bp = sizeof buf;
979 			memmove(buf, a, bp);
980 			putstrn0(buf, bp, 1);
981 			a += bp;
982 			l -= bp;
983 		}
984 		break;
985 
986 	case Qconsctl:
987 		if(n >= sizeof(buf))
988 			n = sizeof(buf)-1;
989 		strncpy(buf, a, n);
990 		buf[n] = 0;
991 		for(a = buf; a;){
992 			if(strncmp(a, "rawon", 5) == 0){
993 				kbd.raw = 1;
994 				/* clumsy hack - wake up reader */
995 				ch = 0;
996 				qwrite(kbdq, &ch, 1);
997 			} else if(strncmp(a, "rawoff", 6) == 0){
998 				kbd.raw = 0;
999 			} else if(strncmp(a, "ctlpon", 6) == 0){
1000 				kbd.ctlpoff = 0;
1001 			} else if(strncmp(a, "ctlpoff", 7) == 0){
1002 				kbd.ctlpoff = 1;
1003 			}
1004 			if(a = strchr(a, ' '))
1005 				a++;
1006 		}
1007 		break;
1008 
1009 	case Qtime:
1010 		if(!iseve())
1011 			error(Eperm);
1012 		return writetime(a, n);
1013 
1014 	case Qbintime:
1015 		if(!iseve())
1016 			error(Eperm);
1017 		return writebintime(a, n);
1018 
1019 	case Qhostowner:
1020 		return hostownerwrite(a, n);
1021 
1022 	case Qhostdomain:
1023 		return hostdomainwrite(a, n);
1024 
1025 	case Quser:
1026 		return userwrite(a, n);
1027 
1028 	case Qnull:
1029 		break;
1030 
1031 	case Qreboot:
1032 		if(!iseve())
1033 			error(Eperm);
1034 		cb = parsecmd(a, n);
1035 
1036 		if(waserror()) {
1037 			free(cb);
1038 			nexterror();
1039 		}
1040 		ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
1041 		switch(ct->index) {
1042 		case CMhalt:
1043 			reboot(nil, 0, 0);
1044 			break;
1045 		case CMreboot:
1046 			rebootcmd(cb->nf-1, cb->f+1);
1047 			break;
1048 		case CMpanic:
1049 			*(ulong*)0=0;
1050 			panic("/dev/reboot");
1051 		}
1052 		poperror();
1053 		free(cb);
1054 		break;
1055 
1056 	case Qsysstat:
1057 		for(id = 0; id < 32; id++) {
1058 			if(active.machs & (1<<id)) {
1059 				mp = MACHP(id);
1060 				mp->cs = 0;
1061 				mp->intr = 0;
1062 				mp->syscall = 0;
1063 				mp->pfault = 0;
1064 				mp->tlbfault = 0;
1065 				mp->tlbpurge = 0;
1066 			}
1067 		}
1068 		break;
1069 
1070 	case Qswap:
1071 		if(n >= sizeof buf)
1072 			error(Egreg);
1073 		memmove(buf, va, n);	/* so we can NUL-terminate */
1074 		buf[n] = 0;
1075 		/* start a pager if not already started */
1076 		if(strncmp(buf, "start", 5) == 0){
1077 			kickpager();
1078 			break;
1079 		}
1080 		if(!iseve())
1081 			error(Eperm);
1082 		if(buf[0]<'0' || '9'<buf[0])
1083 			error(Ebadarg);
1084 		fd = strtoul(buf, 0, 0);
1085 		swc = fdtochan(fd, -1, 1, 1);
1086 		setswapchan(swc);
1087 		break;
1088 
1089 	case Qsysname:
1090 		if(offset != 0)
1091 			error(Ebadarg);
1092 		if(n <= 0 || n >= sizeof buf)
1093 			error(Ebadarg);
1094 		strncpy(buf, a, n);
1095 		buf[n] = 0;
1096 		if(buf[n-1] == '\n')
1097 			buf[n-1] = 0;
1098 		kstrdup(&sysname, buf);
1099 		break;
1100 
1101 	default:
1102 		print("conswrite: 0x%llux\n", c->qid.path);
1103 		error(Egreg);
1104 	}
1105 	return n;
1106 }
1107 
1108 Dev consdevtab = {
1109 	'c',
1110 	"cons",
1111 
1112 	devreset,
1113 	consinit,
1114 	devshutdown,
1115 	consattach,
1116 	conswalk,
1117 	consstat,
1118 	consopen,
1119 	devcreate,
1120 	consclose,
1121 	consread,
1122 	devbread,
1123 	conswrite,
1124 	devbwrite,
1125 	devremove,
1126 	devwstat,
1127 };
1128 
1129 static	ulong	randn;
1130 
1131 static void
1132 seedrand(void)
1133 {
1134 	if(!waserror()){
1135 		randomread((void*)&randn, sizeof(randn));
1136 		poperror();
1137 	}
1138 }
1139 
1140 int
1141 nrand(int n)
1142 {
1143 	if(randn == 0)
1144 		seedrand();
1145 	randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
1146 	return (randn>>16) % n;
1147 }
1148 
1149 int
1150 rand(void)
1151 {
1152 	nrand(1);
1153 	return randn;
1154 }
1155 
1156 static uvlong uvorder = 0x0001020304050607ULL;
1157 
1158 static uchar*
1159 le2vlong(vlong *to, uchar *f)
1160 {
1161 	uchar *t, *o;
1162 	int i;
1163 
1164 	t = (uchar*)to;
1165 	o = (uchar*)&uvorder;
1166 	for(i = 0; i < sizeof(vlong); i++)
1167 		t[o[i]] = f[i];
1168 	return f+sizeof(vlong);
1169 }
1170 
1171 static uchar*
1172 vlong2le(uchar *t, vlong from)
1173 {
1174 	uchar *f, *o;
1175 	int i;
1176 
1177 	f = (uchar*)&from;
1178 	o = (uchar*)&uvorder;
1179 	for(i = 0; i < sizeof(vlong); i++)
1180 		t[i] = f[o[i]];
1181 	return t+sizeof(vlong);
1182 }
1183 
1184 static long order = 0x00010203;
1185 
1186 static uchar*
1187 le2long(long *to, uchar *f)
1188 {
1189 	uchar *t, *o;
1190 	int i;
1191 
1192 	t = (uchar*)to;
1193 	o = (uchar*)&order;
1194 	for(i = 0; i < sizeof(long); i++)
1195 		t[o[i]] = f[i];
1196 	return f+sizeof(long);
1197 }
1198 
1199 static uchar*
1200 long2le(uchar *t, long from)
1201 {
1202 	uchar *f, *o;
1203 	int i;
1204 
1205 	f = (uchar*)&from;
1206 	o = (uchar*)&order;
1207 	for(i = 0; i < sizeof(long); i++)
1208 		t[i] = f[o[i]];
1209 	return t+sizeof(long);
1210 }
1211 
1212 char *Ebadtimectl = "bad time control";
1213 
1214 /*
1215  *  like the old #c/time but with added info.  Return
1216  *
1217  *	secs	nanosecs	fastticks	fasthz
1218  */
1219 static int
1220 readtime(ulong off, char *buf, int n)
1221 {
1222 	vlong	nsec, ticks;
1223 	long sec;
1224 	char str[7*NUMSIZE];
1225 
1226 	nsec = todget(&ticks);
1227 	if(fasthz == 0LL)
1228 		fastticks((uvlong*)&fasthz);
1229 	sec = nsec/1000000000ULL;
1230 	snprint(str, sizeof(str), "%*.0lud %*.0llud %*.0llud %*.0llud ",
1231 		NUMSIZE-1, sec,
1232 		VLNUMSIZE-1, nsec,
1233 		VLNUMSIZE-1, ticks,
1234 		VLNUMSIZE-1, fasthz);
1235 	return readstr(off, buf, n, str);
1236 }
1237 
1238 /*
1239  *  set the time in seconds
1240  */
1241 static int
1242 writetime(char *buf, int n)
1243 {
1244 	char b[13];
1245 	long i;
1246 	vlong now;
1247 
1248 	if(n >= sizeof(b))
1249 		error(Ebadtimectl);
1250 	strncpy(b, buf, n);
1251 	b[n] = 0;
1252 	i = strtol(b, 0, 0);
1253 	if(i <= 0)
1254 		error(Ebadtimectl);
1255 	now = i*1000000000LL;
1256 	todset(now, 0, 0);
1257 	return n;
1258 }
1259 
1260 /*
1261  *  read binary time info.  all numbers are little endian.
1262  *  ticks and nsec are syncronized.
1263  */
1264 static int
1265 readbintime(char *buf, int n)
1266 {
1267 	int i;
1268 	vlong nsec, ticks;
1269 	uchar *b = (uchar*)buf;
1270 
1271 	i = 0;
1272 	if(fasthz == 0LL)
1273 		fastticks((uvlong*)&fasthz);
1274 	nsec = todget(&ticks);
1275 	if(n >= 3*sizeof(uvlong)){
1276 		vlong2le(b+2*sizeof(uvlong), fasthz);
1277 		i += sizeof(uvlong);
1278 	}
1279 	if(n >= 2*sizeof(uvlong)){
1280 		vlong2le(b+sizeof(uvlong), ticks);
1281 		i += sizeof(uvlong);
1282 	}
1283 	if(n >= 8){
1284 		vlong2le(b, nsec);
1285 		i += sizeof(vlong);
1286 	}
1287 	return i;
1288 }
1289 
1290 /*
1291  *  set any of the following
1292  *	- time in nsec
1293  *	- nsec trim applied over some seconds
1294  *	- clock frequency
1295  */
1296 static int
1297 writebintime(char *buf, int n)
1298 {
1299 	uchar *p;
1300 	vlong delta;
1301 	long period;
1302 
1303 	n--;
1304 	p = (uchar*)buf + 1;
1305 	switch(*buf){
1306 	case 'n':
1307 		if(n < sizeof(vlong))
1308 			error(Ebadtimectl);
1309 		le2vlong(&delta, p);
1310 		todset(delta, 0, 0);
1311 		break;
1312 	case 'd':
1313 		if(n < sizeof(vlong)+sizeof(long))
1314 			error(Ebadtimectl);
1315 		p = le2vlong(&delta, p);
1316 		le2long(&period, p);
1317 		todset(-1, delta, period);
1318 		break;
1319 	case 'f':
1320 		if(n < sizeof(uvlong))
1321 			error(Ebadtimectl);
1322 		le2vlong(&fasthz, p);
1323 		todsetfreq(fasthz);
1324 		break;
1325 	}
1326 	return n;
1327 }
1328