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