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