xref: /plan9-contrib/sys/src/9k/port/devcons.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
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 
8 #include	<authsrv.h>
9 
10 enum
11 {
12 	Nconsdevs	= 64,		/* max number of consoles */
13 
14 	/* Consdev flags */
15 	Ciprint		= 2,		/* call this fn from iprint */
16 	Cntorn		= 4,		/* change \n to \r\n */
17 };
18 
19 typedef struct Consdev Consdev;
20 
21 struct Consdev
22 {
23 	Chan*	c;			/* external file */
24 	Queue*	q;			/* i/o queue, if any */
25 	void	(*fn)(char*, int);	/* i/o function when no queue */
26 	int	flags;
27 };
28 
29 void	(*consdebug)(void) = nil;
30 void	(*consputs)(char*, int) = nil;
31 
32 static void kmesgputs(char *, int);
33 static void kprintputs(char*, int);
34 
35 static	Lock	consdevslock;
36 static	int	nconsdevs = 3;
37 static	Consdev	consdevs[Nconsdevs] =			/* keep this order */
38 {
39 	{nil, nil,	kmesgputs,	0},			/* kmesg */
40 	{nil, nil,	kprintputs,	Ciprint},		/* kprint */
41 	{nil, nil,	uartputs,	Ciprint|Cntorn},	/* serial */
42 };
43 
44 static	int	nkbdqs;
45 static	int	nkbdprocs;
46 static	Queue*	kbdqs[Nconsdevs];
47 static	int	kbdprocs[Nconsdevs];
48 static	Queue*	kbdq;		/* unprocessed console input */
49 static	Queue*	lineq;		/* processed console input */
50 static	Queue*	serialoq;	/* serial console output */
51 static	Queue*	kprintoq;	/* console output, for /dev/kprint */
52 static	ulong	kprintinuse;	/* test and set whether /dev/kprint is open */
53 
54 int	panicking;
55 
56 static struct
57 {
58 	QLock;
59 
60 	int	raw;		/* true if we shouldn't process input */
61 	Ref	ctl;		/* number of opens to the control file */
62 	int	x;		/* index into line */
63 	char	line[1024];	/* current input line */
64 
65 	int	count;
66 	int	ctlpoff;
67 
68 	/*
69 	 * A place to save up characters at interrupt time
70 	 * before dumping them in the queue
71 	 */
72 	Lock	lockputc;
73 	char	istage[1024];
74 	char	*iw;
75 	char	*ir;
76 	char	*ie;
77 } kbd = {
78 	.iw	= kbd.istage,
79 	.ir	= kbd.istage,
80 	.ie	= kbd.istage + sizeof(kbd.istage),
81 };
82 
83 char	*sysname;
84 vlong	fasthz;
85 
86 static void	seedrand(void);
87 static int	readtime(ulong, char*, int);
88 static int	readbintime(char*, int);
89 static int	writetime(char*, int);
90 static int	writebintime(char*, int);
91 
92 enum
93 {
94 	CMhalt,
95 	CMreboot,
96 	CMpanic,
97 };
98 
99 Cmdtab rebootmsg[] =
100 {
101 	CMhalt,		"halt",		1,
102 	CMreboot,	"reboot",	0,
103 	CMpanic,	"panic",	0,
104 };
105 
106 /* To keep the rest of the kernel unware of new consdevs for now */
107 static void
kprintputs(char * s,int n)108 kprintputs(char *s, int n)
109 {
110 	if(consputs != nil)
111 		consputs(s, n);
112 }
113 
114 int
addconsdev(Queue * q,void (* fn)(char *,int),int i,int flags)115 addconsdev(Queue *q, void (*fn)(char*,int), int i, int flags)
116 {
117 	Consdev *c;
118 
119 	ilock(&consdevslock);
120 	if(i < 0)
121 		i = nconsdevs;
122 	else
123 		flags |= consdevs[i].flags;
124 	if(nconsdevs == Nconsdevs)
125 		panic("Nconsdevs too small");
126 	c = &consdevs[i];
127 	c->flags = flags;
128 	c->q = q;
129 	c->fn = fn;
130 	if(i == nconsdevs)
131 		nconsdevs++;
132 	iunlock(&consdevslock);
133 	return i;
134 }
135 
136 void
delconsdevs(void)137 delconsdevs(void)
138 {
139 	nconsdevs = 2;	/* throw away serial consoles and kprint */
140 	consdevs[1].q = nil;
141 }
142 
143 static void
conskbdqproc(void * a)144 conskbdqproc(void *a)
145 {
146 	char buf[64];
147 	Queue *q;
148 	int nr;
149 
150 	q = a;
151 	while((nr = qread(q, buf, sizeof(buf))) > 0)
152 		qwrite(kbdq, buf, nr);
153 	pexit("hangup", 1);
154 }
155 
156 static void
kickkbdq(void)157 kickkbdq(void)
158 {
159 	int i;
160 
161 	if(up != nil && nkbdqs > 1 && nkbdprocs != nkbdqs){
162 		lock(&consdevslock);
163 		if(nkbdprocs == nkbdqs){
164 			unlock(&consdevslock);
165 			return;
166 		}
167 		for(i = 0; i < nkbdqs; i++)
168 			if(kbdprocs[i] == 0){
169 				kbdprocs[i] = 1;
170 				kproc("conskbdq", conskbdqproc, kbdqs[i]);
171 			}
172 		unlock(&consdevslock);
173 	}
174 }
175 
176 int
addkbdq(Queue * q,int i)177 addkbdq(Queue *q, int i)
178 {
179 	int n;
180 
181 	ilock(&consdevslock);
182 	if(i < 0)
183 		i = nkbdqs++;
184 	if(nkbdqs == Nconsdevs)
185 		panic("Nconsdevs too small");
186 	kbdqs[i] = q;
187 	n = nkbdqs;
188 	iunlock(&consdevslock);
189 	switch(n){
190 	case 1:
191 		/* if there's just one, pull directly from it. */
192 		kbdq = q;
193 		break;
194 	case 2:
195 		/* later we'll merge bytes from all kbdqs into a single kbdq */
196 		kbdq = qopen(4*1024, 0, 0, 0);
197 		if(kbdq == nil)
198 			panic("no kbdq");
199 		/* fall */
200 	default:
201 		kickkbdq();
202 	}
203 	return i;
204 }
205 
206 void
printinit(void)207 printinit(void)
208 {
209 	lineq = qopen(2*1024, 0, nil, nil);
210 	if(lineq == nil)
211 		panic("printinit");
212 	qnoblock(lineq, 1);
213 }
214 
215 int
consactive(void)216 consactive(void)
217 {
218 	int i;
219 	Queue *q;
220 
221 	for(i = 0; i < nconsdevs; i++)
222 		if((q = consdevs[i].q) != nil && qlen(q) > 0)
223 			return 1;
224 	return 0;
225 }
226 
227 void
prflush(void)228 prflush(void)
229 {
230 	ulong now;
231 
232 	now = m->ticks;
233 	while(consactive())
234 		if(m->ticks - now >= 10*HZ)
235 			break;
236 }
237 
238 /*
239  * Log console output so it can be retrieved via /dev/kmesg.
240  * This is good for catching boot-time messages after the fact.
241  */
242 struct {
243 	Lock lk;
244 	char buf[16384];
245 	uint n;
246 } kmesg;
247 
248 static void
kmesgputs(char * str,int n)249 kmesgputs(char *str, int n)
250 {
251 	uint nn, d;
252 
253 	ilock(&kmesg.lk);
254 	/* take the tail of huge writes */
255 	if(n > sizeof kmesg.buf){
256 		d = n - sizeof kmesg.buf;
257 		str += d;
258 		n -= d;
259 	}
260 
261 	/* slide the buffer down to make room */
262 	nn = kmesg.n;
263 	if(nn + n >= sizeof kmesg.buf){
264 		d = nn + n - sizeof kmesg.buf;
265 		if(d)
266 			memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
267 		nn -= d;
268 	}
269 
270 	/* copy the data in */
271 	memmove(kmesg.buf+nn, str, n);
272 	nn += n;
273 	kmesg.n = nn;
274 	iunlock(&kmesg.lk);
275 }
276 
277 static void
consdevputs(Consdev * c,char * s,int n,int usewrite)278 consdevputs(Consdev *c, char *s, int n, int usewrite)
279 {
280 	Chan *cc;
281 	Queue *q;
282 
283 	if((cc = c->c) != nil && usewrite)
284 		cc->dev->write(cc, s, n, 0);
285 	else if((q = c->q) != nil && !qisclosed(q))
286 		if(usewrite)
287 			qwrite(q, s, n);
288 		else
289 			qiwrite(q, s, n);
290 	else if(c->fn != nil)
291 		c->fn(s, n);
292 }
293 
294 /*
295  *   Print a string on the console.  Convert \n to \r\n for serial
296  *   line consoles.  Locking of the queues is left up to the screen
297  *   or uart code.  Multi-line messages to serial consoles may get
298  *   interspersed with other messages.
299  */
300 static void
putstrn0(char * str,int n,int usewrite)301 putstrn0(char *str, int n, int usewrite)
302 {
303 	Consdev *c;
304 	char *s, *t;
305 	int i, len, m;
306 
307 	if(!islo())
308 		usewrite = 0;
309 
310 	for(i = 0; i < nconsdevs; i++){
311 		c = &consdevs[i];
312 		len = n;
313 		s = str;
314 		while(len > 0){
315 			t = nil;
316 			if((c->flags&Cntorn) && !kbd.raw)
317 				t = memchr(s, '\n', len);
318 			if(t != nil && !kbd.raw){
319 				m = t-s;
320 				consdevputs(c, s, m, usewrite);
321 				consdevputs(c, "\r\n", 2, usewrite);
322 				len -= m+1;
323 				s = t+1;
324 			}else{
325 				consdevputs(c, s, len, usewrite);
326 				break;
327 			}
328 		}
329 	}
330 }
331 
332 void
putstrn(char * str,int n)333 putstrn(char *str, int n)
334 {
335 	putstrn0(str, n, 0);
336 }
337 
338 int
print(char * fmt,...)339 print(char *fmt, ...)
340 {
341 	int n;
342 	va_list arg;
343 	char buf[PRINTSIZE];
344 
345 	va_start(arg, fmt);
346 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
347 	va_end(arg);
348 	if(panicking <= 0 || up == nil || up->pid == panicking)
349 		putstrn(buf, n);
350 
351 	return n;
352 }
353 
354 /*
355  * Want to interlock iprints to avoid interlaced output on
356  * multiprocessor, but don't want to deadlock if one processor
357  * dies during print and another has something important to say.
358  * Make a good faith effort.
359  */
360 static Lock iprintlock;
361 
362 static int
iprintcanlock(Lock * l)363 iprintcanlock(Lock *l)
364 {
365 	int i;
366 
367 	for(i=0; i<1000; i++){
368 		if(canlock(l))
369 			return 1;
370 		if(l->m == m)
371 			return 0;
372 		microdelay(100);
373 	}
374 	return 0;
375 }
376 
377 int
iprint(char * fmt,...)378 iprint(char *fmt, ...)
379 {
380 	Mreg s;
381 	int i, n, locked;
382 	va_list arg;
383 	char buf[PRINTSIZE];
384 
385 	s = splhi();
386 	va_start(arg, fmt);
387 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
388 	va_end(arg);
389 	if(panicking > 0 && up != nil && up->pid != panicking)
390 		return n;
391 	locked = iprintcanlock(&iprintlock);
392 	for(i = 0; i < nconsdevs; i++){
393 		if((consdevs[i].flags&Ciprint) != 0){
394 			if(consdevs[i].q != nil)
395 				qiwrite(consdevs[i].q, buf, n);
396 			else
397 				consdevs[i].fn(buf, n);
398 		}
399 	}
400 	if(locked)
401 		unlock(&iprintlock);
402 	splx(s);
403 
404 	return n;
405 }
406 
407 #pragma profile 0
408 void
panic(char * fmt,...)409 panic(char *fmt, ...)
410 {
411 	int n;
412 	Mreg s;
413 	va_list arg;
414 	char buf[PRINTSIZE];
415 
416 	consdevs[1].q = nil;	/* don't try to write to /dev/kprint */
417 
418 	if(panicking)
419 		for(;;);
420 	panicking = -1;
421 	if(up)
422 		panicking = up->pid;
423 
424 	s = splhi();
425 	strcpy(buf, "panic: ");
426 	va_start(arg, fmt);
427 	n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
428 	va_end(arg);
429 //	iprint("%s\n", buf);
430 	if(consdebug)
431 		(*consdebug)();
432 	splx(s);
433 	prflush();
434 	buf[n] = '\n';
435 	putstrn(buf, n+1);
436 	prflush();
437 	dumpstack();
438 	prflush();
439 
440 	exit(1);
441 }
442 #pragma profile 1
443 /* libmp at least contains a few calls to sysfatal; simulate with panic */
444 void
sysfatal(char * fmt,...)445 sysfatal(char *fmt, ...)
446 {
447 	char err[256];
448 	va_list arg;
449 
450 	va_start(arg, fmt);
451 	vseprint(err, err + sizeof err, fmt, arg);
452 	va_end(arg);
453 	panic("sysfatal: %s", err);
454 }
455 
456 void
_assert(char * fmt)457 _assert(char *fmt)
458 {
459 	panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
460 }
461 
462 int
pprint(char * fmt,...)463 pprint(char *fmt, ...)
464 {
465 	int n;
466 	Chan *c;
467 	va_list arg;
468 	char buf[2*PRINTSIZE];
469 
470 	if(up == nil || up->fgrp == nil)
471 		return 0;
472 
473 	c = up->fgrp->fd[2];
474 	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
475 		return 0;
476 	n = snprint(buf, sizeof buf, "%s %d: ", up->text, up->pid);
477 	va_start(arg, fmt);
478 	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
479 	va_end(arg);
480 
481 	if(waserror())
482 		return 0;
483 	c->dev->write(c, buf, n, c->offset);
484 	poperror();
485 
486 	lock(c);
487 	c->offset += n;
488 	unlock(c);
489 
490 	return n;
491 }
492 
493 static void
echo(char * buf,int n)494 echo(char *buf, int n)
495 {
496 	Mreg s;
497 	static int ctrlt, pid;
498 	char *e, *p;
499 
500 	if(n == 0)
501 		return;
502 
503 	e = buf+n;
504 	for(p = buf; p < e; p++){
505 		switch(*p){
506 		case 0x10:	/* ^P */
507 			if(cpuserver && !kbd.ctlpoff){
508 				active.exiting = 1;
509 				return;
510 			}
511 			break;
512 		case 0x14:	/* ^T */
513 			ctrlt++;
514 			if(ctrlt > 2)
515 				ctrlt = 2;
516 			continue;
517 		}
518 
519 		if(ctrlt != 2)
520 			continue;
521 
522 		/* ^T escapes */
523 		ctrlt = 0;
524 		switch(*p){
525 		case 'S':
526 			s = splhi();
527 			dumpstack();
528 			procdump();
529 			splx(s);
530 			return;
531 		case 's':
532 			dumpstack();
533 			return;
534 		case 'x':
535 			ixsummary();
536 			mallocsummary();
537 //			memorysummary();
538 			return;
539 		case 'd':
540 			if(consdebug == nil)
541 				consdebug = rdb;
542 			else
543 				consdebug = nil;
544 			print("consdebug now %#p\n", consdebug);
545 			return;
546 		case 'D':
547 			if(consdebug == nil)
548 				consdebug = rdb;
549 			consdebug();
550 			return;
551 		case 'p':
552 			s = spllo();
553 			procdump();
554 			splx(s);
555 			return;
556 		case 'q':
557 			scheddump();
558 			return;
559 		case 'k':
560 			killbig("^t ^t k");
561 			return;
562 		case 'r':
563 			exit(0);
564 			return;
565 		}
566 	}
567 
568 	if(kbdq != nil)
569 		qproduce(kbdq, buf, n);
570 	if(kbd.raw == 0)
571 		putstrn(buf, n);
572 }
573 
574 /*
575  *  Called by a uart interrupt for console input.
576  *
577  *  turn '\r' into '\n' before putting it into the queue.
578  */
579 int
kbdcr2nl(Queue *,int ch)580 kbdcr2nl(Queue*, int ch)
581 {
582 	char *next;
583 
584 	ilock(&kbd.lockputc);		/* just a mutex */
585 	if(ch == '\r' && !kbd.raw)
586 		ch = '\n';
587 	next = kbd.iw+1;
588 	if(next >= kbd.ie)
589 		next = kbd.istage;
590 	if(next != kbd.ir){
591 		*kbd.iw = ch;
592 		kbd.iw = next;
593 	}
594 	iunlock(&kbd.lockputc);
595 	return 0;
596 }
597 
598 /*
599  *  Put character, possibly a rune, into read queue at interrupt time.
600  *  Called at interrupt time to process a character.
601  */
602 int
kbdputc(Queue *,int ch)603 kbdputc(Queue*, int ch)
604 {
605 	int i, n;
606 	char buf[UTFmax];
607 	Rune r;
608 	char *next;
609 
610 	if(kbd.ir == nil)
611 		return 0;		/* in case we're not inited yet */
612 
613 	ilock(&kbd.lockputc);		/* just a mutex */
614 	r = ch;
615 	n = runetochar(buf, &r);
616 	for(i = 0; i < n; i++){
617 		next = kbd.iw+1;
618 		if(next >= kbd.ie)
619 			next = kbd.istage;
620 		if(next == kbd.ir)
621 			break;
622 		*kbd.iw = buf[i];
623 		kbd.iw = next;
624 	}
625 	iunlock(&kbd.lockputc);
626 	return 0;
627 }
628 
629 /*
630  *  we save up input characters till clock time to reduce
631  *  per character interrupt overhead.
632  */
633 static void
kbdputcclock(void)634 kbdputcclock(void)
635 {
636 	char *iw;
637 
638 	/* this amortizes cost of qproduce */
639 	if(kbd.iw != kbd.ir){
640 		iw = kbd.iw;
641 		if(iw < kbd.ir){
642 			echo(kbd.ir, kbd.ie-kbd.ir);
643 			kbd.ir = kbd.istage;
644 		}
645 		if(kbd.ir != iw){
646 			echo(kbd.ir, iw-kbd.ir);
647 			kbd.ir = iw;
648 		}
649 	}
650 }
651 
652 enum{
653 	Qdir,
654 	Qbintime,
655 	Qcons,
656 	Qconsctl,
657 	Qcputime,
658 	Qdrivers,
659 	Qkmesg,
660 	Qkprint,
661 	Qhostdomain,
662 	Qhostowner,
663 	Qnull,
664 	Qosversion,
665 	Qpgrpid,
666 	Qpid,
667 	Qppid,
668 	Qrandom,
669 	Qreboot,
670 	Qswap,
671 	Qsysname,
672 	Qsysstat,
673 	Qtime,
674 	Quser,
675 	Qzero,
676 	Qconfig,
677 };
678 
679 enum
680 {
681 	VLNUMSIZE=	22,
682 };
683 
684 static Dirtab consdir[]={
685 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
686 	"bintime",	{Qbintime},	24,		0664,
687 	"cons",		{Qcons},	0,		0660,
688 	"consctl",	{Qconsctl},	0,		0220,
689 	"cputime",	{Qcputime},	6*NUMSIZE,	0444,
690 	"drivers",	{Qdrivers},	0,		0444,
691 	"hostdomain",	{Qhostdomain},	DOMLEN,		0664,
692 	"hostowner",	{Qhostowner},	0,		0664,
693 	"kmesg",	{Qkmesg},	0,		0440,
694 	"kprint",	{Qkprint, 0, QTEXCL},	0,	DMEXCL|0440,
695 	"null",		{Qnull},	0,		0666,
696 	"osversion",	{Qosversion},	0,		0444,
697 	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444,
698 	"pid",		{Qpid},		NUMSIZE,	0444,
699 	"ppid",		{Qppid},	NUMSIZE,	0444,
700 	"random",	{Qrandom},	0,		0444,
701 	"reboot",	{Qreboot},	0,		0660,
702 	"swap",		{Qswap},	0,		0664,
703 	"sysname",	{Qsysname},	0,		0664,
704 	"sysstat",	{Qsysstat},	0,		0666,
705 	"time",		{Qtime},	NUMSIZE+3*VLNUMSIZE,	0664,
706 	"user",		{Quser},	0,		0666,
707 	"zero",		{Qzero},	0,		0444,
708 	"config",	{Qconfig},	0,		0444,
709 };
710 
711 int
readnum(ulong off,char * buf,ulong n,ulong val,int size)712 readnum(ulong off, char *buf, ulong n, ulong val, int size)
713 {
714 	char tmp[64];
715 
716 	snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
717 	tmp[size-1] = ' ';
718 	if(off >= size)
719 		return 0;
720 	if(off+n > size)
721 		n = size-off;
722 	memmove(buf, tmp+off, n);
723 	return n;
724 }
725 
726 long
readstr(long offset,char * buf,long n,char * str)727 readstr(long offset, char *buf, long n, char *str)
728 {
729 	long size;
730 
731 	size = strlen(str);
732 	if(offset >= size)
733 		return 0;
734 	if(offset+n > size)
735 		n = size-offset;
736 	memmove(buf, str+offset, n);
737 	return n;
738 }
739 
740 static void
consinit(void)741 consinit(void)
742 {
743 	todinit();
744 	randominit();
745 	/*
746 	 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
747 	 * processing it every 22 ms should be fine
748 	 */
749 	addclock0link(kbdputcclock, 22);
750 	kickkbdq();
751 }
752 
753 static Chan*
consattach(char * spec)754 consattach(char *spec)
755 {
756 	return devattach('c', spec);
757 }
758 
759 static Walkqid*
conswalk(Chan * c,Chan * nc,char ** name,int nname)760 conswalk(Chan *c, Chan *nc, char **name, int nname)
761 {
762 	return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
763 }
764 
765 static long
consstat(Chan * c,uchar * dp,long n)766 consstat(Chan *c, uchar *dp, long n)
767 {
768 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
769 }
770 
771 static Chan*
consopen(Chan * c,int omode)772 consopen(Chan *c, int omode)
773 {
774 	c->aux = nil;
775 	c = devopen(c, omode, consdir, nelem(consdir), devgen);
776 	switch((ulong)c->qid.path){
777 	case Qconsctl:
778 		incref(&kbd.ctl);
779 		break;
780 
781 	case Qkprint:
782 		if(TAS(&kprintinuse) != 0){
783 			c->flag &= ~COPEN;
784 			error(Einuse);
785 		}
786 		if(kprintoq == nil){
787 			kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
788 			if(kprintoq == nil){
789 				c->flag &= ~COPEN;
790 				error(Enomem);
791 			}
792 			qnoblock(kprintoq, 1);
793 			consdevs[1].q = kprintoq;
794 		}else
795 			qreopen(kprintoq);
796 		c->iounit = qiomaxatomic;
797 		break;
798 	}
799 	return c;
800 }
801 
802 static void
consclose(Chan * c)803 consclose(Chan *c)
804 {
805 	switch((ulong)c->qid.path){
806 	/* last close of control file turns off raw */
807 	case Qconsctl:
808 		if(c->flag&COPEN){
809 			if(decref(&kbd.ctl) == 0)
810 				kbd.raw = 0;
811 		}
812 		break;
813 
814 	/* close of kprint allows other opens */
815 	case Qkprint:
816 		if(c->flag & COPEN){
817 			kprintinuse = 0;
818 			qhangup(kprintoq, nil);
819 		}
820 		break;
821 	}
822 }
823 
824 static long
consread(Chan * c,void * buf,long n,vlong off)825 consread(Chan *c, void *buf, long n, vlong off)
826 {
827 	ulong l;
828 	Mach *mp;
829 	char *b, *bp, ch, *s;
830 	char tmp[256];		/* must be >= 18*NUMSIZE (Qswap) */
831 	int i, k, id, send;
832 	long offset;
833 
834 
835 	if(n <= 0)
836 		return n;
837 
838 	offset = off;
839 	switch((ulong)c->qid.path){
840 	case Qdir:
841 		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
842 
843 	case Qcons:
844 		qlock(&kbd);
845 		if(waserror()) {
846 			qunlock(&kbd);
847 			nexterror();
848 		}
849 		while(!qcanread(lineq)){
850 			if(qread(kbdq, &ch, 1) == 0)
851 				continue;
852 			send = 0;
853 			if(ch == 0){
854 				/* flush output on rawoff -> rawon */
855 				if(kbd.x > 0)
856 					send = !qcanread(kbdq);
857 			}else if(kbd.raw){
858 				kbd.line[kbd.x++] = ch;
859 				send = !qcanread(kbdq);
860 			}else{
861 				switch(ch){
862 				case '\b':
863 					if(kbd.x > 0)
864 						kbd.x--;
865 					break;
866 				case 0x15:	/* ^U */
867 					kbd.x = 0;
868 					break;
869 				case '\n':
870 				case 0x04:	/* ^D */
871 					send = 1;
872 				default:
873 					if(ch != 0x04)
874 						kbd.line[kbd.x++] = ch;
875 					break;
876 				}
877 			}
878 			if(send || kbd.x == sizeof kbd.line){
879 				qwrite(lineq, kbd.line, kbd.x);
880 				kbd.x = 0;
881 			}
882 		}
883 		n = qread(lineq, buf, n);
884 		qunlock(&kbd);
885 		poperror();
886 		return n;
887 
888 	case Qcputime:
889 		k = offset;
890 		if(k >= 6*NUMSIZE)
891 			return 0;
892 		if(k+n > 6*NUMSIZE)
893 			n = 6*NUMSIZE - k;
894 		/* easiest to format in a separate buffer and copy out */
895 		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
896 			l = up->time[i];
897 			if(i == TReal)
898 				l = sys->ticks - l;
899 			l = TK2MS(l);
900 			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
901 		}
902 		memmove(buf, tmp+k, n);
903 		return n;
904 
905 	case Qkmesg:
906 		/*
907 		 * This is unlocked to avoid tying up a process
908 		 * that's writing to the buffer.  kmesg.n never
909 		 * gets smaller, so worst case the reader will
910 		 * see a slurred buffer.
911 		 */
912 		if(off >= kmesg.n)
913 			n = 0;
914 		else{
915 			if(off+n > kmesg.n)
916 				n = kmesg.n - off;
917 			memmove(buf, kmesg.buf+off, n);
918 		}
919 		return n;
920 
921 	case Qkprint:
922 		return qread(kprintoq, buf, n);
923 
924 	case Qpgrpid:
925 		return readnum(offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
926 
927 	case Qpid:
928 		return readnum(offset, buf, n, up->pid, NUMSIZE);
929 
930 	case Qppid:
931 		return readnum(offset, buf, n, up->parentpid, NUMSIZE);
932 
933 	case Qtime:
934 		return readtime(offset, buf, n);
935 
936 	case Qbintime:
937 		return readbintime(buf, n);
938 
939 	case Qhostowner:
940 		return readstr(offset, buf, n, eve);
941 
942 	case Qhostdomain:
943 		return readstr(offset, buf, n, hostdomain);
944 
945 	case Quser:
946 		return readstr(offset, buf, n, up->user);
947 
948 	case Qnull:
949 		return 0;
950 
951 	case Qconfig:
952 		return readstr(offset, buf, n, configfile);
953 
954 	case Qsysstat:
955 		b = smalloc(sys->nonline*(NUMSIZE*11+1) + 1);	/* +1 for NUL */
956 		bp = b;
957 		for(id = 0; id < MACHMAX; id++){
958 			if((mp = sys->machptr[id]) == nil || !mp->online)
959 				continue;
960 			readnum(0, bp, NUMSIZE, id, NUMSIZE);
961 			bp += NUMSIZE;
962 			readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
963 			bp += NUMSIZE;
964 			readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
965 			bp += NUMSIZE;
966 			readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
967 			bp += NUMSIZE;
968 			readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
969 			bp += NUMSIZE;
970 			readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
971 			bp += NUMSIZE;
972 			readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
973 			bp += NUMSIZE;
974 			readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
975 			bp += NUMSIZE;
976 			readnum(0, bp, NUMSIZE,
977 				(mp->perf.avg_inidle*100)/mp->perf.period,
978 				NUMSIZE);
979 			bp += NUMSIZE;
980 			readnum(0, bp, NUMSIZE,
981 				(mp->perf.avg_inintr*100)/mp->perf.period,
982 				NUMSIZE);
983 			bp += NUMSIZE;
984 			*bp++ = '\n';
985 		}
986 		if(waserror()){
987 			free(b);
988 			nexterror();
989 		}
990 		n = readstr(offset, buf, n, b);
991 		free(b);
992 		poperror();
993 		return n;
994 
995 	case Qswap:
996 		tmp[0] = 0;
997 		s = seprintpagestats(tmp, tmp + sizeof tmp);
998 		s = seprintphysstats(s, tmp + sizeof tmp);
999 		b = buf;
1000 		l = s - tmp;
1001 		i = readstr(offset, b, l, tmp);
1002 		b += i;
1003 		n -= i;
1004 		if(offset > l)
1005 			offset -= l;
1006 		else
1007 			offset = 0;
1008 
1009 		return i + mallocreadsummary(c, b, n, offset);
1010 
1011 	case Qsysname:
1012 		if(sysname == nil)
1013 			return 0;
1014 		return readstr(offset, buf, n, sysname);
1015 
1016 	case Qrandom:
1017 		return randomread(buf, n);
1018 
1019 	case Qdrivers:
1020 		return devtabread(c, buf, n, off);
1021 
1022 	case Qzero:
1023 		memset(buf, 0, n);
1024 		return n;
1025 
1026 	case Qosversion:
1027 		snprint(tmp, sizeof tmp, "2000");
1028 		n = readstr(offset, buf, n, tmp);
1029 		return n;
1030 
1031 	default:
1032 		print("consread %#llux\n", c->qid.path);
1033 		error(Egreg);
1034 	}
1035 	return -1;		/* never reached */
1036 }
1037 
1038 static long
conswrite(Chan * c,void * va,long n,vlong off)1039 conswrite(Chan *c, void *va, long n, vlong off)
1040 {
1041 	char buf[256], ch;
1042 	long l, bp;
1043 	char *a;
1044 	Mach *mp;
1045 	int i;
1046 	ulong offset;
1047 	Cmdbuf *cb;
1048 	Cmdtab *ct;
1049 
1050 	a = va;
1051 	offset = off;
1052 
1053 	switch((ulong)c->qid.path){
1054 	case Qcons:
1055 		/*
1056 		 * Can't page fault in putstrn, so copy the data locally.
1057 		 */
1058 		l = n;
1059 		while(l > 0){
1060 			bp = l;
1061 			if(bp > sizeof buf)
1062 				bp = sizeof buf;
1063 			memmove(buf, a, bp);
1064 			putstrn0(buf, bp, 1);
1065 			a += bp;
1066 			l -= bp;
1067 		}
1068 		break;
1069 
1070 	case Qconsctl:
1071 		if(n >= sizeof(buf))
1072 			n = sizeof(buf)-1;
1073 		strncpy(buf, a, n);
1074 		buf[n] = 0;
1075 		for(a = buf; a;){
1076 			if(strncmp(a, "rawon", 5) == 0){
1077 				kbd.raw = 1;
1078 				/* clumsy hack - wake up reader */
1079 				ch = 0;
1080 				qwrite(kbdq, &ch, 1);
1081 			}
1082 			else if(strncmp(a, "rawoff", 6) == 0)
1083 				kbd.raw = 0;
1084 			else if(strncmp(a, "ctlpon", 6) == 0)
1085 				kbd.ctlpoff = 0;
1086 			else if(strncmp(a, "ctlpoff", 7) == 0)
1087 				kbd.ctlpoff = 1;
1088 			if(a = strchr(a, ' '))
1089 				a++;
1090 		}
1091 		break;
1092 
1093 	case Qtime:
1094 		if(!iseve())
1095 			error(Eperm);
1096 		return writetime(a, n);
1097 
1098 	case Qbintime:
1099 		if(!iseve())
1100 			error(Eperm);
1101 		return writebintime(a, n);
1102 
1103 	case Qhostowner:
1104 		return hostownerwrite(a, n);
1105 
1106 	case Qhostdomain:
1107 		return hostdomainwrite(a, n);
1108 
1109 	case Quser:
1110 		return userwrite(a, n);
1111 
1112 	case Qnull:
1113 		break;
1114 
1115 	case Qconfig:
1116 		error(Eperm);
1117 		break;
1118 
1119 	case Qreboot:
1120 		if(!iseve())
1121 			error(Eperm);
1122 		cb = parsecmd(a, n);
1123 
1124 		if(waserror()) {
1125 			free(cb);
1126 			nexterror();
1127 		}
1128 		ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
1129 		switch(ct->index) {
1130 		case CMhalt:
1131 			reboot(nil, 0, 0);
1132 			break;
1133 		case CMreboot:
1134 			rebootcmd(cb->nf-1, cb->f+1);
1135 			break;
1136 		case CMpanic:
1137 			*(ulong*)0=0;
1138 			panic("/dev/reboot");
1139 		}
1140 		poperror();
1141 		free(cb);
1142 		break;
1143 
1144 	case Qsysstat:
1145 		for(i = 0; i < MACHMAX; i++){
1146 			if((mp = sys->machptr[i]) == nil || !mp->online)
1147 				continue;
1148 			mp->cs = 0;
1149 			mp->intr = 0;
1150 			mp->syscall = 0;
1151 			mp->pfault = 0;
1152 			mp->tlbfault = 0;
1153 			mp->tlbpurge = 0;
1154 		}
1155 		break;
1156 
1157 	case Qswap:
1158 		/* no more */
1159 		break;
1160 
1161 	case Qsysname:
1162 		if(offset != 0)
1163 			error(Ebadarg);
1164 		if(n <= 0 || n >= sizeof buf)
1165 			error(Ebadarg);
1166 		strncpy(buf, a, n);
1167 		buf[n] = 0;
1168 		if(buf[n-1] == '\n')
1169 			buf[n-1] = 0;
1170 		kstrdup(&sysname, buf);
1171 		break;
1172 
1173 	default:
1174 		print("conswrite: %#llux\n", c->qid.path);
1175 		error(Egreg);
1176 	}
1177 	return n;
1178 }
1179 
1180 Dev consdevtab = {
1181 	'c',
1182 	"cons",
1183 
1184 	devreset,
1185 	consinit,
1186 	devshutdown,
1187 	consattach,
1188 	conswalk,
1189 	consstat,
1190 	consopen,
1191 	devcreate,
1192 	consclose,
1193 	consread,
1194 	devbread,
1195 	conswrite,
1196 	devbwrite,
1197 	devremove,
1198 	devwstat,
1199 };
1200 
1201 static	ulong	randn;
1202 
1203 static void
seedrand(void)1204 seedrand(void)
1205 {
1206 	if(!waserror()){
1207 		randomread((void*)&randn, sizeof(randn));
1208 		poperror();
1209 	}
1210 }
1211 
1212 int
nrand(int n)1213 nrand(int n)
1214 {
1215 	if(randn == 0)
1216 		seedrand();
1217 	randn = randn*1103515245 + 12345 + sys->ticks;
1218 	return (randn>>16) % n;
1219 }
1220 
1221 int
rand(void)1222 rand(void)
1223 {
1224 	nrand(1);
1225 	return randn;
1226 }
1227 
1228 static uvlong uvorder = 0x0001020304050607ULL;
1229 
1230 static uchar*
le2vlong(vlong * to,uchar * f)1231 le2vlong(vlong *to, uchar *f)
1232 {
1233 	uchar *t, *o;
1234 	int i;
1235 
1236 	t = (uchar*)to;
1237 	o = (uchar*)&uvorder;
1238 	for(i = 0; i < sizeof(vlong); i++)
1239 		t[o[i]] = f[i];
1240 	return f+sizeof(vlong);
1241 }
1242 
1243 static uchar*
vlong2le(uchar * t,vlong from)1244 vlong2le(uchar *t, vlong from)
1245 {
1246 	uchar *f, *o;
1247 	int i;
1248 
1249 	f = (uchar*)&from;
1250 	o = (uchar*)&uvorder;
1251 	for(i = 0; i < sizeof(vlong); i++)
1252 		t[i] = f[o[i]];
1253 	return t+sizeof(vlong);
1254 }
1255 
1256 static long order = 0x00010203;
1257 
1258 static uchar*
le2long(long * to,uchar * f)1259 le2long(long *to, uchar *f)
1260 {
1261 	uchar *t, *o;
1262 	int i;
1263 
1264 	t = (uchar*)to;
1265 	o = (uchar*)&order;
1266 	for(i = 0; i < sizeof(long); i++)
1267 		t[o[i]] = f[i];
1268 	return f+sizeof(long);
1269 }
1270 
1271 static uchar*
long2le(uchar * t,long from)1272 long2le(uchar *t, long from)
1273 {
1274 	uchar *f, *o;
1275 	int i;
1276 
1277 	f = (uchar*)&from;
1278 	o = (uchar*)&order;
1279 	for(i = 0; i < sizeof(long); i++)
1280 		t[i] = f[o[i]];
1281 	return t+sizeof(long);
1282 }
1283 
1284 char *Ebadtimectl = "bad time control";
1285 
1286 /*
1287  *  like the old #c/time but with added info.  Return
1288  *
1289  *	secs	nanosecs	fastticks	fasthz
1290  */
1291 static int
readtime(ulong off,char * buf,int n)1292 readtime(ulong off, char *buf, int n)
1293 {
1294 	vlong nsec, ticks;
1295 	long sec;
1296 	char str[7*NUMSIZE];
1297 
1298 	nsec = todget(&ticks);
1299 	if(fasthz == 0LL)
1300 		fastticks((uvlong*)&fasthz);
1301 	sec = nsec/1000000000ULL;
1302 	snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
1303 		NUMSIZE-1, sec,
1304 		VLNUMSIZE-1, nsec,
1305 		VLNUMSIZE-1, ticks,
1306 		VLNUMSIZE-1, fasthz);
1307 	return readstr(off, buf, n, str);
1308 }
1309 
1310 /*
1311  *  set the time in seconds
1312  */
1313 static int
writetime(char * buf,int n)1314 writetime(char *buf, int n)
1315 {
1316 	char b[13];
1317 	long i;
1318 	vlong now;
1319 
1320 	if(n >= sizeof(b))
1321 		error(Ebadtimectl);
1322 	strncpy(b, buf, n);
1323 	b[n] = 0;
1324 	i = strtol(b, 0, 0);
1325 	if(i <= 0)
1326 		error(Ebadtimectl);
1327 	now = i*1000000000LL;
1328 	todset(now, 0, 0);
1329 	return n;
1330 }
1331 
1332 /*
1333  *  read binary time info.  all numbers are little endian.
1334  *  ticks and nsec are syncronized.
1335  */
1336 static int
readbintime(char * buf,int n)1337 readbintime(char *buf, int n)
1338 {
1339 	int i;
1340 	vlong nsec, ticks;
1341 	uchar *b = (uchar*)buf;
1342 
1343 	i = 0;
1344 	if(fasthz == 0LL)
1345 		fastticks((uvlong*)&fasthz);
1346 	nsec = todget(&ticks);
1347 	if(n >= 3*sizeof(uvlong)){
1348 		vlong2le(b+2*sizeof(uvlong), fasthz);
1349 		i += sizeof(uvlong);
1350 	}
1351 	if(n >= 2*sizeof(uvlong)){
1352 		vlong2le(b+sizeof(uvlong), ticks);
1353 		i += sizeof(uvlong);
1354 	}
1355 	if(n >= 8){
1356 		vlong2le(b, nsec);
1357 		i += sizeof(vlong);
1358 	}
1359 	return i;
1360 }
1361 
1362 /*
1363  *  set any of the following
1364  *	- time in nsec
1365  *	- nsec trim applied over some seconds
1366  *	- clock frequency
1367  */
1368 static int
writebintime(char * buf,int n)1369 writebintime(char *buf, int n)
1370 {
1371 	uchar *p;
1372 	vlong delta;
1373 	long period;
1374 
1375 	n--;
1376 	p = (uchar*)buf + 1;
1377 	switch(*buf){
1378 	case 'n':
1379 		if(n < sizeof(vlong))
1380 			error(Ebadtimectl);
1381 		le2vlong(&delta, p);
1382 		todset(delta, 0, 0);
1383 		break;
1384 	case 'd':
1385 		if(n < sizeof(vlong)+sizeof(long))
1386 			error(Ebadtimectl);
1387 		p = le2vlong(&delta, p);
1388 		le2long(&period, p);
1389 		todset(-1, delta, period);
1390 		break;
1391 	case 'f':
1392 		if(n < sizeof(uvlong))
1393 			error(Ebadtimectl);
1394 		le2vlong(&fasthz, p);
1395 		todsetfreq(fasthz);
1396 		break;
1397 	}
1398 	return n;
1399 }
1400