xref: /plan9/sys/src/9/port/devcons.c (revision a826b788f46ccc92a1e0e05eb47067d9d683fddd)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"../port/error.h"
7e059317eSDavid du Colombier #include	"pool.h"
83e12c5d1SDavid du Colombier 
99a747e4fSDavid du Colombier #include	<authsrv.h>
109a747e4fSDavid du Colombier 
117dd7cddfSDavid du Colombier void	(*consdebug)(void) = nil;
129a747e4fSDavid du Colombier void	(*screenputs)(char*, int) = nil;
133e12c5d1SDavid du Colombier 
147dd7cddfSDavid du Colombier Queue*	kbdq;			/* unprocessed console input */
157dd7cddfSDavid du Colombier Queue*	lineq;			/* processed console input */
169a747e4fSDavid du Colombier Queue*	serialoq;		/* serial console output */
179a747e4fSDavid du Colombier Queue*	kprintoq;		/* console output, for /dev/kprint */
189a747e4fSDavid du Colombier ulong	kprintinuse;		/* test and set whether /dev/kprint is open */
199a747e4fSDavid du Colombier int	iprintscreenputs = 1;
203e12c5d1SDavid du Colombier 
21d9306527SDavid du Colombier int	panicking;
22d9306527SDavid du Colombier 
237dd7cddfSDavid du Colombier static struct
247dd7cddfSDavid du Colombier {
257dd7cddfSDavid du Colombier 	QLock;
263e12c5d1SDavid du Colombier 
277dd7cddfSDavid du Colombier 	int	raw;		/* true if we shouldn't process input */
2888110b43SDavid du Colombier 	Ref	ctl;		/* number of opens to the control file */
297dd7cddfSDavid du Colombier 	int	x;		/* index into line */
307dd7cddfSDavid du Colombier 	char	line[1024];	/* current input line */
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier 	int	count;
337dd7cddfSDavid du Colombier 	int	ctlpoff;
3480ee5cbfSDavid du Colombier 
3580ee5cbfSDavid du Colombier 	/* a place to save up characters at interrupt time before dumping them in the queue */
3680ee5cbfSDavid du Colombier 	Lock	lockputc;
37d9306527SDavid du Colombier 	char	istage[1024];
3880ee5cbfSDavid du Colombier 	char	*iw;
3980ee5cbfSDavid du Colombier 	char	*ir;
4080ee5cbfSDavid du Colombier 	char	*ie;
419a747e4fSDavid du Colombier } kbd = {
429a747e4fSDavid du Colombier 	.iw	= kbd.istage,
439a747e4fSDavid du Colombier 	.ir	= kbd.istage,
449a747e4fSDavid du Colombier 	.ie	= kbd.istage + sizeof(kbd.istage),
459a747e4fSDavid du Colombier };
463e12c5d1SDavid du Colombier 
479a747e4fSDavid du Colombier char	*sysname;
487dd7cddfSDavid du Colombier vlong	fasthz;
493e12c5d1SDavid du Colombier 
507dd7cddfSDavid du Colombier static void	seedrand(void);
517dd7cddfSDavid du Colombier static int	readtime(ulong, char*, int);
527dd7cddfSDavid du Colombier static int	readbintime(char*, int);
537dd7cddfSDavid du Colombier static int	writetime(char*, int);
547dd7cddfSDavid du Colombier static int	writebintime(char*, int);
557dd7cddfSDavid du Colombier 
569a747e4fSDavid du Colombier enum
579a747e4fSDavid du Colombier {
58e288d156SDavid du Colombier 	CMhalt,
599a747e4fSDavid du Colombier 	CMreboot,
609a747e4fSDavid du Colombier 	CMpanic,
619a747e4fSDavid du Colombier };
629a747e4fSDavid du Colombier 
639a747e4fSDavid du Colombier Cmdtab rebootmsg[] =
649a747e4fSDavid du Colombier {
65e288d156SDavid du Colombier 	CMhalt,		"halt",		1,
669a747e4fSDavid du Colombier 	CMreboot,	"reboot",	0,
679a747e4fSDavid du Colombier 	CMpanic,	"panic",	0,
689a747e4fSDavid du Colombier };
699a747e4fSDavid du Colombier 
703e12c5d1SDavid du Colombier void
printinit(void)713e12c5d1SDavid du Colombier printinit(void)
723e12c5d1SDavid du Colombier {
733ff48bf5SDavid du Colombier 	lineq = qopen(2*1024, 0, nil, nil);
747dd7cddfSDavid du Colombier 	if(lineq == nil)
757dd7cddfSDavid du Colombier 		panic("printinit");
767dd7cddfSDavid du Colombier 	qnoblock(lineq, 1);
777dd7cddfSDavid du Colombier }
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier int
consactive(void)807dd7cddfSDavid du Colombier consactive(void)
817dd7cddfSDavid du Colombier {
829a747e4fSDavid du Colombier 	if(serialoq)
839a747e4fSDavid du Colombier 		return qlen(serialoq) > 0;
847dd7cddfSDavid du Colombier 	return 0;
857dd7cddfSDavid du Colombier }
867dd7cddfSDavid du Colombier 
877dd7cddfSDavid du Colombier void
prflush(void)887dd7cddfSDavid du Colombier prflush(void)
897dd7cddfSDavid du Colombier {
9080ee5cbfSDavid du Colombier 	ulong now;
9180ee5cbfSDavid du Colombier 
9280ee5cbfSDavid du Colombier 	now = m->ticks;
937dd7cddfSDavid du Colombier 	while(consactive())
9480ee5cbfSDavid du Colombier 		if(m->ticks - now >= HZ)
9580ee5cbfSDavid du Colombier 			break;
963e12c5d1SDavid du Colombier }
973e12c5d1SDavid du Colombier 
98fe853e23SDavid du Colombier /*
99fe853e23SDavid du Colombier  * Log console output so it can be retrieved via /dev/kmesg.
100fe853e23SDavid du Colombier  * This is good for catching boot-time messages after the fact.
101fe853e23SDavid du Colombier  */
102f6eb8b35SDavid du Colombier struct {
103f6eb8b35SDavid du Colombier 	Lock lk;
10485878a71SDavid du Colombier 	char buf[KMESGSIZE];
105f6eb8b35SDavid du Colombier 	uint n;
106f6eb8b35SDavid du Colombier } kmesg;
107f6eb8b35SDavid du Colombier 
108f6eb8b35SDavid du Colombier static void
kmesgputs(char * str,int n)109f6eb8b35SDavid du Colombier kmesgputs(char *str, int n)
110f6eb8b35SDavid du Colombier {
111f6eb8b35SDavid du Colombier 	uint nn, d;
112f6eb8b35SDavid du Colombier 
113f6eb8b35SDavid du Colombier 	ilock(&kmesg.lk);
114f6eb8b35SDavid du Colombier 	/* take the tail of huge writes */
115f6eb8b35SDavid du Colombier 	if(n > sizeof kmesg.buf){
116f6eb8b35SDavid du Colombier 		d = n - sizeof kmesg.buf;
117f6eb8b35SDavid du Colombier 		str += d;
118f6eb8b35SDavid du Colombier 		n -= d;
119f6eb8b35SDavid du Colombier 	}
120f6eb8b35SDavid du Colombier 
121f6eb8b35SDavid du Colombier 	/* slide the buffer down to make room */
122f6eb8b35SDavid du Colombier 	nn = kmesg.n;
123f6eb8b35SDavid du Colombier 	if(nn + n >= sizeof kmesg.buf){
124f6eb8b35SDavid du Colombier 		d = nn + n - sizeof kmesg.buf;
125f6eb8b35SDavid du Colombier 		if(d)
126f6eb8b35SDavid du Colombier 			memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
127f6eb8b35SDavid du Colombier 		nn -= d;
128f6eb8b35SDavid du Colombier 	}
129f6eb8b35SDavid du Colombier 
130f6eb8b35SDavid du Colombier 	/* copy the data in */
131f6eb8b35SDavid du Colombier 	memmove(kmesg.buf+nn, str, n);
132f6eb8b35SDavid du Colombier 	nn += n;
133f6eb8b35SDavid du Colombier 	kmesg.n = nn;
134f6eb8b35SDavid du Colombier 	iunlock(&kmesg.lk);
135f6eb8b35SDavid du Colombier }
136f6eb8b35SDavid du Colombier 
1373e12c5d1SDavid du Colombier /*
1383e12c5d1SDavid du Colombier  *   Print a string on the console.  Convert \n to \r\n for serial
1393e12c5d1SDavid du Colombier  *   line consoles.  Locking of the queues is left up to the screen
1403e12c5d1SDavid du Colombier  *   or uart code.  Multi-line messages to serial consoles may get
1413e12c5d1SDavid du Colombier  *   interspersed with other messages.
1423e12c5d1SDavid du Colombier  */
1437dd7cddfSDavid du Colombier static void
putstrn0(char * str,int n,int usewrite)1447dd7cddfSDavid du Colombier putstrn0(char *str, int n, int usewrite)
1453e12c5d1SDavid du Colombier {
1463e12c5d1SDavid du Colombier 	int m;
1473e12c5d1SDavid du Colombier 	char *t;
1483e12c5d1SDavid du Colombier 
14988110b43SDavid du Colombier 	if(!islo())
15088110b43SDavid du Colombier 		usewrite = 0;
15188110b43SDavid du Colombier 
1523e12c5d1SDavid du Colombier 	/*
153f6eb8b35SDavid du Colombier 	 *  how many different output devices do we need?
154f6eb8b35SDavid du Colombier 	 */
155f6eb8b35SDavid du Colombier 	kmesgputs(str, n);
156f6eb8b35SDavid du Colombier 
157f6eb8b35SDavid du Colombier 	/*
1589a747e4fSDavid du Colombier 	 *  if someone is reading /dev/kprint,
1599a747e4fSDavid du Colombier 	 *  put the message there.
1609a747e4fSDavid du Colombier 	 *  if not and there's an attached bit mapped display,
1619a747e4fSDavid du Colombier 	 *  put the message there.
1629a747e4fSDavid du Colombier 	 *
1633e12c5d1SDavid du Colombier 	 *  if there's a serial line being used as a console,
1647dd7cddfSDavid du Colombier 	 *  put the message there.
1653e12c5d1SDavid du Colombier 	 */
1669a747e4fSDavid du Colombier 	if(kprintoq != nil && !qisclosed(kprintoq)){
1679a747e4fSDavid du Colombier 		if(usewrite)
1689a747e4fSDavid du Colombier 			qwrite(kprintoq, str, n);
1699a747e4fSDavid du Colombier 		else
1709a747e4fSDavid du Colombier 			qiwrite(kprintoq, str, n);
1719a747e4fSDavid du Colombier 	}else if(screenputs != nil)
1729a747e4fSDavid du Colombier 		screenputs(str, n);
1739a747e4fSDavid du Colombier 
1749a747e4fSDavid du Colombier 	if(serialoq == nil){
1759a747e4fSDavid du Colombier 		uartputs(str, n);
1763e12c5d1SDavid du Colombier 		return;
1779a747e4fSDavid du Colombier 	}
178219b2ee8SDavid du Colombier 
1793e12c5d1SDavid du Colombier 	while(n > 0) {
1803e12c5d1SDavid du Colombier 		t = memchr(str, '\n', n);
18180ee5cbfSDavid du Colombier 		if(t && !kbd.raw) {
1823e12c5d1SDavid du Colombier 			m = t-str;
18380ee5cbfSDavid du Colombier 			if(usewrite){
1849a747e4fSDavid du Colombier 				qwrite(serialoq, str, m);
1859a747e4fSDavid du Colombier 				qwrite(serialoq, "\r\n", 2);
18680ee5cbfSDavid du Colombier 			} else {
1879a747e4fSDavid du Colombier 				qiwrite(serialoq, str, m);
1889a747e4fSDavid du Colombier 				qiwrite(serialoq, "\r\n", 2);
18980ee5cbfSDavid du Colombier 			}
1903e12c5d1SDavid du Colombier 			n -= m+1;
19180ee5cbfSDavid du Colombier 			str = t+1;
1923e12c5d1SDavid du Colombier 		} else {
1937dd7cddfSDavid du Colombier 			if(usewrite)
1949a747e4fSDavid du Colombier 				qwrite(serialoq, str, n);
1957dd7cddfSDavid du Colombier 			else
1969a747e4fSDavid du Colombier 				qiwrite(serialoq, str, n);
1973e12c5d1SDavid du Colombier 			break;
1983e12c5d1SDavid du Colombier 		}
1993e12c5d1SDavid du Colombier 	}
2003e12c5d1SDavid du Colombier }
2013e12c5d1SDavid du Colombier 
2023e12c5d1SDavid du Colombier void
putstrn(char * str,int n)2037dd7cddfSDavid du Colombier putstrn(char *str, int n)
2043e12c5d1SDavid du Colombier {
2057dd7cddfSDavid du Colombier 	putstrn0(str, n, 0);
2063e12c5d1SDavid du Colombier }
2073e12c5d1SDavid du Colombier 
2087dd7cddfSDavid du Colombier int noprint;
2097dd7cddfSDavid du Colombier 
2107dd7cddfSDavid du Colombier int
print(char * fmt,...)2117dd7cddfSDavid du Colombier print(char *fmt, ...)
2127dd7cddfSDavid du Colombier {
2137dd7cddfSDavid du Colombier 	int n;
2147dd7cddfSDavid du Colombier 	va_list arg;
2157dd7cddfSDavid du Colombier 	char buf[PRINTSIZE];
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier 	if(noprint)
2187dd7cddfSDavid du Colombier 		return -1;
2197dd7cddfSDavid du Colombier 
2207dd7cddfSDavid du Colombier 	va_start(arg, fmt);
2219a747e4fSDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
2227dd7cddfSDavid du Colombier 	va_end(arg);
2237dd7cddfSDavid du Colombier 	putstrn(buf, n);
2247dd7cddfSDavid du Colombier 
2257dd7cddfSDavid du Colombier 	return n;
2267dd7cddfSDavid du Colombier }
2277dd7cddfSDavid du Colombier 
228ea15f0ccSDavid du Colombier /*
229ea15f0ccSDavid du Colombier  * Want to interlock iprints to avoid interlaced output on
230ea15f0ccSDavid du Colombier  * multiprocessor, but don't want to deadlock if one processor
231ea15f0ccSDavid du Colombier  * dies during print and another has something important to say.
232ea15f0ccSDavid du Colombier  * Make a good faith effort.
233ea15f0ccSDavid du Colombier  */
234ea15f0ccSDavid du Colombier static Lock iprintlock;
235ea15f0ccSDavid du Colombier static int
iprintcanlock(Lock * l)236ea15f0ccSDavid du Colombier iprintcanlock(Lock *l)
237ea15f0ccSDavid du Colombier {
238ea15f0ccSDavid du Colombier 	int i;
239ea15f0ccSDavid du Colombier 
240ea15f0ccSDavid du Colombier 	for(i=0; i<1000; i++){
241ea15f0ccSDavid du Colombier 		if(canlock(l))
242ea15f0ccSDavid du Colombier 			return 1;
243ea15f0ccSDavid du Colombier 		if(l->m == MACHP(m->machno))
244ea15f0ccSDavid du Colombier 			return 0;
245ea15f0ccSDavid du Colombier 		microdelay(100);
246ea15f0ccSDavid du Colombier 	}
247ea15f0ccSDavid du Colombier 	return 0;
248ea15f0ccSDavid du Colombier }
249ea15f0ccSDavid du Colombier 
2507dd7cddfSDavid du Colombier int
iprint(char * fmt,...)2517dd7cddfSDavid du Colombier iprint(char *fmt, ...)
2527dd7cddfSDavid du Colombier {
253ea15f0ccSDavid du Colombier 	int n, s, locked;
2547dd7cddfSDavid du Colombier 	va_list arg;
2557dd7cddfSDavid du Colombier 	char buf[PRINTSIZE];
2567dd7cddfSDavid du Colombier 
2577dd7cddfSDavid du Colombier 	s = splhi();
2587dd7cddfSDavid du Colombier 	va_start(arg, fmt);
2599a747e4fSDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
2607dd7cddfSDavid du Colombier 	va_end(arg);
261ea15f0ccSDavid du Colombier 	locked = iprintcanlock(&iprintlock);
2629a747e4fSDavid du Colombier 	if(screenputs != nil && iprintscreenputs)
2639a747e4fSDavid du Colombier 		screenputs(buf, n);
2649a747e4fSDavid du Colombier 	uartputs(buf, n);
265ea15f0ccSDavid du Colombier 	if(locked)
266ea15f0ccSDavid du Colombier 		unlock(&iprintlock);
2677dd7cddfSDavid du Colombier 	splx(s);
2687dd7cddfSDavid du Colombier 
2693e12c5d1SDavid du Colombier 	return n;
2703e12c5d1SDavid du Colombier }
2713e12c5d1SDavid du Colombier 
2723e12c5d1SDavid du Colombier void
panic(char * fmt,...)2733e12c5d1SDavid du Colombier panic(char *fmt, ...)
2743e12c5d1SDavid du Colombier {
2755979f962SDavid du Colombier 	int n, s;
2767dd7cddfSDavid du Colombier 	va_list arg;
2777dd7cddfSDavid du Colombier 	char buf[PRINTSIZE];
2789a747e4fSDavid du Colombier 
2799a747e4fSDavid du Colombier 	kprintoq = nil;	/* don't try to write to /dev/kprint */
2809a747e4fSDavid du Colombier 
2819a747e4fSDavid du Colombier 	if(panicking)
2829a747e4fSDavid du Colombier 		for(;;);
2839a747e4fSDavid du Colombier 	panicking = 1;
2843e12c5d1SDavid du Colombier 
2855979f962SDavid du Colombier 	s = splhi();
2863e12c5d1SDavid du Colombier 	strcpy(buf, "panic: ");
2877dd7cddfSDavid du Colombier 	va_start(arg, fmt);
2889a747e4fSDavid du Colombier 	n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
2897dd7cddfSDavid du Colombier 	va_end(arg);
2900b9a5132SDavid du Colombier 	iprint("%s\n", buf);
2917dd7cddfSDavid du Colombier 	if(consdebug)
2929a747e4fSDavid du Colombier 		(*consdebug)();
2935979f962SDavid du Colombier 	splx(s);
2947dd7cddfSDavid du Colombier 	prflush();
2950b9a5132SDavid du Colombier 	buf[n] = '\n';
29680ee5cbfSDavid du Colombier 	putstrn(buf, n+1);
2973e12c5d1SDavid du Colombier 	dumpstack();
2987dd7cddfSDavid du Colombier 
2993e12c5d1SDavid du Colombier 	exit(1);
3003e12c5d1SDavid du Colombier }
3017dd7cddfSDavid du Colombier 
302ea58ad6fSDavid du Colombier /* libmp at least contains a few calls to sysfatal; simulate with panic */
303ea58ad6fSDavid du Colombier void
sysfatal(char * fmt,...)304ea58ad6fSDavid du Colombier sysfatal(char *fmt, ...)
305ea58ad6fSDavid du Colombier {
306ea58ad6fSDavid du Colombier 	char err[256];
307ea58ad6fSDavid du Colombier 	va_list arg;
308ea58ad6fSDavid du Colombier 
309ea58ad6fSDavid du Colombier 	va_start(arg, fmt);
310ea58ad6fSDavid du Colombier 	vseprint(err, err + sizeof err, fmt, arg);
311ea58ad6fSDavid du Colombier 	va_end(arg);
312ea58ad6fSDavid du Colombier 	panic("sysfatal: %s", err);
313ea58ad6fSDavid du Colombier }
314ea58ad6fSDavid du Colombier 
3157dd7cddfSDavid du Colombier void
_assert(char * fmt)3167dd7cddfSDavid du Colombier _assert(char *fmt)
3177dd7cddfSDavid du Colombier {
318567483c8SDavid du Colombier 	panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
3197dd7cddfSDavid du Colombier }
3207dd7cddfSDavid du Colombier 
3213e12c5d1SDavid du Colombier int
pprint(char * fmt,...)3223e12c5d1SDavid du Colombier pprint(char *fmt, ...)
3233e12c5d1SDavid du Colombier {
3243e12c5d1SDavid du Colombier 	int n;
3257dd7cddfSDavid du Colombier 	Chan *c;
3267dd7cddfSDavid du Colombier 	va_list arg;
3277dd7cddfSDavid du Colombier 	char buf[2*PRINTSIZE];
3283e12c5d1SDavid du Colombier 
3297dd7cddfSDavid du Colombier 	if(up == nil || up->fgrp == nil)
3303e12c5d1SDavid du Colombier 		return 0;
3313e12c5d1SDavid du Colombier 
3327dd7cddfSDavid du Colombier 	c = up->fgrp->fd[2];
3333e12c5d1SDavid du Colombier 	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
3343e12c5d1SDavid du Colombier 		return 0;
335208510e1SDavid du Colombier 	n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
3367dd7cddfSDavid du Colombier 	va_start(arg, fmt);
3379a747e4fSDavid du Colombier 	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
3387dd7cddfSDavid du Colombier 	va_end(arg);
3393e12c5d1SDavid du Colombier 
340219b2ee8SDavid du Colombier 	if(waserror())
341219b2ee8SDavid du Colombier 		return 0;
3427dd7cddfSDavid du Colombier 	devtab[c->type]->write(c, buf, n, c->offset);
343219b2ee8SDavid du Colombier 	poperror();
3443e12c5d1SDavid du Colombier 
3453e12c5d1SDavid du Colombier 	lock(c);
3463e12c5d1SDavid du Colombier 	c->offset += n;
3473e12c5d1SDavid du Colombier 	unlock(c);
3483e12c5d1SDavid du Colombier 
3493e12c5d1SDavid du Colombier 	return n;
3503e12c5d1SDavid du Colombier }
3513e12c5d1SDavid du Colombier 
35280ee5cbfSDavid du Colombier static void
echoscreen(char * buf,int n)35380ee5cbfSDavid du Colombier echoscreen(char *buf, int n)
35480ee5cbfSDavid du Colombier {
35580ee5cbfSDavid du Colombier 	char *e, *p;
35680ee5cbfSDavid du Colombier 	char ebuf[128];
35780ee5cbfSDavid du Colombier 	int x;
35880ee5cbfSDavid du Colombier 
35980ee5cbfSDavid du Colombier 	p = ebuf;
36080ee5cbfSDavid du Colombier 	e = ebuf + sizeof(ebuf) - 4;
36180ee5cbfSDavid du Colombier 	while(n-- > 0){
36280ee5cbfSDavid du Colombier 		if(p >= e){
36380ee5cbfSDavid du Colombier 			screenputs(ebuf, p - ebuf);
36480ee5cbfSDavid du Colombier 			p = ebuf;
36580ee5cbfSDavid du Colombier 		}
36680ee5cbfSDavid du Colombier 		x = *buf++;
36780ee5cbfSDavid du Colombier 		if(x == 0x15){
36880ee5cbfSDavid du Colombier 			*p++ = '^';
36980ee5cbfSDavid du Colombier 			*p++ = 'U';
37080ee5cbfSDavid du Colombier 			*p++ = '\n';
37180ee5cbfSDavid du Colombier 		} else
37280ee5cbfSDavid du Colombier 			*p++ = x;
37380ee5cbfSDavid du Colombier 	}
37480ee5cbfSDavid du Colombier 	if(p != ebuf)
37580ee5cbfSDavid du Colombier 		screenputs(ebuf, p - ebuf);
37680ee5cbfSDavid du Colombier }
37780ee5cbfSDavid du Colombier 
37880ee5cbfSDavid du Colombier static void
echoserialoq(char * buf,int n)3799a747e4fSDavid du Colombier echoserialoq(char *buf, int n)
38080ee5cbfSDavid du Colombier {
38180ee5cbfSDavid du Colombier 	char *e, *p;
38280ee5cbfSDavid du Colombier 	char ebuf[128];
38380ee5cbfSDavid du Colombier 	int x;
38480ee5cbfSDavid du Colombier 
38580ee5cbfSDavid du Colombier 	p = ebuf;
38680ee5cbfSDavid du Colombier 	e = ebuf + sizeof(ebuf) - 4;
38780ee5cbfSDavid du Colombier 	while(n-- > 0){
38880ee5cbfSDavid du Colombier 		if(p >= e){
3899a747e4fSDavid du Colombier 			qiwrite(serialoq, ebuf, p - ebuf);
39080ee5cbfSDavid du Colombier 			p = ebuf;
39180ee5cbfSDavid du Colombier 		}
39280ee5cbfSDavid du Colombier 		x = *buf++;
39380ee5cbfSDavid du Colombier 		if(x == '\n'){
39480ee5cbfSDavid du Colombier 			*p++ = '\r';
39580ee5cbfSDavid du Colombier 			*p++ = '\n';
39680ee5cbfSDavid du Colombier 		} else if(x == 0x15){
39780ee5cbfSDavid du Colombier 			*p++ = '^';
39880ee5cbfSDavid du Colombier 			*p++ = 'U';
39980ee5cbfSDavid du Colombier 			*p++ = '\n';
40080ee5cbfSDavid du Colombier 		} else
40180ee5cbfSDavid du Colombier 			*p++ = x;
40280ee5cbfSDavid du Colombier 	}
40380ee5cbfSDavid du Colombier 	if(p != ebuf)
4049a747e4fSDavid du Colombier 		qiwrite(serialoq, ebuf, p - ebuf);
40580ee5cbfSDavid du Colombier }
40680ee5cbfSDavid du Colombier 
407ec46fab0SDavid du Colombier static void
echo(char * buf,int n)40880ee5cbfSDavid du Colombier echo(char *buf, int n)
4093e12c5d1SDavid du Colombier {
4107dd7cddfSDavid du Colombier 	static int ctrlt, pid;
4117dd7cddfSDavid du Colombier 	int x;
41280ee5cbfSDavid du Colombier 	char *e, *p;
4133e12c5d1SDavid du Colombier 
414ec46fab0SDavid du Colombier 	if(n == 0)
415ec46fab0SDavid du Colombier 		return;
416ec46fab0SDavid du Colombier 
41780ee5cbfSDavid du Colombier 	e = buf+n;
41880ee5cbfSDavid du Colombier 	for(p = buf; p < e; p++){
41980ee5cbfSDavid du Colombier 		switch(*p){
42080ee5cbfSDavid du Colombier 		case 0x10:	/* ^P */
42180ee5cbfSDavid du Colombier 			if(cpuserver && !kbd.ctlpoff){
4227dd7cddfSDavid du Colombier 				active.exiting = 1;
42380ee5cbfSDavid du Colombier 				return;
42480ee5cbfSDavid du Colombier 			}
42580ee5cbfSDavid du Colombier 			break;
42680ee5cbfSDavid du Colombier 		case 0x14:	/* ^T */
42780ee5cbfSDavid du Colombier 			ctrlt++;
42880ee5cbfSDavid du Colombier 			if(ctrlt > 2)
42980ee5cbfSDavid du Colombier 				ctrlt = 2;
43080ee5cbfSDavid du Colombier 			continue;
4317dd7cddfSDavid du Colombier 		}
4323e12c5d1SDavid du Colombier 
43380ee5cbfSDavid du Colombier 		if(ctrlt != 2)
43480ee5cbfSDavid du Colombier 			continue;
43580ee5cbfSDavid du Colombier 
43680ee5cbfSDavid du Colombier 		/* ^T escapes */
4373e12c5d1SDavid du Colombier 		ctrlt = 0;
43880ee5cbfSDavid du Colombier 		switch(*p){
4399a747e4fSDavid du Colombier 		case 'S':
4409a747e4fSDavid du Colombier 			x = splhi();
4419a747e4fSDavid du Colombier 			dumpstack();
4429a747e4fSDavid du Colombier 			procdump();
4439a747e4fSDavid du Colombier 			splx(x);
4449a747e4fSDavid du Colombier 			return;
4457dd7cddfSDavid du Colombier 		case 's':
4467dd7cddfSDavid du Colombier 			dumpstack();
4479a747e4fSDavid du Colombier 			return;
4483e12c5d1SDavid du Colombier 		case 'x':
4493e12c5d1SDavid du Colombier 			xsummary();
4507dd7cddfSDavid du Colombier 			ixsummary();
4517dd7cddfSDavid du Colombier 			mallocsummary();
45288110b43SDavid du Colombier 		//	memorysummary();
4537dd7cddfSDavid du Colombier 			pagersummary();
4549a747e4fSDavid du Colombier 			return;
4553e12c5d1SDavid du Colombier 		case 'd':
4567dd7cddfSDavid du Colombier 			if(consdebug == nil)
4577dd7cddfSDavid du Colombier 				consdebug = rdb;
4587dd7cddfSDavid du Colombier 			else
4597dd7cddfSDavid du Colombier 				consdebug = nil;
460567483c8SDavid du Colombier 			print("consdebug now %#p\n", consdebug);
4617dd7cddfSDavid du Colombier 			return;
4627dd7cddfSDavid du Colombier 		case 'D':
4637dd7cddfSDavid du Colombier 			if(consdebug == nil)
4647dd7cddfSDavid du Colombier 				consdebug = rdb;
4653e12c5d1SDavid du Colombier 			consdebug();
4663e12c5d1SDavid du Colombier 			return;
4673e12c5d1SDavid du Colombier 		case 'p':
4687dd7cddfSDavid du Colombier 			x = spllo();
4693e12c5d1SDavid du Colombier 			procdump();
4707dd7cddfSDavid du Colombier 			splx(x);
4713e12c5d1SDavid du Colombier 			return;
4727dd7cddfSDavid du Colombier 		case 'q':
4737dd7cddfSDavid du Colombier 			scheddump();
4749a747e4fSDavid du Colombier 			return;
4757dd7cddfSDavid du Colombier 		case 'k':
476cd42b314SDavid du Colombier 			killbig("^t ^t k");
4779a747e4fSDavid du Colombier 			return;
4783e12c5d1SDavid du Colombier 		case 'r':
4793e12c5d1SDavid du Colombier 			exit(0);
4809a747e4fSDavid du Colombier 			return;
4813e12c5d1SDavid du Colombier 		}
4827dd7cddfSDavid du Colombier 	}
48380ee5cbfSDavid du Colombier 
48480ee5cbfSDavid du Colombier 	qproduce(kbdq, buf, n);
4857dd7cddfSDavid du Colombier 	if(kbd.raw)
4863e12c5d1SDavid du Colombier 		return;
487f6eb8b35SDavid du Colombier 	kmesgputs(buf, n);
4889a747e4fSDavid du Colombier 	if(screenputs != nil)
48980ee5cbfSDavid du Colombier 		echoscreen(buf, n);
4909a747e4fSDavid du Colombier 	if(serialoq)
4919a747e4fSDavid du Colombier 		echoserialoq(buf, n);
4923e12c5d1SDavid du Colombier }
4933e12c5d1SDavid du Colombier 
4943e12c5d1SDavid du Colombier /*
4957dd7cddfSDavid du Colombier  *  Called by a uart interrupt for console input.
4967dd7cddfSDavid du Colombier  *
4977dd7cddfSDavid du Colombier  *  turn '\r' into '\n' before putting it into the queue.
4983e12c5d1SDavid du Colombier  */
4993e12c5d1SDavid du Colombier int
kbdcr2nl(Queue *,int ch)50080ee5cbfSDavid du Colombier kbdcr2nl(Queue*, int ch)
5013e12c5d1SDavid du Colombier {
50280ee5cbfSDavid du Colombier 	char *next;
50380ee5cbfSDavid du Colombier 
50480ee5cbfSDavid du Colombier 	ilock(&kbd.lockputc);		/* just a mutex */
50580ee5cbfSDavid du Colombier 	if(ch == '\r' && !kbd.raw)
5063e12c5d1SDavid du Colombier 		ch = '\n';
50780ee5cbfSDavid du Colombier 	next = kbd.iw+1;
50880ee5cbfSDavid du Colombier 	if(next >= kbd.ie)
50980ee5cbfSDavid du Colombier 		next = kbd.istage;
51080ee5cbfSDavid du Colombier 	if(next != kbd.ir){
51180ee5cbfSDavid du Colombier 		*kbd.iw = ch;
51280ee5cbfSDavid du Colombier 		kbd.iw = next;
51380ee5cbfSDavid du Colombier 	}
51480ee5cbfSDavid du Colombier 	iunlock(&kbd.lockputc);
51580ee5cbfSDavid du Colombier 	return 0;
5163e12c5d1SDavid du Colombier }
5173e12c5d1SDavid du Colombier 
5183e12c5d1SDavid du Colombier /*
5193e12c5d1SDavid du Colombier  *  Put character, possibly a rune, into read queue at interrupt time.
5207dd7cddfSDavid du Colombier  *  Called at interrupt time to process a character.
5213e12c5d1SDavid du Colombier  */
5223e12c5d1SDavid du Colombier int
kbdputc(Queue *,int ch)5237dd7cddfSDavid du Colombier kbdputc(Queue*, int ch)
5243e12c5d1SDavid du Colombier {
52580ee5cbfSDavid du Colombier 	int i, n;
5263e12c5d1SDavid du Colombier 	char buf[3];
5273e12c5d1SDavid du Colombier 	Rune r;
52880ee5cbfSDavid du Colombier 	char *next;
5293e12c5d1SDavid du Colombier 
5309a747e4fSDavid du Colombier 	if(kbd.ir == nil)
5319a747e4fSDavid du Colombier 		return 0;		/* in case we're not inited yet */
5329a747e4fSDavid du Colombier 
53380ee5cbfSDavid du Colombier 	ilock(&kbd.lockputc);		/* just a mutex */
5343e12c5d1SDavid du Colombier 	r = ch;
5353e12c5d1SDavid du Colombier 	n = runetochar(buf, &r);
53680ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++){
53780ee5cbfSDavid du Colombier 		next = kbd.iw+1;
53880ee5cbfSDavid du Colombier 		if(next >= kbd.ie)
53980ee5cbfSDavid du Colombier 			next = kbd.istage;
54080ee5cbfSDavid du Colombier 		if(next == kbd.ir)
54180ee5cbfSDavid du Colombier 			break;
54280ee5cbfSDavid du Colombier 		*kbd.iw = buf[i];
54380ee5cbfSDavid du Colombier 		kbd.iw = next;
54480ee5cbfSDavid du Colombier 	}
54580ee5cbfSDavid du Colombier 	iunlock(&kbd.lockputc);
5463e12c5d1SDavid du Colombier 	return 0;
5473e12c5d1SDavid du Colombier }
5483e12c5d1SDavid du Colombier 
54980ee5cbfSDavid du Colombier /*
55080ee5cbfSDavid du Colombier  *  we save up input characters till clock time to reduce
55180ee5cbfSDavid du Colombier  *  per character interrupt overhead.
55280ee5cbfSDavid du Colombier  */
55380ee5cbfSDavid du Colombier static void
kbdputcclock(void)55480ee5cbfSDavid du Colombier kbdputcclock(void)
5553e12c5d1SDavid du Colombier {
55680ee5cbfSDavid du Colombier 	char *iw;
557f6eb8b35SDavid du Colombier 
55880ee5cbfSDavid du Colombier 	/* this amortizes cost of qproduce */
55980ee5cbfSDavid du Colombier 	if(kbd.iw != kbd.ir){
56080ee5cbfSDavid du Colombier 		iw = kbd.iw;
56180ee5cbfSDavid du Colombier 		if(iw < kbd.ir){
56280ee5cbfSDavid du Colombier 			echo(kbd.ir, kbd.ie-kbd.ir);
56380ee5cbfSDavid du Colombier 			kbd.ir = kbd.istage;
56480ee5cbfSDavid du Colombier 		}
565ec46fab0SDavid du Colombier 		if(kbd.ir != iw){
56680ee5cbfSDavid du Colombier 			echo(kbd.ir, iw-kbd.ir);
56780ee5cbfSDavid du Colombier 			kbd.ir = iw;
56880ee5cbfSDavid du Colombier 		}
5693e12c5d1SDavid du Colombier 	}
570ec46fab0SDavid du Colombier }
5713e12c5d1SDavid du Colombier 
5723e12c5d1SDavid du Colombier enum{
5733e12c5d1SDavid du Colombier 	Qdir,
5747dd7cddfSDavid du Colombier 	Qbintime,
5753e12c5d1SDavid du Colombier 	Qcons,
5763e12c5d1SDavid du Colombier 	Qconsctl,
5773e12c5d1SDavid du Colombier 	Qcputime,
5787dd7cddfSDavid du Colombier 	Qdrivers,
579f6eb8b35SDavid du Colombier 	Qkmesg,
5809a747e4fSDavid du Colombier 	Qkprint,
581219b2ee8SDavid du Colombier 	Qhostdomain,
582219b2ee8SDavid du Colombier 	Qhostowner,
5833e12c5d1SDavid du Colombier 	Qnull,
5849a747e4fSDavid du Colombier 	Qosversion,
5853e12c5d1SDavid du Colombier 	Qpgrpid,
5863e12c5d1SDavid du Colombier 	Qpid,
5873e12c5d1SDavid du Colombier 	Qppid,
5887dd7cddfSDavid du Colombier 	Qrandom,
5897dd7cddfSDavid du Colombier 	Qreboot,
5903e12c5d1SDavid du Colombier 	Qswap,
5913e12c5d1SDavid du Colombier 	Qsysname,
5923e12c5d1SDavid du Colombier 	Qsysstat,
5933e12c5d1SDavid du Colombier 	Qtime,
5943e12c5d1SDavid du Colombier 	Quser,
5957dd7cddfSDavid du Colombier 	Qzero,
596add6b5c5SDavid du Colombier 	Qconfig,
5973e12c5d1SDavid du Colombier };
5983e12c5d1SDavid du Colombier 
5997dd7cddfSDavid du Colombier enum
6007dd7cddfSDavid du Colombier {
6017dd7cddfSDavid du Colombier 	VLNUMSIZE=	22,
6027dd7cddfSDavid du Colombier };
6037dd7cddfSDavid du Colombier 
6047dd7cddfSDavid du Colombier static Dirtab consdir[]={
6059a747e4fSDavid du Colombier 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
6067dd7cddfSDavid du Colombier 	"bintime",	{Qbintime},	24,		0664,
6073e12c5d1SDavid du Colombier 	"cons",		{Qcons},	0,		0660,
6083e12c5d1SDavid du Colombier 	"consctl",	{Qconsctl},	0,		0220,
6093e12c5d1SDavid du Colombier 	"cputime",	{Qcputime},	6*NUMSIZE,	0444,
6109a747e4fSDavid du Colombier 	"drivers",	{Qdrivers},	0,		0444,
611219b2ee8SDavid du Colombier 	"hostdomain",	{Qhostdomain},	DOMLEN,		0664,
6129a747e4fSDavid du Colombier 	"hostowner",	{Qhostowner},	0,		0664,
613f6eb8b35SDavid du Colombier 	"kmesg",	{Qkmesg},	0,		0440,
6149a747e4fSDavid du Colombier 	"kprint",	{Qkprint, 0, QTEXCL},	0,	DMEXCL|0440,
6153e12c5d1SDavid du Colombier 	"null",		{Qnull},	0,		0666,
6169a747e4fSDavid du Colombier 	"osversion",	{Qosversion},	0,		0444,
6173e12c5d1SDavid du Colombier 	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444,
6183e12c5d1SDavid du Colombier 	"pid",		{Qpid},		NUMSIZE,	0444,
6193e12c5d1SDavid du Colombier 	"ppid",		{Qppid},	NUMSIZE,	0444,
6209a747e4fSDavid du Colombier 	"random",	{Qrandom},	0,		0444,
621*a826b788SDavid du Colombier 	"reboot",	{Qreboot},	0,		0660,
6223e12c5d1SDavid du Colombier 	"swap",		{Qswap},	0,		0664,
6233e12c5d1SDavid du Colombier 	"sysname",	{Qsysname},	0,		0664,
6243e12c5d1SDavid du Colombier 	"sysstat",	{Qsysstat},	0,		0666,
6257dd7cddfSDavid du Colombier 	"time",		{Qtime},	NUMSIZE+3*VLNUMSIZE,	0664,
6269a747e4fSDavid du Colombier 	"user",		{Quser},	0,		0666,
6277dd7cddfSDavid du Colombier 	"zero",		{Qzero},	0,		0444,
628add6b5c5SDavid du Colombier 	"config",	{Qconfig},	0,		0444,
6293e12c5d1SDavid du Colombier };
6303e12c5d1SDavid du Colombier 
6313e12c5d1SDavid du Colombier int
readnum(ulong off,char * buf,ulong n,ulong val,int size)6323e12c5d1SDavid du Colombier readnum(ulong off, char *buf, ulong n, ulong val, int size)
6333e12c5d1SDavid du Colombier {
6343e12c5d1SDavid du Colombier 	char tmp[64];
6353e12c5d1SDavid du Colombier 
636567483c8SDavid du Colombier 	snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
6373e12c5d1SDavid du Colombier 	tmp[size-1] = ' ';
6383e12c5d1SDavid du Colombier 	if(off >= size)
6393e12c5d1SDavid du Colombier 		return 0;
6403e12c5d1SDavid du Colombier 	if(off+n > size)
6413e12c5d1SDavid du Colombier 		n = size-off;
6423e12c5d1SDavid du Colombier 	memmove(buf, tmp+off, n);
6433e12c5d1SDavid du Colombier 	return n;
6443e12c5d1SDavid du Colombier }
6453e12c5d1SDavid du Colombier 
6463e12c5d1SDavid du Colombier int
readstr(ulong off,char * buf,ulong n,char * str)6473e12c5d1SDavid du Colombier readstr(ulong off, char *buf, ulong n, char *str)
6483e12c5d1SDavid du Colombier {
6493e12c5d1SDavid du Colombier 	int size;
6503e12c5d1SDavid du Colombier 
6513e12c5d1SDavid du Colombier 	size = strlen(str);
6523e12c5d1SDavid du Colombier 	if(off >= size)
6533e12c5d1SDavid du Colombier 		return 0;
6543e12c5d1SDavid du Colombier 	if(off+n > size)
6553e12c5d1SDavid du Colombier 		n = size-off;
6563e12c5d1SDavid du Colombier 	memmove(buf, str+off, n);
6573e12c5d1SDavid du Colombier 	return n;
6583e12c5d1SDavid du Colombier }
6593e12c5d1SDavid du Colombier 
6607dd7cddfSDavid du Colombier static void
consinit(void)6613e12c5d1SDavid du Colombier consinit(void)
6623e12c5d1SDavid du Colombier {
6637dd7cddfSDavid du Colombier 	todinit();
6647dd7cddfSDavid du Colombier 	randominit();
665d9306527SDavid du Colombier 	/*
666d9306527SDavid du Colombier 	 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
667d9306527SDavid du Colombier 	 * processing it every 22 ms should be fine
668d9306527SDavid du Colombier 	 */
669d9306527SDavid du Colombier 	addclock0link(kbdputcclock, 22);
6703e12c5d1SDavid du Colombier }
6713e12c5d1SDavid du Colombier 
6727dd7cddfSDavid du Colombier static Chan*
consattach(char * spec)6733e12c5d1SDavid du Colombier consattach(char *spec)
6743e12c5d1SDavid du Colombier {
6753e12c5d1SDavid du Colombier 	return devattach('c', spec);
6763e12c5d1SDavid du Colombier }
6773e12c5d1SDavid du Colombier 
6789a747e4fSDavid du Colombier static Walkqid*
conswalk(Chan * c,Chan * nc,char ** name,int nname)6799a747e4fSDavid du Colombier conswalk(Chan *c, Chan *nc, char **name, int nname)
6803e12c5d1SDavid du Colombier {
6819a747e4fSDavid du Colombier 	return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
6823e12c5d1SDavid du Colombier }
6833e12c5d1SDavid du Colombier 
6849a747e4fSDavid du Colombier static int
consstat(Chan * c,uchar * dp,int n)6859a747e4fSDavid du Colombier consstat(Chan *c, uchar *dp, int n)
6863e12c5d1SDavid du Colombier {
6879a747e4fSDavid du Colombier 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
6883e12c5d1SDavid du Colombier }
6893e12c5d1SDavid du Colombier 
6907dd7cddfSDavid du Colombier static Chan*
consopen(Chan * c,int omode)6913e12c5d1SDavid du Colombier consopen(Chan *c, int omode)
6923e12c5d1SDavid du Colombier {
6939a747e4fSDavid du Colombier 	c->aux = nil;
6949a747e4fSDavid du Colombier 	c = devopen(c, omode, consdir, nelem(consdir), devgen);
6959a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
6963e12c5d1SDavid du Colombier 	case Qconsctl:
69788110b43SDavid du Colombier 		incref(&kbd.ctl);
6983e12c5d1SDavid du Colombier 		break;
6999a747e4fSDavid du Colombier 
7009a747e4fSDavid du Colombier 	case Qkprint:
7019a747e4fSDavid du Colombier 		if(tas(&kprintinuse) != 0){
7029a747e4fSDavid du Colombier 			c->flag &= ~COPEN;
7039a747e4fSDavid du Colombier 			error(Einuse);
7043e12c5d1SDavid du Colombier 		}
7059a747e4fSDavid du Colombier 		if(kprintoq == nil){
7063ff48bf5SDavid du Colombier 			kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
7079a747e4fSDavid du Colombier 			if(kprintoq == nil){
7089a747e4fSDavid du Colombier 				c->flag &= ~COPEN;
7099a747e4fSDavid du Colombier 				error(Enomem);
7109a747e4fSDavid du Colombier 			}
7119a747e4fSDavid du Colombier 			qnoblock(kprintoq, 1);
7129a747e4fSDavid du Colombier 		}else
7139a747e4fSDavid du Colombier 			qreopen(kprintoq);
7149a747e4fSDavid du Colombier 		c->iounit = qiomaxatomic;
7159a747e4fSDavid du Colombier 		break;
7169a747e4fSDavid du Colombier 	}
7179a747e4fSDavid du Colombier 	return c;
7183e12c5d1SDavid du Colombier }
7193e12c5d1SDavid du Colombier 
7207dd7cddfSDavid du Colombier static void
consclose(Chan * c)7213e12c5d1SDavid du Colombier consclose(Chan *c)
7223e12c5d1SDavid du Colombier {
7239a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
7243e12c5d1SDavid du Colombier 	/* last close of control file turns off raw */
725219b2ee8SDavid du Colombier 	case Qconsctl:
726219b2ee8SDavid du Colombier 		if(c->flag&COPEN){
72788110b43SDavid du Colombier 			if(decref(&kbd.ctl) == 0)
7287dd7cddfSDavid du Colombier 				kbd.raw = 0;
7293e12c5d1SDavid du Colombier 		}
730219b2ee8SDavid du Colombier 		break;
7319a747e4fSDavid du Colombier 
7329a747e4fSDavid du Colombier 	/* close of kprint allows other opens */
7339a747e4fSDavid du Colombier 	case Qkprint:
7349a747e4fSDavid du Colombier 		if(c->flag & COPEN){
7359a747e4fSDavid du Colombier 			kprintinuse = 0;
7369a747e4fSDavid du Colombier 			qhangup(kprintoq, nil);
7379a747e4fSDavid du Colombier 		}
7389a747e4fSDavid du Colombier 		break;
739219b2ee8SDavid du Colombier 	}
7403e12c5d1SDavid du Colombier }
7413e12c5d1SDavid du Colombier 
7427dd7cddfSDavid du Colombier static long
consread(Chan * c,void * buf,long n,vlong off)7437dd7cddfSDavid du Colombier consread(Chan *c, void *buf, long n, vlong off)
7443e12c5d1SDavid du Colombier {
7453e12c5d1SDavid du Colombier 	ulong l;
7467dd7cddfSDavid du Colombier 	Mach *mp;
74788110b43SDavid du Colombier 	char *b, *bp, ch;
748e059317eSDavid du Colombier 	char tmp[256];		/* must be >= 18*NUMSIZE (Qswap) */
74988110b43SDavid du Colombier 	int i, k, id, send;
7507dd7cddfSDavid du Colombier 	vlong offset = off;
751add6b5c5SDavid du Colombier 	extern char configfile[];
7523e12c5d1SDavid du Colombier 
7533e12c5d1SDavid du Colombier 	if(n <= 0)
7543e12c5d1SDavid du Colombier 		return n;
75588110b43SDavid du Colombier 
7569a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
7573e12c5d1SDavid du Colombier 	case Qdir:
7587dd7cddfSDavid du Colombier 		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
7593e12c5d1SDavid du Colombier 
7603e12c5d1SDavid du Colombier 	case Qcons:
7617dd7cddfSDavid du Colombier 		qlock(&kbd);
7623e12c5d1SDavid du Colombier 		if(waserror()) {
7637dd7cddfSDavid du Colombier 			qunlock(&kbd);
7643e12c5d1SDavid du Colombier 			nexterror();
7653e12c5d1SDavid du Colombier 		}
7667dd7cddfSDavid du Colombier 		while(!qcanread(lineq)){
767ec46fab0SDavid du Colombier 			if(qread(kbdq, &ch, 1) == 0)
768ec46fab0SDavid du Colombier 				continue;
76988110b43SDavid du Colombier 			send = 0;
77088110b43SDavid du Colombier 			if(ch == 0){
77188110b43SDavid du Colombier 				/* flush output on rawoff -> rawon */
77288110b43SDavid du Colombier 				if(kbd.x > 0)
77388110b43SDavid du Colombier 					send = !qcanread(kbdq);
77488110b43SDavid du Colombier 			}else if(kbd.raw){
77588110b43SDavid du Colombier 				kbd.line[kbd.x++] = ch;
77688110b43SDavid du Colombier 				send = !qcanread(kbdq);
77788110b43SDavid du Colombier 			}else{
7783e12c5d1SDavid du Colombier 				switch(ch){
7793e12c5d1SDavid du Colombier 				case '\b':
78088110b43SDavid du Colombier 					if(kbd.x > 0)
7817dd7cddfSDavid du Colombier 						kbd.x--;
7823e12c5d1SDavid du Colombier 					break;
78388110b43SDavid du Colombier 				case 0x15:	/* ^U */
7847dd7cddfSDavid du Colombier 					kbd.x = 0;
7853e12c5d1SDavid du Colombier 					break;
7867dd7cddfSDavid du Colombier 				case '\n':
78788110b43SDavid du Colombier 				case 0x04:	/* ^D */
78888110b43SDavid du Colombier 					send = 1;
7893e12c5d1SDavid du Colombier 				default:
79088110b43SDavid du Colombier 					if(ch != 0x04)
7917dd7cddfSDavid du Colombier 						kbd.line[kbd.x++] = ch;
7923e12c5d1SDavid du Colombier 					break;
7933e12c5d1SDavid du Colombier 				}
79488110b43SDavid du Colombier 			}
79588110b43SDavid du Colombier 			if(send || kbd.x == sizeof kbd.line){
7967dd7cddfSDavid du Colombier 				qwrite(lineq, kbd.line, kbd.x);
7977dd7cddfSDavid du Colombier 				kbd.x = 0;
7987dd7cddfSDavid du Colombier 			}
7997dd7cddfSDavid du Colombier 		}
8007dd7cddfSDavid du Colombier 		n = qread(lineq, buf, n);
8017dd7cddfSDavid du Colombier 		qunlock(&kbd);
8023e12c5d1SDavid du Colombier 		poperror();
8037dd7cddfSDavid du Colombier 		return n;
8043e12c5d1SDavid du Colombier 
8053e12c5d1SDavid du Colombier 	case Qcputime:
8063e12c5d1SDavid du Colombier 		k = offset;
807219b2ee8SDavid du Colombier 		if(k >= 6*NUMSIZE)
8083e12c5d1SDavid du Colombier 			return 0;
809219b2ee8SDavid du Colombier 		if(k+n > 6*NUMSIZE)
810219b2ee8SDavid du Colombier 			n = 6*NUMSIZE - k;
8113e12c5d1SDavid du Colombier 		/* easiest to format in a separate buffer and copy out */
8123e12c5d1SDavid du Colombier 		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
8137dd7cddfSDavid du Colombier 			l = up->time[i];
8143e12c5d1SDavid du Colombier 			if(i == TReal)
8153e12c5d1SDavid du Colombier 				l = MACHP(0)->ticks - l;
8163e12c5d1SDavid du Colombier 			l = TK2MS(l);
8173e12c5d1SDavid du Colombier 			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
8183e12c5d1SDavid du Colombier 		}
8193e12c5d1SDavid du Colombier 		memmove(buf, tmp+k, n);
8203e12c5d1SDavid du Colombier 		return n;
8213e12c5d1SDavid du Colombier 
822f6eb8b35SDavid du Colombier 	case Qkmesg:
823f6eb8b35SDavid du Colombier 		/*
824f6eb8b35SDavid du Colombier 		 * This is unlocked to avoid tying up a process
825f6eb8b35SDavid du Colombier 		 * that's writing to the buffer.  kmesg.n never
826f6eb8b35SDavid du Colombier 		 * gets smaller, so worst case the reader will
827f6eb8b35SDavid du Colombier 		 * see a slurred buffer.
828f6eb8b35SDavid du Colombier 		 */
829f6eb8b35SDavid du Colombier 		if(off >= kmesg.n)
830f6eb8b35SDavid du Colombier 			n = 0;
831f6eb8b35SDavid du Colombier 		else{
832f6eb8b35SDavid du Colombier 			if(off+n > kmesg.n)
833f6eb8b35SDavid du Colombier 				n = kmesg.n - off;
834f6eb8b35SDavid du Colombier 			memmove(buf, kmesg.buf+off, n);
835f6eb8b35SDavid du Colombier 		}
836f6eb8b35SDavid du Colombier 		return n;
837f6eb8b35SDavid du Colombier 
8389a747e4fSDavid du Colombier 	case Qkprint:
8399a747e4fSDavid du Colombier 		return qread(kprintoq, buf, n);
8409a747e4fSDavid du Colombier 
8413e12c5d1SDavid du Colombier 	case Qpgrpid:
8427dd7cddfSDavid du Colombier 		return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
8433e12c5d1SDavid du Colombier 
8443e12c5d1SDavid du Colombier 	case Qpid:
8457dd7cddfSDavid du Colombier 		return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
8463e12c5d1SDavid du Colombier 
8473e12c5d1SDavid du Colombier 	case Qppid:
8487dd7cddfSDavid du Colombier 		return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
8493e12c5d1SDavid du Colombier 
8503e12c5d1SDavid du Colombier 	case Qtime:
8517dd7cddfSDavid du Colombier 		return readtime((ulong)offset, buf, n);
8523e12c5d1SDavid du Colombier 
8537dd7cddfSDavid du Colombier 	case Qbintime:
8547dd7cddfSDavid du Colombier 		return readbintime(buf, n);
8553e12c5d1SDavid du Colombier 
856219b2ee8SDavid du Colombier 	case Qhostowner:
8577dd7cddfSDavid du Colombier 		return readstr((ulong)offset, buf, n, eve);
858219b2ee8SDavid du Colombier 
859219b2ee8SDavid du Colombier 	case Qhostdomain:
8607dd7cddfSDavid du Colombier 		return readstr((ulong)offset, buf, n, hostdomain);
8613e12c5d1SDavid du Colombier 
8623e12c5d1SDavid du Colombier 	case Quser:
8637dd7cddfSDavid du Colombier 		return readstr((ulong)offset, buf, n, up->user);
8643e12c5d1SDavid du Colombier 
8653e12c5d1SDavid du Colombier 	case Qnull:
8663e12c5d1SDavid du Colombier 		return 0;
8673e12c5d1SDavid du Colombier 
868add6b5c5SDavid du Colombier 	case Qconfig:
869add6b5c5SDavid du Colombier 		return readstr((ulong)offset, buf, n, configfile);
870add6b5c5SDavid du Colombier 
8713e12c5d1SDavid du Colombier 	case Qsysstat:
8723ff48bf5SDavid du Colombier 		b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1);	/* +1 for NUL */
8733e12c5d1SDavid du Colombier 		bp = b;
8743e12c5d1SDavid du Colombier 		for(id = 0; id < 32; id++) {
8753e12c5d1SDavid du Colombier 			if(active.machs & (1<<id)) {
8763e12c5d1SDavid du Colombier 				mp = MACHP(id);
8773e12c5d1SDavid du Colombier 				readnum(0, bp, NUMSIZE, id, NUMSIZE);
8783e12c5d1SDavid du Colombier 				bp += NUMSIZE;
8793e12c5d1SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
8803e12c5d1SDavid du Colombier 				bp += NUMSIZE;
8813e12c5d1SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
8823e12c5d1SDavid du Colombier 				bp += NUMSIZE;
8833e12c5d1SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
8843e12c5d1SDavid du Colombier 				bp += NUMSIZE;
8853e12c5d1SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
8863e12c5d1SDavid du Colombier 				bp += NUMSIZE;
8873e12c5d1SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
8883e12c5d1SDavid du Colombier 				bp += NUMSIZE;
8893e12c5d1SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
8903e12c5d1SDavid du Colombier 				bp += NUMSIZE;
8913e12c5d1SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
8923e12c5d1SDavid du Colombier 				bp += NUMSIZE;
8933ff48bf5SDavid du Colombier 				readnum(0, bp, NUMSIZE,
8943ff48bf5SDavid du Colombier 					(mp->perf.avg_inidle*100)/mp->perf.period,
8953ff48bf5SDavid du Colombier 					NUMSIZE);
8963ff48bf5SDavid du Colombier 				bp += NUMSIZE;
8973ff48bf5SDavid du Colombier 				readnum(0, bp, NUMSIZE,
8983ff48bf5SDavid du Colombier 					(mp->perf.avg_inintr*100)/mp->perf.period,
8993ff48bf5SDavid du Colombier 					NUMSIZE);
9003ff48bf5SDavid du Colombier 				bp += NUMSIZE;
9013e12c5d1SDavid du Colombier 				*bp++ = '\n';
9023e12c5d1SDavid du Colombier 			}
9033e12c5d1SDavid du Colombier 		}
9049a747e4fSDavid du Colombier 		if(waserror()){
9059a747e4fSDavid du Colombier 			free(b);
9069a747e4fSDavid du Colombier 			nexterror();
9079a747e4fSDavid du Colombier 		}
9087dd7cddfSDavid du Colombier 		n = readstr((ulong)offset, buf, n, b);
9093e12c5d1SDavid du Colombier 		free(b);
9109a747e4fSDavid du Colombier 		poperror();
9113e12c5d1SDavid du Colombier 		return n;
9123e12c5d1SDavid du Colombier 
9133e12c5d1SDavid du Colombier 	case Qswap:
914e059317eSDavid du Colombier 		snprint(tmp, sizeof tmp,
915e059317eSDavid du Colombier 			"%lud memory\n"
916e059317eSDavid du Colombier 			"%d pagesize\n"
917e059317eSDavid du Colombier 			"%lud kernel\n"
918e059317eSDavid du Colombier 			"%lud/%lud user\n"
919e059317eSDavid du Colombier 			"%lud/%lud swap\n"
920e059317eSDavid du Colombier 			"%lud/%lud kernel malloc\n"
921e059317eSDavid du Colombier 			"%lud/%lud kernel draw\n",
922e059317eSDavid du Colombier 			conf.npage*BY2PG,
923e059317eSDavid du Colombier 			BY2PG,
924e059317eSDavid du Colombier 			conf.npage-conf.upages,
925e059317eSDavid du Colombier 			palloc.user-palloc.freecount, palloc.user,
926e059317eSDavid du Colombier 			conf.nswap-swapalloc.free, conf.nswap,
927e059317eSDavid du Colombier 			mainmem->cursize, mainmem->maxsize,
928e059317eSDavid du Colombier 			imagmem->cursize, imagmem->maxsize);
9293e12c5d1SDavid du Colombier 
9307dd7cddfSDavid du Colombier 		return readstr((ulong)offset, buf, n, tmp);
9313e12c5d1SDavid du Colombier 
9323e12c5d1SDavid du Colombier 	case Qsysname:
9339a747e4fSDavid du Colombier 		if(sysname == nil)
9349a747e4fSDavid du Colombier 			return 0;
9357dd7cddfSDavid du Colombier 		return readstr((ulong)offset, buf, n, sysname);
9367dd7cddfSDavid du Colombier 
9377dd7cddfSDavid du Colombier 	case Qrandom:
9387dd7cddfSDavid du Colombier 		return randomread(buf, n);
9397dd7cddfSDavid du Colombier 
9407dd7cddfSDavid du Colombier 	case Qdrivers:
9417dd7cddfSDavid du Colombier 		b = malloc(READSTR);
9427dd7cddfSDavid du Colombier 		if(b == nil)
9437dd7cddfSDavid du Colombier 			error(Enomem);
944fcbb35d1SDavid du Colombier 		k = 0;
9457dd7cddfSDavid du Colombier 		for(i = 0; devtab[i] != nil; i++)
946fcbb35d1SDavid du Colombier 			k += snprint(b+k, READSTR-k, "#%C %s\n",
947fcbb35d1SDavid du Colombier 				devtab[i]->dc, devtab[i]->name);
9489a747e4fSDavid du Colombier 		if(waserror()){
9499a747e4fSDavid du Colombier 			free(b);
9509a747e4fSDavid du Colombier 			nexterror();
9519a747e4fSDavid du Colombier 		}
9527dd7cddfSDavid du Colombier 		n = readstr((ulong)offset, buf, n, b);
9537dd7cddfSDavid du Colombier 		free(b);
9549a747e4fSDavid du Colombier 		poperror();
9557dd7cddfSDavid du Colombier 		return n;
9567dd7cddfSDavid du Colombier 
9577dd7cddfSDavid du Colombier 	case Qzero:
9587dd7cddfSDavid du Colombier 		memset(buf, 0, n);
9597dd7cddfSDavid du Colombier 		return n;
9603e12c5d1SDavid du Colombier 
9619a747e4fSDavid du Colombier 	case Qosversion:
9629a747e4fSDavid du Colombier 		snprint(tmp, sizeof tmp, "2000");
9639a747e4fSDavid du Colombier 		n = readstr((ulong)offset, buf, n, tmp);
9649a747e4fSDavid du Colombier 		return n;
9659a747e4fSDavid du Colombier 
9663e12c5d1SDavid du Colombier 	default:
967567483c8SDavid du Colombier 		print("consread %#llux\n", c->qid.path);
9683e12c5d1SDavid du Colombier 		error(Egreg);
9693e12c5d1SDavid du Colombier 	}
9703e12c5d1SDavid du Colombier 	return -1;		/* never reached */
9713e12c5d1SDavid du Colombier }
9723e12c5d1SDavid du Colombier 
9737dd7cddfSDavid du Colombier static long
conswrite(Chan * c,void * va,long n,vlong off)9747dd7cddfSDavid du Colombier conswrite(Chan *c, void *va, long n, vlong off)
9753e12c5d1SDavid du Colombier {
97688110b43SDavid du Colombier 	char buf[256], ch;
9773e12c5d1SDavid du Colombier 	long l, bp;
97888110b43SDavid du Colombier 	char *a;
9793e12c5d1SDavid du Colombier 	Mach *mp;
9807dd7cddfSDavid du Colombier 	int id, fd;
9813e12c5d1SDavid du Colombier 	Chan *swc;
98288110b43SDavid du Colombier 	ulong offset;
9839a747e4fSDavid du Colombier 	Cmdbuf *cb;
9849a747e4fSDavid du Colombier 	Cmdtab *ct;
9853e12c5d1SDavid du Colombier 
98688110b43SDavid du Colombier 	a = va;
98788110b43SDavid du Colombier 	offset = off;
98888110b43SDavid du Colombier 
9899a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
9903e12c5d1SDavid du Colombier 	case Qcons:
9917dd7cddfSDavid du Colombier 		/*
9927dd7cddfSDavid du Colombier 		 * Can't page fault in putstrn, so copy the data locally.
9937dd7cddfSDavid du Colombier 		 */
9943e12c5d1SDavid du Colombier 		l = n;
9953e12c5d1SDavid du Colombier 		while(l > 0){
9963e12c5d1SDavid du Colombier 			bp = l;
9973e12c5d1SDavid du Colombier 			if(bp > sizeof buf)
9983e12c5d1SDavid du Colombier 				bp = sizeof buf;
9993e12c5d1SDavid du Colombier 			memmove(buf, a, bp);
100080ee5cbfSDavid du Colombier 			putstrn0(buf, bp, 1);
10013e12c5d1SDavid du Colombier 			a += bp;
10023e12c5d1SDavid du Colombier 			l -= bp;
10033e12c5d1SDavid du Colombier 		}
10043e12c5d1SDavid du Colombier 		break;
10053e12c5d1SDavid du Colombier 
10063e12c5d1SDavid du Colombier 	case Qconsctl:
10073e12c5d1SDavid du Colombier 		if(n >= sizeof(buf))
10083e12c5d1SDavid du Colombier 			n = sizeof(buf)-1;
10093e12c5d1SDavid du Colombier 		strncpy(buf, a, n);
10103e12c5d1SDavid du Colombier 		buf[n] = 0;
10117dd7cddfSDavid du Colombier 		for(a = buf; a;){
10123e12c5d1SDavid du Colombier 			if(strncmp(a, "rawon", 5) == 0){
10137dd7cddfSDavid du Colombier 				kbd.raw = 1;
101488110b43SDavid du Colombier 				/* clumsy hack - wake up reader */
101588110b43SDavid du Colombier 				ch = 0;
101688110b43SDavid du Colombier 				qwrite(kbdq, &ch, 1);
10177dd7cddfSDavid du Colombier 			} else if(strncmp(a, "rawoff", 6) == 0){
10187dd7cddfSDavid du Colombier 				kbd.raw = 0;
10197dd7cddfSDavid du Colombier 			} else if(strncmp(a, "ctlpon", 6) == 0){
10207dd7cddfSDavid du Colombier 				kbd.ctlpoff = 0;
10217dd7cddfSDavid du Colombier 			} else if(strncmp(a, "ctlpoff", 7) == 0){
10227dd7cddfSDavid du Colombier 				kbd.ctlpoff = 1;
1023219b2ee8SDavid du Colombier 			}
10247dd7cddfSDavid du Colombier 			if(a = strchr(a, ' '))
10257dd7cddfSDavid du Colombier 				a++;
10263e12c5d1SDavid du Colombier 		}
10273e12c5d1SDavid du Colombier 		break;
10283e12c5d1SDavid du Colombier 
10293e12c5d1SDavid du Colombier 	case Qtime:
10307dd7cddfSDavid du Colombier 		if(!iseve())
10317dd7cddfSDavid du Colombier 			error(Eperm);
10327dd7cddfSDavid du Colombier 		return writetime(a, n);
10337dd7cddfSDavid du Colombier 
10347dd7cddfSDavid du Colombier 	case Qbintime:
10357dd7cddfSDavid du Colombier 		if(!iseve())
10367dd7cddfSDavid du Colombier 			error(Eperm);
10377dd7cddfSDavid du Colombier 		return writebintime(a, n);
10383e12c5d1SDavid du Colombier 
1039219b2ee8SDavid du Colombier 	case Qhostowner:
1040219b2ee8SDavid du Colombier 		return hostownerwrite(a, n);
1041219b2ee8SDavid du Colombier 
1042219b2ee8SDavid du Colombier 	case Qhostdomain:
1043219b2ee8SDavid du Colombier 		return hostdomainwrite(a, n);
10443e12c5d1SDavid du Colombier 
10453e12c5d1SDavid du Colombier 	case Quser:
1046219b2ee8SDavid du Colombier 		return userwrite(a, n);
10473e12c5d1SDavid du Colombier 
10483e12c5d1SDavid du Colombier 	case Qnull:
10493e12c5d1SDavid du Colombier 		break;
10503e12c5d1SDavid du Colombier 
1051add6b5c5SDavid du Colombier 	case Qconfig:
1052add6b5c5SDavid du Colombier 		error(Eperm);
1053add6b5c5SDavid du Colombier 		break;
1054add6b5c5SDavid du Colombier 
10557dd7cddfSDavid du Colombier 	case Qreboot:
10567dd7cddfSDavid du Colombier 		if(!iseve())
10577dd7cddfSDavid du Colombier 			error(Eperm);
10589a747e4fSDavid du Colombier 		cb = parsecmd(a, n);
10599a747e4fSDavid du Colombier 
10609a747e4fSDavid du Colombier 		if(waserror()) {
10619a747e4fSDavid du Colombier 			free(cb);
10629a747e4fSDavid du Colombier 			nexterror();
10637dd7cddfSDavid du Colombier 		}
10649a747e4fSDavid du Colombier 		ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
10659a747e4fSDavid du Colombier 		switch(ct->index) {
1066e288d156SDavid du Colombier 		case CMhalt:
1067e288d156SDavid du Colombier 			reboot(nil, 0, 0);
1068e288d156SDavid du Colombier 			break;
10699a747e4fSDavid du Colombier 		case CMreboot:
10709a747e4fSDavid du Colombier 			rebootcmd(cb->nf-1, cb->f+1);
10719a747e4fSDavid du Colombier 			break;
10729a747e4fSDavid du Colombier 		case CMpanic:
1073e288d156SDavid du Colombier 			*(ulong*)0=0;
10747dd7cddfSDavid du Colombier 			panic("/dev/reboot");
10759a747e4fSDavid du Colombier 		}
10769a747e4fSDavid du Colombier 		poperror();
10779a747e4fSDavid du Colombier 		free(cb);
10783e12c5d1SDavid du Colombier 		break;
10793e12c5d1SDavid du Colombier 
10803e12c5d1SDavid du Colombier 	case Qsysstat:
10813e12c5d1SDavid du Colombier 		for(id = 0; id < 32; id++) {
10823e12c5d1SDavid du Colombier 			if(active.machs & (1<<id)) {
10833e12c5d1SDavid du Colombier 				mp = MACHP(id);
10843e12c5d1SDavid du Colombier 				mp->cs = 0;
10853e12c5d1SDavid du Colombier 				mp->intr = 0;
10863e12c5d1SDavid du Colombier 				mp->syscall = 0;
10873e12c5d1SDavid du Colombier 				mp->pfault = 0;
10883e12c5d1SDavid du Colombier 				mp->tlbfault = 0;
10893e12c5d1SDavid du Colombier 				mp->tlbpurge = 0;
10903e12c5d1SDavid du Colombier 			}
10913e12c5d1SDavid du Colombier 		}
10923e12c5d1SDavid du Colombier 		break;
10933e12c5d1SDavid du Colombier 
10943e12c5d1SDavid du Colombier 	case Qswap:
10953e12c5d1SDavid du Colombier 		if(n >= sizeof buf)
10963e12c5d1SDavid du Colombier 			error(Egreg);
10973e12c5d1SDavid du Colombier 		memmove(buf, va, n);	/* so we can NUL-terminate */
10983e12c5d1SDavid du Colombier 		buf[n] = 0;
10993e12c5d1SDavid du Colombier 		/* start a pager if not already started */
11003e12c5d1SDavid du Colombier 		if(strncmp(buf, "start", 5) == 0){
11013e12c5d1SDavid du Colombier 			kickpager();
11023e12c5d1SDavid du Colombier 			break;
11033e12c5d1SDavid du Colombier 		}
1104dc5a79c1SDavid du Colombier 		if(!iseve())
11053e12c5d1SDavid du Colombier 			error(Eperm);
11063e12c5d1SDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0])
11077dd7cddfSDavid du Colombier 			error(Ebadarg);
11083e12c5d1SDavid du Colombier 		fd = strtoul(buf, 0, 0);
11097dd7cddfSDavid du Colombier 		swc = fdtochan(fd, -1, 1, 1);
11103e12c5d1SDavid du Colombier 		setswapchan(swc);
11113e12c5d1SDavid du Colombier 		break;
11123e12c5d1SDavid du Colombier 
11133e12c5d1SDavid du Colombier 	case Qsysname:
11143e12c5d1SDavid du Colombier 		if(offset != 0)
11153e12c5d1SDavid du Colombier 			error(Ebadarg);
11169a747e4fSDavid du Colombier 		if(n <= 0 || n >= sizeof buf)
11173e12c5d1SDavid du Colombier 			error(Ebadarg);
11189a747e4fSDavid du Colombier 		strncpy(buf, a, n);
11199a747e4fSDavid du Colombier 		buf[n] = 0;
11209a747e4fSDavid du Colombier 		if(buf[n-1] == '\n')
11219a747e4fSDavid du Colombier 			buf[n-1] = 0;
11229a747e4fSDavid du Colombier 		kstrdup(&sysname, buf);
11233e12c5d1SDavid du Colombier 		break;
11243e12c5d1SDavid du Colombier 
11253e12c5d1SDavid du Colombier 	default:
1126567483c8SDavid du Colombier 		print("conswrite: %#llux\n", c->qid.path);
11273e12c5d1SDavid du Colombier 		error(Egreg);
11283e12c5d1SDavid du Colombier 	}
11293e12c5d1SDavid du Colombier 	return n;
11303e12c5d1SDavid du Colombier }
11313e12c5d1SDavid du Colombier 
11327dd7cddfSDavid du Colombier Dev consdevtab = {
11337dd7cddfSDavid du Colombier 	'c',
11347dd7cddfSDavid du Colombier 	"cons",
11357dd7cddfSDavid du Colombier 
11367dd7cddfSDavid du Colombier 	devreset,
11377dd7cddfSDavid du Colombier 	consinit,
11389a747e4fSDavid du Colombier 	devshutdown,
11397dd7cddfSDavid du Colombier 	consattach,
11407dd7cddfSDavid du Colombier 	conswalk,
11417dd7cddfSDavid du Colombier 	consstat,
11427dd7cddfSDavid du Colombier 	consopen,
11437dd7cddfSDavid du Colombier 	devcreate,
11447dd7cddfSDavid du Colombier 	consclose,
11457dd7cddfSDavid du Colombier 	consread,
11467dd7cddfSDavid du Colombier 	devbread,
11477dd7cddfSDavid du Colombier 	conswrite,
11487dd7cddfSDavid du Colombier 	devbwrite,
11497dd7cddfSDavid du Colombier 	devremove,
11507dd7cddfSDavid du Colombier 	devwstat,
11517dd7cddfSDavid du Colombier };
11527dd7cddfSDavid du Colombier 
115314414594SDavid du Colombier static	ulong	randn;
11547dd7cddfSDavid du Colombier 
11557dd7cddfSDavid du Colombier static void
seedrand(void)11567dd7cddfSDavid du Colombier seedrand(void)
11577dd7cddfSDavid du Colombier {
1158d04cc87cSDavid du Colombier 	if(!waserror()){
115914414594SDavid du Colombier 		randomread((void*)&randn, sizeof(randn));
1160d04cc87cSDavid du Colombier 		poperror();
1161d04cc87cSDavid du Colombier 	}
11627dd7cddfSDavid du Colombier }
11637dd7cddfSDavid du Colombier 
11647dd7cddfSDavid du Colombier int
nrand(int n)11657dd7cddfSDavid du Colombier nrand(int n)
11667dd7cddfSDavid du Colombier {
116714414594SDavid du Colombier 	if(randn == 0)
11687dd7cddfSDavid du Colombier 		seedrand();
116914414594SDavid du Colombier 	randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
117014414594SDavid du Colombier 	return (randn>>16) % n;
11717dd7cddfSDavid du Colombier }
11727dd7cddfSDavid du Colombier 
11737dd7cddfSDavid du Colombier int
rand(void)11747dd7cddfSDavid du Colombier rand(void)
11757dd7cddfSDavid du Colombier {
11767dd7cddfSDavid du Colombier 	nrand(1);
117714414594SDavid du Colombier 	return randn;
11787dd7cddfSDavid du Colombier }
11797dd7cddfSDavid du Colombier 
11807dd7cddfSDavid du Colombier static uvlong uvorder = 0x0001020304050607ULL;
11817dd7cddfSDavid du Colombier 
11827dd7cddfSDavid du Colombier static uchar*
le2vlong(vlong * to,uchar * f)11837dd7cddfSDavid du Colombier le2vlong(vlong *to, uchar *f)
11847dd7cddfSDavid du Colombier {
11857dd7cddfSDavid du Colombier 	uchar *t, *o;
11867dd7cddfSDavid du Colombier 	int i;
11877dd7cddfSDavid du Colombier 
11887dd7cddfSDavid du Colombier 	t = (uchar*)to;
11897dd7cddfSDavid du Colombier 	o = (uchar*)&uvorder;
11907dd7cddfSDavid du Colombier 	for(i = 0; i < sizeof(vlong); i++)
11917dd7cddfSDavid du Colombier 		t[o[i]] = f[i];
11927dd7cddfSDavid du Colombier 	return f+sizeof(vlong);
11937dd7cddfSDavid du Colombier }
11947dd7cddfSDavid du Colombier 
11957dd7cddfSDavid du Colombier static uchar*
vlong2le(uchar * t,vlong from)11967dd7cddfSDavid du Colombier vlong2le(uchar *t, vlong from)
11977dd7cddfSDavid du Colombier {
11987dd7cddfSDavid du Colombier 	uchar *f, *o;
11997dd7cddfSDavid du Colombier 	int i;
12007dd7cddfSDavid du Colombier 
12017dd7cddfSDavid du Colombier 	f = (uchar*)&from;
12027dd7cddfSDavid du Colombier 	o = (uchar*)&uvorder;
12037dd7cddfSDavid du Colombier 	for(i = 0; i < sizeof(vlong); i++)
12047dd7cddfSDavid du Colombier 		t[i] = f[o[i]];
12057dd7cddfSDavid du Colombier 	return t+sizeof(vlong);
12067dd7cddfSDavid du Colombier }
12077dd7cddfSDavid du Colombier 
12087dd7cddfSDavid du Colombier static long order = 0x00010203;
12097dd7cddfSDavid du Colombier 
12107dd7cddfSDavid du Colombier static uchar*
le2long(long * to,uchar * f)12117dd7cddfSDavid du Colombier le2long(long *to, uchar *f)
12127dd7cddfSDavid du Colombier {
12137dd7cddfSDavid du Colombier 	uchar *t, *o;
12147dd7cddfSDavid du Colombier 	int i;
12157dd7cddfSDavid du Colombier 
12167dd7cddfSDavid du Colombier 	t = (uchar*)to;
12177dd7cddfSDavid du Colombier 	o = (uchar*)&order;
12187dd7cddfSDavid du Colombier 	for(i = 0; i < sizeof(long); i++)
12197dd7cddfSDavid du Colombier 		t[o[i]] = f[i];
12207dd7cddfSDavid du Colombier 	return f+sizeof(long);
12217dd7cddfSDavid du Colombier }
12227dd7cddfSDavid du Colombier 
12237dd7cddfSDavid du Colombier static uchar*
long2le(uchar * t,long from)12247dd7cddfSDavid du Colombier long2le(uchar *t, long from)
12257dd7cddfSDavid du Colombier {
12267dd7cddfSDavid du Colombier 	uchar *f, *o;
12277dd7cddfSDavid du Colombier 	int i;
12287dd7cddfSDavid du Colombier 
12297dd7cddfSDavid du Colombier 	f = (uchar*)&from;
12307dd7cddfSDavid du Colombier 	o = (uchar*)&order;
12317dd7cddfSDavid du Colombier 	for(i = 0; i < sizeof(long); i++)
12327dd7cddfSDavid du Colombier 		t[i] = f[o[i]];
12337dd7cddfSDavid du Colombier 	return t+sizeof(long);
12347dd7cddfSDavid du Colombier }
12357dd7cddfSDavid du Colombier 
12367dd7cddfSDavid du Colombier char *Ebadtimectl = "bad time control";
12377dd7cddfSDavid du Colombier 
12387dd7cddfSDavid du Colombier /*
12397dd7cddfSDavid du Colombier  *  like the old #c/time but with added info.  Return
12407dd7cddfSDavid du Colombier  *
12417dd7cddfSDavid du Colombier  *	secs	nanosecs	fastticks	fasthz
12427dd7cddfSDavid du Colombier  */
12437dd7cddfSDavid du Colombier static int
readtime(ulong off,char * buf,int n)12447dd7cddfSDavid du Colombier readtime(ulong off, char *buf, int n)
12457dd7cddfSDavid du Colombier {
12467dd7cddfSDavid du Colombier 	vlong	nsec, ticks;
12477dd7cddfSDavid du Colombier 	long sec;
124859cc4ca5SDavid du Colombier 	char str[7*NUMSIZE];
12497dd7cddfSDavid du Colombier 
12507dd7cddfSDavid du Colombier 	nsec = todget(&ticks);
12517dd7cddfSDavid du Colombier 	if(fasthz == 0LL)
12527dd7cddfSDavid du Colombier 		fastticks((uvlong*)&fasthz);
12537dd7cddfSDavid du Colombier 	sec = nsec/1000000000ULL;
1254567483c8SDavid du Colombier 	snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
12557dd7cddfSDavid du Colombier 		NUMSIZE-1, sec,
12567dd7cddfSDavid du Colombier 		VLNUMSIZE-1, nsec,
12577dd7cddfSDavid du Colombier 		VLNUMSIZE-1, ticks,
12587dd7cddfSDavid du Colombier 		VLNUMSIZE-1, fasthz);
12597dd7cddfSDavid du Colombier 	return readstr(off, buf, n, str);
12607dd7cddfSDavid du Colombier }
12617dd7cddfSDavid du Colombier 
12627dd7cddfSDavid du Colombier /*
12637dd7cddfSDavid du Colombier  *  set the time in seconds
12647dd7cddfSDavid du Colombier  */
12657dd7cddfSDavid du Colombier static int
writetime(char * buf,int n)12667dd7cddfSDavid du Colombier writetime(char *buf, int n)
12677dd7cddfSDavid du Colombier {
12687dd7cddfSDavid du Colombier 	char b[13];
12697dd7cddfSDavid du Colombier 	long i;
12707dd7cddfSDavid du Colombier 	vlong now;
12717dd7cddfSDavid du Colombier 
12727dd7cddfSDavid du Colombier 	if(n >= sizeof(b))
12737dd7cddfSDavid du Colombier 		error(Ebadtimectl);
12747dd7cddfSDavid du Colombier 	strncpy(b, buf, n);
12757dd7cddfSDavid du Colombier 	b[n] = 0;
12767dd7cddfSDavid du Colombier 	i = strtol(b, 0, 0);
12777dd7cddfSDavid du Colombier 	if(i <= 0)
12787dd7cddfSDavid du Colombier 		error(Ebadtimectl);
12797dd7cddfSDavid du Colombier 	now = i*1000000000LL;
12807dd7cddfSDavid du Colombier 	todset(now, 0, 0);
12817dd7cddfSDavid du Colombier 	return n;
12827dd7cddfSDavid du Colombier }
12837dd7cddfSDavid du Colombier 
12847dd7cddfSDavid du Colombier /*
12857dd7cddfSDavid du Colombier  *  read binary time info.  all numbers are little endian.
12867dd7cddfSDavid du Colombier  *  ticks and nsec are syncronized.
12877dd7cddfSDavid du Colombier  */
12887dd7cddfSDavid du Colombier static int
readbintime(char * buf,int n)12897dd7cddfSDavid du Colombier readbintime(char *buf, int n)
12907dd7cddfSDavid du Colombier {
12917dd7cddfSDavid du Colombier 	int i;
12927dd7cddfSDavid du Colombier 	vlong nsec, ticks;
12937dd7cddfSDavid du Colombier 	uchar *b = (uchar*)buf;
12947dd7cddfSDavid du Colombier 
12957dd7cddfSDavid du Colombier 	i = 0;
12967dd7cddfSDavid du Colombier 	if(fasthz == 0LL)
12977dd7cddfSDavid du Colombier 		fastticks((uvlong*)&fasthz);
12987dd7cddfSDavid du Colombier 	nsec = todget(&ticks);
12997dd7cddfSDavid du Colombier 	if(n >= 3*sizeof(uvlong)){
13007dd7cddfSDavid du Colombier 		vlong2le(b+2*sizeof(uvlong), fasthz);
13017dd7cddfSDavid du Colombier 		i += sizeof(uvlong);
13027dd7cddfSDavid du Colombier 	}
13037dd7cddfSDavid du Colombier 	if(n >= 2*sizeof(uvlong)){
13047dd7cddfSDavid du Colombier 		vlong2le(b+sizeof(uvlong), ticks);
13057dd7cddfSDavid du Colombier 		i += sizeof(uvlong);
13067dd7cddfSDavid du Colombier 	}
13077dd7cddfSDavid du Colombier 	if(n >= 8){
13087dd7cddfSDavid du Colombier 		vlong2le(b, nsec);
13097dd7cddfSDavid du Colombier 		i += sizeof(vlong);
13107dd7cddfSDavid du Colombier 	}
13117dd7cddfSDavid du Colombier 	return i;
13127dd7cddfSDavid du Colombier }
13137dd7cddfSDavid du Colombier 
13147dd7cddfSDavid du Colombier /*
13157dd7cddfSDavid du Colombier  *  set any of the following
13167dd7cddfSDavid du Colombier  *	- time in nsec
13177dd7cddfSDavid du Colombier  *	- nsec trim applied over some seconds
13187dd7cddfSDavid du Colombier  *	- clock frequency
13197dd7cddfSDavid du Colombier  */
13207dd7cddfSDavid du Colombier static int
writebintime(char * buf,int n)13217dd7cddfSDavid du Colombier writebintime(char *buf, int n)
13227dd7cddfSDavid du Colombier {
13237dd7cddfSDavid du Colombier 	uchar *p;
13247dd7cddfSDavid du Colombier 	vlong delta;
13257dd7cddfSDavid du Colombier 	long period;
13267dd7cddfSDavid du Colombier 
13277dd7cddfSDavid du Colombier 	n--;
13287dd7cddfSDavid du Colombier 	p = (uchar*)buf + 1;
13297dd7cddfSDavid du Colombier 	switch(*buf){
13307dd7cddfSDavid du Colombier 	case 'n':
13317dd7cddfSDavid du Colombier 		if(n < sizeof(vlong))
13327dd7cddfSDavid du Colombier 			error(Ebadtimectl);
13337dd7cddfSDavid du Colombier 		le2vlong(&delta, p);
13347dd7cddfSDavid du Colombier 		todset(delta, 0, 0);
13357dd7cddfSDavid du Colombier 		break;
13367dd7cddfSDavid du Colombier 	case 'd':
13377dd7cddfSDavid du Colombier 		if(n < sizeof(vlong)+sizeof(long))
13387dd7cddfSDavid du Colombier 			error(Ebadtimectl);
13397dd7cddfSDavid du Colombier 		p = le2vlong(&delta, p);
13407dd7cddfSDavid du Colombier 		le2long(&period, p);
13417dd7cddfSDavid du Colombier 		todset(-1, delta, period);
13427dd7cddfSDavid du Colombier 		break;
13437dd7cddfSDavid du Colombier 	case 'f':
13447dd7cddfSDavid du Colombier 		if(n < sizeof(uvlong))
13457dd7cddfSDavid du Colombier 			error(Ebadtimectl);
13467dd7cddfSDavid du Colombier 		le2vlong(&fasthz, p);
1347d1be6b08SDavid du Colombier 		if(fasthz <= 0)
1348d1be6b08SDavid du Colombier 			error(Ebadtimectl);
13497dd7cddfSDavid du Colombier 		todsetfreq(fasthz);
13507dd7cddfSDavid du Colombier 		break;
13517dd7cddfSDavid du Colombier 	}
13527dd7cddfSDavid du Colombier 	return n;
13537dd7cddfSDavid du Colombier }
1354