xref: /plan9/sys/src/9/omap/devcons.c (revision e5a0fbb75eb58a1e71232e731bb6db9c54abf8b7)
18e32b400SDavid du Colombier #include	"u.h"
28e32b400SDavid du Colombier #include	"../port/lib.h"
38e32b400SDavid du Colombier #include	"mem.h"
48e32b400SDavid du Colombier #include	"dat.h"
58e32b400SDavid du Colombier #include	"fns.h"
68e32b400SDavid du Colombier #include	"../port/error.h"
78e32b400SDavid du Colombier #include	"pool.h"
88e32b400SDavid du Colombier #include	<authsrv.h>
98e32b400SDavid du Colombier 
108e32b400SDavid du Colombier void	(*consdebug)(void) = nil;
118e32b400SDavid du Colombier void	(*screenputs)(char*, int) = nil;
128e32b400SDavid du Colombier 
138e32b400SDavid du Colombier Queue*	kbdq;			/* unprocessed console input */
148e32b400SDavid du Colombier Queue*	lineq;			/* processed console input */
158e32b400SDavid du Colombier Queue*	serialoq;		/* serial console output */
168e32b400SDavid du Colombier Queue*	kprintoq;		/* console output, for /dev/kprint */
178e32b400SDavid du Colombier ulong	kprintinuse;		/* test and set whether /dev/kprint is open */
188e32b400SDavid du Colombier int	iprintscreenputs = 1;
198e32b400SDavid du Colombier 
208e32b400SDavid du Colombier int	panicking;
218e32b400SDavid du Colombier 
228e32b400SDavid du Colombier static struct
238e32b400SDavid du Colombier {
248e32b400SDavid du Colombier 	QLock;
258e32b400SDavid du Colombier 
268e32b400SDavid du Colombier 	int	raw;		/* true if we shouldn't process input */
278e32b400SDavid du Colombier 	Ref	ctl;		/* number of opens to the control file */
288e32b400SDavid du Colombier 	int	x;		/* index into line */
298e32b400SDavid du Colombier 	char	line[1024];	/* current input line */
308e32b400SDavid du Colombier 
318e32b400SDavid du Colombier 	int	count;
328e32b400SDavid du Colombier 	int	ctlpoff;
338e32b400SDavid du Colombier 
348e32b400SDavid du Colombier 	/* a place to save up characters at interrupt time before dumping them in the queue */
358e32b400SDavid du Colombier 	Lock	lockputc;
368e32b400SDavid du Colombier 	char	istage[1024];
378e32b400SDavid du Colombier 	char	*iw;
388e32b400SDavid du Colombier 	char	*ir;
398e32b400SDavid du Colombier 	char	*ie;
408e32b400SDavid du Colombier } kbd = {
418e32b400SDavid du Colombier 	.iw	= kbd.istage,
428e32b400SDavid du Colombier 	.ir	= kbd.istage,
438e32b400SDavid du Colombier 	.ie	= kbd.istage + sizeof(kbd.istage),
448e32b400SDavid du Colombier };
458e32b400SDavid du Colombier 
468e32b400SDavid du Colombier char	*sysname;
478e32b400SDavid du Colombier vlong	fasthz;
488e32b400SDavid du Colombier 
498e32b400SDavid du Colombier static void	seedrand(void);
508e32b400SDavid du Colombier static int	readtime(ulong, char*, int);
518e32b400SDavid du Colombier static int	readbintime(char*, int);
528e32b400SDavid du Colombier static int	writetime(char*, int);
538e32b400SDavid du Colombier static int	writebintime(char*, int);
548e32b400SDavid du Colombier 
558e32b400SDavid du Colombier enum
568e32b400SDavid du Colombier {
578e32b400SDavid du Colombier 	CMhalt,
588e32b400SDavid du Colombier 	CMreboot,
598e32b400SDavid du Colombier 	CMpanic,
608e32b400SDavid du Colombier };
618e32b400SDavid du Colombier 
628e32b400SDavid du Colombier Cmdtab rebootmsg[] =
638e32b400SDavid du Colombier {
648e32b400SDavid du Colombier 	CMhalt,		"halt",		1,
658e32b400SDavid du Colombier 	CMreboot,	"reboot",	0,
668e32b400SDavid du Colombier 	CMpanic,	"panic",	0,
678e32b400SDavid du Colombier };
688e32b400SDavid du Colombier 
698e32b400SDavid du Colombier void
printinit(void)708e32b400SDavid du Colombier printinit(void)
718e32b400SDavid du Colombier {
728e32b400SDavid du Colombier 	lineq = qopen(2*1024, 0, nil, nil);
738e32b400SDavid du Colombier 	if(lineq == nil)
748e32b400SDavid du Colombier 		panic("printinit");
758e32b400SDavid du Colombier 	qnoblock(lineq, 1);
768e32b400SDavid du Colombier }
778e32b400SDavid du Colombier 
788e32b400SDavid du Colombier int
consactive(void)798e32b400SDavid du Colombier consactive(void)
808e32b400SDavid du Colombier {
818e32b400SDavid du Colombier 	if(serialoq)
828e32b400SDavid du Colombier 		return qlen(serialoq) > 0;
838e32b400SDavid du Colombier 	return 0;
848e32b400SDavid du Colombier }
858e32b400SDavid du Colombier 
868e32b400SDavid du Colombier void
prflush(void)878e32b400SDavid du Colombier prflush(void)
888e32b400SDavid du Colombier {
898e32b400SDavid du Colombier 	ulong now;
908e32b400SDavid du Colombier 
918e32b400SDavid du Colombier 	now = m->ticks;
928e32b400SDavid du Colombier 	while(consactive())
938e32b400SDavid du Colombier 		if(m->ticks - now >= HZ)
948e32b400SDavid du Colombier 			break;
958e32b400SDavid du Colombier }
968e32b400SDavid du Colombier 
978e32b400SDavid du Colombier /*
988e32b400SDavid du Colombier  * Log console output so it can be retrieved via /dev/kmesg.
998e32b400SDavid du Colombier  * This is good for catching boot-time messages after the fact.
1008e32b400SDavid du Colombier  */
1018e32b400SDavid du Colombier struct {
1028e32b400SDavid du Colombier 	Lock lk;
103*e5a0fbb7SDavid du Colombier 	char buf[KMESGSIZE];
1048e32b400SDavid du Colombier 	uint n;
1058e32b400SDavid du Colombier } kmesg;
1068e32b400SDavid du Colombier 
1078e32b400SDavid du Colombier static void
kmesgputs(char * str,int n)1088e32b400SDavid du Colombier kmesgputs(char *str, int n)
1098e32b400SDavid du Colombier {
1108e32b400SDavid du Colombier 	uint nn, d;
1118e32b400SDavid du Colombier 
1128e32b400SDavid du Colombier 	ilock(&kmesg.lk);
1138e32b400SDavid du Colombier 	/* take the tail of huge writes */
1148e32b400SDavid du Colombier 	if(n > sizeof kmesg.buf){
1158e32b400SDavid du Colombier 		d = n - sizeof kmesg.buf;
1168e32b400SDavid du Colombier 		str += d;
1178e32b400SDavid du Colombier 		n -= d;
1188e32b400SDavid du Colombier 	}
1198e32b400SDavid du Colombier 
1208e32b400SDavid du Colombier 	/* slide the buffer down to make room */
1218e32b400SDavid du Colombier 	nn = kmesg.n;
1228e32b400SDavid du Colombier 	if(nn + n >= sizeof kmesg.buf){
1238e32b400SDavid du Colombier 		d = nn + n - sizeof kmesg.buf;
1248e32b400SDavid du Colombier 		if(d)
1258e32b400SDavid du Colombier 			memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
1268e32b400SDavid du Colombier 		nn -= d;
1278e32b400SDavid du Colombier 	}
1288e32b400SDavid du Colombier 
1298e32b400SDavid du Colombier 	/* copy the data in */
1308e32b400SDavid du Colombier 	memmove(kmesg.buf+nn, str, n);
1318e32b400SDavid du Colombier 	nn += n;
1328e32b400SDavid du Colombier 	kmesg.n = nn;
1338e32b400SDavid du Colombier 	iunlock(&kmesg.lk);
1348e32b400SDavid du Colombier }
1358e32b400SDavid du Colombier 
1368e32b400SDavid du Colombier /*
1378e32b400SDavid du Colombier  *   Print a string on the console.  Convert \n to \r\n for serial
1388e32b400SDavid du Colombier  *   line consoles.  Locking of the queues is left up to the screen
1398e32b400SDavid du Colombier  *   or uart code.  Multi-line messages to serial consoles may get
1408e32b400SDavid du Colombier  *   interspersed with other messages.
1418e32b400SDavid du Colombier  */
1428e32b400SDavid du Colombier static void
putstrn0(char * str,int n,int usewrite)1438e32b400SDavid du Colombier putstrn0(char *str, int n, int usewrite)
1448e32b400SDavid du Colombier {
1458e32b400SDavid du Colombier 	int m;
1468e32b400SDavid du Colombier 	char *t;
1478e32b400SDavid du Colombier 
1488e32b400SDavid du Colombier 	if(!islo())
1498e32b400SDavid du Colombier 		usewrite = 0;
1508e32b400SDavid du Colombier 
1518e32b400SDavid du Colombier 	/*
1528e32b400SDavid du Colombier 	 *  how many different output devices do we need?
1538e32b400SDavid du Colombier 	 */
1548e32b400SDavid du Colombier 	kmesgputs(str, n);
1558e32b400SDavid du Colombier 
1568e32b400SDavid du Colombier 	/*
1578e32b400SDavid du Colombier 	 *  if someone is reading /dev/kprint,
1588e32b400SDavid du Colombier 	 *  put the message there.
1598e32b400SDavid du Colombier 	 *  if not and there's an attached bit mapped display,
1608e32b400SDavid du Colombier 	 *  put the message there.
1618e32b400SDavid du Colombier 	 *
1628e32b400SDavid du Colombier 	 *  if there's a serial line being used as a console,
1638e32b400SDavid du Colombier 	 *  put the message there.
1648e32b400SDavid du Colombier 	 */
1658e32b400SDavid du Colombier 	if(kprintoq != nil && !qisclosed(kprintoq)){
1668e32b400SDavid du Colombier 		if(usewrite)
1678e32b400SDavid du Colombier 			qwrite(kprintoq, str, n);
1688e32b400SDavid du Colombier 		else
1698e32b400SDavid du Colombier 			qiwrite(kprintoq, str, n);
1708e32b400SDavid du Colombier 	}else if(screenputs != nil)
1718e32b400SDavid du Colombier 		screenputs(str, n);
1728e32b400SDavid du Colombier 
1738e32b400SDavid du Colombier 	if(serialoq == nil){
1748e32b400SDavid du Colombier 		uartputs(str, n);
1758e32b400SDavid du Colombier 		return;
1768e32b400SDavid du Colombier 	}
1778e32b400SDavid du Colombier 
1788e32b400SDavid du Colombier 	while(n > 0) {
1798e32b400SDavid du Colombier 		t = memchr(str, '\n', n);
1808e32b400SDavid du Colombier 		if(t && !kbd.raw) {
1818e32b400SDavid du Colombier 			m = t-str;
1828e32b400SDavid du Colombier 			if(usewrite){
1838e32b400SDavid du Colombier 				qwrite(serialoq, str, m);
1848e32b400SDavid du Colombier 				qwrite(serialoq, "\r\n", 2);
1858e32b400SDavid du Colombier 			} else {
1868e32b400SDavid du Colombier 				qiwrite(serialoq, str, m);
1878e32b400SDavid du Colombier 				qiwrite(serialoq, "\r\n", 2);
1888e32b400SDavid du Colombier 			}
1898e32b400SDavid du Colombier 			n -= m+1;
1908e32b400SDavid du Colombier 			str = t+1;
1918e32b400SDavid du Colombier 		} else {
1928e32b400SDavid du Colombier 			if(usewrite)
1938e32b400SDavid du Colombier 				qwrite(serialoq, str, n);
1948e32b400SDavid du Colombier 			else
1958e32b400SDavid du Colombier 				qiwrite(serialoq, str, n);
1968e32b400SDavid du Colombier 			break;
1978e32b400SDavid du Colombier 		}
1988e32b400SDavid du Colombier 	}
1998e32b400SDavid du Colombier }
2008e32b400SDavid du Colombier 
2018e32b400SDavid du Colombier void
putstrn(char * str,int n)2028e32b400SDavid du Colombier putstrn(char *str, int n)
2038e32b400SDavid du Colombier {
2048e32b400SDavid du Colombier 	putstrn0(str, n, 0);
2058e32b400SDavid du Colombier }
2068e32b400SDavid du Colombier 
2078e32b400SDavid du Colombier int noprint;
2088e32b400SDavid du Colombier 
2098e32b400SDavid du Colombier int
print(char * fmt,...)2108e32b400SDavid du Colombier print(char *fmt, ...)
2118e32b400SDavid du Colombier {
2128e32b400SDavid du Colombier 	int n;
2138e32b400SDavid du Colombier 	va_list arg;
2148e32b400SDavid du Colombier 	char buf[PRINTSIZE];
2158e32b400SDavid du Colombier 
2168e32b400SDavid du Colombier 	if(noprint)
2178e32b400SDavid du Colombier 		return -1;
2188e32b400SDavid du Colombier 
2198e32b400SDavid du Colombier 	va_start(arg, fmt);
2208e32b400SDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
2218e32b400SDavid du Colombier 	va_end(arg);
22293631029SDavid du Colombier 
22393631029SDavid du Colombier 	if(!normalprint) {
22493631029SDavid du Colombier 		if(0) iprint("\nprint called too early from %#lux\n",
22593631029SDavid du Colombier 			getcallerpc(&fmt));
22693631029SDavid du Colombier 		iprint("%.*s", n, buf);
22793631029SDavid du Colombier 	} else
2288e32b400SDavid du Colombier 		putstrn(buf, n);
2298e32b400SDavid du Colombier 
2308e32b400SDavid du Colombier 	return n;
2318e32b400SDavid du Colombier }
2328e32b400SDavid du Colombier 
2338e32b400SDavid du Colombier /*
2348e32b400SDavid du Colombier  * Want to interlock iprints to avoid interlaced output on
2358e32b400SDavid du Colombier  * multiprocessor, but don't want to deadlock if one processor
2368e32b400SDavid du Colombier  * dies during print and another has something important to say.
2378e32b400SDavid du Colombier  * Make a good faith effort.
2388e32b400SDavid du Colombier  */
2398e32b400SDavid du Colombier static Lock iprintlock;
2408e32b400SDavid du Colombier static int
iprintcanlock(Lock * l)2418e32b400SDavid du Colombier iprintcanlock(Lock *l)
2428e32b400SDavid du Colombier {
2438e32b400SDavid du Colombier 	int i;
2448e32b400SDavid du Colombier 
2458e32b400SDavid du Colombier 	for(i=0; i<1000; i++){
2468e32b400SDavid du Colombier 		if(canlock(l))
2478e32b400SDavid du Colombier 			return 1;
2488e32b400SDavid du Colombier 		if(l->m == MACHP(m->machno))
2498e32b400SDavid du Colombier 			return 0;
2508e32b400SDavid du Colombier 		microdelay(100);
2518e32b400SDavid du Colombier 	}
2528e32b400SDavid du Colombier 	return 0;
2538e32b400SDavid du Colombier }
2548e32b400SDavid du Colombier 
2558e32b400SDavid du Colombier int
iprint(char * fmt,...)2568e32b400SDavid du Colombier iprint(char *fmt, ...)
2578e32b400SDavid du Colombier {
2588e32b400SDavid du Colombier 	int n, s, locked;
2598e32b400SDavid du Colombier 	va_list arg;
2608e32b400SDavid du Colombier 	char buf[PRINTSIZE];
2618e32b400SDavid du Colombier 
2628e32b400SDavid du Colombier 	s = splhi();
2638e32b400SDavid du Colombier 	va_start(arg, fmt);
2648e32b400SDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
2658e32b400SDavid du Colombier 	va_end(arg);
2668e32b400SDavid du Colombier 	locked = iprintcanlock(&iprintlock);
2678e32b400SDavid du Colombier 	if(screenputs != nil && iprintscreenputs)
2688e32b400SDavid du Colombier 		screenputs(buf, n);
26993631029SDavid du Colombier 	if(consuart == nil || consuart->phys == nil ||
27093631029SDavid du Colombier 	    consuart->phys->putc == nil)
27193631029SDavid du Colombier 		_uartputs(buf, n);
27293631029SDavid du Colombier 	else
2738e32b400SDavid du Colombier 		uartputs(buf, n);
2748e32b400SDavid du Colombier 	if(locked)
2758e32b400SDavid du Colombier 		unlock(&iprintlock);
2768e32b400SDavid du Colombier 	splx(s);
2778e32b400SDavid du Colombier 
2788e32b400SDavid du Colombier 	return n;
2798e32b400SDavid du Colombier }
2808e32b400SDavid du Colombier 
2818e32b400SDavid du Colombier void
panic(char * fmt,...)2828e32b400SDavid du Colombier panic(char *fmt, ...)
2838e32b400SDavid du Colombier {
2848e32b400SDavid du Colombier 	int n, s;
2858e32b400SDavid du Colombier 	va_list arg;
2868e32b400SDavid du Colombier 	char buf[PRINTSIZE];
2878e32b400SDavid du Colombier 
2888e32b400SDavid du Colombier 	kprintoq = nil;	/* don't try to write to /dev/kprint */
2898e32b400SDavid du Colombier 
2908e32b400SDavid du Colombier 	if(panicking)
2918e32b400SDavid du Colombier 		for(;;);
2928e32b400SDavid du Colombier 	panicking = 1;
2938e32b400SDavid du Colombier 
2948e32b400SDavid du Colombier 	delay(20);
2958e32b400SDavid du Colombier 	s = splhi();
2968e32b400SDavid du Colombier 	strcpy(buf, "panic: ");
2978e32b400SDavid du Colombier 	va_start(arg, fmt);
2988e32b400SDavid du Colombier 	n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
2998e32b400SDavid du Colombier 	va_end(arg);
3008e32b400SDavid du Colombier 	iprint("%s\n", buf);
3018e32b400SDavid du Colombier 	if(consdebug)
3028e32b400SDavid du Colombier 		(*consdebug)();
3038e32b400SDavid du Colombier 	splx(s);
3048e32b400SDavid du Colombier 	prflush();
3058e32b400SDavid du Colombier 	buf[n] = '\n';
306047f1f95SDavid du Colombier //	putstrn(buf, n+1);
307047f1f95SDavid du Colombier //	dumpstack();
3088e32b400SDavid du Colombier 
3098e32b400SDavid du Colombier 	exit(1);
3108e32b400SDavid du Colombier }
3118e32b400SDavid du Colombier 
3128e32b400SDavid du Colombier /* libmp at least contains a few calls to sysfatal; simulate with panic */
3138e32b400SDavid du Colombier void
sysfatal(char * fmt,...)3148e32b400SDavid du Colombier sysfatal(char *fmt, ...)
3158e32b400SDavid du Colombier {
3168e32b400SDavid du Colombier 	char err[256];
3178e32b400SDavid du Colombier 	va_list arg;
3188e32b400SDavid du Colombier 
3198e32b400SDavid du Colombier 	va_start(arg, fmt);
3208e32b400SDavid du Colombier 	vseprint(err, err + sizeof err, fmt, arg);
3218e32b400SDavid du Colombier 	va_end(arg);
3228e32b400SDavid du Colombier 	panic("sysfatal: %s", err);
3238e32b400SDavid du Colombier }
3248e32b400SDavid du Colombier 
3258e32b400SDavid du Colombier void
_assert(char * fmt)3268e32b400SDavid du Colombier _assert(char *fmt)
3278e32b400SDavid du Colombier {
3288e32b400SDavid du Colombier 	panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
3298e32b400SDavid du Colombier }
3308e32b400SDavid du Colombier 
3318e32b400SDavid du Colombier int
pprint(char * fmt,...)3328e32b400SDavid du Colombier pprint(char *fmt, ...)
3338e32b400SDavid du Colombier {
3348e32b400SDavid du Colombier 	int n;
3358e32b400SDavid du Colombier 	Chan *c;
3368e32b400SDavid du Colombier 	va_list arg;
3378e32b400SDavid du Colombier 	char buf[2*PRINTSIZE];
3388e32b400SDavid du Colombier 
3398e32b400SDavid du Colombier 	if(up == nil || up->fgrp == nil)
3408e32b400SDavid du Colombier 		return 0;
3418e32b400SDavid du Colombier 
3428e32b400SDavid du Colombier 	c = up->fgrp->fd[2];
3438e32b400SDavid du Colombier 	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
3448e32b400SDavid du Colombier 		return 0;
3458e32b400SDavid du Colombier 	n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
3468e32b400SDavid du Colombier 	va_start(arg, fmt);
3478e32b400SDavid du Colombier 	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
3488e32b400SDavid du Colombier 	va_end(arg);
3498e32b400SDavid du Colombier 
3508e32b400SDavid du Colombier 	if(waserror())
3518e32b400SDavid du Colombier 		return 0;
3528e32b400SDavid du Colombier 	devtab[c->type]->write(c, buf, n, c->offset);
3538e32b400SDavid du Colombier 	poperror();
3548e32b400SDavid du Colombier 
3558e32b400SDavid du Colombier 	lock(c);
3568e32b400SDavid du Colombier 	c->offset += n;
3578e32b400SDavid du Colombier 	unlock(c);
3588e32b400SDavid du Colombier 
3598e32b400SDavid du Colombier 	return n;
3608e32b400SDavid du Colombier }
3618e32b400SDavid du Colombier 
3628e32b400SDavid du Colombier static void
echoscreen(char * buf,int n)3638e32b400SDavid du Colombier echoscreen(char *buf, int n)
3648e32b400SDavid du Colombier {
3658e32b400SDavid du Colombier 	char *e, *p;
3668e32b400SDavid du Colombier 	char ebuf[128];
3678e32b400SDavid du Colombier 	int x;
3688e32b400SDavid du Colombier 
3698e32b400SDavid du Colombier 	p = ebuf;
3708e32b400SDavid du Colombier 	e = ebuf + sizeof(ebuf) - 4;
3718e32b400SDavid du Colombier 	while(n-- > 0){
3728e32b400SDavid du Colombier 		if(p >= e){
3738e32b400SDavid du Colombier 			screenputs(ebuf, p - ebuf);
3748e32b400SDavid du Colombier 			p = ebuf;
3758e32b400SDavid du Colombier 		}
3768e32b400SDavid du Colombier 		x = *buf++;
3778e32b400SDavid du Colombier 		if(x == 0x15){
3788e32b400SDavid du Colombier 			*p++ = '^';
3798e32b400SDavid du Colombier 			*p++ = 'U';
3808e32b400SDavid du Colombier 			*p++ = '\n';
3818e32b400SDavid du Colombier 		} else
3828e32b400SDavid du Colombier 			*p++ = x;
3838e32b400SDavid du Colombier 	}
3848e32b400SDavid du Colombier 	if(p != ebuf)
3858e32b400SDavid du Colombier 		screenputs(ebuf, p - ebuf);
3868e32b400SDavid du Colombier }
3878e32b400SDavid du Colombier 
3888e32b400SDavid du Colombier static void
echoserialoq(char * buf,int n)3898e32b400SDavid du Colombier echoserialoq(char *buf, int n)
3908e32b400SDavid du Colombier {
3918e32b400SDavid du Colombier 	int x;
3928e32b400SDavid du Colombier 	char *e, *p;
3938e32b400SDavid du Colombier 	char ebuf[128];
3948e32b400SDavid du Colombier 
3958e32b400SDavid du Colombier 	p = ebuf;
3968e32b400SDavid du Colombier 	e = ebuf + sizeof(ebuf) - 4;
3978e32b400SDavid du Colombier 	while(n-- > 0){
3988e32b400SDavid du Colombier 		if(p >= e){
3998e32b400SDavid du Colombier 			qiwrite(serialoq, ebuf, p - ebuf);
4008e32b400SDavid du Colombier 			p = ebuf;
4018e32b400SDavid du Colombier 		}
4028e32b400SDavid du Colombier 		x = *buf++;
4038e32b400SDavid du Colombier 		if(x == '\n'){
4048e32b400SDavid du Colombier 			*p++ = '\r';
4058e32b400SDavid du Colombier 			*p++ = '\n';
4068e32b400SDavid du Colombier 		} else if(x == 0x15){
4078e32b400SDavid du Colombier 			*p++ = '^';
4088e32b400SDavid du Colombier 			*p++ = 'U';
4098e32b400SDavid du Colombier 			*p++ = '\n';
4108e32b400SDavid du Colombier 		} else
4118e32b400SDavid du Colombier 			*p++ = x;
4128e32b400SDavid du Colombier 	}
4138e32b400SDavid du Colombier 	if(p != ebuf)
4148e32b400SDavid du Colombier 		qiwrite(serialoq, ebuf, p - ebuf);
4158e32b400SDavid du Colombier }
4168e32b400SDavid du Colombier 
4178e32b400SDavid du Colombier static void
echo(char * buf,int n)4188e32b400SDavid du Colombier echo(char *buf, int n)
4198e32b400SDavid du Colombier {
4208e32b400SDavid du Colombier 	static int ctrlt, pid;
4218e32b400SDavid du Colombier 	int x;
4228e32b400SDavid du Colombier 	char *e, *p;
4238e32b400SDavid du Colombier 
4248e32b400SDavid du Colombier 	if(n == 0)
4258e32b400SDavid du Colombier 		return;
4268e32b400SDavid du Colombier 
4278e32b400SDavid du Colombier 	e = buf+n;
4288e32b400SDavid du Colombier 	for(p = buf; p < e; p++){
4298e32b400SDavid du Colombier 		switch(*p){
4308e32b400SDavid du Colombier 		case 0x10:	/* ^P */
4318e32b400SDavid du Colombier 			if(cpuserver && !kbd.ctlpoff){
4328e32b400SDavid du Colombier 				active.exiting = 1;
4338e32b400SDavid du Colombier 				return;
4348e32b400SDavid du Colombier 			}
4358e32b400SDavid du Colombier 			break;
4368e32b400SDavid du Colombier 		case 0x14:	/* ^T */
4378e32b400SDavid du Colombier 			ctrlt++;
4388e32b400SDavid du Colombier 			if(ctrlt > 2)
4398e32b400SDavid du Colombier 				ctrlt = 2;
4408e32b400SDavid du Colombier 			continue;
4418e32b400SDavid du Colombier 		}
4428e32b400SDavid du Colombier 
4438e32b400SDavid du Colombier 		if(ctrlt != 2)
4448e32b400SDavid du Colombier 			continue;
4458e32b400SDavid du Colombier 
4468e32b400SDavid du Colombier 		/* ^T escapes */
4478e32b400SDavid du Colombier 		ctrlt = 0;
4488e32b400SDavid du Colombier 		switch(*p){
4498e32b400SDavid du Colombier 		case 'S':
4508e32b400SDavid du Colombier 			x = splhi();
4518e32b400SDavid du Colombier 			dumpstack();
4528e32b400SDavid du Colombier 			procdump();
4538e32b400SDavid du Colombier 			splx(x);
4548e32b400SDavid du Colombier 			return;
4558e32b400SDavid du Colombier 		case 's':
4568e32b400SDavid du Colombier 			dumpstack();
4578e32b400SDavid du Colombier 			return;
4588e32b400SDavid du Colombier 		case 'x':
4598e32b400SDavid du Colombier 			xsummary();
4608e32b400SDavid du Colombier 			ixsummary();
4618e32b400SDavid du Colombier 			mallocsummary();
4628e32b400SDavid du Colombier 		//	memorysummary();
4638e32b400SDavid du Colombier 			pagersummary();
4648e32b400SDavid du Colombier 			return;
4658e32b400SDavid du Colombier 		case 'd':
4668e32b400SDavid du Colombier 			if(consdebug == nil)
4678e32b400SDavid du Colombier 				consdebug = rdb;
4688e32b400SDavid du Colombier 			else
4698e32b400SDavid du Colombier 				consdebug = nil;
4708e32b400SDavid du Colombier 			print("consdebug now %#p\n", consdebug);
4718e32b400SDavid du Colombier 			return;
4728e32b400SDavid du Colombier 		case 'D':
4738e32b400SDavid du Colombier 			if(consdebug == nil)
4748e32b400SDavid du Colombier 				consdebug = rdb;
4758e32b400SDavid du Colombier 			consdebug();
4768e32b400SDavid du Colombier 			return;
4778e32b400SDavid du Colombier 		case 'p':
4788e32b400SDavid du Colombier 			x = spllo();
4798e32b400SDavid du Colombier 			procdump();
4808e32b400SDavid du Colombier 			splx(x);
4818e32b400SDavid du Colombier 			return;
4828e32b400SDavid du Colombier 		case 'q':
4838e32b400SDavid du Colombier 			scheddump();
4848e32b400SDavid du Colombier 			return;
4858e32b400SDavid du Colombier 		case 'k':
4868e32b400SDavid du Colombier 			killbig("^t ^t k");
4878e32b400SDavid du Colombier 			return;
4888e32b400SDavid du Colombier 		case 'r':
4898e32b400SDavid du Colombier 			exit(0);
4908e32b400SDavid du Colombier 			return;
4918e32b400SDavid du Colombier 		}
4928e32b400SDavid du Colombier 	}
4938e32b400SDavid du Colombier 
4948e32b400SDavid du Colombier 	qproduce(kbdq, buf, n);
4958e32b400SDavid du Colombier 	if(kbd.raw)
4968e32b400SDavid du Colombier 		return;
4978e32b400SDavid du Colombier 	kmesgputs(buf, n);
4988e32b400SDavid du Colombier 	if(screenputs != nil)
4998e32b400SDavid du Colombier 		echoscreen(buf, n);
5008e32b400SDavid du Colombier 	if(serialoq)
5018e32b400SDavid du Colombier 		echoserialoq(buf, n);
5028e32b400SDavid du Colombier }
5038e32b400SDavid du Colombier 
5048e32b400SDavid du Colombier /*
5058e32b400SDavid du Colombier  *  Called by a uart interrupt for console input.
5068e32b400SDavid du Colombier  *
5078e32b400SDavid du Colombier  *  turn '\r' into '\n' before putting it into the queue.
5088e32b400SDavid du Colombier  */
5098e32b400SDavid du Colombier int
kbdcr2nl(Queue *,int ch)5108e32b400SDavid du Colombier kbdcr2nl(Queue*, int ch)
5118e32b400SDavid du Colombier {
5128e32b400SDavid du Colombier 	char *next;
5138e32b400SDavid du Colombier 
5148e32b400SDavid du Colombier 	ilock(&kbd.lockputc);		/* just a mutex */
5158e32b400SDavid du Colombier 	if(ch == '\r' && !kbd.raw)
5168e32b400SDavid du Colombier 		ch = '\n';
5178e32b400SDavid du Colombier 	next = kbd.iw+1;
5188e32b400SDavid du Colombier 	if(next >= kbd.ie)
5198e32b400SDavid du Colombier 		next = kbd.istage;
5208e32b400SDavid du Colombier 	if(next != kbd.ir){
5218e32b400SDavid du Colombier 		*kbd.iw = ch;
5228e32b400SDavid du Colombier 		kbd.iw = next;
5238e32b400SDavid du Colombier 	}
5248e32b400SDavid du Colombier 	iunlock(&kbd.lockputc);
5258e32b400SDavid du Colombier 	return 0;
5268e32b400SDavid du Colombier }
5278e32b400SDavid du Colombier 
5288e32b400SDavid du Colombier /*
5298e32b400SDavid du Colombier  *  Put character, possibly a rune, into read queue at interrupt time.
5308e32b400SDavid du Colombier  *  Called at interrupt time to process a character.
5318e32b400SDavid du Colombier  */
5328e32b400SDavid du Colombier int
kbdputc(Queue *,int ch)5338e32b400SDavid du Colombier kbdputc(Queue*, int ch)
5348e32b400SDavid du Colombier {
5358e32b400SDavid du Colombier 	int i, n;
5368e32b400SDavid du Colombier 	char buf[3];
5378e32b400SDavid du Colombier 	Rune r;
5388e32b400SDavid du Colombier 	char *next;
5398e32b400SDavid du Colombier 
5408e32b400SDavid du Colombier 	if(kbd.ir == nil)
5418e32b400SDavid du Colombier 		return 0;		/* in case we're not inited yet */
5428e32b400SDavid du Colombier 
5438e32b400SDavid du Colombier 	ilock(&kbd.lockputc);		/* just a mutex */
5448e32b400SDavid du Colombier 	r = ch;
5458e32b400SDavid du Colombier 	n = runetochar(buf, &r);
5468e32b400SDavid du Colombier 	for(i = 0; i < n; i++){
5478e32b400SDavid du Colombier 		next = kbd.iw+1;
5488e32b400SDavid du Colombier 		if(next >= kbd.ie)
5498e32b400SDavid du Colombier 			next = kbd.istage;
5508e32b400SDavid du Colombier 		if(next == kbd.ir)
5518e32b400SDavid du Colombier 			break;
5528e32b400SDavid du Colombier 		*kbd.iw = buf[i];
5538e32b400SDavid du Colombier 		kbd.iw = next;
5548e32b400SDavid du Colombier 	}
5558e32b400SDavid du Colombier 	iunlock(&kbd.lockputc);
5568e32b400SDavid du Colombier 	return 0;
5578e32b400SDavid du Colombier }
5588e32b400SDavid du Colombier 
5598e32b400SDavid du Colombier /*
5608e32b400SDavid du Colombier  *  we save up input characters till clock time to reduce
5618e32b400SDavid du Colombier  *  per character interrupt overhead.
5628e32b400SDavid du Colombier  */
5638e32b400SDavid du Colombier static void
kbdputcclock(void)5648e32b400SDavid du Colombier kbdputcclock(void)
5658e32b400SDavid du Colombier {
5668e32b400SDavid du Colombier 	char *iw;
5678e32b400SDavid du Colombier 
5688e32b400SDavid du Colombier 	/* this amortizes cost of qproduce */
5698e32b400SDavid du Colombier 	if(kbd.iw != kbd.ir){
5708e32b400SDavid du Colombier 		iw = kbd.iw;
5718e32b400SDavid du Colombier 		if(iw < kbd.ir){
5728e32b400SDavid du Colombier 			echo(kbd.ir, kbd.ie-kbd.ir);
5738e32b400SDavid du Colombier 			kbd.ir = kbd.istage;
5748e32b400SDavid du Colombier 		}
5758e32b400SDavid du Colombier 		if(kbd.ir != iw){
5768e32b400SDavid du Colombier 			echo(kbd.ir, iw-kbd.ir);
5778e32b400SDavid du Colombier 			kbd.ir = iw;
5788e32b400SDavid du Colombier 		}
5798e32b400SDavid du Colombier 	}
5808e32b400SDavid du Colombier }
5818e32b400SDavid du Colombier 
5828e32b400SDavid du Colombier enum{
5838e32b400SDavid du Colombier 	Qdir,
5848e32b400SDavid du Colombier 	Qbintime,
5858e32b400SDavid du Colombier 	Qcons,
5868e32b400SDavid du Colombier 	Qconsctl,
5878e32b400SDavid du Colombier 	Qcputime,
5888e32b400SDavid du Colombier 	Qdrivers,
5898e32b400SDavid du Colombier 	Qkmesg,
5908e32b400SDavid du Colombier 	Qkprint,
5918e32b400SDavid du Colombier 	Qhostdomain,
5928e32b400SDavid du Colombier 	Qhostowner,
5938e32b400SDavid du Colombier 	Qnull,
5948e32b400SDavid du Colombier 	Qosversion,
5958e32b400SDavid du Colombier 	Qpgrpid,
5968e32b400SDavid du Colombier 	Qpid,
5978e32b400SDavid du Colombier 	Qppid,
5988e32b400SDavid du Colombier 	Qrandom,
5998e32b400SDavid du Colombier 	Qreboot,
6008e32b400SDavid du Colombier 	Qswap,
6018e32b400SDavid du Colombier 	Qsysname,
6028e32b400SDavid du Colombier 	Qsysstat,
6038e32b400SDavid du Colombier 	Qtime,
6048e32b400SDavid du Colombier 	Quser,
6058e32b400SDavid du Colombier 	Qzero,
6068e32b400SDavid du Colombier };
6078e32b400SDavid du Colombier 
6088e32b400SDavid du Colombier enum
6098e32b400SDavid du Colombier {
6108e32b400SDavid du Colombier 	VLNUMSIZE=	22,
6118e32b400SDavid du Colombier };
6128e32b400SDavid du Colombier 
6138e32b400SDavid du Colombier static Dirtab consdir[]={
6148e32b400SDavid du Colombier 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
6158e32b400SDavid du Colombier 	"bintime",	{Qbintime},	24,		0664,
6168e32b400SDavid du Colombier 	"cons",		{Qcons},	0,		0660,
6178e32b400SDavid du Colombier 	"consctl",	{Qconsctl},	0,		0220,
6188e32b400SDavid du Colombier 	"cputime",	{Qcputime},	6*NUMSIZE,	0444,
6198e32b400SDavid du Colombier 	"drivers",	{Qdrivers},	0,		0444,
6208e32b400SDavid du Colombier 	"hostdomain",	{Qhostdomain},	DOMLEN,		0664,
6218e32b400SDavid du Colombier 	"hostowner",	{Qhostowner},	0,		0664,
6228e32b400SDavid du Colombier 	"kmesg",	{Qkmesg},	0,		0440,
6238e32b400SDavid du Colombier 	"kprint",	{Qkprint, 0, QTEXCL},	0,	DMEXCL|0440,
6248e32b400SDavid du Colombier 	"null",		{Qnull},	0,		0666,
6258e32b400SDavid du Colombier 	"osversion",	{Qosversion},	0,		0444,
6268e32b400SDavid du Colombier 	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444,
6278e32b400SDavid du Colombier 	"pid",		{Qpid},		NUMSIZE,	0444,
6288e32b400SDavid du Colombier 	"ppid",		{Qppid},	NUMSIZE,	0444,
6298e32b400SDavid du Colombier 	"random",	{Qrandom},	0,		0444,
6308e32b400SDavid du Colombier 	"reboot",	{Qreboot},	0,		0664,
6318e32b400SDavid du Colombier 	"swap",		{Qswap},	0,		0664,
6328e32b400SDavid du Colombier 	"sysname",	{Qsysname},	0,		0664,
6338e32b400SDavid du Colombier 	"sysstat",	{Qsysstat},	0,		0666,
6348e32b400SDavid du Colombier 	"time",		{Qtime},	NUMSIZE+3*VLNUMSIZE,	0664,
6358e32b400SDavid du Colombier 	"user",		{Quser},	0,		0666,
6368e32b400SDavid du Colombier 	"zero",		{Qzero},	0,		0444,
6378e32b400SDavid du Colombier };
6388e32b400SDavid du Colombier 
6398e32b400SDavid du Colombier int
readnum(ulong off,char * buf,ulong n,ulong val,int size)6408e32b400SDavid du Colombier readnum(ulong off, char *buf, ulong n, ulong val, int size)
6418e32b400SDavid du Colombier {
6428e32b400SDavid du Colombier 	char tmp[64];
6438e32b400SDavid du Colombier 
6448e32b400SDavid du Colombier 	snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
6458e32b400SDavid du Colombier 	tmp[size-1] = ' ';
6468e32b400SDavid du Colombier 	if(off >= size)
6478e32b400SDavid du Colombier 		return 0;
6488e32b400SDavid du Colombier 	if(off+n > size)
6498e32b400SDavid du Colombier 		n = size-off;
6508e32b400SDavid du Colombier 	memmove(buf, tmp+off, n);
6518e32b400SDavid du Colombier 	return n;
6528e32b400SDavid du Colombier }
6538e32b400SDavid du Colombier 
6548e32b400SDavid du Colombier int
readstr(ulong off,char * buf,ulong n,char * str)6558e32b400SDavid du Colombier readstr(ulong off, char *buf, ulong n, char *str)
6568e32b400SDavid du Colombier {
6578e32b400SDavid du Colombier 	int size;
6588e32b400SDavid du Colombier 
6598e32b400SDavid du Colombier 	size = strlen(str);
6608e32b400SDavid du Colombier 	if(off >= size)
6618e32b400SDavid du Colombier 		return 0;
6628e32b400SDavid du Colombier 	if(off+n > size)
6638e32b400SDavid du Colombier 		n = size-off;
6648e32b400SDavid du Colombier 	memmove(buf, str+off, n);
6658e32b400SDavid du Colombier 	return n;
6668e32b400SDavid du Colombier }
6678e32b400SDavid du Colombier 
6688e32b400SDavid du Colombier static void
consinit(void)6698e32b400SDavid du Colombier consinit(void)
6708e32b400SDavid du Colombier {
6718e32b400SDavid du Colombier 	todinit();
6728e32b400SDavid du Colombier 	randominit();
6738e32b400SDavid du Colombier 	/*
6748e32b400SDavid du Colombier 	 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
6758e32b400SDavid du Colombier 	 * processing it every 22 ms should be fine
6768e32b400SDavid du Colombier 	 */
6778e32b400SDavid du Colombier 	addclock0link(kbdputcclock, 22);
6788e32b400SDavid du Colombier }
6798e32b400SDavid du Colombier 
6808e32b400SDavid du Colombier static Chan*
consattach(char * spec)6818e32b400SDavid du Colombier consattach(char *spec)
6828e32b400SDavid du Colombier {
6838e32b400SDavid du Colombier 	return devattach('c', spec);
6848e32b400SDavid du Colombier }
6858e32b400SDavid du Colombier 
6868e32b400SDavid du Colombier static Walkqid*
conswalk(Chan * c,Chan * nc,char ** name,int nname)6878e32b400SDavid du Colombier conswalk(Chan *c, Chan *nc, char **name, int nname)
6888e32b400SDavid du Colombier {
6898e32b400SDavid du Colombier 	return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
6908e32b400SDavid du Colombier }
6918e32b400SDavid du Colombier 
6928e32b400SDavid du Colombier static int
consstat(Chan * c,uchar * dp,int n)6938e32b400SDavid du Colombier consstat(Chan *c, uchar *dp, int n)
6948e32b400SDavid du Colombier {
6958e32b400SDavid du Colombier 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
6968e32b400SDavid du Colombier }
6978e32b400SDavid du Colombier 
6988e32b400SDavid du Colombier static Chan*
consopen(Chan * c,int omode)6998e32b400SDavid du Colombier consopen(Chan *c, int omode)
7008e32b400SDavid du Colombier {
7018e32b400SDavid du Colombier 	c->aux = nil;
7028e32b400SDavid du Colombier 	c = devopen(c, omode, consdir, nelem(consdir), devgen);
7038e32b400SDavid du Colombier 	switch((ulong)c->qid.path){
7048e32b400SDavid du Colombier 	case Qconsctl:
7058e32b400SDavid du Colombier 		incref(&kbd.ctl);
7068e32b400SDavid du Colombier 		break;
7078e32b400SDavid du Colombier 
7088e32b400SDavid du Colombier 	case Qkprint:
7098e32b400SDavid du Colombier 		if(tas(&kprintinuse) != 0){
7108e32b400SDavid du Colombier 			c->flag &= ~COPEN;
7118e32b400SDavid du Colombier 			error(Einuse);
7128e32b400SDavid du Colombier 		}
7138e32b400SDavid du Colombier 		if(kprintoq == nil){
7148e32b400SDavid du Colombier 			kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
7158e32b400SDavid du Colombier 			if(kprintoq == nil){
7168e32b400SDavid du Colombier 				c->flag &= ~COPEN;
7178e32b400SDavid du Colombier 				error(Enomem);
7188e32b400SDavid du Colombier 			}
7198e32b400SDavid du Colombier 			qnoblock(kprintoq, 1);
7208e32b400SDavid du Colombier 		}else
7218e32b400SDavid du Colombier 			qreopen(kprintoq);
7228e32b400SDavid du Colombier 		c->iounit = qiomaxatomic;
7238e32b400SDavid du Colombier 		break;
7248e32b400SDavid du Colombier 	}
7258e32b400SDavid du Colombier 	return c;
7268e32b400SDavid du Colombier }
7278e32b400SDavid du Colombier 
7288e32b400SDavid du Colombier static void
consclose(Chan * c)7298e32b400SDavid du Colombier consclose(Chan *c)
7308e32b400SDavid du Colombier {
7318e32b400SDavid du Colombier 	switch((ulong)c->qid.path){
7328e32b400SDavid du Colombier 	/* last close of control file turns off raw */
7338e32b400SDavid du Colombier 	case Qconsctl:
7348e32b400SDavid du Colombier 		if(c->flag&COPEN){
7358e32b400SDavid du Colombier 			if(decref(&kbd.ctl) == 0)
7368e32b400SDavid du Colombier 				kbd.raw = 0;
7378e32b400SDavid du Colombier 		}
7388e32b400SDavid du Colombier 		break;
7398e32b400SDavid du Colombier 
7408e32b400SDavid du Colombier 	/* close of kprint allows other opens */
7418e32b400SDavid du Colombier 	case Qkprint:
7428e32b400SDavid du Colombier 		if(c->flag & COPEN){
7438e32b400SDavid du Colombier 			kprintinuse = 0;
7448e32b400SDavid du Colombier 			qhangup(kprintoq, nil);
7458e32b400SDavid du Colombier 		}
7468e32b400SDavid du Colombier 		break;
7478e32b400SDavid du Colombier 	}
7488e32b400SDavid du Colombier }
7498e32b400SDavid du Colombier 
7508e32b400SDavid du Colombier static long
consread(Chan * c,void * buf,long n,vlong off)7518e32b400SDavid du Colombier consread(Chan *c, void *buf, long n, vlong off)
7528e32b400SDavid du Colombier {
7538e32b400SDavid du Colombier 	ulong l;
7548e32b400SDavid du Colombier 	Mach *mp;
7558e32b400SDavid du Colombier 	char *b, *bp, ch;
7568e32b400SDavid du Colombier 	char tmp[256];		/* must be >= 18*NUMSIZE (Qswap) */
7578e32b400SDavid du Colombier 	int i, k, id, send;
7588e32b400SDavid du Colombier 	vlong offset = off;
7598e32b400SDavid du Colombier 
7608e32b400SDavid du Colombier 	if(n <= 0)
7618e32b400SDavid du Colombier 		return n;
7628e32b400SDavid du Colombier 
7638e32b400SDavid du Colombier 	switch((ulong)c->qid.path){
7648e32b400SDavid du Colombier 	case Qdir:
7658e32b400SDavid du Colombier 		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
7668e32b400SDavid du Colombier 
7678e32b400SDavid du Colombier 	case Qcons:
7688e32b400SDavid du Colombier 		qlock(&kbd);
7698e32b400SDavid du Colombier 		if(waserror()) {
7708e32b400SDavid du Colombier 			qunlock(&kbd);
7718e32b400SDavid du Colombier 			nexterror();
7728e32b400SDavid du Colombier 		}
7738e32b400SDavid du Colombier 		while(!qcanread(lineq)){
7748e32b400SDavid du Colombier 			if(qread(kbdq, &ch, 1) == 0)
7758e32b400SDavid du Colombier 				continue;
7768e32b400SDavid du Colombier 			send = 0;
7778e32b400SDavid du Colombier 			if(ch == 0){
7788e32b400SDavid du Colombier 				/* flush output on rawoff -> rawon */
7798e32b400SDavid du Colombier 				if(kbd.x > 0)
7808e32b400SDavid du Colombier 					send = !qcanread(kbdq);
7818e32b400SDavid du Colombier 			}else if(kbd.raw){
7828e32b400SDavid du Colombier 				kbd.line[kbd.x++] = ch;
7838e32b400SDavid du Colombier 				send = !qcanread(kbdq);
7848e32b400SDavid du Colombier 			}else{
7858e32b400SDavid du Colombier 				switch(ch){
7868e32b400SDavid du Colombier 				case '\b':
7878e32b400SDavid du Colombier 					if(kbd.x > 0)
7888e32b400SDavid du Colombier 						kbd.x--;
7898e32b400SDavid du Colombier 					break;
7908e32b400SDavid du Colombier 				case 0x15:	/* ^U */
7918e32b400SDavid du Colombier 					kbd.x = 0;
7928e32b400SDavid du Colombier 					break;
7938e32b400SDavid du Colombier 				case '\n':
7948e32b400SDavid du Colombier 				case 0x04:	/* ^D */
7958e32b400SDavid du Colombier 					send = 1;
7968e32b400SDavid du Colombier 				default:
7978e32b400SDavid du Colombier 					if(ch != 0x04)
7988e32b400SDavid du Colombier 						kbd.line[kbd.x++] = ch;
7998e32b400SDavid du Colombier 					break;
8008e32b400SDavid du Colombier 				}
8018e32b400SDavid du Colombier 			}
8028e32b400SDavid du Colombier 			if(send || kbd.x == sizeof kbd.line){
8038e32b400SDavid du Colombier 				qwrite(lineq, kbd.line, kbd.x);
8048e32b400SDavid du Colombier 				kbd.x = 0;
8058e32b400SDavid du Colombier 			}
8068e32b400SDavid du Colombier 		}
8078e32b400SDavid du Colombier 		n = qread(lineq, buf, n);
8088e32b400SDavid du Colombier 		qunlock(&kbd);
8098e32b400SDavid du Colombier 		poperror();
8108e32b400SDavid du Colombier 		return n;
8118e32b400SDavid du Colombier 
8128e32b400SDavid du Colombier 	case Qcputime:
8138e32b400SDavid du Colombier 		k = offset;
8148e32b400SDavid du Colombier 		if(k >= 6*NUMSIZE)
8158e32b400SDavid du Colombier 			return 0;
8168e32b400SDavid du Colombier 		if(k+n > 6*NUMSIZE)
8178e32b400SDavid du Colombier 			n = 6*NUMSIZE - k;
8188e32b400SDavid du Colombier 		/* easiest to format in a separate buffer and copy out */
8198e32b400SDavid du Colombier 		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
8208e32b400SDavid du Colombier 			l = up->time[i];
8218e32b400SDavid du Colombier 			if(i == TReal)
8228e32b400SDavid du Colombier 				l = MACHP(0)->ticks - l;
8238e32b400SDavid du Colombier 			l = TK2MS(l);
8248e32b400SDavid du Colombier 			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
8258e32b400SDavid du Colombier 		}
8268e32b400SDavid du Colombier 		memmove(buf, tmp+k, n);
8278e32b400SDavid du Colombier 		return n;
8288e32b400SDavid du Colombier 
8298e32b400SDavid du Colombier 	case Qkmesg:
8308e32b400SDavid du Colombier 		/*
8318e32b400SDavid du Colombier 		 * This is unlocked to avoid tying up a process
8328e32b400SDavid du Colombier 		 * that's writing to the buffer.  kmesg.n never
8338e32b400SDavid du Colombier 		 * gets smaller, so worst case the reader will
8348e32b400SDavid du Colombier 		 * see a slurred buffer.
8358e32b400SDavid du Colombier 		 */
8368e32b400SDavid du Colombier 		if(off >= kmesg.n)
8378e32b400SDavid du Colombier 			n = 0;
8388e32b400SDavid du Colombier 		else{
8398e32b400SDavid du Colombier 			if(off+n > kmesg.n)
8408e32b400SDavid du Colombier 				n = kmesg.n - off;
8418e32b400SDavid du Colombier 			memmove(buf, kmesg.buf+off, n);
8428e32b400SDavid du Colombier 		}
8438e32b400SDavid du Colombier 		return n;
8448e32b400SDavid du Colombier 
8458e32b400SDavid du Colombier 	case Qkprint:
8468e32b400SDavid du Colombier 		return qread(kprintoq, buf, n);
8478e32b400SDavid du Colombier 
8488e32b400SDavid du Colombier 	case Qpgrpid:
8498e32b400SDavid du Colombier 		return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
8508e32b400SDavid du Colombier 
8518e32b400SDavid du Colombier 	case Qpid:
8528e32b400SDavid du Colombier 		return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
8538e32b400SDavid du Colombier 
8548e32b400SDavid du Colombier 	case Qppid:
8558e32b400SDavid du Colombier 		return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
8568e32b400SDavid du Colombier 
8578e32b400SDavid du Colombier 	case Qtime:
8588e32b400SDavid du Colombier 		return readtime((ulong)offset, buf, n);
8598e32b400SDavid du Colombier 
8608e32b400SDavid du Colombier 	case Qbintime:
8618e32b400SDavid du Colombier 		return readbintime(buf, n);
8628e32b400SDavid du Colombier 
8638e32b400SDavid du Colombier 	case Qhostowner:
8648e32b400SDavid du Colombier 		return readstr((ulong)offset, buf, n, eve);
8658e32b400SDavid du Colombier 
8668e32b400SDavid du Colombier 	case Qhostdomain:
8678e32b400SDavid du Colombier 		return readstr((ulong)offset, buf, n, hostdomain);
8688e32b400SDavid du Colombier 
8698e32b400SDavid du Colombier 	case Quser:
8708e32b400SDavid du Colombier 		return readstr((ulong)offset, buf, n, up->user);
8718e32b400SDavid du Colombier 
8728e32b400SDavid du Colombier 	case Qnull:
8738e32b400SDavid du Colombier 		return 0;
8748e32b400SDavid du Colombier 
8758e32b400SDavid du Colombier 	case Qsysstat:
8768e32b400SDavid du Colombier 		b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1);	/* +1 for NUL */
8778e32b400SDavid du Colombier 		bp = b;
8788e32b400SDavid du Colombier 		for(id = 0; id < 32; id++) {
8798e32b400SDavid du Colombier 			if(active.machs & (1<<id)) {
8808e32b400SDavid du Colombier 				mp = MACHP(id);
8818e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, id, NUMSIZE);
8828e32b400SDavid du Colombier 				bp += NUMSIZE;
8838e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
8848e32b400SDavid du Colombier 				bp += NUMSIZE;
8858e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
8868e32b400SDavid du Colombier 				bp += NUMSIZE;
8878e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
8888e32b400SDavid du Colombier 				bp += NUMSIZE;
8898e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
8908e32b400SDavid du Colombier 				bp += NUMSIZE;
8918e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
8928e32b400SDavid du Colombier 				bp += NUMSIZE;
8938e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
8948e32b400SDavid du Colombier 				bp += NUMSIZE;
8958e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
8968e32b400SDavid du Colombier 				bp += NUMSIZE;
8978e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE,
8988e32b400SDavid du Colombier 					(mp->perf.avg_inidle*100)/mp->perf.period,
8998e32b400SDavid du Colombier 					NUMSIZE);
9008e32b400SDavid du Colombier 				bp += NUMSIZE;
9018e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE,
9028e32b400SDavid du Colombier 					(mp->perf.avg_inintr*100)/mp->perf.period,
9038e32b400SDavid du Colombier 					NUMSIZE);
9048e32b400SDavid du Colombier 				bp += NUMSIZE;
9058e32b400SDavid du Colombier 				*bp++ = '\n';
9068e32b400SDavid du Colombier 			}
9078e32b400SDavid du Colombier 		}
9088e32b400SDavid du Colombier 		if(waserror()){
9098e32b400SDavid du Colombier 			free(b);
9108e32b400SDavid du Colombier 			nexterror();
9118e32b400SDavid du Colombier 		}
9128e32b400SDavid du Colombier 		n = readstr((ulong)offset, buf, n, b);
9138e32b400SDavid du Colombier 		free(b);
9148e32b400SDavid du Colombier 		poperror();
9158e32b400SDavid du Colombier 		return n;
9168e32b400SDavid du Colombier 
9178e32b400SDavid du Colombier 	case Qswap:
9188e32b400SDavid du Colombier 		snprint(tmp, sizeof tmp,
9198e32b400SDavid du Colombier 			"%lud memory\n"
9208e32b400SDavid du Colombier 			"%d pagesize\n"
9218e32b400SDavid du Colombier 			"%lud kernel\n"
9228e32b400SDavid du Colombier 			"%lud/%lud user\n"
9238e32b400SDavid du Colombier 			"%lud/%lud swap\n"
9248e32b400SDavid du Colombier 			"%lud/%lud kernel malloc\n"
9258e32b400SDavid du Colombier 			"%lud/%lud kernel draw\n",
9268e32b400SDavid du Colombier 			conf.npage*BY2PG,
9278e32b400SDavid du Colombier 			BY2PG,
9288e32b400SDavid du Colombier 			conf.npage-conf.upages,
9298e32b400SDavid du Colombier 			palloc.user-palloc.freecount, palloc.user,
9308e32b400SDavid du Colombier 			conf.nswap-swapalloc.free, conf.nswap,
9318e32b400SDavid du Colombier 			mainmem->cursize, mainmem->maxsize,
9328e32b400SDavid du Colombier 			imagmem->cursize, imagmem->maxsize);
9338e32b400SDavid du Colombier 
9348e32b400SDavid du Colombier 		return readstr((ulong)offset, buf, n, tmp);
9358e32b400SDavid du Colombier 
9368e32b400SDavid du Colombier 	case Qsysname:
9378e32b400SDavid du Colombier 		if(sysname == nil)
9388e32b400SDavid du Colombier 			return 0;
9398e32b400SDavid du Colombier 		return readstr((ulong)offset, buf, n, sysname);
9408e32b400SDavid du Colombier 
9418e32b400SDavid du Colombier 	case Qrandom:
9428e32b400SDavid du Colombier 		return randomread(buf, n);
9438e32b400SDavid du Colombier 
9448e32b400SDavid du Colombier 	case Qdrivers:
9458e32b400SDavid du Colombier 		b = malloc(READSTR);
9468e32b400SDavid du Colombier 		if(b == nil)
9478e32b400SDavid du Colombier 			error(Enomem);
94893631029SDavid du Colombier 		k = 0;
9498e32b400SDavid du Colombier 		for(i = 0; devtab[i] != nil; i++)
95093631029SDavid du Colombier 			k += snprint(b+k, READSTR-k, "#%C %s\n",
95193631029SDavid du Colombier 				devtab[i]->dc,  devtab[i]->name);
9528e32b400SDavid du Colombier 		if(waserror()){
9538e32b400SDavid du Colombier 			free(b);
9548e32b400SDavid du Colombier 			nexterror();
9558e32b400SDavid du Colombier 		}
9568e32b400SDavid du Colombier 		n = readstr((ulong)offset, buf, n, b);
9578e32b400SDavid du Colombier 		free(b);
9588e32b400SDavid du Colombier 		poperror();
9598e32b400SDavid du Colombier 		return n;
9608e32b400SDavid du Colombier 
9618e32b400SDavid du Colombier 	case Qzero:
9628e32b400SDavid du Colombier 		memset(buf, 0, n);
9638e32b400SDavid du Colombier 		return n;
9648e32b400SDavid du Colombier 
9658e32b400SDavid du Colombier 	case Qosversion:
9668e32b400SDavid du Colombier 		snprint(tmp, sizeof tmp, "2000");
9678e32b400SDavid du Colombier 		n = readstr((ulong)offset, buf, n, tmp);
9688e32b400SDavid du Colombier 		return n;
9698e32b400SDavid du Colombier 
9708e32b400SDavid du Colombier 	default:
9718e32b400SDavid du Colombier 		print("consread %#llux\n", c->qid.path);
9728e32b400SDavid du Colombier 		error(Egreg);
9738e32b400SDavid du Colombier 	}
9748e32b400SDavid du Colombier 	return -1;		/* never reached */
9758e32b400SDavid du Colombier }
9768e32b400SDavid du Colombier 
9778e32b400SDavid du Colombier static long
conswrite(Chan * c,void * va,long n,vlong off)9788e32b400SDavid du Colombier conswrite(Chan *c, void *va, long n, vlong off)
9798e32b400SDavid du Colombier {
9808e32b400SDavid du Colombier 	char buf[256], ch;
9818e32b400SDavid du Colombier 	long l, bp;
9828e32b400SDavid du Colombier 	char *a;
9838e32b400SDavid du Colombier 	Mach *mp;
9848e32b400SDavid du Colombier 	int id, fd;
9858e32b400SDavid du Colombier 	Chan *swc;
9868e32b400SDavid du Colombier 	ulong offset;
9878e32b400SDavid du Colombier 	Cmdbuf *cb;
9888e32b400SDavid du Colombier 	Cmdtab *ct;
9898e32b400SDavid du Colombier 
9908e32b400SDavid du Colombier 	a = va;
9918e32b400SDavid du Colombier 	offset = off;
9928e32b400SDavid du Colombier 
9938e32b400SDavid du Colombier 	switch((ulong)c->qid.path){
9948e32b400SDavid du Colombier 	case Qcons:
9958e32b400SDavid du Colombier 		/*
9968e32b400SDavid du Colombier 		 * Can't page fault in putstrn, so copy the data locally.
9978e32b400SDavid du Colombier 		 */
9988e32b400SDavid du Colombier 		l = n;
9998e32b400SDavid du Colombier 		while(l > 0){
10008e32b400SDavid du Colombier 			bp = l;
10018e32b400SDavid du Colombier 			if(bp > sizeof buf)
10028e32b400SDavid du Colombier 				bp = sizeof buf;
10038e32b400SDavid du Colombier 			memmove(buf, a, bp);
10048e32b400SDavid du Colombier 			putstrn0(buf, bp, 1);
10058e32b400SDavid du Colombier 			a += bp;
10068e32b400SDavid du Colombier 			l -= bp;
10078e32b400SDavid du Colombier 		}
10088e32b400SDavid du Colombier 		break;
10098e32b400SDavid du Colombier 
10108e32b400SDavid du Colombier 	case Qconsctl:
10118e32b400SDavid du Colombier 		if(n >= sizeof(buf))
10128e32b400SDavid du Colombier 			n = sizeof(buf)-1;
10138e32b400SDavid du Colombier 		strncpy(buf, a, n);
10148e32b400SDavid du Colombier 		buf[n] = 0;
10158e32b400SDavid du Colombier 		for(a = buf; a;){
10168e32b400SDavid du Colombier 			if(strncmp(a, "rawon", 5) == 0){
10178e32b400SDavid du Colombier 				kbd.raw = 1;
10188e32b400SDavid du Colombier 				/* clumsy hack - wake up reader */
10198e32b400SDavid du Colombier 				ch = 0;
10208e32b400SDavid du Colombier 				qwrite(kbdq, &ch, 1);
10218e32b400SDavid du Colombier 			} else if(strncmp(a, "rawoff", 6) == 0){
10228e32b400SDavid du Colombier 				kbd.raw = 0;
10238e32b400SDavid du Colombier 			} else if(strncmp(a, "ctlpon", 6) == 0){
10248e32b400SDavid du Colombier 				kbd.ctlpoff = 0;
10258e32b400SDavid du Colombier 			} else if(strncmp(a, "ctlpoff", 7) == 0){
10268e32b400SDavid du Colombier 				kbd.ctlpoff = 1;
10278e32b400SDavid du Colombier 			}
10288e32b400SDavid du Colombier 			if(a = strchr(a, ' '))
10298e32b400SDavid du Colombier 				a++;
10308e32b400SDavid du Colombier 		}
10318e32b400SDavid du Colombier 		break;
10328e32b400SDavid du Colombier 
10338e32b400SDavid du Colombier 	case Qtime:
10348e32b400SDavid du Colombier 		if(!iseve())
10358e32b400SDavid du Colombier 			error(Eperm);
10368e32b400SDavid du Colombier 		return writetime(a, n);
10378e32b400SDavid du Colombier 
10388e32b400SDavid du Colombier 	case Qbintime:
10398e32b400SDavid du Colombier 		if(!iseve())
10408e32b400SDavid du Colombier 			error(Eperm);
10418e32b400SDavid du Colombier 		return writebintime(a, n);
10428e32b400SDavid du Colombier 
10438e32b400SDavid du Colombier 	case Qhostowner:
10448e32b400SDavid du Colombier 		return hostownerwrite(a, n);
10458e32b400SDavid du Colombier 
10468e32b400SDavid du Colombier 	case Qhostdomain:
10478e32b400SDavid du Colombier 		return hostdomainwrite(a, n);
10488e32b400SDavid du Colombier 
10498e32b400SDavid du Colombier 	case Quser:
10508e32b400SDavid du Colombier 		return userwrite(a, n);
10518e32b400SDavid du Colombier 
10528e32b400SDavid du Colombier 	case Qnull:
10538e32b400SDavid du Colombier 		break;
10548e32b400SDavid du Colombier 
10558e32b400SDavid du Colombier 	case Qreboot:
10568e32b400SDavid du Colombier 		if(!iseve())
10578e32b400SDavid du Colombier 			error(Eperm);
10588e32b400SDavid du Colombier 		cb = parsecmd(a, n);
10598e32b400SDavid du Colombier 
10608e32b400SDavid du Colombier 		if(waserror()) {
10618e32b400SDavid du Colombier 			free(cb);
10628e32b400SDavid du Colombier 			nexterror();
10638e32b400SDavid du Colombier 		}
10648e32b400SDavid du Colombier 		ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
10658e32b400SDavid du Colombier 		switch(ct->index) {
10668e32b400SDavid du Colombier 		case CMhalt:
10678e32b400SDavid du Colombier 			reboot(nil, 0, 0);
10688e32b400SDavid du Colombier 			break;
10698e32b400SDavid du Colombier 		case CMreboot:
10708e32b400SDavid du Colombier 			rebootcmd(cb->nf-1, cb->f+1);
10718e32b400SDavid du Colombier 			break;
10728e32b400SDavid du Colombier 		case CMpanic:
10738e32b400SDavid du Colombier 			*(ulong*)0=0;
10748e32b400SDavid du Colombier 			panic("/dev/reboot");
10758e32b400SDavid du Colombier 		}
10768e32b400SDavid du Colombier 		poperror();
10778e32b400SDavid du Colombier 		free(cb);
10788e32b400SDavid du Colombier 		break;
10798e32b400SDavid du Colombier 
10808e32b400SDavid du Colombier 	case Qsysstat:
10818e32b400SDavid du Colombier 		for(id = 0; id < 32; id++) {
10828e32b400SDavid du Colombier 			if(active.machs & (1<<id)) {
10838e32b400SDavid du Colombier 				mp = MACHP(id);
10848e32b400SDavid du Colombier 				mp->cs = 0;
10858e32b400SDavid du Colombier 				mp->intr = 0;
10868e32b400SDavid du Colombier 				mp->syscall = 0;
10878e32b400SDavid du Colombier 				mp->pfault = 0;
10888e32b400SDavid du Colombier 				mp->tlbfault = 0;
10898e32b400SDavid du Colombier 				mp->tlbpurge = 0;
10908e32b400SDavid du Colombier 			}
10918e32b400SDavid du Colombier 		}
10928e32b400SDavid du Colombier 		break;
10938e32b400SDavid du Colombier 
10948e32b400SDavid du Colombier 	case Qswap:
10958e32b400SDavid du Colombier 		if(n >= sizeof buf)
10968e32b400SDavid du Colombier 			error(Egreg);
10978e32b400SDavid du Colombier 		memmove(buf, va, n);	/* so we can NUL-terminate */
10988e32b400SDavid du Colombier 		buf[n] = 0;
10998e32b400SDavid du Colombier 		/* start a pager if not already started */
11008e32b400SDavid du Colombier 		if(strncmp(buf, "start", 5) == 0){
11018e32b400SDavid du Colombier 			kickpager();
11028e32b400SDavid du Colombier 			break;
11038e32b400SDavid du Colombier 		}
11048e32b400SDavid du Colombier 		if(!iseve())
11058e32b400SDavid du Colombier 			error(Eperm);
11068e32b400SDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0])
11078e32b400SDavid du Colombier 			error(Ebadarg);
11088e32b400SDavid du Colombier 		fd = strtoul(buf, 0, 0);
11098e32b400SDavid du Colombier 		swc = fdtochan(fd, -1, 1, 1);
11108e32b400SDavid du Colombier 		setswapchan(swc);
11118e32b400SDavid du Colombier 		break;
11128e32b400SDavid du Colombier 
11138e32b400SDavid du Colombier 	case Qsysname:
11148e32b400SDavid du Colombier 		if(offset != 0)
11158e32b400SDavid du Colombier 			error(Ebadarg);
11168e32b400SDavid du Colombier 		if(n <= 0 || n >= sizeof buf)
11178e32b400SDavid du Colombier 			error(Ebadarg);
11188e32b400SDavid du Colombier 		strncpy(buf, a, n);
11198e32b400SDavid du Colombier 		buf[n] = 0;
11208e32b400SDavid du Colombier 		if(buf[n-1] == '\n')
11218e32b400SDavid du Colombier 			buf[n-1] = 0;
11228e32b400SDavid du Colombier 		kstrdup(&sysname, buf);
11238e32b400SDavid du Colombier 		break;
11248e32b400SDavid du Colombier 
11258e32b400SDavid du Colombier 	default:
11268e32b400SDavid du Colombier 		print("conswrite: %#llux\n", c->qid.path);
11278e32b400SDavid du Colombier 		error(Egreg);
11288e32b400SDavid du Colombier 	}
11298e32b400SDavid du Colombier 	return n;
11308e32b400SDavid du Colombier }
11318e32b400SDavid du Colombier 
11328e32b400SDavid du Colombier Dev consdevtab = {
11338e32b400SDavid du Colombier 	'c',
11348e32b400SDavid du Colombier 	"cons",
11358e32b400SDavid du Colombier 
11368e32b400SDavid du Colombier 	devreset,
11378e32b400SDavid du Colombier 	consinit,
11388e32b400SDavid du Colombier 	devshutdown,
11398e32b400SDavid du Colombier 	consattach,
11408e32b400SDavid du Colombier 	conswalk,
11418e32b400SDavid du Colombier 	consstat,
11428e32b400SDavid du Colombier 	consopen,
11438e32b400SDavid du Colombier 	devcreate,
11448e32b400SDavid du Colombier 	consclose,
11458e32b400SDavid du Colombier 	consread,
11468e32b400SDavid du Colombier 	devbread,
11478e32b400SDavid du Colombier 	conswrite,
11488e32b400SDavid du Colombier 	devbwrite,
11498e32b400SDavid du Colombier 	devremove,
11508e32b400SDavid du Colombier 	devwstat,
11518e32b400SDavid du Colombier };
11528e32b400SDavid du Colombier 
11538e32b400SDavid du Colombier static	ulong	randn;
11548e32b400SDavid du Colombier 
11558e32b400SDavid du Colombier static void
seedrand(void)11568e32b400SDavid du Colombier seedrand(void)
11578e32b400SDavid du Colombier {
11588e32b400SDavid du Colombier 	if(!waserror()){
11598e32b400SDavid du Colombier 		randomread((void*)&randn, sizeof(randn));
11608e32b400SDavid du Colombier 		poperror();
11618e32b400SDavid du Colombier 	}
11628e32b400SDavid du Colombier }
11638e32b400SDavid du Colombier 
11648e32b400SDavid du Colombier int
nrand(int n)11658e32b400SDavid du Colombier nrand(int n)
11668e32b400SDavid du Colombier {
11678e32b400SDavid du Colombier 	if(randn == 0)
11688e32b400SDavid du Colombier 		seedrand();
11698e32b400SDavid du Colombier 	randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
11708e32b400SDavid du Colombier 	return (randn>>16) % n;
11718e32b400SDavid du Colombier }
11728e32b400SDavid du Colombier 
11738e32b400SDavid du Colombier int
rand(void)11748e32b400SDavid du Colombier rand(void)
11758e32b400SDavid du Colombier {
11768e32b400SDavid du Colombier 	nrand(1);
11778e32b400SDavid du Colombier 	return randn;
11788e32b400SDavid du Colombier }
11798e32b400SDavid du Colombier 
11808e32b400SDavid du Colombier static uvlong uvorder = 0x0001020304050607ULL;
11818e32b400SDavid du Colombier 
11828e32b400SDavid du Colombier static uchar*
le2vlong(vlong * to,uchar * f)11838e32b400SDavid du Colombier le2vlong(vlong *to, uchar *f)
11848e32b400SDavid du Colombier {
11858e32b400SDavid du Colombier 	uchar *t, *o;
11868e32b400SDavid du Colombier 	int i;
11878e32b400SDavid du Colombier 
11888e32b400SDavid du Colombier 	t = (uchar*)to;
11898e32b400SDavid du Colombier 	o = (uchar*)&uvorder;
11908e32b400SDavid du Colombier 	for(i = 0; i < sizeof(vlong); i++)
11918e32b400SDavid du Colombier 		t[o[i]] = f[i];
11928e32b400SDavid du Colombier 	return f+sizeof(vlong);
11938e32b400SDavid du Colombier }
11948e32b400SDavid du Colombier 
11958e32b400SDavid du Colombier static uchar*
vlong2le(uchar * t,vlong from)11968e32b400SDavid du Colombier vlong2le(uchar *t, vlong from)
11978e32b400SDavid du Colombier {
11988e32b400SDavid du Colombier 	uchar *f, *o;
11998e32b400SDavid du Colombier 	int i;
12008e32b400SDavid du Colombier 
12018e32b400SDavid du Colombier 	f = (uchar*)&from;
12028e32b400SDavid du Colombier 	o = (uchar*)&uvorder;
12038e32b400SDavid du Colombier 	for(i = 0; i < sizeof(vlong); i++)
12048e32b400SDavid du Colombier 		t[i] = f[o[i]];
12058e32b400SDavid du Colombier 	return t+sizeof(vlong);
12068e32b400SDavid du Colombier }
12078e32b400SDavid du Colombier 
12088e32b400SDavid du Colombier static long order = 0x00010203;
12098e32b400SDavid du Colombier 
12108e32b400SDavid du Colombier static uchar*
le2long(long * to,uchar * f)12118e32b400SDavid du Colombier le2long(long *to, uchar *f)
12128e32b400SDavid du Colombier {
12138e32b400SDavid du Colombier 	uchar *t, *o;
12148e32b400SDavid du Colombier 	int i;
12158e32b400SDavid du Colombier 
12168e32b400SDavid du Colombier 	t = (uchar*)to;
12178e32b400SDavid du Colombier 	o = (uchar*)&order;
12188e32b400SDavid du Colombier 	for(i = 0; i < sizeof(long); i++)
12198e32b400SDavid du Colombier 		t[o[i]] = f[i];
12208e32b400SDavid du Colombier 	return f+sizeof(long);
12218e32b400SDavid du Colombier }
12228e32b400SDavid du Colombier 
12238e32b400SDavid du Colombier static uchar*
long2le(uchar * t,long from)12248e32b400SDavid du Colombier long2le(uchar *t, long from)
12258e32b400SDavid du Colombier {
12268e32b400SDavid du Colombier 	uchar *f, *o;
12278e32b400SDavid du Colombier 	int i;
12288e32b400SDavid du Colombier 
12298e32b400SDavid du Colombier 	f = (uchar*)&from;
12308e32b400SDavid du Colombier 	o = (uchar*)&order;
12318e32b400SDavid du Colombier 	for(i = 0; i < sizeof(long); i++)
12328e32b400SDavid du Colombier 		t[i] = f[o[i]];
12338e32b400SDavid du Colombier 	return t+sizeof(long);
12348e32b400SDavid du Colombier }
12358e32b400SDavid du Colombier 
12368e32b400SDavid du Colombier char *Ebadtimectl = "bad time control";
12378e32b400SDavid du Colombier 
12388e32b400SDavid du Colombier /*
12398e32b400SDavid du Colombier  *  like the old #c/time but with added info.  Return
12408e32b400SDavid du Colombier  *
12418e32b400SDavid du Colombier  *	secs	nanosecs	fastticks	fasthz
12428e32b400SDavid du Colombier  */
12438e32b400SDavid du Colombier static int
readtime(ulong off,char * buf,int n)12448e32b400SDavid du Colombier readtime(ulong off, char *buf, int n)
12458e32b400SDavid du Colombier {
12468e32b400SDavid du Colombier 	vlong	nsec, ticks;
12478e32b400SDavid du Colombier 	long sec;
12488e32b400SDavid du Colombier 	char str[7*NUMSIZE];
12498e32b400SDavid du Colombier 
12508e32b400SDavid du Colombier 	nsec = todget(&ticks);
12518e32b400SDavid du Colombier 	if(fasthz == 0LL)
12528e32b400SDavid du Colombier 		fastticks((uvlong*)&fasthz);
12538e32b400SDavid du Colombier 	sec = nsec/1000000000ULL;
12548e32b400SDavid du Colombier 	snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
12558e32b400SDavid du Colombier 		NUMSIZE-1, sec,
12568e32b400SDavid du Colombier 		VLNUMSIZE-1, nsec,
12578e32b400SDavid du Colombier 		VLNUMSIZE-1, ticks,
12588e32b400SDavid du Colombier 		VLNUMSIZE-1, fasthz);
12598e32b400SDavid du Colombier 	return readstr(off, buf, n, str);
12608e32b400SDavid du Colombier }
12618e32b400SDavid du Colombier 
12628e32b400SDavid du Colombier /*
12638e32b400SDavid du Colombier  *  set the time in seconds
12648e32b400SDavid du Colombier  */
12658e32b400SDavid du Colombier static int
writetime(char * buf,int n)12668e32b400SDavid du Colombier writetime(char *buf, int n)
12678e32b400SDavid du Colombier {
12688e32b400SDavid du Colombier 	char b[13];
12698e32b400SDavid du Colombier 	long i;
12708e32b400SDavid du Colombier 	vlong now;
12718e32b400SDavid du Colombier 
12728e32b400SDavid du Colombier 	if(n >= sizeof(b))
12738e32b400SDavid du Colombier 		error(Ebadtimectl);
12748e32b400SDavid du Colombier 	strncpy(b, buf, n);
12758e32b400SDavid du Colombier 	b[n] = 0;
12768e32b400SDavid du Colombier 	i = strtol(b, 0, 0);
12778e32b400SDavid du Colombier 	if(i <= 0)
12788e32b400SDavid du Colombier 		error(Ebadtimectl);
12798e32b400SDavid du Colombier 	now = i*1000000000LL;
12808e32b400SDavid du Colombier 	todset(now, 0, 0);
12818e32b400SDavid du Colombier 	return n;
12828e32b400SDavid du Colombier }
12838e32b400SDavid du Colombier 
12848e32b400SDavid du Colombier /*
12858e32b400SDavid du Colombier  *  read binary time info.  all numbers are little endian.
12868e32b400SDavid du Colombier  *  ticks and nsec are syncronized.
12878e32b400SDavid du Colombier  */
12888e32b400SDavid du Colombier static int
readbintime(char * buf,int n)12898e32b400SDavid du Colombier readbintime(char *buf, int n)
12908e32b400SDavid du Colombier {
12918e32b400SDavid du Colombier 	int i;
12928e32b400SDavid du Colombier 	vlong nsec, ticks;
12938e32b400SDavid du Colombier 	uchar *b = (uchar*)buf;
12948e32b400SDavid du Colombier 
12958e32b400SDavid du Colombier 	i = 0;
12968e32b400SDavid du Colombier 	if(fasthz == 0LL)
12978e32b400SDavid du Colombier 		fastticks((uvlong*)&fasthz);
12988e32b400SDavid du Colombier 	nsec = todget(&ticks);
12998e32b400SDavid du Colombier 	if(n >= 3*sizeof(uvlong)){
13008e32b400SDavid du Colombier 		vlong2le(b+2*sizeof(uvlong), fasthz);
13018e32b400SDavid du Colombier 		i += sizeof(uvlong);
13028e32b400SDavid du Colombier 	}
13038e32b400SDavid du Colombier 	if(n >= 2*sizeof(uvlong)){
13048e32b400SDavid du Colombier 		vlong2le(b+sizeof(uvlong), ticks);
13058e32b400SDavid du Colombier 		i += sizeof(uvlong);
13068e32b400SDavid du Colombier 	}
13078e32b400SDavid du Colombier 	if(n >= 8){
13088e32b400SDavid du Colombier 		vlong2le(b, nsec);
13098e32b400SDavid du Colombier 		i += sizeof(vlong);
13108e32b400SDavid du Colombier 	}
13118e32b400SDavid du Colombier 	return i;
13128e32b400SDavid du Colombier }
13138e32b400SDavid du Colombier 
13148e32b400SDavid du Colombier /*
13158e32b400SDavid du Colombier  *  set any of the following
13168e32b400SDavid du Colombier  *	- time in nsec
13178e32b400SDavid du Colombier  *	- nsec trim applied over some seconds
13188e32b400SDavid du Colombier  *	- clock frequency
13198e32b400SDavid du Colombier  */
13208e32b400SDavid du Colombier static int
writebintime(char * buf,int n)13218e32b400SDavid du Colombier writebintime(char *buf, int n)
13228e32b400SDavid du Colombier {
13238e32b400SDavid du Colombier 	uchar *p;
13248e32b400SDavid du Colombier 	vlong delta;
13258e32b400SDavid du Colombier 	long period;
13268e32b400SDavid du Colombier 
13278e32b400SDavid du Colombier 	n--;
13288e32b400SDavid du Colombier 	p = (uchar*)buf + 1;
13298e32b400SDavid du Colombier 	switch(*buf){
13308e32b400SDavid du Colombier 	case 'n':
13318e32b400SDavid du Colombier 		if(n < sizeof(vlong))
13328e32b400SDavid du Colombier 			error(Ebadtimectl);
13338e32b400SDavid du Colombier 		le2vlong(&delta, p);
13348e32b400SDavid du Colombier 		todset(delta, 0, 0);
13358e32b400SDavid du Colombier 		break;
13368e32b400SDavid du Colombier 	case 'd':
13378e32b400SDavid du Colombier 		if(n < sizeof(vlong)+sizeof(long))
13388e32b400SDavid du Colombier 			error(Ebadtimectl);
13398e32b400SDavid du Colombier 		p = le2vlong(&delta, p);
13408e32b400SDavid du Colombier 		le2long(&period, p);
13418e32b400SDavid du Colombier 		todset(-1, delta, period);
13428e32b400SDavid du Colombier 		break;
13438e32b400SDavid du Colombier 	case 'f':
13448e32b400SDavid du Colombier 		if(n < sizeof(uvlong))
13458e32b400SDavid du Colombier 			error(Ebadtimectl);
13468e32b400SDavid du Colombier 		le2vlong(&fasthz, p);
13478e32b400SDavid du Colombier 		if(fasthz <= 0)
13488e32b400SDavid du Colombier 			error(Ebadtimectl);
13498e32b400SDavid du Colombier 		todsetfreq(fasthz);
13508e32b400SDavid du Colombier 		break;
13518e32b400SDavid du Colombier 	}
13528e32b400SDavid du Colombier 	return n;
13538e32b400SDavid du Colombier }
1354