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