code: 9ferno

Download patch

ref: 702ddcd8846c7c9b64e95e93e035003d1cab38d8
parent: d820cecf3f0e00f02da03d85f6db118d989e140b
author: 9ferno <gophone2015@gmail.com>
date: Sat Aug 7 08:45:30 EDT 2021

going for kbdfs

--- a/os/pc64/dat.h
+++ b/os/pc64/dat.h
@@ -37,6 +37,10 @@
 	u32	sr;
 	uintptr	pc;
 	u32	pri;
+	void *p;	/* Proc */
+	Mach *m;
+	u16 isilock;
+	u32 lockcycles;
 };
 
 struct Label
--- a/os/pc64/fns.h
+++ b/os/pc64/fns.h
@@ -158,7 +158,6 @@
 void	(*_pcmspecialclose)(int);
 void	pcmunmap(int, PCMmap*);
 void	pmap(uintptr, u64, s64);
-void	poolinit(void);
 void	poolsizeinit(void);
 void	procsave(Proc*);
 void	procsetup(Proc*);
@@ -183,7 +182,6 @@
 void	setconfenv(void);
 void*	sigsearch(char*, int);
 s32	segflush(void*, u32);
-void	setpanic(void);
 void	showframe(void*, void*);
 void	syncclock(void);
 uvlong	tscticks(uvlong*);
--- a/os/pc64/main.c
+++ b/os/pc64/main.c
@@ -135,7 +135,6 @@
 	meminit();			/* builds the conf.mem entries */
 	confinit();
 	xinit();
-	kbdinit();
 	i8253init();
 	/* TODO 9front if(i8237alloc != nil)
 		i8237alloc(); */
@@ -157,8 +156,6 @@
 	timersinit();
 	doc("mathinit");
 	mathinit();
-	doc("kbdenable");
-	kbdenable();
 	if(arch->clockenable){
 		doc("clockinit");
 		arch->clockenable();
--- a/os/pc64/mkfile
+++ b/os/pc64/mkfile
@@ -30,7 +30,6 @@
 	i8253.$O\
 	i8259.$O\
 	main.$O\
-	kbd.$O\
 	memmap.$O\
 	memory.$O\
 	mmu.$O\
--- a/os/pc64/pc64
+++ b/os/pc64/pc64
@@ -13,14 +13,16 @@
 	ssl
 	cap
 
+	ether		netif netaux ethermedium
+#	bridge		netif log
+	ip	bootp ip ipv6 ipaux iproute arp netlog ptclbsum iprouter plan9 nullmedium pktmedium
+
 	draw	screen vga vgax cga
+#	mouse		mouse
 	pointer
+	kbd
 	vga	pci
 
-	ip	bootp ip ipv6 ipaux iproute arp netlog ptclbsum iprouter plan9 nullmedium pktmedium
-	ether		netif netaux ethermedium
-#	bridge		netif log
-
 #	ata
 	audio		dma
 	uart
@@ -27,8 +29,6 @@
 	sd
 #	floppy	dma
 	tinyfs
-#	kbd
-#	mouse		mouse
 #	dbg	x86break
 
 ip
--- a/os/port/alloc.c
+++ b/os/port/alloc.c
@@ -918,7 +918,6 @@
 static void
 _poolfault(void *v, char *msg, uintptr c)
 {
-	setpanic();
 	auditmemloc(msg, v);
 	panic("%s %p (from %p/%zux)", msg, v, getcallerpc(&v), c);
 }
@@ -1078,8 +1077,10 @@
 	return r;
 }
 
+/*
 void
 poolinit(void)
 {
 	debugkey('m', "memory pools", poolsummary, 0);
 }
+*/
--- a/os/port/devcons.c
+++ b/os/port/devcons.c
@@ -14,37 +14,16 @@
 
 void	(*serwrite)(char *, int);
 
-Queue*	kscanq;			/* keyboard raw scancodes (when needed) */
-char*	kscanid;		/* name of raw scan format (if defined) */
-Queue*	kbdq;			/* unprocessed console input */
-Queue*	lineq;			/* processed console input */
-Queue*	printq;			/* console output */
-Queue*	klogq;			/* kernel print (log) output */
+void	(*consdebug)(void) = nil;
+void	(*screenputs)(char*, int) = nil;
+
+Queue*	serialoq;		/* serial console output */
+Queue*	kprintoq;		/* console output, for /dev/kprint */
+ulong	kprintinuse;	/* test and set whether /dev/kprint is open */
 int	iprintscreenputs = 1;
+
 int	panicking;
 
-static struct
-{
-	RWlock;
-	Queue*	q;
-} kprintq;
-
-static struct
-{
-	QLock;
-
-	int	raw;		/* true if we shouldn't process input */
-	int	ctl;		/* number of opens to the control file */
-	int	kbdr;		/* number of open reads to the keyboard */
-	int	scan;		/* true if reading raw scancodes */
-	int	x;		/* index into line */
-	char	line[1024];	/* current input line */
-
-	char	c;
-	int	count;
-	int	repeat;
-} kbd;
-
 char*	sysname;
 char*	eve;
 
@@ -71,10 +50,6 @@
 void
 printinit(void)
 {
-	lineq = qopen(2*1024, 0, nil, nil);
-	if(lineq == nil)
-		panic("printinit");
-	qnoblock(lineq, 1);
 }
 
 /*
@@ -92,8 +67,8 @@
 static int
 consactive(void)
 {
-	if(printq)
-		return qlen(printq) > 0;
+	if(serialoq)
+		return qlen(serialoq) > 0;
 	return 0;
 }
 
@@ -103,7 +78,7 @@
 	ulong now;
 
 	now = m->ticks;
-	while(serwrite==nil && consactive())
+	while(consactive())
 		if(m->ticks - now >= HZ)
 			break;
 }
@@ -148,7 +123,7 @@
 {
 	int m;
 	char *t;
-	char buf[PRINTSIZE+2];
+	int (*wq)(Queue*, void*, int);
 
 	/*
 	 *  how many different output devices do we need?
@@ -156,62 +131,35 @@
 	kmesgputs(str, n);
 
 	/*
-	 *  if kprint is open, put the message there, otherwise
-	 *  if there's an attached bit mapped display,
+	 *  if someone is reading /dev/kprint,
 	 *  put the message there.
-	 */
-	m = consoleprint;
-	if(canrlock(&kprintq)){
-		if(kprintq.q != nil){
-			if(waserror()){
-				runlock(&kprintq);
-				nexterror();
-			}
-			if(usewrite)
-				qwrite(kprintq.q, str, n);
-			else
-				qiwrite(kprintq.q, str, n);
-			poperror();
-			m = 0;
-		}
-		runlock(&kprintq);
-	}
-	if(m && screenputs != nil){
-		screenputs(str, n);
-	}
-
-	/*
+	 *  if not and there's an attached bit mapped display,
+	 *  put the message there.
+	 *
 	 *  if there's a serial line being used as a console,
 	 *  put the message there.
 	 */
-	if(serwrite != nil) {
-		serwrite(str, n);
+	wq = usewrite && islo() ? qwrite : qiwrite;
+	if(kprintoq != nil && !qisclosed(kprintoq))
+		(*wq)(kprintoq, str, n);
+	else if(screenputs != nil)
+		screenputs(str, n);
+
+	if(serialoq == nil){
+		uartputs(str, n);
 		return;
 	}
 
-	if(printq == 0)
-		return;
-
 	while(n > 0) {
 		t = memchr(str, '\n', n);
-		if(t && !kbd.raw) {
-			m = t - str;
-			if(m > sizeof(buf)-2)
-				m = sizeof(buf)-2;
-			memmove(buf, str, m);
-			buf[m] = '\r';
-			buf[m+1] = '\n';
-			if(usewrite)
-				qwrite(printq, buf, m+2);
-			else
-				qiwrite(printq, buf, m+2);
-			str = t + 1;
-			n -= m + 1;
+		if(t != nil) {
+			m = t-str;
+			(*wq)(serialoq, str, m);
+			(*wq)(serialoq, "\r\n", 2);
+			n -= m+1;
+			str = t+1;
 		} else {
-			if(usewrite)
-				qwrite(printq, str, n);
-			else 
-				qiwrite(printq, str, n);
+			(*wq)(serialoq, str, n);
 			break;
 		}
 	}
@@ -279,25 +227,32 @@
 	return n;
 }
 
-int
-kprint(char *fmt, ...)
+/*
+ * Want to interlock iprints to avoid interlaced output on 
+ * multiprocessor, but don't want to deadlock if one processor
+ * dies during print and another has something important to say.
+ * Make a good faith effort.
+ */
+static Lock iprintlock;
+static int
+iprintcanlock(Lock *l)
 {
-	va_list arg;
-	char buf[PRINTSIZE];
-	int n;
-
-	va_start(arg, fmt);
-	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
-	va_end(arg);
-	if(qfull(klogq))
-		qflush(klogq);
-	return qproduce(klogq, buf, n);
+	int i;
+	
+	for(i=0; i<1000; i++){
+		if(canlock(l))
+			return 1;
+		if(l->m == MACHP(m->machno))
+			return 0;
+		microdelay(100);
+	}
+	return 0;
 }
 
 int
 iprint(char *fmt, ...)
 {
-	int n, s;
+	int n, s, locked;
 	va_list arg;
 	char buf[PRINTSIZE];
 
@@ -305,9 +260,12 @@
 	va_start(arg, fmt);
 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
 	va_end(arg);
+	locked = iprintcanlock(&iprintlock);
 	if(screenputs != nil && iprintscreenputs)
 		screenputs(buf, n);
 	uartputs(buf, n);
+	if(locked)
+		unlock(&iprintlock);
 	splx(s);
 
 	return n;
@@ -314,36 +272,44 @@
 }
 
 void
-setpanic(void)
-{
-	panicking = 1;
-}
-
-void
 panic(char *fmt, ...)
 {
-	int n;
+	int s;
 	va_list arg;
 	char buf[PRINTSIZE];
 
-	setpanic();
-	kprintq.q = nil;
+	kprintoq = nil;	/* don't try to write to /dev/kprint */
+
+	if(panicking)
+		for(;;);
+	panicking = 1;
+
+	s = splhi();
 	strcpy(buf, "panic: ");
 	va_start(arg, fmt);
-	n = vseprint(buf+strlen(buf), buf+sizeof(buf)-1, fmt, arg) - buf;
+	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
 	va_end(arg);
-	buf[n] = '\n';
-	putstrn(buf, n+1);
-	spllo();
+	iprint("%s\n", buf);
+	if(consdebug)
+		(*consdebug)();
+	splx(s);
+	prflush();
 	dumpstack();
 
-	exit(1);
+	/* reboot cpu servers and headless machines when not debugging */
+	if(getconf("*debug") == nil)
+	if(!conf.monitor)
+		exit(1);
+
+	/* otherwise, just hang */
+	while(islo()) idlehands();
+	for(;;);
 }
 
 void
 _assert(char *fmt)
 {
-	panic("assert failed: %s", fmt);
+	panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
 }
 
 /*
@@ -352,13 +318,13 @@
 void
 sysfatal(char *fmt, ...)
 {
+	char err[256];
 	va_list arg;
-	char buf[64];
 
 	va_start(arg, fmt);
-	vsnprint(buf, sizeof(buf), fmt, arg);
+	vseprint(err, err + sizeof err, fmt, arg);
 	va_end(arg);
-	error(buf);
+	panic("sysfatal: %s", err);
 }
 
 int
@@ -366,30 +332,22 @@
 {
 	int n;
 	Chan *c;
-	Osenv *o;
 	va_list arg;
 	char buf[2*PRINTSIZE];
 
-	n = sprint(buf, "%s %d: ", up->text, up->pid);
+	if(up == nil || up->env->fgrp == nil)
+		return 0;
+
+	c = up->env->fgrp->fd[2];
+	if(c==nil || (c->flag&CMSG)!=0 || (c->mode!=OWRITE && c->mode!=ORDWR))
+		return 0;
+	n = snprint(buf, sizeof buf, "%s %ud: ", up->text, up->pid);
 	va_start(arg, fmt);
 	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
 	va_end(arg);
 
-	o = up->env;
-	if(o->fgrp == 0) {
-		print("%s", buf);
+	if(waserror())
 		return 0;
-	}
-	c = o->fgrp->fd[2];
-	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) {
-		print("%s", buf);
-		return 0;
-	}
-
-	if(waserror()) {
-		print("%s", buf);
-		return 0;
-	}
 	devtab[c->type]->write(c, buf, n, c->offset);
 	poperror();
 
@@ -400,260 +358,6 @@
 	return n;
 }
 
-void
-echo(Rune r, char *buf, int n)
-{
-	if(kbd.raw)
-		return;
-
-	if(r == '\n'){
-		if(printq)
-			qiwrite(printq, "\r", 1);
-	} else if(r == 0x15){
-		buf = "^U\n";
-		n = 3;
-	}
-	if(consoleprint && screenputs != nil)
-		screenputs(buf, n);
-	if(printq)
-		qiwrite(printq, buf, n);
-}
-
-/*
- *	Debug key support.  Allows other parts of the kernel to register debug
- *	key handlers, instead of devcons.c having to know whatever's out there.
- *	A kproc is used to invoke most handlers, rather than tying up the CPU at
- *	splhi, which can choke some device drivers (eg softmodem).
- */
-typedef struct {
-	Rune	r;
-	char	*m;
-	void	(*f)(Rune);
-	int	i;	/* function called at interrupt time */
-} Dbgkey;
-
-static struct {
-	Rendez;
-	Dbgkey	*work;
-	Dbgkey	keys[50];
-	int	nkeys;
-	int	on;
-} dbg;
-
-static Dbgkey *
-finddbgkey(Rune r)
-{
-	int i;
-	Dbgkey *dp;
-
-	for(dp = dbg.keys, i = 0; i < dbg.nkeys; i++, dp++)
-		if(dp->r == r)
-			return dp;
-	return nil;
-}
-
-static int
-dbgwork(void *)
-{
-	return dbg.work != 0;
-}
-
-static void
-dbgproc(void *)
-{
-	Dbgkey *dp;
-
-	setpri(PriRealtime);
-	for(;;) {
-		do {
-			sleep(&dbg, dbgwork, 0);
-			dp = dbg.work;
-		} while(dp == nil);
-		dp->f(dp->r);
-		dbg.work = nil;
-	}
-}
-
-void
-debugkey(Rune r, char *msg, void (*fcn)(), int iflag)
-{
-	Dbgkey *dp;
-
-	if(dbg.nkeys >= nelem(dbg.keys))
-		return;
-	if(finddbgkey(r) != nil)
-		return;
-	for(dp = &dbg.keys[dbg.nkeys++] - 1; dp >= dbg.keys; dp--) {
-		if(strcmp(dp->m, msg) < 0)
-			break;
-		dp[1] = dp[0];
-	}
-	dp++;
-	dp->r = r;
-	dp->m = msg;
-	dp->f = fcn;
-	dp->i = iflag;
-}
-
-static int
-isdbgkey(Rune r)
-{
-	static int ctrlt;
-	Dbgkey *dp;
-	int echoctrlt = ctrlt;
-
-	/*
-	 * ^t hack BUG
-	 */
-	if(dbg.on || (ctrlt >= 2)) {
-		if(r == 0x14 || r == 0x05) {
-			ctrlt++;
-			return 0;
-		}
-		if(dp = finddbgkey(r)) {
-			if(dp->i || ctrlt > 2)
-				dp->f(r);
-			else {
-				dbg.work = dp;
-				wakeup(&dbg);
-			}
-			ctrlt = 0;
-			return 1;
-		}
-		ctrlt = 0;
-	}
-	else if(r == 0x14){
-		ctrlt++;
-		return 1;
-	}
-	else
-		ctrlt = 0;
-	if(echoctrlt){
-		char buf[UTFmax];
-
-		buf[0] = 0x14;
-		while(--echoctrlt >= 0){
-			echo(buf[0], buf, 1);
-			qproduce(kbdq, buf, 1);
-		}
-	}
-	return 0;
-}
-
-static void
-dbgtoggle(Rune)
-{
-	dbg.on = !dbg.on;
-	print("Debug keys %s\n", dbg.on ? "HOT" : "COLD");
-}
-
-static void
-dbghelp(void)
-{
-	int i;
-	Dbgkey *dp;
-	Dbgkey *dp2;
-	static char fmt[] = "%c: %-22s";
-
-	dp = dbg.keys;
-	dp2 = dp + (dbg.nkeys + 1)/2;
-	for(i = dbg.nkeys; i > 1; i -= 2, dp++, dp2++) {
-		print(fmt, dp->r, dp->m);
-		print(fmt, dp2->r, dp2->m);
-		print("\n");
-	}
-	if(i)
-		print(fmt, dp->r, dp->m);
-	print("\n");
-}
-
-static void
-debuginit(void)
-{
-	kproc("consdbg", dbgproc, nil, 0);
-	debugkey('|', "HOT|COLD keys", dbgtoggle, 0);
-	debugkey('?', "help", dbghelp, 0);
-}
-
-/*
- *  Called by a uart interrupt for console input.
- *
- *  turn '\r' into '\n' before putting it into the queue.
- */
-int
-kbdcr2nl(Queue *q, int ch)
-{
-	if(ch == '\r')
-		ch = '\n';
-	return kbdputc(q, ch);
-}
-
-/*
- *  Put character, possibly a rune, into read queue at interrupt time.
- *  Performs translation for compose sequences
- *  Called at interrupt time to process a character.
- */
-int
-kbdputc(Queue *q, int ch)
-{
-	int n;
-	char buf[UTFmax];
-	Rune r;
-	static Rune kc[15];
-	static int nk, collecting = 0;
-
-	r = ch;
-	if(r == Latin) {
-		collecting = 1;
-		nk = 0;
-		return 0;
-	}
-	if(collecting) {
-		int c;
-		nk += runetochar((char*)&kc[nk], &r);
-		c = latin1(kc, nk);
-		if(c < -1)	/* need more keystrokes */
-			return 0;
-		collecting = 0;
-		if(c == -1) {	/* invalid sequence */
-			echo(kc[0], (char*)kc, nk);
-			qproduce(q, kc, nk);
-			return 0;
-		}
-		r = (Rune)c;
-	}
-	kbd.c = r;
-	n = runetochar(buf, &r);
-	if(n == 0)
-		return 0;
-	if(!isdbgkey(r)) {
-		echo(r, buf, n);
-		qproduce(q, buf, n);
-	}
-	return 0;
-}
-
-void
-kbdrepeat(int rep)
-{
-	kbd.repeat = rep;
-	kbd.count = 0;
-}
-
-void
-kbdclock(void)
-{
-	if(kbd.repeat == 0)
-		return;
-	if(kbd.repeat==1 && ++kbd.count>HZ){
-		kbd.repeat = 2;
-		kbd.count = 0;
-		return;
-	}
-	if(++kbd.count&1)
-		kbdputc(kbdq, kbd.c);
-}
-
 enum{
 	Qdir,
 	Qcons,
@@ -662,8 +366,8 @@
 	Qdrivers,
 	Qhostowner,
 	Qkeyboard,
-	Qklog,
-	Qkprint,
+	Qklog,		/* same as 9front's kmesg */
+	Qkprint,	/* tail of kprint's and cons. Why not just a tail of klog? Why is this needed? */
 	Qscancode,
 	Qmemory,
 	Qmsec,
@@ -680,7 +384,6 @@
 {
 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
 	"cons",		{Qcons},	0,		0660,
-	"consctl",	{Qconsctl},	0,		0220,
 	"sysctl",	{Qsysctl},	0,		0644,
 	"drivers",	{Qdrivers},	0,		0444,
 	"hostowner",	{Qhostowner},	0,	0644,
@@ -787,12 +490,13 @@
 static void
 consinit(void)
 {
+	todinit();
 	randominit();
-	debuginit();
+/*
 	debugkey('f', "files/6", fddump, 0);
 	debugkey('q', "panic", qpanic, 1);
 	debugkey('r', "exit", rexit, 1);
-	klogq = qopen(128*1024, 0, 0, 0);
+*/
 }
 
 static Chan*
@@ -813,111 +517,43 @@
 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
 }
 
-static void
-flushkbdline(Queue *q)
-{
-	if(kbd.x){
-		qwrite(q, kbd.line, kbd.x);
-		kbd.x = 0;
-	}
-}
-
 static Chan*
 consopen(Chan *c, u32 omode)
 {
-	c->aux = 0;
+	c->aux = nil;
+	c = devopen(c, omode, consdir, nelem(consdir), devgen);
 	switch((u64)c->qid.path){
-	case Qconsctl:
-		if(!iseve())
-			error(Eperm);
-		qlock(&kbd);
-		kbd.ctl++;
-		qunlock(&kbd);
-		break;
-
-	case Qkeyboard:
-		if((omode & 3) != OWRITE) {
-			qlock(&kbd);
-			kbd.kbdr++;
-			flushkbdline(kbdq);
-			kbd.raw = 1;
-			qunlock(&kbd);
-		}
-		break;
-
-	case Qscancode:
-		qlock(&kbd);
-		if(kscanq || !kscanid) {
-			qunlock(&kbd);
+	case Qkprint:
+		if(tas(&kprintinuse) != 0){
 			c->flag &= ~COPEN;
-			if(kscanq)
-				error(Einuse);
-			else
-				error(Ebadarg);
+			error(Einuse);
 		}
-		kscanq = qopen(256, 0, nil, nil);
-		qunlock(&kbd);
-		break;
-
-	case Qkprint:
-		if((omode & 3) != OWRITE) {
-			wlock(&kprintq);
-			if(kprintq.q != nil){
-				wunlock(&kprintq);
-				error(Einuse);
-			}
-			kprintq.q = qopen(32*1024, Qcoalesce, nil, nil);
-			if(kprintq.q == nil){
-				wunlock(&kprintq);
+		if(kprintoq == nil){
+			kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
+			if(kprintoq == nil){
+				c->flag &= ~COPEN;
 				error(Enomem);
 			}
-			qnoblock(kprintq.q, 1);
-			wunlock(&kprintq);
-			c->iounit = qiomaxatomic;
-		}
+			qnoblock(kprintoq, 1);
+		}else
+			qreopen(kprintoq);
+		c->iounit = qiomaxatomic;
 		break;
 	}
-	return devopen(c, omode, consdir, nelem(consdir), devgen);
+	return c;
 }
 
 static void
 consclose(Chan *c)
 {
-	if((c->flag&COPEN) == 0)
-		return;
-
 	switch((u64)c->qid.path){
-	case Qconsctl:
-		/* last close of control file turns off raw */
-		qlock(&kbd);
-		if(--kbd.ctl == 0)
-			kbd.raw = 0;
-		qunlock(&kbd);
-		break;
-
-	case Qkeyboard:
-		if(c->mode != OWRITE) {
-			qlock(&kbd);
-			--kbd.kbdr;
-			qunlock(&kbd);
+	/* close of kprint allows other opens */
+	case Qkprint:
+		if(c->flag & COPEN){
+			kprintinuse = 0;
+			qhangup(kprintoq, nil);
 		}
 		break;
-
-	case Qscancode:
-		qlock(&kbd);
-		if(kscanq) {
-			qfree(kscanq);
-			kscanq = 0;
-		}
-		qunlock(&kbd);
-		break;
-
-	case Qkprint:
-		wlock(&kprintq);
-		qfree(kprintq.q);
-		kprintq.q = nil;
-		wunlock(&kprintq);
-		break;
 	}
 }
 
@@ -926,9 +562,8 @@
 {
 	int l;
 	Osenv *o;
-	int ch, eol, i;
+	int i;
 	char *p, tmp[128];
-	char *cbuf = buf;
 
 	if(n <= 0)
 		return n;
@@ -939,63 +574,8 @@
 	case Qsysctl:
 		return readstr(offset, buf, n, VERSION);
 	case Qcons:
-	case Qkeyboard:
-		qlock(&kbd);
-		if(waserror()) {
-			qunlock(&kbd);
-			nexterror();
-		}
-		if(kbd.raw || kbd.kbdr) {
-			if(qcanread(lineq))
-				n = qread(lineq, buf, n);
-			else {
-				/* read as much as possible */
-				do {
-					i = qread(kbdq, cbuf, n);
-					cbuf += i;
-					n -= i;
-				} while(n>0 && qcanread(kbdq));
-				n = cbuf - (char*)buf;
-			}
-		} else {
-			while(!qcanread(lineq)) {
-				qread(kbdq, &kbd.line[kbd.x], 1);
-				ch = kbd.line[kbd.x];
-				eol = 0;
-				switch(ch){
-				case '\b':
-					if(kbd.x)
-						kbd.x--;
-					break;
-				case 0x15:
-					kbd.x = 0;
-					break;
-				case '\n':
-				case 0x04:
-					eol = 1;
-				default:
-					kbd.line[kbd.x++] = ch;
-					break;
-				}
-				if(kbd.x == sizeof(kbd.line) || eol) {
-					if(ch == 0x04)
-						kbd.x--;
-					qwrite(lineq, kbd.line, kbd.x);
-					kbd.x = 0;
-				}
-			}
-			n = qread(lineq, buf, n);
-		}
-		qunlock(&kbd);
-		poperror();
-		return n;
+		error(Egreg);
 
-	case Qscancode:
-		if(offset == 0)
-			return readstr(0, buf, n, kscanid);
-		else
-			return qread(kscanq, buf, n);
-
 	case Qtime:
 		snprint(tmp, sizeof(tmp), "%.lld", (vlong)mseconds()*1000);
 		return readstr(offset, buf, n, tmp);
@@ -1048,19 +628,24 @@
 		return n;
 
 	case Qklog:
-		return qread(klogq, buf, n);
-
-	case Qkprint:
-		rlock(&kprintq);
-		if(waserror()){
-			runlock(&kprintq);
-			nexterror();
+		/*
+		 * This is unlocked to avoid tying up a process
+		 * that's writing to the buffer.  kmesg.n never 
+		 * gets smaller, so worst case the reader will
+		 * see a slurred buffer.
+		 */
+		if(offset >= kmesg.n)
+			n = 0;
+		else{
+			if(offset+n > kmesg.n)
+				n = kmesg.n - offset;
+			memmove(buf, kmesg.buf+offset, n);
 		}
-		n = qread(kprintq.q, buf, n);
-		poperror();
-		runlock(&kprintq);
 		return n;
 
+	case Qkprint:
+		return qread(kprintoq, buf, n);
+
 	default:
 		print("consread %llud\n", c->qid.path);
 		error(Egreg);
@@ -1097,34 +682,7 @@
 		break;
 
 	case Qconsctl:
-		if(n >= sizeof(buf))
-			n = sizeof(buf)-1;
-		strncpy(buf, a, n);
-		buf[n] = 0;
-		for(a = buf; a;){
-			if(strncmp(a, "rawon", 5) == 0){
-				qlock(&kbd);
-				flushkbdline(kbdq);
-				kbd.raw = 1;
-				qunlock(&kbd);
-			} else if(strncmp(a, "rawoff", 6) == 0){
-				qlock(&kbd);
-				kbd.raw = 0;
-				kbd.x = 0;
-				qunlock(&kbd);
-			}
-			if(a = strchr(a, ' '))
-				a++;
-		}
-		break;
-
-	case Qkeyboard:
-		for(x=0; x<n; ) {
-			Rune r;
-			x += chartorune(&r, &a[x]);
-			kbdputc(kbdq, r);
-		}
-		break;
+		error(Egreg);
 	
 	case Qtime:
 		if(n >= sizeof(buf))
--- a/os/port/devuart.c
+++ b/os/port/devuart.c
@@ -5,6 +5,7 @@
 #include	"fns.h"
 #include	"io.h"
 #include	"../port/error.h"
+
 #include	"../port/netif.h"
 
 enum
@@ -22,6 +23,7 @@
 static int uartnuart;
 static Dirtab *uartdir;
 static int uartndir;
+static Timer *uarttimer;
 
 struct Uartalloc {
 	Lock;
@@ -34,19 +36,21 @@
 /*
  *  enable/disable uart and add/remove to list of enabled uarts
  */
-static Uart*
+Uart*
 uartenable(Uart *p)
 {
 	Uart **l;
 
+	if(p->enabled)
+		return p;
 	if(p->iq == nil){
-		if((p->iq = qopen(4*1024, 0, uartflow, p)) == nil)
+		if((p->iq = qopen(8*1024, Qcoalesce, uartflow, p)) == nil)
 			return nil;
 	}
 	else
 		qreopen(p->iq);
 	if(p->oq == nil){
-		if((p->oq = qopen(4*1024, 0, uartkick, p)) == nil){
+		if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){
 			qfree(p->iq);
 			p->iq = nil;
 			return nil;
@@ -78,7 +82,11 @@
 		uartctl(p, "b9600");
 	(*p->phys->enable)(p, 1);
 
-	lock(&uartalloc);
+	/*
+	 * use ilock because uartclock can otherwise interrupt here
+	 * and would hang on an attempt to lock uartalloc.
+	 */
+	ilock(&uartalloc);
 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
 		if(*l == p)
 			break;
@@ -88,7 +96,7 @@
 		uartalloc.elist = p;
 	}
 	p->enabled = 1;
-	unlock(&uartalloc);
+	iunlock(&uartalloc);
 
 	return p;
 }
@@ -98,9 +106,11 @@
 {
 	Uart **l;
 
+	if(!p->enabled)
+		return;
 	(*p->phys->disable)(p);
 
-	lock(&uartalloc);
+	ilock(&uartalloc);
 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
 		if(*l == p){
 			*l = p->elist;
@@ -108,7 +118,7 @@
 		}
 	}
 	p->enabled = 0;
-	unlock(&uartalloc);
+	iunlock(&uartalloc);
 }
 
 static Uart*
@@ -204,6 +214,8 @@
 
 	uartndir = 1 + 3*uartnuart;
 	uartdir = xalloc(uartndir * sizeof(Dirtab));
+	if(uartnuart && uart == nil || uartdir == nil)
+		panic("uartreset: no memory");
 	dp = uartdir;
 	strcpy(dp->name, ".");
 	mkqid(&dp->qid, 0, 0, QTDIR);
@@ -213,15 +225,15 @@
 	p = uartlist;
 	for(i = 0; i < uartnuart; i++){
 		/* 3 directory entries per port */
-		sprint(dp->name, "eia%d", i);
+		snprint(dp->name, sizeof dp->name, "eia%d", i);
 		dp->qid.path = NETQID(i, Ndataqid);
 		dp->perm = 0660;
 		dp++;
-		sprint(dp->name, "eia%dctl", i);
+		snprint(dp->name, sizeof dp->name, "eia%dctl", i);
 		dp->qid.path = NETQID(i, Nctlqid);
 		dp->perm = 0660;
 		dp++;
-		sprint(dp->name, "eia%dstatus", i);
+		snprint(dp->name, sizeof dp->name, "eia%dstatus", i);
 		dp->qid.path = NETQID(i, Nstatqid);
 		dp->perm = 0444;
 		dp++;
@@ -231,9 +243,7 @@
 		if(p->console || p->special){
 			if(uartenable(p) != nil){
 				if(p->console){
-					kbdq = p->iq;
-					printq = p->oq;
-					p->putc = kbdcr2nl;
+					serialoq = p->oq;
 				}
 				p->opens++;
 			}
@@ -244,9 +254,9 @@
 	if(uartnuart){
 		/*
 		 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
-		 * processing it every 22 ms should be fine
+		 * processing it every 22 ms should be fine.
 		 */
-		addclock0link(uartclock, 22);
+		uarttimer = addclock0link(uartclock, 22);
 	}
 }
 
@@ -258,13 +268,13 @@
 }
 
 static Walkqid*
-uartwalk(Chan *c, Chan *nc, char **name, int nname)
+uartwalk(Chan *c, Chan *nc, char **name, s32 nname)
 {
 	return devwalk(c, nc, name, nname, uartdir, uartndir, devgen);
 }
 
-static int
-uartstat(Chan *c, uchar *dp, int n)
+static s32
+uartstat(Chan *c, uchar *dp, s32 n)
 {
 	if(NETTYPE(c->qid.path) == Ndataqid)
 		setlength(NETID(c->qid.path));
@@ -308,9 +318,8 @@
 static void
 uartdrainoutput(Uart *p)
 {
-	if(!p->enabled)
+	if(!p->enabled || up == nil || !islo())
 		return;
-
 	p->drain = 1;
 	if(waserror()){
 		p->drain = 0;
@@ -336,7 +345,9 @@
 		qlock(p);
 		if(--(p->opens) == 0){
 			qclose(p->iq);
+			ilock(&p->rlock);
 			p->ir = p->iw = p->istage;
+			iunlock(&p->rlock);
 
 			/*
 			 */
@@ -474,22 +485,18 @@
 			if((*p->phys->stop)(p, n) < 0)
 				return -1;
 			break;
-		case 'T':
-		case 't':
-			p->dcdts = n;
-			break;
 		case 'W':
 		case 'w':
-			/* TODO 9front manages the timer here */
-			/* obsolete */
+			if(uarttimer == nil || n < 1)
+				return -1;
+			uarttimer->tns = (vlong)n * 100000LL;
 			break;
 		case 'X':
 		case 'x':
-			if(p->enabled){
-				ilock(&p->tlock);
-				p->xonoff = n;
-				iunlock(&p->tlock);
-			}
+			ilock(&p->tlock);
+			p->xonoff = n;
+			p->blocked = 0;
+			iunlock(&p->tlock);
 			break;
 		}
 	}
@@ -521,7 +528,7 @@
 		poperror();
 		break;
 	case Nctlqid:
-		cmd = malloc(n+1);
+		cmd = smalloc(n+1);
 		memmove(cmd, buf, n);
 		cmd[n] = 0;
 		qlock(p);
@@ -544,8 +551,8 @@
 	return n;
 }
 
-static int
-uartwstat(Chan *c, uchar *dp, int n)
+static s32
+uartwstat(Chan *c, uchar *dp, s32 n)
 {
 	Dir d;
 	Dirtab *dt;
@@ -567,7 +574,7 @@
 }
 
 void
-uartpower(int on)
+uartpower(s32 on)
 {
 	Uart *p;
 
@@ -637,7 +644,7 @@
 {
 	Uart *p = v;
 
-	if(p->blocked)
+	if(!p->enabled || p->blocked)
 		return;
 
 	ilock(&p->tlock);
@@ -651,6 +658,35 @@
 }
 
 /*
+ * Move data from the interrupt staging area to
+ * the input Queue.
+ */
+static void
+uartstageinput(Uart *p)
+{
+	int n;
+	uchar *ir, *iw;
+
+	while(p->ir != p->iw){
+		ir = p->ir;
+		if(p->ir > p->iw){
+			iw = p->ie;
+			p->ir = p->istage;
+		}
+		else{
+			iw = p->iw;
+			p->ir = p->iw;
+		}
+		if((n = qproduce(p->iq, ir, iw - ir)) < 0){
+			p->serr++;
+			(*p->phys->rts)(p, 0);
+		}
+		else if(n == 0)
+			p->berr++;
+	}
+}
+
+/*
  *  receive a character at interrupt time
  */
 void
@@ -671,14 +707,18 @@
 	/* receive the character */
 	if(p->putc)
 		p->putc(p->iq, ch);
-	else{
+	else if (p->iw) {		/* maybe the line isn't enabled yet */
+		ilock(&p->rlock);
 		next = p->iw + 1;
 		if(next == p->ie)
 			next = p->istage;
+		if(next == p->ir)
+			uartstageinput(p);
 		if(next != p->ir){
 			*p->iw = ch;
 			p->iw = next;
 		}
+		iunlock(&p->rlock);
 	}
 }
 
@@ -690,22 +730,15 @@
 uartclock(void)
 {
 	Uart *p;
-	uchar *iw;
 
+	ilock(&uartalloc);
 	for(p = uartalloc.elist; p; p = p->elist){
 
-		/* this amortizes cost of qproduce to many chars */
+		/* this hopefully amortizes cost of qproduce to many chars */
 		if(p->iw != p->ir){
-			iw = p->iw;
-			if(iw < p->ir){
-				if(qproduce(p->iq, p->ir, p->ie-p->ir) < 0)
-					(*p->phys->rts)(p, 0);
-				p->ir = p->istage;
-			}
-			if(iw > p->ir)
-				if(qproduce(p->iq, p->ir, iw-p->ir) < 0)
-					(*p->phys->rts)(p, 0);
-			p->ir = iw;
+			ilock(&p->rlock);
+			uartstageinput(p);
+			iunlock(&p->rlock);
 		}
 
 		/* hang up if requested */
@@ -725,6 +758,7 @@
 			iunlock(&p->tlock);
 		}
 	}
+	iunlock(&uartalloc);
 }
 
 /*
--- a/os/port/portdat.h
+++ b/os/port/portdat.h
@@ -575,11 +575,12 @@
 extern	Dev*	devtab[];
 extern	char*	eve;
 extern	int	hwcurs;
+extern	Queue*	kprintoq;
 extern  Queue	*kbdq;
 extern  Queue	*kscanq;
 extern  Ref	noteidalloc;
-extern  Queue	*printq;
 extern	uint	qiomaxatomic;
+extern	Queue*	serialoq;
 extern	char*	statename[];
 extern	char*	sysname;
 extern	Talarm	talarm;
--- a/os/port/proc.c
+++ b/os/port/proc.c
@@ -306,7 +306,7 @@
 		p->qnext = p+1;
 	p->qnext = 0;
 
-	debugkey('p', "processes", procdump, 0);
+	/* debugkey('p', "processes", procdump, 0); */
 }
 
 void
--- a/os/port/qio.c
+++ b/os/port/qio.c
@@ -1524,6 +1524,6 @@
 qdump(Queue *q)
 {
 	if(q)
-	kprint("q=%p bfirst=%p blast=%p len=%d dlen=%d limit=%d state=#%x\n",
+	iprint("q=%p bfirst=%p blast=%p len=%d dlen=%d limit=%d state=#%x\n",
 		q, q->bfirst, q->blast, q->len, q->dlen, q->limit, q->state);
 }
--- a/os/port/taslock.c
+++ b/os/port/taslock.c
@@ -12,7 +12,6 @@
 
 	if(panicking)
 		return;
-	setpanic();
 	panic("lock loop 0x%p key 0x%ux pc 0x%zux held by pc 0x%zux\n", l, l->key, pc, l->pc);
 	panic("lockloop");
 }
@@ -36,6 +35,9 @@
 			}
 		}
 		l->pc = pc;
+		l->p = up;
+		l->m = MACHP(m->machno);
+		l->isilock = 0;
 		return;
 	}
 
@@ -54,6 +56,9 @@
 	l->pri = up->pri;
 	up->pri = PriLock;
 	l->pc = pc;
+	l->p = up;
+	l->m = MACHP(m->machno);
+	l->isilock = 0;
 }
 
 void
@@ -68,6 +73,9 @@
 		if(_tas((int*)&l->key) == 0) {
 			l->sr = x;
 			l->pc = pc;
+			l->p = up;
+			l->m = MACHP(m->machno);
+			l->isilock = 1;
 			return;
 		}
 		if(conf.nmach < 2)
@@ -94,6 +102,9 @@
 		up->pri = PriLock;
 	}
 	l->pc = getcallerpc(&l);
+	l->p = up;
+	l->m = MACHP(m->machno);
+	l->isilock = 0;
 	return 1;
 }
 
@@ -104,10 +115,17 @@
 
 	if(l->key == 0)
 		print("unlock: not locked: pc %zux\n", getcallerpc(&l));
+	if(l->isilock)
+		print("unlock(%#p) of ilock: pc %#p, held by %#p\n",
+			l, getcallerpc(&l), l->pc);
+	if(l->p != up)
+		print("unlock(%#p): up changed: pc %#p, acquired at pc %#p, lock p %#p, unlock up %#p\n",
+			l, getcallerpc(&l), l->pc, l->p, up);
 	p = l->pri;
+	l->m = nil;
+	coherence();
 	l->key = 0;
 	l->pc = 0;
-	coherence();
 	if(up && islo()){
 		/*
 		 * Call sched if the need arose while locks were held
@@ -122,13 +140,14 @@
 void
 iunlock(Lock *l)
 {
-	ulong sr;
+	u32 sr;
 
 	if(l->key == 0)
 		print("iunlock: not locked: pc %zux\n", getcallerpc(&l));
 	sr = l->sr;
+	l->m = nil;
+	coherence();
 	l->pc = 0;
 	l->key = 0;
-	coherence();
 	splx(sr);
 }
--- a/os/port/xalloc.c
+++ b/os/port/xalloc.c
@@ -67,7 +67,7 @@
 		xhole(cm->base, cm->npage*BY2PG);
 	}
 
-	debugkey('x', "xalloc/ialloc", ixprt, 0);
+	/* debugkey('x', "xalloc/ialloc", ixprt, 0); */
 	xsummary();
 }