xref: /plan9-contrib/sys/src/9k/port/devcons.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier #include	<authsrv.h>
99ef1f84bSDavid du Colombier 
109ef1f84bSDavid du Colombier enum
119ef1f84bSDavid du Colombier {
129ef1f84bSDavid du Colombier 	Nconsdevs	= 64,		/* max number of consoles */
139ef1f84bSDavid du Colombier 
149ef1f84bSDavid du Colombier 	/* Consdev flags */
159ef1f84bSDavid du Colombier 	Ciprint		= 2,		/* call this fn from iprint */
169ef1f84bSDavid du Colombier 	Cntorn		= 4,		/* change \n to \r\n */
179ef1f84bSDavid du Colombier };
189ef1f84bSDavid du Colombier 
199ef1f84bSDavid du Colombier typedef struct Consdev Consdev;
209ef1f84bSDavid du Colombier 
219ef1f84bSDavid du Colombier struct Consdev
229ef1f84bSDavid du Colombier {
239ef1f84bSDavid du Colombier 	Chan*	c;			/* external file */
249ef1f84bSDavid du Colombier 	Queue*	q;			/* i/o queue, if any */
259ef1f84bSDavid du Colombier 	void	(*fn)(char*, int);	/* i/o function when no queue */
269ef1f84bSDavid du Colombier 	int	flags;
279ef1f84bSDavid du Colombier };
289ef1f84bSDavid du Colombier 
299ef1f84bSDavid du Colombier void	(*consdebug)(void) = nil;
309ef1f84bSDavid du Colombier void	(*consputs)(char*, int) = nil;
319ef1f84bSDavid du Colombier 
329ef1f84bSDavid du Colombier static void kmesgputs(char *, int);
339ef1f84bSDavid du Colombier static void kprintputs(char*, int);
349ef1f84bSDavid du Colombier 
359ef1f84bSDavid du Colombier static	Lock	consdevslock;
369ef1f84bSDavid du Colombier static	int	nconsdevs = 3;
379ef1f84bSDavid du Colombier static	Consdev	consdevs[Nconsdevs] =			/* keep this order */
389ef1f84bSDavid du Colombier {
399ef1f84bSDavid du Colombier 	{nil, nil,	kmesgputs,	0},			/* kmesg */
409ef1f84bSDavid du Colombier 	{nil, nil,	kprintputs,	Ciprint},		/* kprint */
419ef1f84bSDavid du Colombier 	{nil, nil,	uartputs,	Ciprint|Cntorn},	/* serial */
429ef1f84bSDavid du Colombier };
439ef1f84bSDavid du Colombier 
449ef1f84bSDavid du Colombier static	int	nkbdqs;
459ef1f84bSDavid du Colombier static	int	nkbdprocs;
469ef1f84bSDavid du Colombier static	Queue*	kbdqs[Nconsdevs];
479ef1f84bSDavid du Colombier static	int	kbdprocs[Nconsdevs];
489ef1f84bSDavid du Colombier static	Queue*	kbdq;		/* unprocessed console input */
499ef1f84bSDavid du Colombier static	Queue*	lineq;		/* processed console input */
509ef1f84bSDavid du Colombier static	Queue*	serialoq;	/* serial console output */
519ef1f84bSDavid du Colombier static	Queue*	kprintoq;	/* console output, for /dev/kprint */
529ef1f84bSDavid du Colombier static	ulong	kprintinuse;	/* test and set whether /dev/kprint is open */
539ef1f84bSDavid du Colombier 
549ef1f84bSDavid du Colombier int	panicking;
559ef1f84bSDavid du Colombier 
569ef1f84bSDavid du Colombier static struct
579ef1f84bSDavid du Colombier {
589ef1f84bSDavid du Colombier 	QLock;
599ef1f84bSDavid du Colombier 
609ef1f84bSDavid du Colombier 	int	raw;		/* true if we shouldn't process input */
619ef1f84bSDavid du Colombier 	Ref	ctl;		/* number of opens to the control file */
629ef1f84bSDavid du Colombier 	int	x;		/* index into line */
639ef1f84bSDavid du Colombier 	char	line[1024];	/* current input line */
649ef1f84bSDavid du Colombier 
659ef1f84bSDavid du Colombier 	int	count;
669ef1f84bSDavid du Colombier 	int	ctlpoff;
679ef1f84bSDavid du Colombier 
689ef1f84bSDavid du Colombier 	/*
699ef1f84bSDavid du Colombier 	 * A place to save up characters at interrupt time
709ef1f84bSDavid du Colombier 	 * before dumping them in the queue
719ef1f84bSDavid du Colombier 	 */
729ef1f84bSDavid du Colombier 	Lock	lockputc;
739ef1f84bSDavid du Colombier 	char	istage[1024];
749ef1f84bSDavid du Colombier 	char	*iw;
759ef1f84bSDavid du Colombier 	char	*ir;
769ef1f84bSDavid du Colombier 	char	*ie;
779ef1f84bSDavid du Colombier } kbd = {
789ef1f84bSDavid du Colombier 	.iw	= kbd.istage,
799ef1f84bSDavid du Colombier 	.ir	= kbd.istage,
809ef1f84bSDavid du Colombier 	.ie	= kbd.istage + sizeof(kbd.istage),
819ef1f84bSDavid du Colombier };
829ef1f84bSDavid du Colombier 
839ef1f84bSDavid du Colombier char	*sysname;
849ef1f84bSDavid du Colombier vlong	fasthz;
859ef1f84bSDavid du Colombier 
869ef1f84bSDavid du Colombier static void	seedrand(void);
879ef1f84bSDavid du Colombier static int	readtime(ulong, char*, int);
889ef1f84bSDavid du Colombier static int	readbintime(char*, int);
899ef1f84bSDavid du Colombier static int	writetime(char*, int);
909ef1f84bSDavid du Colombier static int	writebintime(char*, int);
919ef1f84bSDavid du Colombier 
929ef1f84bSDavid du Colombier enum
939ef1f84bSDavid du Colombier {
949ef1f84bSDavid du Colombier 	CMhalt,
959ef1f84bSDavid du Colombier 	CMreboot,
969ef1f84bSDavid du Colombier 	CMpanic,
979ef1f84bSDavid du Colombier };
989ef1f84bSDavid du Colombier 
999ef1f84bSDavid du Colombier Cmdtab rebootmsg[] =
1009ef1f84bSDavid du Colombier {
1019ef1f84bSDavid du Colombier 	CMhalt,		"halt",		1,
1029ef1f84bSDavid du Colombier 	CMreboot,	"reboot",	0,
1039ef1f84bSDavid du Colombier 	CMpanic,	"panic",	0,
1049ef1f84bSDavid du Colombier };
1059ef1f84bSDavid du Colombier 
1069ef1f84bSDavid du Colombier /* To keep the rest of the kernel unware of new consdevs for now */
1079ef1f84bSDavid du Colombier static void
kprintputs(char * s,int n)1089ef1f84bSDavid du Colombier kprintputs(char *s, int n)
1099ef1f84bSDavid du Colombier {
1109ef1f84bSDavid du Colombier 	if(consputs != nil)
1119ef1f84bSDavid du Colombier 		consputs(s, n);
1129ef1f84bSDavid du Colombier }
1139ef1f84bSDavid du Colombier 
1149ef1f84bSDavid du Colombier int
addconsdev(Queue * q,void (* fn)(char *,int),int i,int flags)1159ef1f84bSDavid du Colombier addconsdev(Queue *q, void (*fn)(char*,int), int i, int flags)
1169ef1f84bSDavid du Colombier {
1179ef1f84bSDavid du Colombier 	Consdev *c;
1189ef1f84bSDavid du Colombier 
1199ef1f84bSDavid du Colombier 	ilock(&consdevslock);
1209ef1f84bSDavid du Colombier 	if(i < 0)
1219ef1f84bSDavid du Colombier 		i = nconsdevs;
1229ef1f84bSDavid du Colombier 	else
1239ef1f84bSDavid du Colombier 		flags |= consdevs[i].flags;
1249ef1f84bSDavid du Colombier 	if(nconsdevs == Nconsdevs)
1259ef1f84bSDavid du Colombier 		panic("Nconsdevs too small");
1269ef1f84bSDavid du Colombier 	c = &consdevs[i];
1279ef1f84bSDavid du Colombier 	c->flags = flags;
1289ef1f84bSDavid du Colombier 	c->q = q;
1299ef1f84bSDavid du Colombier 	c->fn = fn;
1309ef1f84bSDavid du Colombier 	if(i == nconsdevs)
1319ef1f84bSDavid du Colombier 		nconsdevs++;
1329ef1f84bSDavid du Colombier 	iunlock(&consdevslock);
1339ef1f84bSDavid du Colombier 	return i;
1349ef1f84bSDavid du Colombier }
1359ef1f84bSDavid du Colombier 
1369ef1f84bSDavid du Colombier void
delconsdevs(void)1379ef1f84bSDavid du Colombier delconsdevs(void)
1389ef1f84bSDavid du Colombier {
1399ef1f84bSDavid du Colombier 	nconsdevs = 2;	/* throw away serial consoles and kprint */
1409ef1f84bSDavid du Colombier 	consdevs[1].q = nil;
1419ef1f84bSDavid du Colombier }
1429ef1f84bSDavid du Colombier 
1439ef1f84bSDavid du Colombier static void
conskbdqproc(void * a)1449ef1f84bSDavid du Colombier conskbdqproc(void *a)
1459ef1f84bSDavid du Colombier {
1469ef1f84bSDavid du Colombier 	char buf[64];
1479ef1f84bSDavid du Colombier 	Queue *q;
1489ef1f84bSDavid du Colombier 	int nr;
1499ef1f84bSDavid du Colombier 
1509ef1f84bSDavid du Colombier 	q = a;
1519ef1f84bSDavid du Colombier 	while((nr = qread(q, buf, sizeof(buf))) > 0)
1529ef1f84bSDavid du Colombier 		qwrite(kbdq, buf, nr);
1539ef1f84bSDavid du Colombier 	pexit("hangup", 1);
1549ef1f84bSDavid du Colombier }
1559ef1f84bSDavid du Colombier 
1569ef1f84bSDavid du Colombier static void
kickkbdq(void)1579ef1f84bSDavid du Colombier kickkbdq(void)
1589ef1f84bSDavid du Colombier {
1599ef1f84bSDavid du Colombier 	int i;
1609ef1f84bSDavid du Colombier 
1619ef1f84bSDavid du Colombier 	if(up != nil && nkbdqs > 1 && nkbdprocs != nkbdqs){
1629ef1f84bSDavid du Colombier 		lock(&consdevslock);
1639ef1f84bSDavid du Colombier 		if(nkbdprocs == nkbdqs){
1649ef1f84bSDavid du Colombier 			unlock(&consdevslock);
1659ef1f84bSDavid du Colombier 			return;
1669ef1f84bSDavid du Colombier 		}
1679ef1f84bSDavid du Colombier 		for(i = 0; i < nkbdqs; i++)
1689ef1f84bSDavid du Colombier 			if(kbdprocs[i] == 0){
1699ef1f84bSDavid du Colombier 				kbdprocs[i] = 1;
1709ef1f84bSDavid du Colombier 				kproc("conskbdq", conskbdqproc, kbdqs[i]);
1719ef1f84bSDavid du Colombier 			}
1729ef1f84bSDavid du Colombier 		unlock(&consdevslock);
1739ef1f84bSDavid du Colombier 	}
1749ef1f84bSDavid du Colombier }
1759ef1f84bSDavid du Colombier 
1769ef1f84bSDavid du Colombier int
addkbdq(Queue * q,int i)1779ef1f84bSDavid du Colombier addkbdq(Queue *q, int i)
1789ef1f84bSDavid du Colombier {
1799ef1f84bSDavid du Colombier 	int n;
1809ef1f84bSDavid du Colombier 
1819ef1f84bSDavid du Colombier 	ilock(&consdevslock);
1829ef1f84bSDavid du Colombier 	if(i < 0)
1839ef1f84bSDavid du Colombier 		i = nkbdqs++;
1849ef1f84bSDavid du Colombier 	if(nkbdqs == Nconsdevs)
1859ef1f84bSDavid du Colombier 		panic("Nconsdevs too small");
1869ef1f84bSDavid du Colombier 	kbdqs[i] = q;
1879ef1f84bSDavid du Colombier 	n = nkbdqs;
1889ef1f84bSDavid du Colombier 	iunlock(&consdevslock);
1899ef1f84bSDavid du Colombier 	switch(n){
1909ef1f84bSDavid du Colombier 	case 1:
1919ef1f84bSDavid du Colombier 		/* if there's just one, pull directly from it. */
1929ef1f84bSDavid du Colombier 		kbdq = q;
1939ef1f84bSDavid du Colombier 		break;
1949ef1f84bSDavid du Colombier 	case 2:
1959ef1f84bSDavid du Colombier 		/* later we'll merge bytes from all kbdqs into a single kbdq */
1969ef1f84bSDavid du Colombier 		kbdq = qopen(4*1024, 0, 0, 0);
1979ef1f84bSDavid du Colombier 		if(kbdq == nil)
1989ef1f84bSDavid du Colombier 			panic("no kbdq");
1999ef1f84bSDavid du Colombier 		/* fall */
2009ef1f84bSDavid du Colombier 	default:
2019ef1f84bSDavid du Colombier 		kickkbdq();
2029ef1f84bSDavid du Colombier 	}
2039ef1f84bSDavid du Colombier 	return i;
2049ef1f84bSDavid du Colombier }
2059ef1f84bSDavid du Colombier 
2069ef1f84bSDavid du Colombier void
printinit(void)2079ef1f84bSDavid du Colombier printinit(void)
2089ef1f84bSDavid du Colombier {
2099ef1f84bSDavid du Colombier 	lineq = qopen(2*1024, 0, nil, nil);
2109ef1f84bSDavid du Colombier 	if(lineq == nil)
2119ef1f84bSDavid du Colombier 		panic("printinit");
2129ef1f84bSDavid du Colombier 	qnoblock(lineq, 1);
2139ef1f84bSDavid du Colombier }
2149ef1f84bSDavid du Colombier 
2159ef1f84bSDavid du Colombier int
consactive(void)2169ef1f84bSDavid du Colombier consactive(void)
2179ef1f84bSDavid du Colombier {
2189ef1f84bSDavid du Colombier 	int i;
2199ef1f84bSDavid du Colombier 	Queue *q;
2209ef1f84bSDavid du Colombier 
2219ef1f84bSDavid du Colombier 	for(i = 0; i < nconsdevs; i++)
2229ef1f84bSDavid du Colombier 		if((q = consdevs[i].q) != nil && qlen(q) > 0)
2239ef1f84bSDavid du Colombier 			return 1;
2249ef1f84bSDavid du Colombier 	return 0;
2259ef1f84bSDavid du Colombier }
2269ef1f84bSDavid du Colombier 
2279ef1f84bSDavid du Colombier void
prflush(void)2289ef1f84bSDavid du Colombier prflush(void)
2299ef1f84bSDavid du Colombier {
2309ef1f84bSDavid du Colombier 	ulong now;
2319ef1f84bSDavid du Colombier 
2329ef1f84bSDavid du Colombier 	now = m->ticks;
2339ef1f84bSDavid du Colombier 	while(consactive())
2349ef1f84bSDavid du Colombier 		if(m->ticks - now >= 10*HZ)
2359ef1f84bSDavid du Colombier 			break;
2369ef1f84bSDavid du Colombier }
2379ef1f84bSDavid du Colombier 
2389ef1f84bSDavid du Colombier /*
2399ef1f84bSDavid du Colombier  * Log console output so it can be retrieved via /dev/kmesg.
2409ef1f84bSDavid du Colombier  * This is good for catching boot-time messages after the fact.
2419ef1f84bSDavid du Colombier  */
2429ef1f84bSDavid du Colombier struct {
2439ef1f84bSDavid du Colombier 	Lock lk;
2449ef1f84bSDavid du Colombier 	char buf[16384];
2459ef1f84bSDavid du Colombier 	uint n;
2469ef1f84bSDavid du Colombier } kmesg;
2479ef1f84bSDavid du Colombier 
2489ef1f84bSDavid du Colombier static void
kmesgputs(char * str,int n)2499ef1f84bSDavid du Colombier kmesgputs(char *str, int n)
2509ef1f84bSDavid du Colombier {
2519ef1f84bSDavid du Colombier 	uint nn, d;
2529ef1f84bSDavid du Colombier 
2539ef1f84bSDavid du Colombier 	ilock(&kmesg.lk);
2549ef1f84bSDavid du Colombier 	/* take the tail of huge writes */
2559ef1f84bSDavid du Colombier 	if(n > sizeof kmesg.buf){
2569ef1f84bSDavid du Colombier 		d = n - sizeof kmesg.buf;
2579ef1f84bSDavid du Colombier 		str += d;
2589ef1f84bSDavid du Colombier 		n -= d;
2599ef1f84bSDavid du Colombier 	}
2609ef1f84bSDavid du Colombier 
2619ef1f84bSDavid du Colombier 	/* slide the buffer down to make room */
2629ef1f84bSDavid du Colombier 	nn = kmesg.n;
2639ef1f84bSDavid du Colombier 	if(nn + n >= sizeof kmesg.buf){
2649ef1f84bSDavid du Colombier 		d = nn + n - sizeof kmesg.buf;
2659ef1f84bSDavid du Colombier 		if(d)
2669ef1f84bSDavid du Colombier 			memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
2679ef1f84bSDavid du Colombier 		nn -= d;
2689ef1f84bSDavid du Colombier 	}
2699ef1f84bSDavid du Colombier 
2709ef1f84bSDavid du Colombier 	/* copy the data in */
2719ef1f84bSDavid du Colombier 	memmove(kmesg.buf+nn, str, n);
2729ef1f84bSDavid du Colombier 	nn += n;
2739ef1f84bSDavid du Colombier 	kmesg.n = nn;
2749ef1f84bSDavid du Colombier 	iunlock(&kmesg.lk);
2759ef1f84bSDavid du Colombier }
2769ef1f84bSDavid du Colombier 
2779ef1f84bSDavid du Colombier static void
consdevputs(Consdev * c,char * s,int n,int usewrite)2789ef1f84bSDavid du Colombier consdevputs(Consdev *c, char *s, int n, int usewrite)
2799ef1f84bSDavid du Colombier {
2809ef1f84bSDavid du Colombier 	Chan *cc;
2819ef1f84bSDavid du Colombier 	Queue *q;
2829ef1f84bSDavid du Colombier 
2839ef1f84bSDavid du Colombier 	if((cc = c->c) != nil && usewrite)
2849ef1f84bSDavid du Colombier 		cc->dev->write(cc, s, n, 0);
2859ef1f84bSDavid du Colombier 	else if((q = c->q) != nil && !qisclosed(q))
2869ef1f84bSDavid du Colombier 		if(usewrite)
2879ef1f84bSDavid du Colombier 			qwrite(q, s, n);
2889ef1f84bSDavid du Colombier 		else
2899ef1f84bSDavid du Colombier 			qiwrite(q, s, n);
2909ef1f84bSDavid du Colombier 	else if(c->fn != nil)
2919ef1f84bSDavid du Colombier 		c->fn(s, n);
2929ef1f84bSDavid du Colombier }
2939ef1f84bSDavid du Colombier 
2949ef1f84bSDavid du Colombier /*
2959ef1f84bSDavid du Colombier  *   Print a string on the console.  Convert \n to \r\n for serial
2969ef1f84bSDavid du Colombier  *   line consoles.  Locking of the queues is left up to the screen
2979ef1f84bSDavid du Colombier  *   or uart code.  Multi-line messages to serial consoles may get
2989ef1f84bSDavid du Colombier  *   interspersed with other messages.
2999ef1f84bSDavid du Colombier  */
3009ef1f84bSDavid du Colombier static void
putstrn0(char * str,int n,int usewrite)3019ef1f84bSDavid du Colombier putstrn0(char *str, int n, int usewrite)
3029ef1f84bSDavid du Colombier {
3039ef1f84bSDavid du Colombier 	Consdev *c;
3049ef1f84bSDavid du Colombier 	char *s, *t;
3059ef1f84bSDavid du Colombier 	int i, len, m;
3069ef1f84bSDavid du Colombier 
3079ef1f84bSDavid du Colombier 	if(!islo())
3089ef1f84bSDavid du Colombier 		usewrite = 0;
3099ef1f84bSDavid du Colombier 
3109ef1f84bSDavid du Colombier 	for(i = 0; i < nconsdevs; i++){
3119ef1f84bSDavid du Colombier 		c = &consdevs[i];
3129ef1f84bSDavid du Colombier 		len = n;
3139ef1f84bSDavid du Colombier 		s = str;
3149ef1f84bSDavid du Colombier 		while(len > 0){
3159ef1f84bSDavid du Colombier 			t = nil;
3169ef1f84bSDavid du Colombier 			if((c->flags&Cntorn) && !kbd.raw)
3179ef1f84bSDavid du Colombier 				t = memchr(s, '\n', len);
3189ef1f84bSDavid du Colombier 			if(t != nil && !kbd.raw){
3199ef1f84bSDavid du Colombier 				m = t-s;
3209ef1f84bSDavid du Colombier 				consdevputs(c, s, m, usewrite);
3219ef1f84bSDavid du Colombier 				consdevputs(c, "\r\n", 2, usewrite);
3229ef1f84bSDavid du Colombier 				len -= m+1;
3239ef1f84bSDavid du Colombier 				s = t+1;
3249ef1f84bSDavid du Colombier 			}else{
3259ef1f84bSDavid du Colombier 				consdevputs(c, s, len, usewrite);
3269ef1f84bSDavid du Colombier 				break;
3279ef1f84bSDavid du Colombier 			}
3289ef1f84bSDavid du Colombier 		}
3299ef1f84bSDavid du Colombier 	}
3309ef1f84bSDavid du Colombier }
3319ef1f84bSDavid du Colombier 
3329ef1f84bSDavid du Colombier void
putstrn(char * str,int n)3339ef1f84bSDavid du Colombier putstrn(char *str, int n)
3349ef1f84bSDavid du Colombier {
3359ef1f84bSDavid du Colombier 	putstrn0(str, n, 0);
3369ef1f84bSDavid du Colombier }
3379ef1f84bSDavid du Colombier 
3389ef1f84bSDavid du Colombier int
print(char * fmt,...)3399ef1f84bSDavid du Colombier print(char *fmt, ...)
3409ef1f84bSDavid du Colombier {
3419ef1f84bSDavid du Colombier 	int n;
3429ef1f84bSDavid du Colombier 	va_list arg;
3439ef1f84bSDavid du Colombier 	char buf[PRINTSIZE];
3449ef1f84bSDavid du Colombier 
3459ef1f84bSDavid du Colombier 	va_start(arg, fmt);
3469ef1f84bSDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
3479ef1f84bSDavid du Colombier 	va_end(arg);
3489ef1f84bSDavid du Colombier 	if(panicking <= 0 || up == nil || up->pid == panicking)
3499ef1f84bSDavid du Colombier 		putstrn(buf, n);
3509ef1f84bSDavid du Colombier 
3519ef1f84bSDavid du Colombier 	return n;
3529ef1f84bSDavid du Colombier }
3539ef1f84bSDavid du Colombier 
3549ef1f84bSDavid du Colombier /*
3559ef1f84bSDavid du Colombier  * Want to interlock iprints to avoid interlaced output on
3569ef1f84bSDavid du Colombier  * multiprocessor, but don't want to deadlock if one processor
3579ef1f84bSDavid du Colombier  * dies during print and another has something important to say.
3589ef1f84bSDavid du Colombier  * Make a good faith effort.
3599ef1f84bSDavid du Colombier  */
3609ef1f84bSDavid du Colombier static Lock iprintlock;
3619ef1f84bSDavid du Colombier 
3629ef1f84bSDavid du Colombier static int
iprintcanlock(Lock * l)3639ef1f84bSDavid du Colombier iprintcanlock(Lock *l)
3649ef1f84bSDavid du Colombier {
3659ef1f84bSDavid du Colombier 	int i;
3669ef1f84bSDavid du Colombier 
3679ef1f84bSDavid du Colombier 	for(i=0; i<1000; i++){
3689ef1f84bSDavid du Colombier 		if(canlock(l))
3699ef1f84bSDavid du Colombier 			return 1;
3709ef1f84bSDavid du Colombier 		if(l->m == m)
3719ef1f84bSDavid du Colombier 			return 0;
3729ef1f84bSDavid du Colombier 		microdelay(100);
3739ef1f84bSDavid du Colombier 	}
3749ef1f84bSDavid du Colombier 	return 0;
3759ef1f84bSDavid du Colombier }
3769ef1f84bSDavid du Colombier 
3779ef1f84bSDavid du Colombier int
iprint(char * fmt,...)3789ef1f84bSDavid du Colombier iprint(char *fmt, ...)
3799ef1f84bSDavid du Colombier {
3809ef1f84bSDavid du Colombier 	Mreg s;
3819ef1f84bSDavid du Colombier 	int i, n, locked;
3829ef1f84bSDavid du Colombier 	va_list arg;
3839ef1f84bSDavid du Colombier 	char buf[PRINTSIZE];
3849ef1f84bSDavid du Colombier 
3859ef1f84bSDavid du Colombier 	s = splhi();
3869ef1f84bSDavid du Colombier 	va_start(arg, fmt);
3879ef1f84bSDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
3889ef1f84bSDavid du Colombier 	va_end(arg);
3899ef1f84bSDavid du Colombier 	if(panicking > 0 && up != nil && up->pid != panicking)
3909ef1f84bSDavid du Colombier 		return n;
3919ef1f84bSDavid du Colombier 	locked = iprintcanlock(&iprintlock);
3929ef1f84bSDavid du Colombier 	for(i = 0; i < nconsdevs; i++){
3939ef1f84bSDavid du Colombier 		if((consdevs[i].flags&Ciprint) != 0){
3949ef1f84bSDavid du Colombier 			if(consdevs[i].q != nil)
3959ef1f84bSDavid du Colombier 				qiwrite(consdevs[i].q, buf, n);
3969ef1f84bSDavid du Colombier 			else
3979ef1f84bSDavid du Colombier 				consdevs[i].fn(buf, n);
3989ef1f84bSDavid du Colombier 		}
3999ef1f84bSDavid du Colombier 	}
4009ef1f84bSDavid du Colombier 	if(locked)
4019ef1f84bSDavid du Colombier 		unlock(&iprintlock);
4029ef1f84bSDavid du Colombier 	splx(s);
4039ef1f84bSDavid du Colombier 
4049ef1f84bSDavid du Colombier 	return n;
4059ef1f84bSDavid du Colombier }
4069ef1f84bSDavid du Colombier 
4079ef1f84bSDavid du Colombier #pragma profile 0
4089ef1f84bSDavid du Colombier void
panic(char * fmt,...)4099ef1f84bSDavid du Colombier panic(char *fmt, ...)
4109ef1f84bSDavid du Colombier {
4119ef1f84bSDavid du Colombier 	int n;
4129ef1f84bSDavid du Colombier 	Mreg s;
4139ef1f84bSDavid du Colombier 	va_list arg;
4149ef1f84bSDavid du Colombier 	char buf[PRINTSIZE];
4159ef1f84bSDavid du Colombier 
4169ef1f84bSDavid du Colombier 	consdevs[1].q = nil;	/* don't try to write to /dev/kprint */
4179ef1f84bSDavid du Colombier 
4189ef1f84bSDavid du Colombier 	if(panicking)
4199ef1f84bSDavid du Colombier 		for(;;);
4209ef1f84bSDavid du Colombier 	panicking = -1;
4219ef1f84bSDavid du Colombier 	if(up)
4229ef1f84bSDavid du Colombier 		panicking = up->pid;
4239ef1f84bSDavid du Colombier 
4249ef1f84bSDavid du Colombier 	s = splhi();
4259ef1f84bSDavid du Colombier 	strcpy(buf, "panic: ");
4269ef1f84bSDavid du Colombier 	va_start(arg, fmt);
4279ef1f84bSDavid du Colombier 	n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
4289ef1f84bSDavid du Colombier 	va_end(arg);
4299ef1f84bSDavid du Colombier //	iprint("%s\n", buf);
4309ef1f84bSDavid du Colombier 	if(consdebug)
4319ef1f84bSDavid du Colombier 		(*consdebug)();
4329ef1f84bSDavid du Colombier 	splx(s);
4339ef1f84bSDavid du Colombier 	prflush();
4349ef1f84bSDavid du Colombier 	buf[n] = '\n';
4359ef1f84bSDavid du Colombier 	putstrn(buf, n+1);
4369ef1f84bSDavid du Colombier 	prflush();
4379ef1f84bSDavid du Colombier 	dumpstack();
4389ef1f84bSDavid du Colombier 	prflush();
4399ef1f84bSDavid du Colombier 
4409ef1f84bSDavid du Colombier 	exit(1);
4419ef1f84bSDavid du Colombier }
4429ef1f84bSDavid du Colombier #pragma profile 1
4439ef1f84bSDavid du Colombier /* libmp at least contains a few calls to sysfatal; simulate with panic */
4449ef1f84bSDavid du Colombier void
sysfatal(char * fmt,...)4459ef1f84bSDavid du Colombier sysfatal(char *fmt, ...)
4469ef1f84bSDavid du Colombier {
4479ef1f84bSDavid du Colombier 	char err[256];
4489ef1f84bSDavid du Colombier 	va_list arg;
4499ef1f84bSDavid du Colombier 
4509ef1f84bSDavid du Colombier 	va_start(arg, fmt);
4519ef1f84bSDavid du Colombier 	vseprint(err, err + sizeof err, fmt, arg);
4529ef1f84bSDavid du Colombier 	va_end(arg);
4539ef1f84bSDavid du Colombier 	panic("sysfatal: %s", err);
4549ef1f84bSDavid du Colombier }
4559ef1f84bSDavid du Colombier 
4569ef1f84bSDavid du Colombier void
_assert(char * fmt)4579ef1f84bSDavid du Colombier _assert(char *fmt)
4589ef1f84bSDavid du Colombier {
4599ef1f84bSDavid du Colombier 	panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
4609ef1f84bSDavid du Colombier }
4619ef1f84bSDavid du Colombier 
4629ef1f84bSDavid du Colombier int
pprint(char * fmt,...)4639ef1f84bSDavid du Colombier pprint(char *fmt, ...)
4649ef1f84bSDavid du Colombier {
4659ef1f84bSDavid du Colombier 	int n;
4669ef1f84bSDavid du Colombier 	Chan *c;
4679ef1f84bSDavid du Colombier 	va_list arg;
4689ef1f84bSDavid du Colombier 	char buf[2*PRINTSIZE];
4699ef1f84bSDavid du Colombier 
4709ef1f84bSDavid du Colombier 	if(up == nil || up->fgrp == nil)
4719ef1f84bSDavid du Colombier 		return 0;
4729ef1f84bSDavid du Colombier 
4739ef1f84bSDavid du Colombier 	c = up->fgrp->fd[2];
4749ef1f84bSDavid du Colombier 	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
4759ef1f84bSDavid du Colombier 		return 0;
4769ef1f84bSDavid du Colombier 	n = snprint(buf, sizeof buf, "%s %d: ", up->text, up->pid);
4779ef1f84bSDavid du Colombier 	va_start(arg, fmt);
4789ef1f84bSDavid du Colombier 	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
4799ef1f84bSDavid du Colombier 	va_end(arg);
4809ef1f84bSDavid du Colombier 
4819ef1f84bSDavid du Colombier 	if(waserror())
4829ef1f84bSDavid du Colombier 		return 0;
4839ef1f84bSDavid du Colombier 	c->dev->write(c, buf, n, c->offset);
4849ef1f84bSDavid du Colombier 	poperror();
4859ef1f84bSDavid du Colombier 
4869ef1f84bSDavid du Colombier 	lock(c);
4879ef1f84bSDavid du Colombier 	c->offset += n;
4889ef1f84bSDavid du Colombier 	unlock(c);
4899ef1f84bSDavid du Colombier 
4909ef1f84bSDavid du Colombier 	return n;
4919ef1f84bSDavid du Colombier }
4929ef1f84bSDavid du Colombier 
4939ef1f84bSDavid du Colombier static void
echo(char * buf,int n)4949ef1f84bSDavid du Colombier echo(char *buf, int n)
4959ef1f84bSDavid du Colombier {
4969ef1f84bSDavid du Colombier 	Mreg s;
4979ef1f84bSDavid du Colombier 	static int ctrlt, pid;
4989ef1f84bSDavid du Colombier 	char *e, *p;
4999ef1f84bSDavid du Colombier 
5009ef1f84bSDavid du Colombier 	if(n == 0)
5019ef1f84bSDavid du Colombier 		return;
5029ef1f84bSDavid du Colombier 
5039ef1f84bSDavid du Colombier 	e = buf+n;
5049ef1f84bSDavid du Colombier 	for(p = buf; p < e; p++){
5059ef1f84bSDavid du Colombier 		switch(*p){
5069ef1f84bSDavid du Colombier 		case 0x10:	/* ^P */
5079ef1f84bSDavid du Colombier 			if(cpuserver && !kbd.ctlpoff){
5089ef1f84bSDavid du Colombier 				active.exiting = 1;
5099ef1f84bSDavid du Colombier 				return;
5109ef1f84bSDavid du Colombier 			}
5119ef1f84bSDavid du Colombier 			break;
5129ef1f84bSDavid du Colombier 		case 0x14:	/* ^T */
5139ef1f84bSDavid du Colombier 			ctrlt++;
5149ef1f84bSDavid du Colombier 			if(ctrlt > 2)
5159ef1f84bSDavid du Colombier 				ctrlt = 2;
5169ef1f84bSDavid du Colombier 			continue;
5179ef1f84bSDavid du Colombier 		}
5189ef1f84bSDavid du Colombier 
5199ef1f84bSDavid du Colombier 		if(ctrlt != 2)
5209ef1f84bSDavid du Colombier 			continue;
5219ef1f84bSDavid du Colombier 
5229ef1f84bSDavid du Colombier 		/* ^T escapes */
5239ef1f84bSDavid du Colombier 		ctrlt = 0;
5249ef1f84bSDavid du Colombier 		switch(*p){
5259ef1f84bSDavid du Colombier 		case 'S':
5269ef1f84bSDavid du Colombier 			s = splhi();
5279ef1f84bSDavid du Colombier 			dumpstack();
5289ef1f84bSDavid du Colombier 			procdump();
5299ef1f84bSDavid du Colombier 			splx(s);
5309ef1f84bSDavid du Colombier 			return;
5319ef1f84bSDavid du Colombier 		case 's':
5329ef1f84bSDavid du Colombier 			dumpstack();
5339ef1f84bSDavid du Colombier 			return;
5349ef1f84bSDavid du Colombier 		case 'x':
5359ef1f84bSDavid du Colombier 			ixsummary();
5369ef1f84bSDavid du Colombier 			mallocsummary();
5379ef1f84bSDavid du Colombier //			memorysummary();
5389ef1f84bSDavid du Colombier 			return;
5399ef1f84bSDavid du Colombier 		case 'd':
5409ef1f84bSDavid du Colombier 			if(consdebug == nil)
5419ef1f84bSDavid du Colombier 				consdebug = rdb;
5429ef1f84bSDavid du Colombier 			else
5439ef1f84bSDavid du Colombier 				consdebug = nil;
5449ef1f84bSDavid du Colombier 			print("consdebug now %#p\n", consdebug);
5459ef1f84bSDavid du Colombier 			return;
5469ef1f84bSDavid du Colombier 		case 'D':
5479ef1f84bSDavid du Colombier 			if(consdebug == nil)
5489ef1f84bSDavid du Colombier 				consdebug = rdb;
5499ef1f84bSDavid du Colombier 			consdebug();
5509ef1f84bSDavid du Colombier 			return;
5519ef1f84bSDavid du Colombier 		case 'p':
5529ef1f84bSDavid du Colombier 			s = spllo();
5539ef1f84bSDavid du Colombier 			procdump();
5549ef1f84bSDavid du Colombier 			splx(s);
5559ef1f84bSDavid du Colombier 			return;
5569ef1f84bSDavid du Colombier 		case 'q':
5579ef1f84bSDavid du Colombier 			scheddump();
5589ef1f84bSDavid du Colombier 			return;
5599ef1f84bSDavid du Colombier 		case 'k':
5609ef1f84bSDavid du Colombier 			killbig("^t ^t k");
5619ef1f84bSDavid du Colombier 			return;
5629ef1f84bSDavid du Colombier 		case 'r':
5639ef1f84bSDavid du Colombier 			exit(0);
5649ef1f84bSDavid du Colombier 			return;
5659ef1f84bSDavid du Colombier 		}
5669ef1f84bSDavid du Colombier 	}
5679ef1f84bSDavid du Colombier 
5689ef1f84bSDavid du Colombier 	if(kbdq != nil)
5699ef1f84bSDavid du Colombier 		qproduce(kbdq, buf, n);
5709ef1f84bSDavid du Colombier 	if(kbd.raw == 0)
5719ef1f84bSDavid du Colombier 		putstrn(buf, n);
5729ef1f84bSDavid du Colombier }
5739ef1f84bSDavid du Colombier 
5749ef1f84bSDavid du Colombier /*
5759ef1f84bSDavid du Colombier  *  Called by a uart interrupt for console input.
5769ef1f84bSDavid du Colombier  *
5779ef1f84bSDavid du Colombier  *  turn '\r' into '\n' before putting it into the queue.
5789ef1f84bSDavid du Colombier  */
5799ef1f84bSDavid du Colombier int
kbdcr2nl(Queue *,int ch)5809ef1f84bSDavid du Colombier kbdcr2nl(Queue*, int ch)
5819ef1f84bSDavid du Colombier {
5829ef1f84bSDavid du Colombier 	char *next;
5839ef1f84bSDavid du Colombier 
5849ef1f84bSDavid du Colombier 	ilock(&kbd.lockputc);		/* just a mutex */
5859ef1f84bSDavid du Colombier 	if(ch == '\r' && !kbd.raw)
5869ef1f84bSDavid du Colombier 		ch = '\n';
5879ef1f84bSDavid du Colombier 	next = kbd.iw+1;
5889ef1f84bSDavid du Colombier 	if(next >= kbd.ie)
5899ef1f84bSDavid du Colombier 		next = kbd.istage;
5909ef1f84bSDavid du Colombier 	if(next != kbd.ir){
5919ef1f84bSDavid du Colombier 		*kbd.iw = ch;
5929ef1f84bSDavid du Colombier 		kbd.iw = next;
5939ef1f84bSDavid du Colombier 	}
5949ef1f84bSDavid du Colombier 	iunlock(&kbd.lockputc);
5959ef1f84bSDavid du Colombier 	return 0;
5969ef1f84bSDavid du Colombier }
5979ef1f84bSDavid du Colombier 
5989ef1f84bSDavid du Colombier /*
5999ef1f84bSDavid du Colombier  *  Put character, possibly a rune, into read queue at interrupt time.
6009ef1f84bSDavid du Colombier  *  Called at interrupt time to process a character.
6019ef1f84bSDavid du Colombier  */
6029ef1f84bSDavid du Colombier int
kbdputc(Queue *,int ch)6039ef1f84bSDavid du Colombier kbdputc(Queue*, int ch)
6049ef1f84bSDavid du Colombier {
6059ef1f84bSDavid du Colombier 	int i, n;
6063b1e49d4SDavid du Colombier 	char buf[UTFmax];
6079ef1f84bSDavid du Colombier 	Rune r;
6089ef1f84bSDavid du Colombier 	char *next;
6099ef1f84bSDavid du Colombier 
6109ef1f84bSDavid du Colombier 	if(kbd.ir == nil)
6119ef1f84bSDavid du Colombier 		return 0;		/* in case we're not inited yet */
6129ef1f84bSDavid du Colombier 
6139ef1f84bSDavid du Colombier 	ilock(&kbd.lockputc);		/* just a mutex */
6149ef1f84bSDavid du Colombier 	r = ch;
6159ef1f84bSDavid du Colombier 	n = runetochar(buf, &r);
6169ef1f84bSDavid du Colombier 	for(i = 0; i < n; i++){
6179ef1f84bSDavid du Colombier 		next = kbd.iw+1;
6189ef1f84bSDavid du Colombier 		if(next >= kbd.ie)
6199ef1f84bSDavid du Colombier 			next = kbd.istage;
6209ef1f84bSDavid du Colombier 		if(next == kbd.ir)
6219ef1f84bSDavid du Colombier 			break;
6229ef1f84bSDavid du Colombier 		*kbd.iw = buf[i];
6239ef1f84bSDavid du Colombier 		kbd.iw = next;
6249ef1f84bSDavid du Colombier 	}
6259ef1f84bSDavid du Colombier 	iunlock(&kbd.lockputc);
6269ef1f84bSDavid du Colombier 	return 0;
6279ef1f84bSDavid du Colombier }
6289ef1f84bSDavid du Colombier 
6299ef1f84bSDavid du Colombier /*
6309ef1f84bSDavid du Colombier  *  we save up input characters till clock time to reduce
6319ef1f84bSDavid du Colombier  *  per character interrupt overhead.
6329ef1f84bSDavid du Colombier  */
6339ef1f84bSDavid du Colombier static void
kbdputcclock(void)6349ef1f84bSDavid du Colombier kbdputcclock(void)
6359ef1f84bSDavid du Colombier {
6369ef1f84bSDavid du Colombier 	char *iw;
6379ef1f84bSDavid du Colombier 
6389ef1f84bSDavid du Colombier 	/* this amortizes cost of qproduce */
6399ef1f84bSDavid du Colombier 	if(kbd.iw != kbd.ir){
6409ef1f84bSDavid du Colombier 		iw = kbd.iw;
6419ef1f84bSDavid du Colombier 		if(iw < kbd.ir){
6429ef1f84bSDavid du Colombier 			echo(kbd.ir, kbd.ie-kbd.ir);
6439ef1f84bSDavid du Colombier 			kbd.ir = kbd.istage;
6449ef1f84bSDavid du Colombier 		}
6459ef1f84bSDavid du Colombier 		if(kbd.ir != iw){
6469ef1f84bSDavid du Colombier 			echo(kbd.ir, iw-kbd.ir);
6479ef1f84bSDavid du Colombier 			kbd.ir = iw;
6489ef1f84bSDavid du Colombier 		}
6499ef1f84bSDavid du Colombier 	}
6509ef1f84bSDavid du Colombier }
6519ef1f84bSDavid du Colombier 
6529ef1f84bSDavid du Colombier enum{
6539ef1f84bSDavid du Colombier 	Qdir,
6549ef1f84bSDavid du Colombier 	Qbintime,
6559ef1f84bSDavid du Colombier 	Qcons,
6569ef1f84bSDavid du Colombier 	Qconsctl,
6579ef1f84bSDavid du Colombier 	Qcputime,
6589ef1f84bSDavid du Colombier 	Qdrivers,
6599ef1f84bSDavid du Colombier 	Qkmesg,
6609ef1f84bSDavid du Colombier 	Qkprint,
6619ef1f84bSDavid du Colombier 	Qhostdomain,
6629ef1f84bSDavid du Colombier 	Qhostowner,
6639ef1f84bSDavid du Colombier 	Qnull,
6649ef1f84bSDavid du Colombier 	Qosversion,
6659ef1f84bSDavid du Colombier 	Qpgrpid,
6669ef1f84bSDavid du Colombier 	Qpid,
6679ef1f84bSDavid du Colombier 	Qppid,
6689ef1f84bSDavid du Colombier 	Qrandom,
6699ef1f84bSDavid du Colombier 	Qreboot,
6709ef1f84bSDavid du Colombier 	Qswap,
6719ef1f84bSDavid du Colombier 	Qsysname,
6729ef1f84bSDavid du Colombier 	Qsysstat,
6739ef1f84bSDavid du Colombier 	Qtime,
6749ef1f84bSDavid du Colombier 	Quser,
6759ef1f84bSDavid du Colombier 	Qzero,
6769ef1f84bSDavid du Colombier 	Qconfig,
6779ef1f84bSDavid du Colombier };
6789ef1f84bSDavid du Colombier 
6799ef1f84bSDavid du Colombier enum
6809ef1f84bSDavid du Colombier {
6819ef1f84bSDavid du Colombier 	VLNUMSIZE=	22,
6829ef1f84bSDavid du Colombier };
6839ef1f84bSDavid du Colombier 
6849ef1f84bSDavid du Colombier static Dirtab consdir[]={
6859ef1f84bSDavid du Colombier 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
6869ef1f84bSDavid du Colombier 	"bintime",	{Qbintime},	24,		0664,
6879ef1f84bSDavid du Colombier 	"cons",		{Qcons},	0,		0660,
6889ef1f84bSDavid du Colombier 	"consctl",	{Qconsctl},	0,		0220,
6899ef1f84bSDavid du Colombier 	"cputime",	{Qcputime},	6*NUMSIZE,	0444,
6909ef1f84bSDavid du Colombier 	"drivers",	{Qdrivers},	0,		0444,
6919ef1f84bSDavid du Colombier 	"hostdomain",	{Qhostdomain},	DOMLEN,		0664,
6929ef1f84bSDavid du Colombier 	"hostowner",	{Qhostowner},	0,		0664,
6939ef1f84bSDavid du Colombier 	"kmesg",	{Qkmesg},	0,		0440,
6949ef1f84bSDavid du Colombier 	"kprint",	{Qkprint, 0, QTEXCL},	0,	DMEXCL|0440,
6959ef1f84bSDavid du Colombier 	"null",		{Qnull},	0,		0666,
6969ef1f84bSDavid du Colombier 	"osversion",	{Qosversion},	0,		0444,
6979ef1f84bSDavid du Colombier 	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444,
6989ef1f84bSDavid du Colombier 	"pid",		{Qpid},		NUMSIZE,	0444,
6999ef1f84bSDavid du Colombier 	"ppid",		{Qppid},	NUMSIZE,	0444,
7009ef1f84bSDavid du Colombier 	"random",	{Qrandom},	0,		0444,
701406c76faSDavid du Colombier 	"reboot",	{Qreboot},	0,		0660,
7029ef1f84bSDavid du Colombier 	"swap",		{Qswap},	0,		0664,
7039ef1f84bSDavid du Colombier 	"sysname",	{Qsysname},	0,		0664,
7049ef1f84bSDavid du Colombier 	"sysstat",	{Qsysstat},	0,		0666,
7059ef1f84bSDavid du Colombier 	"time",		{Qtime},	NUMSIZE+3*VLNUMSIZE,	0664,
7069ef1f84bSDavid du Colombier 	"user",		{Quser},	0,		0666,
7079ef1f84bSDavid du Colombier 	"zero",		{Qzero},	0,		0444,
7089ef1f84bSDavid du Colombier 	"config",	{Qconfig},	0,		0444,
7099ef1f84bSDavid du Colombier };
7109ef1f84bSDavid du Colombier 
7119ef1f84bSDavid du Colombier int
readnum(ulong off,char * buf,ulong n,ulong val,int size)7129ef1f84bSDavid du Colombier readnum(ulong off, char *buf, ulong n, ulong val, int size)
7139ef1f84bSDavid du Colombier {
7149ef1f84bSDavid du Colombier 	char tmp[64];
7159ef1f84bSDavid du Colombier 
7169ef1f84bSDavid du Colombier 	snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
7179ef1f84bSDavid du Colombier 	tmp[size-1] = ' ';
7189ef1f84bSDavid du Colombier 	if(off >= size)
7199ef1f84bSDavid du Colombier 		return 0;
7209ef1f84bSDavid du Colombier 	if(off+n > size)
7219ef1f84bSDavid du Colombier 		n = size-off;
7229ef1f84bSDavid du Colombier 	memmove(buf, tmp+off, n);
7239ef1f84bSDavid du Colombier 	return n;
7249ef1f84bSDavid du Colombier }
7259ef1f84bSDavid du Colombier 
7269ef1f84bSDavid du Colombier long
readstr(long offset,char * buf,long n,char * str)7279ef1f84bSDavid du Colombier readstr(long offset, char *buf, long n, char *str)
7289ef1f84bSDavid du Colombier {
7299ef1f84bSDavid du Colombier 	long size;
7309ef1f84bSDavid du Colombier 
7319ef1f84bSDavid du Colombier 	size = strlen(str);
7329ef1f84bSDavid du Colombier 	if(offset >= size)
7339ef1f84bSDavid du Colombier 		return 0;
7349ef1f84bSDavid du Colombier 	if(offset+n > size)
7359ef1f84bSDavid du Colombier 		n = size-offset;
7369ef1f84bSDavid du Colombier 	memmove(buf, str+offset, n);
7379ef1f84bSDavid du Colombier 	return n;
7389ef1f84bSDavid du Colombier }
7399ef1f84bSDavid du Colombier 
7409ef1f84bSDavid du Colombier static void
consinit(void)7419ef1f84bSDavid du Colombier consinit(void)
7429ef1f84bSDavid du Colombier {
7439ef1f84bSDavid du Colombier 	todinit();
7449ef1f84bSDavid du Colombier 	randominit();
7459ef1f84bSDavid du Colombier 	/*
7469ef1f84bSDavid du Colombier 	 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
7479ef1f84bSDavid du Colombier 	 * processing it every 22 ms should be fine
7489ef1f84bSDavid du Colombier 	 */
7499ef1f84bSDavid du Colombier 	addclock0link(kbdputcclock, 22);
7509ef1f84bSDavid du Colombier 	kickkbdq();
7519ef1f84bSDavid du Colombier }
7529ef1f84bSDavid du Colombier 
7539ef1f84bSDavid du Colombier static Chan*
consattach(char * spec)7549ef1f84bSDavid du Colombier consattach(char *spec)
7559ef1f84bSDavid du Colombier {
7569ef1f84bSDavid du Colombier 	return devattach('c', spec);
7579ef1f84bSDavid du Colombier }
7589ef1f84bSDavid du Colombier 
7599ef1f84bSDavid du Colombier static Walkqid*
conswalk(Chan * c,Chan * nc,char ** name,int nname)7609ef1f84bSDavid du Colombier conswalk(Chan *c, Chan *nc, char **name, int nname)
7619ef1f84bSDavid du Colombier {
7629ef1f84bSDavid du Colombier 	return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
7639ef1f84bSDavid du Colombier }
7649ef1f84bSDavid du Colombier 
7659ef1f84bSDavid du Colombier static long
consstat(Chan * c,uchar * dp,long n)7669ef1f84bSDavid du Colombier consstat(Chan *c, uchar *dp, long n)
7679ef1f84bSDavid du Colombier {
7689ef1f84bSDavid du Colombier 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
7699ef1f84bSDavid du Colombier }
7709ef1f84bSDavid du Colombier 
7719ef1f84bSDavid du Colombier static Chan*
consopen(Chan * c,int omode)7729ef1f84bSDavid du Colombier consopen(Chan *c, int omode)
7739ef1f84bSDavid du Colombier {
7749ef1f84bSDavid du Colombier 	c->aux = nil;
7759ef1f84bSDavid du Colombier 	c = devopen(c, omode, consdir, nelem(consdir), devgen);
7769ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
7779ef1f84bSDavid du Colombier 	case Qconsctl:
7789ef1f84bSDavid du Colombier 		incref(&kbd.ctl);
7799ef1f84bSDavid du Colombier 		break;
7809ef1f84bSDavid du Colombier 
7819ef1f84bSDavid du Colombier 	case Qkprint:
7829ef1f84bSDavid du Colombier 		if(TAS(&kprintinuse) != 0){
7839ef1f84bSDavid du Colombier 			c->flag &= ~COPEN;
7849ef1f84bSDavid du Colombier 			error(Einuse);
7859ef1f84bSDavid du Colombier 		}
7869ef1f84bSDavid du Colombier 		if(kprintoq == nil){
7879ef1f84bSDavid du Colombier 			kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
7889ef1f84bSDavid du Colombier 			if(kprintoq == nil){
7899ef1f84bSDavid du Colombier 				c->flag &= ~COPEN;
7909ef1f84bSDavid du Colombier 				error(Enomem);
7919ef1f84bSDavid du Colombier 			}
7929ef1f84bSDavid du Colombier 			qnoblock(kprintoq, 1);
7939ef1f84bSDavid du Colombier 			consdevs[1].q = kprintoq;
7949ef1f84bSDavid du Colombier 		}else
7959ef1f84bSDavid du Colombier 			qreopen(kprintoq);
7969ef1f84bSDavid du Colombier 		c->iounit = qiomaxatomic;
7979ef1f84bSDavid du Colombier 		break;
7989ef1f84bSDavid du Colombier 	}
7999ef1f84bSDavid du Colombier 	return c;
8009ef1f84bSDavid du Colombier }
8019ef1f84bSDavid du Colombier 
8029ef1f84bSDavid du Colombier static void
consclose(Chan * c)8039ef1f84bSDavid du Colombier consclose(Chan *c)
8049ef1f84bSDavid du Colombier {
8059ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
8069ef1f84bSDavid du Colombier 	/* last close of control file turns off raw */
8079ef1f84bSDavid du Colombier 	case Qconsctl:
8089ef1f84bSDavid du Colombier 		if(c->flag&COPEN){
8099ef1f84bSDavid du Colombier 			if(decref(&kbd.ctl) == 0)
8109ef1f84bSDavid du Colombier 				kbd.raw = 0;
8119ef1f84bSDavid du Colombier 		}
8129ef1f84bSDavid du Colombier 		break;
8139ef1f84bSDavid du Colombier 
8149ef1f84bSDavid du Colombier 	/* close of kprint allows other opens */
8159ef1f84bSDavid du Colombier 	case Qkprint:
8169ef1f84bSDavid du Colombier 		if(c->flag & COPEN){
8179ef1f84bSDavid du Colombier 			kprintinuse = 0;
8189ef1f84bSDavid du Colombier 			qhangup(kprintoq, nil);
8199ef1f84bSDavid du Colombier 		}
8209ef1f84bSDavid du Colombier 		break;
8219ef1f84bSDavid du Colombier 	}
8229ef1f84bSDavid du Colombier }
8239ef1f84bSDavid du Colombier 
8249ef1f84bSDavid du Colombier static long
consread(Chan * c,void * buf,long n,vlong off)8259ef1f84bSDavid du Colombier consread(Chan *c, void *buf, long n, vlong off)
8269ef1f84bSDavid du Colombier {
8279ef1f84bSDavid du Colombier 	ulong l;
8289ef1f84bSDavid du Colombier 	Mach *mp;
829*094d6818SDavid du Colombier 	char *b, *bp, ch, *s;
8309ef1f84bSDavid du Colombier 	char tmp[256];		/* must be >= 18*NUMSIZE (Qswap) */
8319ef1f84bSDavid du Colombier 	int i, k, id, send;
8329ef1f84bSDavid du Colombier 	long offset;
8339ef1f84bSDavid du Colombier 
8349ef1f84bSDavid du Colombier 
8359ef1f84bSDavid du Colombier 	if(n <= 0)
8369ef1f84bSDavid du Colombier 		return n;
8379ef1f84bSDavid du Colombier 
8389ef1f84bSDavid du Colombier 	offset = off;
8399ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
8409ef1f84bSDavid du Colombier 	case Qdir:
8419ef1f84bSDavid du Colombier 		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
8429ef1f84bSDavid du Colombier 
8439ef1f84bSDavid du Colombier 	case Qcons:
8449ef1f84bSDavid du Colombier 		qlock(&kbd);
8459ef1f84bSDavid du Colombier 		if(waserror()) {
8469ef1f84bSDavid du Colombier 			qunlock(&kbd);
8479ef1f84bSDavid du Colombier 			nexterror();
8489ef1f84bSDavid du Colombier 		}
8499ef1f84bSDavid du Colombier 		while(!qcanread(lineq)){
8509ef1f84bSDavid du Colombier 			if(qread(kbdq, &ch, 1) == 0)
8519ef1f84bSDavid du Colombier 				continue;
8529ef1f84bSDavid du Colombier 			send = 0;
8539ef1f84bSDavid du Colombier 			if(ch == 0){
8549ef1f84bSDavid du Colombier 				/* flush output on rawoff -> rawon */
8559ef1f84bSDavid du Colombier 				if(kbd.x > 0)
8569ef1f84bSDavid du Colombier 					send = !qcanread(kbdq);
8579ef1f84bSDavid du Colombier 			}else if(kbd.raw){
8589ef1f84bSDavid du Colombier 				kbd.line[kbd.x++] = ch;
8599ef1f84bSDavid du Colombier 				send = !qcanread(kbdq);
8609ef1f84bSDavid du Colombier 			}else{
8619ef1f84bSDavid du Colombier 				switch(ch){
8629ef1f84bSDavid du Colombier 				case '\b':
8639ef1f84bSDavid du Colombier 					if(kbd.x > 0)
8649ef1f84bSDavid du Colombier 						kbd.x--;
8659ef1f84bSDavid du Colombier 					break;
8669ef1f84bSDavid du Colombier 				case 0x15:	/* ^U */
8679ef1f84bSDavid du Colombier 					kbd.x = 0;
8689ef1f84bSDavid du Colombier 					break;
8699ef1f84bSDavid du Colombier 				case '\n':
8709ef1f84bSDavid du Colombier 				case 0x04:	/* ^D */
8719ef1f84bSDavid du Colombier 					send = 1;
8729ef1f84bSDavid du Colombier 				default:
8739ef1f84bSDavid du Colombier 					if(ch != 0x04)
8749ef1f84bSDavid du Colombier 						kbd.line[kbd.x++] = ch;
8759ef1f84bSDavid du Colombier 					break;
8769ef1f84bSDavid du Colombier 				}
8779ef1f84bSDavid du Colombier 			}
8789ef1f84bSDavid du Colombier 			if(send || kbd.x == sizeof kbd.line){
8799ef1f84bSDavid du Colombier 				qwrite(lineq, kbd.line, kbd.x);
8809ef1f84bSDavid du Colombier 				kbd.x = 0;
8819ef1f84bSDavid du Colombier 			}
8829ef1f84bSDavid du Colombier 		}
8839ef1f84bSDavid du Colombier 		n = qread(lineq, buf, n);
8849ef1f84bSDavid du Colombier 		qunlock(&kbd);
8859ef1f84bSDavid du Colombier 		poperror();
8869ef1f84bSDavid du Colombier 		return n;
8879ef1f84bSDavid du Colombier 
8889ef1f84bSDavid du Colombier 	case Qcputime:
8899ef1f84bSDavid du Colombier 		k = offset;
8909ef1f84bSDavid du Colombier 		if(k >= 6*NUMSIZE)
8919ef1f84bSDavid du Colombier 			return 0;
8929ef1f84bSDavid du Colombier 		if(k+n > 6*NUMSIZE)
8939ef1f84bSDavid du Colombier 			n = 6*NUMSIZE - k;
8949ef1f84bSDavid du Colombier 		/* easiest to format in a separate buffer and copy out */
8959ef1f84bSDavid du Colombier 		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
8969ef1f84bSDavid du Colombier 			l = up->time[i];
8979ef1f84bSDavid du Colombier 			if(i == TReal)
8989ef1f84bSDavid du Colombier 				l = sys->ticks - l;
8999ef1f84bSDavid du Colombier 			l = TK2MS(l);
9009ef1f84bSDavid du Colombier 			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
9019ef1f84bSDavid du Colombier 		}
9029ef1f84bSDavid du Colombier 		memmove(buf, tmp+k, n);
9039ef1f84bSDavid du Colombier 		return n;
9049ef1f84bSDavid du Colombier 
9059ef1f84bSDavid du Colombier 	case Qkmesg:
9069ef1f84bSDavid du Colombier 		/*
9079ef1f84bSDavid du Colombier 		 * This is unlocked to avoid tying up a process
9089ef1f84bSDavid du Colombier 		 * that's writing to the buffer.  kmesg.n never
9099ef1f84bSDavid du Colombier 		 * gets smaller, so worst case the reader will
9109ef1f84bSDavid du Colombier 		 * see a slurred buffer.
9119ef1f84bSDavid du Colombier 		 */
9129ef1f84bSDavid du Colombier 		if(off >= kmesg.n)
9139ef1f84bSDavid du Colombier 			n = 0;
9149ef1f84bSDavid du Colombier 		else{
9159ef1f84bSDavid du Colombier 			if(off+n > kmesg.n)
9169ef1f84bSDavid du Colombier 				n = kmesg.n - off;
9179ef1f84bSDavid du Colombier 			memmove(buf, kmesg.buf+off, n);
9189ef1f84bSDavid du Colombier 		}
9199ef1f84bSDavid du Colombier 		return n;
9209ef1f84bSDavid du Colombier 
9219ef1f84bSDavid du Colombier 	case Qkprint:
9229ef1f84bSDavid du Colombier 		return qread(kprintoq, buf, n);
9239ef1f84bSDavid du Colombier 
9249ef1f84bSDavid du Colombier 	case Qpgrpid:
9259ef1f84bSDavid du Colombier 		return readnum(offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
9269ef1f84bSDavid du Colombier 
9279ef1f84bSDavid du Colombier 	case Qpid:
9289ef1f84bSDavid du Colombier 		return readnum(offset, buf, n, up->pid, NUMSIZE);
9299ef1f84bSDavid du Colombier 
9309ef1f84bSDavid du Colombier 	case Qppid:
9319ef1f84bSDavid du Colombier 		return readnum(offset, buf, n, up->parentpid, NUMSIZE);
9329ef1f84bSDavid du Colombier 
9339ef1f84bSDavid du Colombier 	case Qtime:
9349ef1f84bSDavid du Colombier 		return readtime(offset, buf, n);
9359ef1f84bSDavid du Colombier 
9369ef1f84bSDavid du Colombier 	case Qbintime:
9379ef1f84bSDavid du Colombier 		return readbintime(buf, n);
9389ef1f84bSDavid du Colombier 
9399ef1f84bSDavid du Colombier 	case Qhostowner:
9409ef1f84bSDavid du Colombier 		return readstr(offset, buf, n, eve);
9419ef1f84bSDavid du Colombier 
9429ef1f84bSDavid du Colombier 	case Qhostdomain:
9439ef1f84bSDavid du Colombier 		return readstr(offset, buf, n, hostdomain);
9449ef1f84bSDavid du Colombier 
9459ef1f84bSDavid du Colombier 	case Quser:
9469ef1f84bSDavid du Colombier 		return readstr(offset, buf, n, up->user);
9479ef1f84bSDavid du Colombier 
9489ef1f84bSDavid du Colombier 	case Qnull:
9499ef1f84bSDavid du Colombier 		return 0;
9509ef1f84bSDavid du Colombier 
9519ef1f84bSDavid du Colombier 	case Qconfig:
9529ef1f84bSDavid du Colombier 		return readstr(offset, buf, n, configfile);
9539ef1f84bSDavid du Colombier 
9549ef1f84bSDavid du Colombier 	case Qsysstat:
9559ef1f84bSDavid du Colombier 		b = smalloc(sys->nonline*(NUMSIZE*11+1) + 1);	/* +1 for NUL */
9569ef1f84bSDavid du Colombier 		bp = b;
9579ef1f84bSDavid du Colombier 		for(id = 0; id < MACHMAX; id++){
9589ef1f84bSDavid du Colombier 			if((mp = sys->machptr[id]) == nil || !mp->online)
9599ef1f84bSDavid du Colombier 				continue;
9609ef1f84bSDavid du Colombier 			readnum(0, bp, NUMSIZE, id, NUMSIZE);
9619ef1f84bSDavid du Colombier 			bp += NUMSIZE;
9629ef1f84bSDavid du Colombier 			readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
9639ef1f84bSDavid du Colombier 			bp += NUMSIZE;
9649ef1f84bSDavid du Colombier 			readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
9659ef1f84bSDavid du Colombier 			bp += NUMSIZE;
9669ef1f84bSDavid du Colombier 			readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
9679ef1f84bSDavid du Colombier 			bp += NUMSIZE;
9689ef1f84bSDavid du Colombier 			readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
9699ef1f84bSDavid du Colombier 			bp += NUMSIZE;
9709ef1f84bSDavid du Colombier 			readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
9719ef1f84bSDavid du Colombier 			bp += NUMSIZE;
9729ef1f84bSDavid du Colombier 			readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
9739ef1f84bSDavid du Colombier 			bp += NUMSIZE;
9749ef1f84bSDavid du Colombier 			readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
9759ef1f84bSDavid du Colombier 			bp += NUMSIZE;
9769ef1f84bSDavid du Colombier 			readnum(0, bp, NUMSIZE,
9779ef1f84bSDavid du Colombier 				(mp->perf.avg_inidle*100)/mp->perf.period,
9789ef1f84bSDavid du Colombier 				NUMSIZE);
9799ef1f84bSDavid du Colombier 			bp += NUMSIZE;
9809ef1f84bSDavid du Colombier 			readnum(0, bp, NUMSIZE,
9819ef1f84bSDavid du Colombier 				(mp->perf.avg_inintr*100)/mp->perf.period,
9829ef1f84bSDavid du Colombier 				NUMSIZE);
9839ef1f84bSDavid du Colombier 			bp += NUMSIZE;
9849ef1f84bSDavid du Colombier 			*bp++ = '\n';
9859ef1f84bSDavid du Colombier 		}
9869ef1f84bSDavid du Colombier 		if(waserror()){
9879ef1f84bSDavid du Colombier 			free(b);
9889ef1f84bSDavid du Colombier 			nexterror();
9899ef1f84bSDavid du Colombier 		}
9909ef1f84bSDavid du Colombier 		n = readstr(offset, buf, n, b);
9919ef1f84bSDavid du Colombier 		free(b);
9929ef1f84bSDavid du Colombier 		poperror();
9939ef1f84bSDavid du Colombier 		return n;
9949ef1f84bSDavid du Colombier 
9959ef1f84bSDavid du Colombier 	case Qswap:
996*094d6818SDavid du Colombier 		tmp[0] = 0;
997*094d6818SDavid du Colombier 		s = seprintpagestats(tmp, tmp + sizeof tmp);
998*094d6818SDavid du Colombier 		s = seprintphysstats(s, tmp + sizeof tmp);
9999ef1f84bSDavid du Colombier 		b = buf;
1000*094d6818SDavid du Colombier 		l = s - tmp;
1001*094d6818SDavid du Colombier 		i = readstr(offset, b, l, tmp);
10029ef1f84bSDavid du Colombier 		b += i;
10039ef1f84bSDavid du Colombier 		n -= i;
10049ef1f84bSDavid du Colombier 		if(offset > l)
10059ef1f84bSDavid du Colombier 			offset -= l;
10069ef1f84bSDavid du Colombier 		else
10079ef1f84bSDavid du Colombier 			offset = 0;
10089ef1f84bSDavid du Colombier 
10099ef1f84bSDavid du Colombier 		return i + mallocreadsummary(c, b, n, offset);
10109ef1f84bSDavid du Colombier 
10119ef1f84bSDavid du Colombier 	case Qsysname:
10129ef1f84bSDavid du Colombier 		if(sysname == nil)
10139ef1f84bSDavid du Colombier 			return 0;
10149ef1f84bSDavid du Colombier 		return readstr(offset, buf, n, sysname);
10159ef1f84bSDavid du Colombier 
10169ef1f84bSDavid du Colombier 	case Qrandom:
10179ef1f84bSDavid du Colombier 		return randomread(buf, n);
10189ef1f84bSDavid du Colombier 
10199ef1f84bSDavid du Colombier 	case Qdrivers:
10209ef1f84bSDavid du Colombier 		return devtabread(c, buf, n, off);
10219ef1f84bSDavid du Colombier 
10229ef1f84bSDavid du Colombier 	case Qzero:
10239ef1f84bSDavid du Colombier 		memset(buf, 0, n);
10249ef1f84bSDavid du Colombier 		return n;
10259ef1f84bSDavid du Colombier 
10269ef1f84bSDavid du Colombier 	case Qosversion:
10279ef1f84bSDavid du Colombier 		snprint(tmp, sizeof tmp, "2000");
10289ef1f84bSDavid du Colombier 		n = readstr(offset, buf, n, tmp);
10299ef1f84bSDavid du Colombier 		return n;
10309ef1f84bSDavid du Colombier 
10319ef1f84bSDavid du Colombier 	default:
10329ef1f84bSDavid du Colombier 		print("consread %#llux\n", c->qid.path);
10339ef1f84bSDavid du Colombier 		error(Egreg);
10349ef1f84bSDavid du Colombier 	}
10359ef1f84bSDavid du Colombier 	return -1;		/* never reached */
10369ef1f84bSDavid du Colombier }
10379ef1f84bSDavid du Colombier 
10389ef1f84bSDavid du Colombier static long
conswrite(Chan * c,void * va,long n,vlong off)10399ef1f84bSDavid du Colombier conswrite(Chan *c, void *va, long n, vlong off)
10409ef1f84bSDavid du Colombier {
10419ef1f84bSDavid du Colombier 	char buf[256], ch;
10429ef1f84bSDavid du Colombier 	long l, bp;
10439ef1f84bSDavid du Colombier 	char *a;
10449ef1f84bSDavid du Colombier 	Mach *mp;
10459ef1f84bSDavid du Colombier 	int i;
10469ef1f84bSDavid du Colombier 	ulong offset;
10479ef1f84bSDavid du Colombier 	Cmdbuf *cb;
10489ef1f84bSDavid du Colombier 	Cmdtab *ct;
10499ef1f84bSDavid du Colombier 
10509ef1f84bSDavid du Colombier 	a = va;
10519ef1f84bSDavid du Colombier 	offset = off;
10529ef1f84bSDavid du Colombier 
10539ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
10549ef1f84bSDavid du Colombier 	case Qcons:
10559ef1f84bSDavid du Colombier 		/*
10569ef1f84bSDavid du Colombier 		 * Can't page fault in putstrn, so copy the data locally.
10579ef1f84bSDavid du Colombier 		 */
10589ef1f84bSDavid du Colombier 		l = n;
10599ef1f84bSDavid du Colombier 		while(l > 0){
10609ef1f84bSDavid du Colombier 			bp = l;
10619ef1f84bSDavid du Colombier 			if(bp > sizeof buf)
10629ef1f84bSDavid du Colombier 				bp = sizeof buf;
10639ef1f84bSDavid du Colombier 			memmove(buf, a, bp);
10649ef1f84bSDavid du Colombier 			putstrn0(buf, bp, 1);
10659ef1f84bSDavid du Colombier 			a += bp;
10669ef1f84bSDavid du Colombier 			l -= bp;
10679ef1f84bSDavid du Colombier 		}
10689ef1f84bSDavid du Colombier 		break;
10699ef1f84bSDavid du Colombier 
10709ef1f84bSDavid du Colombier 	case Qconsctl:
10719ef1f84bSDavid du Colombier 		if(n >= sizeof(buf))
10729ef1f84bSDavid du Colombier 			n = sizeof(buf)-1;
10739ef1f84bSDavid du Colombier 		strncpy(buf, a, n);
10749ef1f84bSDavid du Colombier 		buf[n] = 0;
10759ef1f84bSDavid du Colombier 		for(a = buf; a;){
10769ef1f84bSDavid du Colombier 			if(strncmp(a, "rawon", 5) == 0){
10779ef1f84bSDavid du Colombier 				kbd.raw = 1;
10789ef1f84bSDavid du Colombier 				/* clumsy hack - wake up reader */
10799ef1f84bSDavid du Colombier 				ch = 0;
10809ef1f84bSDavid du Colombier 				qwrite(kbdq, &ch, 1);
10819ef1f84bSDavid du Colombier 			}
10829ef1f84bSDavid du Colombier 			else if(strncmp(a, "rawoff", 6) == 0)
10839ef1f84bSDavid du Colombier 				kbd.raw = 0;
10849ef1f84bSDavid du Colombier 			else if(strncmp(a, "ctlpon", 6) == 0)
10859ef1f84bSDavid du Colombier 				kbd.ctlpoff = 0;
10869ef1f84bSDavid du Colombier 			else if(strncmp(a, "ctlpoff", 7) == 0)
10879ef1f84bSDavid du Colombier 				kbd.ctlpoff = 1;
10889ef1f84bSDavid du Colombier 			if(a = strchr(a, ' '))
10899ef1f84bSDavid du Colombier 				a++;
10909ef1f84bSDavid du Colombier 		}
10919ef1f84bSDavid du Colombier 		break;
10929ef1f84bSDavid du Colombier 
10939ef1f84bSDavid du Colombier 	case Qtime:
10949ef1f84bSDavid du Colombier 		if(!iseve())
10959ef1f84bSDavid du Colombier 			error(Eperm);
10969ef1f84bSDavid du Colombier 		return writetime(a, n);
10979ef1f84bSDavid du Colombier 
10989ef1f84bSDavid du Colombier 	case Qbintime:
10999ef1f84bSDavid du Colombier 		if(!iseve())
11009ef1f84bSDavid du Colombier 			error(Eperm);
11019ef1f84bSDavid du Colombier 		return writebintime(a, n);
11029ef1f84bSDavid du Colombier 
11039ef1f84bSDavid du Colombier 	case Qhostowner:
11049ef1f84bSDavid du Colombier 		return hostownerwrite(a, n);
11059ef1f84bSDavid du Colombier 
11069ef1f84bSDavid du Colombier 	case Qhostdomain:
11079ef1f84bSDavid du Colombier 		return hostdomainwrite(a, n);
11089ef1f84bSDavid du Colombier 
11099ef1f84bSDavid du Colombier 	case Quser:
11109ef1f84bSDavid du Colombier 		return userwrite(a, n);
11119ef1f84bSDavid du Colombier 
11129ef1f84bSDavid du Colombier 	case Qnull:
11139ef1f84bSDavid du Colombier 		break;
11149ef1f84bSDavid du Colombier 
11159ef1f84bSDavid du Colombier 	case Qconfig:
11169ef1f84bSDavid du Colombier 		error(Eperm);
11179ef1f84bSDavid du Colombier 		break;
11189ef1f84bSDavid du Colombier 
11199ef1f84bSDavid du Colombier 	case Qreboot:
11209ef1f84bSDavid du Colombier 		if(!iseve())
11219ef1f84bSDavid du Colombier 			error(Eperm);
11229ef1f84bSDavid du Colombier 		cb = parsecmd(a, n);
11239ef1f84bSDavid du Colombier 
11249ef1f84bSDavid du Colombier 		if(waserror()) {
11259ef1f84bSDavid du Colombier 			free(cb);
11269ef1f84bSDavid du Colombier 			nexterror();
11279ef1f84bSDavid du Colombier 		}
11289ef1f84bSDavid du Colombier 		ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
11299ef1f84bSDavid du Colombier 		switch(ct->index) {
11309ef1f84bSDavid du Colombier 		case CMhalt:
11319ef1f84bSDavid du Colombier 			reboot(nil, 0, 0);
11329ef1f84bSDavid du Colombier 			break;
11339ef1f84bSDavid du Colombier 		case CMreboot:
11349ef1f84bSDavid du Colombier 			rebootcmd(cb->nf-1, cb->f+1);
11359ef1f84bSDavid du Colombier 			break;
11369ef1f84bSDavid du Colombier 		case CMpanic:
11379ef1f84bSDavid du Colombier 			*(ulong*)0=0;
11389ef1f84bSDavid du Colombier 			panic("/dev/reboot");
11399ef1f84bSDavid du Colombier 		}
11409ef1f84bSDavid du Colombier 		poperror();
11419ef1f84bSDavid du Colombier 		free(cb);
11429ef1f84bSDavid du Colombier 		break;
11439ef1f84bSDavid du Colombier 
11449ef1f84bSDavid du Colombier 	case Qsysstat:
11459ef1f84bSDavid du Colombier 		for(i = 0; i < MACHMAX; i++){
11469ef1f84bSDavid du Colombier 			if((mp = sys->machptr[i]) == nil || !mp->online)
11479ef1f84bSDavid du Colombier 				continue;
11489ef1f84bSDavid du Colombier 			mp->cs = 0;
11499ef1f84bSDavid du Colombier 			mp->intr = 0;
11509ef1f84bSDavid du Colombier 			mp->syscall = 0;
11519ef1f84bSDavid du Colombier 			mp->pfault = 0;
11529ef1f84bSDavid du Colombier 			mp->tlbfault = 0;
11539ef1f84bSDavid du Colombier 			mp->tlbpurge = 0;
11549ef1f84bSDavid du Colombier 		}
11559ef1f84bSDavid du Colombier 		break;
11569ef1f84bSDavid du Colombier 
11579ef1f84bSDavid du Colombier 	case Qswap:
11589ef1f84bSDavid du Colombier 		/* no more */
11599ef1f84bSDavid du Colombier 		break;
11609ef1f84bSDavid du Colombier 
11619ef1f84bSDavid du Colombier 	case Qsysname:
11629ef1f84bSDavid du Colombier 		if(offset != 0)
11639ef1f84bSDavid du Colombier 			error(Ebadarg);
11649ef1f84bSDavid du Colombier 		if(n <= 0 || n >= sizeof buf)
11659ef1f84bSDavid du Colombier 			error(Ebadarg);
11669ef1f84bSDavid du Colombier 		strncpy(buf, a, n);
11679ef1f84bSDavid du Colombier 		buf[n] = 0;
11689ef1f84bSDavid du Colombier 		if(buf[n-1] == '\n')
11699ef1f84bSDavid du Colombier 			buf[n-1] = 0;
11709ef1f84bSDavid du Colombier 		kstrdup(&sysname, buf);
11719ef1f84bSDavid du Colombier 		break;
11729ef1f84bSDavid du Colombier 
11739ef1f84bSDavid du Colombier 	default:
11749ef1f84bSDavid du Colombier 		print("conswrite: %#llux\n", c->qid.path);
11759ef1f84bSDavid du Colombier 		error(Egreg);
11769ef1f84bSDavid du Colombier 	}
11779ef1f84bSDavid du Colombier 	return n;
11789ef1f84bSDavid du Colombier }
11799ef1f84bSDavid du Colombier 
11809ef1f84bSDavid du Colombier Dev consdevtab = {
11819ef1f84bSDavid du Colombier 	'c',
11829ef1f84bSDavid du Colombier 	"cons",
11839ef1f84bSDavid du Colombier 
11849ef1f84bSDavid du Colombier 	devreset,
11859ef1f84bSDavid du Colombier 	consinit,
11869ef1f84bSDavid du Colombier 	devshutdown,
11879ef1f84bSDavid du Colombier 	consattach,
11889ef1f84bSDavid du Colombier 	conswalk,
11899ef1f84bSDavid du Colombier 	consstat,
11909ef1f84bSDavid du Colombier 	consopen,
11919ef1f84bSDavid du Colombier 	devcreate,
11929ef1f84bSDavid du Colombier 	consclose,
11939ef1f84bSDavid du Colombier 	consread,
11949ef1f84bSDavid du Colombier 	devbread,
11959ef1f84bSDavid du Colombier 	conswrite,
11969ef1f84bSDavid du Colombier 	devbwrite,
11979ef1f84bSDavid du Colombier 	devremove,
11989ef1f84bSDavid du Colombier 	devwstat,
11999ef1f84bSDavid du Colombier };
12009ef1f84bSDavid du Colombier 
12019ef1f84bSDavid du Colombier static	ulong	randn;
12029ef1f84bSDavid du Colombier 
12039ef1f84bSDavid du Colombier static void
seedrand(void)12049ef1f84bSDavid du Colombier seedrand(void)
12059ef1f84bSDavid du Colombier {
12069ef1f84bSDavid du Colombier 	if(!waserror()){
12079ef1f84bSDavid du Colombier 		randomread((void*)&randn, sizeof(randn));
12089ef1f84bSDavid du Colombier 		poperror();
12099ef1f84bSDavid du Colombier 	}
12109ef1f84bSDavid du Colombier }
12119ef1f84bSDavid du Colombier 
12129ef1f84bSDavid du Colombier int
nrand(int n)12139ef1f84bSDavid du Colombier nrand(int n)
12149ef1f84bSDavid du Colombier {
12159ef1f84bSDavid du Colombier 	if(randn == 0)
12169ef1f84bSDavid du Colombier 		seedrand();
12179ef1f84bSDavid du Colombier 	randn = randn*1103515245 + 12345 + sys->ticks;
12189ef1f84bSDavid du Colombier 	return (randn>>16) % n;
12199ef1f84bSDavid du Colombier }
12209ef1f84bSDavid du Colombier 
12219ef1f84bSDavid du Colombier int
rand(void)12229ef1f84bSDavid du Colombier rand(void)
12239ef1f84bSDavid du Colombier {
12249ef1f84bSDavid du Colombier 	nrand(1);
12259ef1f84bSDavid du Colombier 	return randn;
12269ef1f84bSDavid du Colombier }
12279ef1f84bSDavid du Colombier 
12289ef1f84bSDavid du Colombier static uvlong uvorder = 0x0001020304050607ULL;
12299ef1f84bSDavid du Colombier 
12309ef1f84bSDavid du Colombier static uchar*
le2vlong(vlong * to,uchar * f)12319ef1f84bSDavid du Colombier le2vlong(vlong *to, uchar *f)
12329ef1f84bSDavid du Colombier {
12339ef1f84bSDavid du Colombier 	uchar *t, *o;
12349ef1f84bSDavid du Colombier 	int i;
12359ef1f84bSDavid du Colombier 
12369ef1f84bSDavid du Colombier 	t = (uchar*)to;
12379ef1f84bSDavid du Colombier 	o = (uchar*)&uvorder;
12389ef1f84bSDavid du Colombier 	for(i = 0; i < sizeof(vlong); i++)
12399ef1f84bSDavid du Colombier 		t[o[i]] = f[i];
12409ef1f84bSDavid du Colombier 	return f+sizeof(vlong);
12419ef1f84bSDavid du Colombier }
12429ef1f84bSDavid du Colombier 
12439ef1f84bSDavid du Colombier static uchar*
vlong2le(uchar * t,vlong from)12449ef1f84bSDavid du Colombier vlong2le(uchar *t, vlong from)
12459ef1f84bSDavid du Colombier {
12469ef1f84bSDavid du Colombier 	uchar *f, *o;
12479ef1f84bSDavid du Colombier 	int i;
12489ef1f84bSDavid du Colombier 
12499ef1f84bSDavid du Colombier 	f = (uchar*)&from;
12509ef1f84bSDavid du Colombier 	o = (uchar*)&uvorder;
12519ef1f84bSDavid du Colombier 	for(i = 0; i < sizeof(vlong); i++)
12529ef1f84bSDavid du Colombier 		t[i] = f[o[i]];
12539ef1f84bSDavid du Colombier 	return t+sizeof(vlong);
12549ef1f84bSDavid du Colombier }
12559ef1f84bSDavid du Colombier 
12569ef1f84bSDavid du Colombier static long order = 0x00010203;
12579ef1f84bSDavid du Colombier 
12589ef1f84bSDavid du Colombier static uchar*
le2long(long * to,uchar * f)12599ef1f84bSDavid du Colombier le2long(long *to, uchar *f)
12609ef1f84bSDavid du Colombier {
12619ef1f84bSDavid du Colombier 	uchar *t, *o;
12629ef1f84bSDavid du Colombier 	int i;
12639ef1f84bSDavid du Colombier 
12649ef1f84bSDavid du Colombier 	t = (uchar*)to;
12659ef1f84bSDavid du Colombier 	o = (uchar*)&order;
12669ef1f84bSDavid du Colombier 	for(i = 0; i < sizeof(long); i++)
12679ef1f84bSDavid du Colombier 		t[o[i]] = f[i];
12689ef1f84bSDavid du Colombier 	return f+sizeof(long);
12699ef1f84bSDavid du Colombier }
12709ef1f84bSDavid du Colombier 
12719ef1f84bSDavid du Colombier static uchar*
long2le(uchar * t,long from)12729ef1f84bSDavid du Colombier long2le(uchar *t, long from)
12739ef1f84bSDavid du Colombier {
12749ef1f84bSDavid du Colombier 	uchar *f, *o;
12759ef1f84bSDavid du Colombier 	int i;
12769ef1f84bSDavid du Colombier 
12779ef1f84bSDavid du Colombier 	f = (uchar*)&from;
12789ef1f84bSDavid du Colombier 	o = (uchar*)&order;
12799ef1f84bSDavid du Colombier 	for(i = 0; i < sizeof(long); i++)
12809ef1f84bSDavid du Colombier 		t[i] = f[o[i]];
12819ef1f84bSDavid du Colombier 	return t+sizeof(long);
12829ef1f84bSDavid du Colombier }
12839ef1f84bSDavid du Colombier 
12849ef1f84bSDavid du Colombier char *Ebadtimectl = "bad time control";
12859ef1f84bSDavid du Colombier 
12869ef1f84bSDavid du Colombier /*
12879ef1f84bSDavid du Colombier  *  like the old #c/time but with added info.  Return
12889ef1f84bSDavid du Colombier  *
12899ef1f84bSDavid du Colombier  *	secs	nanosecs	fastticks	fasthz
12909ef1f84bSDavid du Colombier  */
12919ef1f84bSDavid du Colombier static int
readtime(ulong off,char * buf,int n)12929ef1f84bSDavid du Colombier readtime(ulong off, char *buf, int n)
12939ef1f84bSDavid du Colombier {
12949ef1f84bSDavid du Colombier 	vlong nsec, ticks;
12959ef1f84bSDavid du Colombier 	long sec;
12969ef1f84bSDavid du Colombier 	char str[7*NUMSIZE];
12979ef1f84bSDavid du Colombier 
12989ef1f84bSDavid du Colombier 	nsec = todget(&ticks);
12999ef1f84bSDavid du Colombier 	if(fasthz == 0LL)
13009ef1f84bSDavid du Colombier 		fastticks((uvlong*)&fasthz);
13019ef1f84bSDavid du Colombier 	sec = nsec/1000000000ULL;
13029ef1f84bSDavid du Colombier 	snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
13039ef1f84bSDavid du Colombier 		NUMSIZE-1, sec,
13049ef1f84bSDavid du Colombier 		VLNUMSIZE-1, nsec,
13059ef1f84bSDavid du Colombier 		VLNUMSIZE-1, ticks,
13069ef1f84bSDavid du Colombier 		VLNUMSIZE-1, fasthz);
13079ef1f84bSDavid du Colombier 	return readstr(off, buf, n, str);
13089ef1f84bSDavid du Colombier }
13099ef1f84bSDavid du Colombier 
13109ef1f84bSDavid du Colombier /*
13119ef1f84bSDavid du Colombier  *  set the time in seconds
13129ef1f84bSDavid du Colombier  */
13139ef1f84bSDavid du Colombier static int
writetime(char * buf,int n)13149ef1f84bSDavid du Colombier writetime(char *buf, int n)
13159ef1f84bSDavid du Colombier {
13169ef1f84bSDavid du Colombier 	char b[13];
13179ef1f84bSDavid du Colombier 	long i;
13189ef1f84bSDavid du Colombier 	vlong now;
13199ef1f84bSDavid du Colombier 
13209ef1f84bSDavid du Colombier 	if(n >= sizeof(b))
13219ef1f84bSDavid du Colombier 		error(Ebadtimectl);
13229ef1f84bSDavid du Colombier 	strncpy(b, buf, n);
13239ef1f84bSDavid du Colombier 	b[n] = 0;
13249ef1f84bSDavid du Colombier 	i = strtol(b, 0, 0);
13259ef1f84bSDavid du Colombier 	if(i <= 0)
13269ef1f84bSDavid du Colombier 		error(Ebadtimectl);
13279ef1f84bSDavid du Colombier 	now = i*1000000000LL;
13289ef1f84bSDavid du Colombier 	todset(now, 0, 0);
13299ef1f84bSDavid du Colombier 	return n;
13309ef1f84bSDavid du Colombier }
13319ef1f84bSDavid du Colombier 
13329ef1f84bSDavid du Colombier /*
13339ef1f84bSDavid du Colombier  *  read binary time info.  all numbers are little endian.
13349ef1f84bSDavid du Colombier  *  ticks and nsec are syncronized.
13359ef1f84bSDavid du Colombier  */
13369ef1f84bSDavid du Colombier static int
readbintime(char * buf,int n)13379ef1f84bSDavid du Colombier readbintime(char *buf, int n)
13389ef1f84bSDavid du Colombier {
13399ef1f84bSDavid du Colombier 	int i;
13409ef1f84bSDavid du Colombier 	vlong nsec, ticks;
13419ef1f84bSDavid du Colombier 	uchar *b = (uchar*)buf;
13429ef1f84bSDavid du Colombier 
13439ef1f84bSDavid du Colombier 	i = 0;
13449ef1f84bSDavid du Colombier 	if(fasthz == 0LL)
13459ef1f84bSDavid du Colombier 		fastticks((uvlong*)&fasthz);
13469ef1f84bSDavid du Colombier 	nsec = todget(&ticks);
13479ef1f84bSDavid du Colombier 	if(n >= 3*sizeof(uvlong)){
13489ef1f84bSDavid du Colombier 		vlong2le(b+2*sizeof(uvlong), fasthz);
13499ef1f84bSDavid du Colombier 		i += sizeof(uvlong);
13509ef1f84bSDavid du Colombier 	}
13519ef1f84bSDavid du Colombier 	if(n >= 2*sizeof(uvlong)){
13529ef1f84bSDavid du Colombier 		vlong2le(b+sizeof(uvlong), ticks);
13539ef1f84bSDavid du Colombier 		i += sizeof(uvlong);
13549ef1f84bSDavid du Colombier 	}
13559ef1f84bSDavid du Colombier 	if(n >= 8){
13569ef1f84bSDavid du Colombier 		vlong2le(b, nsec);
13579ef1f84bSDavid du Colombier 		i += sizeof(vlong);
13589ef1f84bSDavid du Colombier 	}
13599ef1f84bSDavid du Colombier 	return i;
13609ef1f84bSDavid du Colombier }
13619ef1f84bSDavid du Colombier 
13629ef1f84bSDavid du Colombier /*
13639ef1f84bSDavid du Colombier  *  set any of the following
13649ef1f84bSDavid du Colombier  *	- time in nsec
13659ef1f84bSDavid du Colombier  *	- nsec trim applied over some seconds
13669ef1f84bSDavid du Colombier  *	- clock frequency
13679ef1f84bSDavid du Colombier  */
13689ef1f84bSDavid du Colombier static int
writebintime(char * buf,int n)13699ef1f84bSDavid du Colombier writebintime(char *buf, int n)
13709ef1f84bSDavid du Colombier {
13719ef1f84bSDavid du Colombier 	uchar *p;
13729ef1f84bSDavid du Colombier 	vlong delta;
13739ef1f84bSDavid du Colombier 	long period;
13749ef1f84bSDavid du Colombier 
13759ef1f84bSDavid du Colombier 	n--;
13769ef1f84bSDavid du Colombier 	p = (uchar*)buf + 1;
13779ef1f84bSDavid du Colombier 	switch(*buf){
13789ef1f84bSDavid du Colombier 	case 'n':
13799ef1f84bSDavid du Colombier 		if(n < sizeof(vlong))
13809ef1f84bSDavid du Colombier 			error(Ebadtimectl);
13819ef1f84bSDavid du Colombier 		le2vlong(&delta, p);
13829ef1f84bSDavid du Colombier 		todset(delta, 0, 0);
13839ef1f84bSDavid du Colombier 		break;
13849ef1f84bSDavid du Colombier 	case 'd':
13859ef1f84bSDavid du Colombier 		if(n < sizeof(vlong)+sizeof(long))
13869ef1f84bSDavid du Colombier 			error(Ebadtimectl);
13879ef1f84bSDavid du Colombier 		p = le2vlong(&delta, p);
13889ef1f84bSDavid du Colombier 		le2long(&period, p);
13899ef1f84bSDavid du Colombier 		todset(-1, delta, period);
13909ef1f84bSDavid du Colombier 		break;
13919ef1f84bSDavid du Colombier 	case 'f':
13929ef1f84bSDavid du Colombier 		if(n < sizeof(uvlong))
13939ef1f84bSDavid du Colombier 			error(Ebadtimectl);
13949ef1f84bSDavid du Colombier 		le2vlong(&fasthz, p);
13959ef1f84bSDavid du Colombier 		todsetfreq(fasthz);
13969ef1f84bSDavid du Colombier 		break;
13979ef1f84bSDavid du Colombier 	}
13989ef1f84bSDavid du Colombier 	return n;
13999ef1f84bSDavid du Colombier }
1400