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