~kris/9p

9hist

09349c777d56efed6ebb384a6bb45244457ad007 — David du Colombier 25 years ago 5d59053
Plan 9 from Bell Labs 2000-10-18
M bitsy/fns.h => bitsy/fns.h +6 -1
@@ 1,7 1,10 @@
#include "../port/portfns.h"

void	cacheflush(void);
void	cacheflushaddr(ulong);
void	cachewb(void);
void	cachewbaddr(void*);
void	cachewbregion(void*, int);
void	dcacheinvalidate(void);
int	cistrcmp(char*, char*);
int	cistrncmp(char*, char*, int);
void	clockinit(void);


@@ 14,6 17,7 @@ ulong	getfar(void);
ulong	getfsr(void);
#define	getpgcolor(a)	0
void	h3650uartsetup(void);
void	icacheinvalidate(void);
void	idle(void);
#define	idlehands()			/* nothing to do in the runproc */
void	intrenable(int, void (*)(Ureg*, void*), void*, char*);


@@ 28,6 32,7 @@ void	mmuinit(void);
void	mmuenable(void);
void	mmudisable(void);
void	mmuinvalidate(void);
void	mmuinvalidateaddr(ulong);
void	noted(Ureg*, ulong);
int	notify(Ureg*);
#define	procrestore(p)

M bitsy/l.s => bitsy/l.s +51 -7
@@ 39,17 39,22 @@ TEXT mmuinvalidate(SB), $-4
	MCR	CpMMU, 0, R0, C(CpTLBFlush), C(0x7)
	RET

/* flush tlb's */
TEXT mmuinvalidateaddr(SB), $-4
	MCR	CpMMU, 0, R0, C(CpTLBFlush), C(0x6), 1
	RET

/* write back and invalidate i and d caches */
TEXT cacheflush(SB), $-4
	/* write back any dirty data */
	MOVW	$0xe0000000,R0
	ADD	$(8*1024),R0,R1
_wbloop:
	MOVW.W	32(R0),R2
_cfloop:
	MOVW.P	32(R0),R2
	CMP	R0,R1
	BNE	_wbloop
	BNE	_cfloop
	
	/* drain write buffer and flush i&d cache contents */
	/* drain write buffer and invalidate i&d cache contents */
	MCR	CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
	MCR	CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0



@@ 60,13 65,52 @@ _wbloop:
	MOVW	R0,R0
	RET

/* clean a single virtual address */
TEXT cacheflushaddr(SB), $-4
/* write back and invalidate i and d caches */
TEXT cachewb(SB), $-4
	/* write back any dirty data */
	MOVW	$0xe0000000,R0
	ADD	$(8*1024),R0,R1
_cwbloop:
	MOVW.P	32(R0),R2
	CMP	R0,R1
	BNE	_cfloop
	
	/* drain write buffer */
	MCR	CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
	RET

/* write back a single cache line */
TEXT cachewbaddr(SB), $-4
	BIC	$31,R0
	MCR	CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 1
	B	_wbflush

/* write back a region of cache lines */
TEXT cachewbregion(SB), $-4
	MOVW	4(FP),R1
	BIC	$31,R0
	ADD	R0,R1
	ADD	$32,R1
_cfrloop:
	MCR	CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 1
	ADD	$32,R0
	CMP.S	R0,R1
	BNE	_cfrloop
	B	_wbflush

/* invalidate the dcache */
TEXT dcacheinvalidate(SB), $-4
	MCR	CpMMU, 0, R0, C(CpCacheFlush), C(0x6)
	RET

/* invalidate the icache */
TEXT icacheinvalidate(SB), $-4
	MCR	CpMMU, 0, R0, C(CpCacheFlush), C(0x9)
	RET

/* drain write buffer */
TEXT wbflush(SB), $-4
_wbflush:
	MCR	CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
	RET



@@ 100,7 144,7 @@ TEXT putttb(SB), $-4
 */
TEXT mmuenable(SB), $-4
	MRC	CpMMU, 0, R0, C(CpControl), C(0x0)
	ORR	$(CpCmmuena|CpCwb|CpCdcache), R0
	ORR	$(CpCmmuena|CpCdcache|CpCwb), R0
	MCR     CpMMU, 0, R0, C(CpControl), C(0x0)
	RET


M bitsy/main.c => bitsy/main.c +3 -24
@@ 29,12 29,13 @@ main(void)
	m->ticks = 1;

	rs232power(1);
	iprint("bitsy kernel\n");
	iprint("\nPlan 9 bitsy kernel\n");
	confinit();
	xinit();
	mmuinit();
	gpioinit();
	trapinit();
	screeninit();
	sa1100_uartsetup(1);
	printinit();	/* from here on, print works, before this we need iprint */
	clockinit();


@@ 44,7 45,6 @@ main(void)
	pageinit();
	swapinit();
	userinit();
//iprint("schedinit(), death soon\n");
	schedinit();
}



@@ 60,34 60,13 @@ exit(int ispanic)
	delay(1000);

	iprint("it's a wonderful day to die\n");
	cacheflush();
	mmuinvalidate();
	mmudisable();
	f = nil;
	(*f)();
}

/*
 *  quicker panic
 */
void
qpanic(char *fmt, ...)
{
	int n;
	va_list arg;
	char buf[PRINTSIZE];

	splhi();
	strcpy(buf, "panic: ");
	va_start(arg, fmt);
	n = doprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
	va_end(arg);
	buf[n] = '\n';
	serialputs(buf, n+1);

	exit(1);
}


static uchar *sp;

/*

M bitsy/mem.h => bitsy/mem.h +1 -1
@@ 21,7 21,7 @@
/*
 * Time
 */
#define	HZ		(10)				/* clock frequency */
#define	HZ		(20)				/* clock frequency */
#define	MS2HZ		(1000/HZ)			/* millisec per clock tick */
#define	TK2SEC(t)	((t)/HZ)			/* ticks to seconds */
#define	TK2MS(t)	((((ulong)(t))*1000)/HZ)	/* ticks to milliseconds */

M bitsy/mmu.c => bitsy/mmu.c +47 -30
@@ 220,40 220,57 @@ static ulong mmubits[16] =
 *  add an entry to the current map
 */
void
putmmu(ulong va, ulong pa, Page*)
putmmu(ulong va, ulong pa, Page *pg)
{
	Page *pg;
	ulong *t;
	Page *l2pg;
	ulong *t, *l1p, *l2p;
	int s;

print("putmmu(0x%.8lux, 0x%.8lux)\n", va, pa);
	/* always point L1 entry to L2 page, can't hurt */
	pg = up->l1page[va>>20];
	if(pg == nil){
		pg = up->mmufree;
		if(pg != nil){
			up->mmufree = pg->next;
	s = splhi();

	/* clear out the current entry */
	mmuinvalidateaddr(va);

	l2pg = up->l1page[va>>20];
	if(l2pg == nil){
		l2pg = up->mmufree;
		if(l2pg != nil){
			up->mmufree = l2pg->next;
		} else {
			pg = auxpage();
			if(pg == nil)
			l2pg = auxpage();
			if(l2pg == nil)
				pexit("out of memory", 1);
		}
		pg->va = VA(kmap(pg));
		up->l1page[va>>20] = pg;
		memset((uchar*)(pg->va), 0, BY2PG);
		l2pg->va = VA(kmap(l2pg));
		up->l1page[va>>20] = l2pg;
		memset((uchar*)(l2pg->va), 0, BY2PG);
	}
	l1table[va>>20] = L1PageTable | L1Domain0 | (pg->pa & L1PTBaseMask);
	cacheflushaddr((ulong)&l1table[va>>20]);
print("%lux[%lux] = %lux\n", l1table, va>>20, l1table[va>>20]);
	up->l1table[va>>20] = l1table[va>>20];
	t = (ulong*)pg->va;

	/* always point L1 entry to L2 page, can't hurt */
	l1p = &l1table[va>>20];
	*l1p = L1PageTable | L1Domain0 | (l2pg->pa & L1PTBaseMask);
	up->l1table[va>>20] = *l1p;
	t = (ulong*)l2pg->va;

	/* set L2 entry */
	t[(va & (OneMeg-1))>>PGSHIFT] = mmubits[pa & (PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)]
	l2p = &t[(va & (OneMeg-1))>>PGSHIFT];
	*l2p = mmubits[pa & (PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)]
		| (pa & ~(PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE));
print("%lux[%lux] = %lux\n", (ulong)t, (va & (OneMeg-1))>>PGSHIFT, t[(va & (OneMeg-1))>>PGSHIFT]);
	cacheflushaddr((ulong)&t[(va & (OneMeg-1))>>PGSHIFT]);

	wbflush();
	/*  write back dirty entries - we need this because the pio() in
	 *  fault.c is writing via a different virt addr and won't clean
	 *  its changes out of the dcache.  Page coloring doesn't work
	 *  on this mmu because the virtual cache is set associative
	 *  rather than direct mapped.
	 */
	cachewb();
	if(pg->cachectl[0] == PG_TXTFLUSH){
		/* pio() sets PG_TXTFLUSH whenever a text page has been written */
		icacheinvalidate();
		pg->cachectl[0] = PG_NOFLUSH;
	}

	splx(s);
}

/*


@@ 300,6 317,7 @@ mmurelease(Proc* p)
	p->mmufree = nil;

	memset(l1table, 0, sizeof(p->l1table));
	cachewbregion(l1table, sizeof(p->l1table));
}

void


@@ 309,20 327,19 @@ mmuswitch(Proc *p)
		return;
	m->mmupid = p->pid;

	/* write back dirty cache entries and invalidate all cache entries */
	cacheflush();

	if(p->newtlb){
		mmuptefree(p);
		p->newtlb = 0;
	}

	/* write back dirty cache entries before changing map */
	cacheflush();

	/* move in new map */
	memmove(l1table, p->l1table, sizeof(p->l1table));

	/* make sure map is in memory and drain write buffer */
	cacheflushaddr((ulong)l1table);
	wbflush();
	/* make sure map is in memory */
	cachewbregion(l1table, sizeof(p->l1table));

	/* lose any possible stale tlb entries */
	mmuinvalidate();

A bitsy/sa1110uart.c => bitsy/sa1110uart.c +400 -0
@@ 0,0 1,400 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"../port/error.h"

#include	"../port/netif.h"

/* this isn't strictly a sa1100 driver.  The rts/cts stuff is h3650 specific */

/* hardware registers */
typedef struct Uartregs Uartregs;
struct Uartregs
{
	ulong	ctl[4];
	ulong	dummya;
	ulong	data;
	ulong	dummyb;
	ulong	status[2];
};

enum
{
	/* ctl[0] bits */
	Parity=		1<<0,
	Even=		1<<1,
	Stop2=		1<<2,
	Bits8=		1<<3,
	SCE=		1<<4,	/* synchronous clock enable */
	RCE=		1<<5,	/* rx on falling edge of clock */
	TCE=		1<<6,	/* tx on falling edge of clock */

	/* ctl[3] bits */
	Rena=		1<<0,	/* receiver enable */
	Tena=		1<<1,	/* transmitter enable */
	Break=		1<<2,	/* force TXD3 low */
	Rintena=	1<<3,	/* enable receive interrupt */
	Tintena=	1<<4,	/* enable transmitter interrupt */
	Loopback=	1<<5,	/* loop back data */

	/* data bits */
	DEparity=	1<<8,	/* parity error */
	DEframe=	1<<9,	/* framing error */
	DEoverrun=	1<<10,	/* overrun error */

	/* status[0] bits */
	Tint=		1<<0,	/* transmit fifo half full interrupt */
	Rint0=		1<<1,	/* receiver fifo 1/3-2/3 full */
	Rint1=		1<<2,	/* receiver fifo not empty and receiver idle */
	Breakstart=	1<<3,
	Breakend=	1<<4,
	Fifoerror=	1<<5,	/* fifo error */

	/* status[1] bits */
	Tbusy=		1<<0,	/* transmitting */
	Rnotempty=	1<<1,	/* receive fifo not empty */
	Tnotfull=	1<<2,	/* transmit fifo not full */
	ParityError=	1<<3,
	FrameError=	1<<4,
	Overrun=	1<<5,
};

Uartregs *uart3regs = UART3REGS;

static void	sa1100_uartbaud(Uart *p, int rate);
static void	sa1100_uartkick(Uart *p);
static void	sa1100_uartrts(Uart *p, int on);
static void	sa1100_uartintr(Ureg*, void*);
static void	sa1100_uartbreak(Uart*, int);
static void	sa1100_uartbits(Uart*, int);
static void	sa1100_uartparity(Uart*, int);
static void	sa1100_uartmodemctl(Uart*, int);
static void	sa1100_uartstop(Uart*, int);
static void	sa1100_uartdtr(Uart*, int);
static long	sa1100_uartstatus(Uart*, void*, long, long);
static void	sa1100_uartenable(Uart*, int);
static void	sa1100_uartdisable(Uart*);

PhysUart sa1100_uart = {
	.enable=	sa1100_uartenable,
	.disable=	sa1100_uartdisable,
	.bits=		sa1100_uartbits,
	.kick=		sa1100_uartkick,
	.intr=		sa1100_uartintr,
	.modemctl=	sa1100_uartmodemctl,
	.baud=		sa1100_uartbaud,
	.stop=		sa1100_uartstop,
	.parity=	sa1100_uartparity,
	.dobreak=	sa1100_uartbreak,
	.rts=		sa1100_uartrts,
	.dtr=		sa1100_uartdtr,
	.status=	sa1100_uartstatus,
};

#define R(p) ((Uartregs*)(p->regs))

/*
 *  enable a port's interrupts.  set DTR and RTS
 */
static void
sa1100_uartenable(Uart *p, int intena)
{
	ulong s;

	s = R(p)->ctl[3] & ~(Rintena|Tintena|Rena|Tena);
	if(intena)
		R(p)->ctl[3] = s |Rintena|Tintena|Rena|Tena;
	else
		R(p)->ctl[3] = s | Rena|Tena;
}

/*
 *  disable interrupts. clear DTR, and RTS
 */
static void
sa1100_uartdisable(Uart *p)
{
	R(p)->ctl[3] &= ~(Rintena|Tintena|Rena|Tena);
}

static long
sa1100_uartstatus(Uart *p, void *buf, long n, long offset)
{
	char str[256];
	ulong ctl0;

	ctl0 = R(p)->ctl[0];
	snprint(str, sizeof(str),
		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
		"dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n",

		p->baud,
		p->hup_dcd, 
		0,
		p->hup_dsr,
		(ctl0 & Bits8) ? 8 : 7,
		0, 
		(ctl0 & Parity) ? ((ctl0 & Even) ? 'e' : 'o') : 'n',
		0,
		(ctl0 & Stop2) ? 2 : 1,
		1,

		p->dev,
		p->type,
		p->frame,
		p->overrun, 
		"",
		"",
		"",
		"" );
	return readstr(offset, buf, n, str);
}

/*
 *  set the buad rate
 */
static void
sa1100_uartbaud(Uart *p, int rate)
{
	ulong brconst;

	if(rate <= 0)
		return;

	brconst = p->freq/(16*rate) - 1;
	R(p)->ctl[1] = (brconst>>8) & 0xf;
	R(p)->ctl[2] = brconst;

	p->baud = rate;
}

/*
 *  send a break
 */
static void
sa1100_uartbreak(Uart *p, int ms)
{
	if(ms == 0)
		ms = 200;

	R(p)->ctl[3] |= Break;
	tsleep(&up->sleep, return0, 0, ms);
	R(p)->ctl[3] &= ~Break;
}

/*
 *  set bits/char
 */
static void
sa1100_uartbits(Uart *p, int n)
{
	switch(n){
	case 7:
		R(p)->ctl[0] &= ~Bits8;
		break;
	case 8:
		R(p)->ctl[0] |= Bits8;
		break;
	default:
		error(Ebadarg);
	}
}

/*
 *  set stop bits
 */
static void
sa1100_uartstop(Uart *p, int n)
{
	switch(n){
	case 1:
		R(p)->ctl[0] &= ~Stop2;
		break;
	case 2:
		R(p)->ctl[0] |= Stop2;
		break;
	default:
		error(Ebadarg);
	}
}

/*
 *  turn on/off rts
 */
static void
sa1100_uartrts(Uart*, int)
{
}

/*
 *  turn on/off dtr
 */
static void
sa1100_uartdtr(Uart*, int)
{
}

/*
 *  turn on/off modem flow control on/off (rts/cts)
 */
static void
sa1100_uartmodemctl(Uart *p, int on)
{
	if(on) {
	} else {
		p->cts = 1;
	}
}

/*
 *  set parity
 */
static void
sa1100_uartparity(Uart *p, int type)
{
	switch(type){
	case 'e':
		R(p)->ctl[0] |= Parity|Even;
		break;
	case 'o':
		R(p)->ctl[0] |= Parity;
		break;
	default:
		R(p)->ctl[0] &= ~(Parity|Even);
		break;
	}
}

/*
 *  restart output if not blocked and OK to send
 */
static void
sa1100_uartkick(Uart *p)
{
	int i;

	R(p)->ctl[3] &= ~Tintena;

	if(p->cts == 0 || p->blocked)
		return;

	/*
	 *  128 here is an arbitrary limit to make sure
	 *  we don't stay in this loop too long.  If the
	 *  chips output queue is longer than 128, too
	 *  bad -- presotto
	 */
	for(i = 0; i < 128; i++){
		if(!(R(p)->status[1] & Tnotfull)){
			R(p)->ctl[3] |= Tintena;
			break;
		}
		if(p->op >= p->oe && uartstageoutput(p) == 0)
			break;
		R(p)->data = *p->op++;
	}
}

/*
 *  for iprint, just write it
 */
void
serialputs(char *str, int n)
{
	Uartregs *ur;

	ur = uart3regs;
	while(n-- > 0){
		/* wait for output ready */
		while((ur->status[1] & Tnotfull) == 0)
			;
		ur->data = *str++;
	}
	while((ur->status[1] & Tbusy))
		;
}

/*
 *  take an interrupt
 */
static void
sa1100_uartintr(Ureg*, void *x)
{
	Uart *p;
	ulong s;
	Uartregs *regs;

	p = x;
	regs = p->regs;

	/* remember and reset interrupt causes */
	s = regs->status[0];
	regs->status[0] |= s;

	if(s & Tint){
		/* transmitter interrupt, restart */
		uartkick(p);
	}

	/* receiver interrupt, snarf bytes */
	while(regs->status[1] & Rnotempty)
		uartrecv(p, regs->data);

	if(s & (ParityError|FrameError|Overrun)){
		if(s & ParityError)
			p->parity++;
		if(s & FrameError)
			p->frame++;
		if(s & Overrun)
			p->overrun++;
	}
}

typedef struct Gpclkregs Gpclkregs;
struct Gpclkregs
{
	ulong	r0;
	ulong	r1;
	ulong	dummya;
	ulong	r2;
	ulong	r3;
};

enum
{
	/* gpclk register 0 */
	Gpclk_sus=	1<<0,	/* set uart mode */
};

Gpclkregs *gpclkregs;

/*
 *  setup all uarts (called early by main() to allow debugging output to
 *  a serial port)
 */
void
sa1100_uartsetup(int console)
{
	Uart *p;
	Uartregs *uartregs;

	/* external serial port (eia0) */
	uart3regs = mapspecial(UART3REGS, 64);
	p = uartsetup(&sa1100_uart, uart3regs, ClockFreq, "serialport3");
	intrenable(IRQuart3, sa1100_uartintr, p, p->name);

	/* set eia0 up as a console */
	if(console)
		uartspecial(p, 115200, &kbdq, &printq, kbdcr2nl);

	/* port for talking to microcontroller (eia1) */
	gpclkregs = mapspecial(GPCLKREGS, 64);
	gpclkregs->r0 = Gpclk_sus;	/* set uart mode */
	uartregs = mapspecial(UART1REGS, 64);
	p = uartsetup(&sa1100_uart, uartregs, ClockFreq, "serialport1");
	sa1100_uartbaud(p, 115200);
	intrenable(IRQuart1b, sa1100_uartintr, p, p->name);
}

M bitsy/screen.c => bitsy/screen.c +41 -20
@@ 18,13 18,13 @@ enum {
	Ht		= 240,
	Pal0	= 0x2000,	/* 16-bit pixel data in active mode (12 in passive) */

	hsw		= 0x4,
	hsw		= 0x04,
	elw		= 0x11,
	blw		= 0xc,
	blw		= 0x0c,

	vsw		= 0x3,
	efw		= 0x1,
	bfw		= 0xa,
	vsw		= 0x03,
	efw		= 0x01,
	bfw		= 0x0a,

	pcd		= 0x10,
};


@@ 93,16 93,16 @@ enum {
};

struct sa1110regs {
	ulong	lccr0;	/* 0xb0100000 */
	ulong	lcsr;	/* 0xb0100004 */
	ulong	dummies[2];	/* unused  0xb0100008 and 0xb010000c */
	short*	dbar1;	/* 0xb0100010 */
	ulong	dcar1;	/* 0xb0100014 */
	ulong	dbar2;	/* 0xb0100018 */
	ulong	dcar2;	/* 0xb010001c */
	ulong	lccr1;	/* 0xb0100020 */
	ulong	lccr2;	/* 0xb0100024 */
	ulong	lccr3;	/* 0xb0100028 */
	ulong	lccr0;
	ulong	lcsr;
	ulong	dummies[2];
	short*	dbar1;
	ulong	dcar1;
	ulong	dbar2;
	ulong	dcar2;
	ulong	lccr1;
	ulong	lccr2;
	ulong	lccr3;
} *lcd;

Point	ZP = {0, 0};


@@ 128,15 128,31 @@ Memimage *back;
Memimage *hwcursor;

static void
lcdstop(void) {
	ulong	lccr0;

	lcd->lccr0 &= ~(0<<LEN);	/* disable the LCD */
	while((lcd->lcsr & LDD) == 0)
		sleep(1);
	lcdpower(0);
}

static void
lcdinit(void)
{
	lcd = (struct sa1110regs*)0xb0100000;
	/* map the lcd regs into the kernel's virtual space */
	lcd = (struct sa1110regs*)mapspecial(LCDREGS, sizeof(struct sa1110regs));;

	/* the following works because main memory is direct mapped */
	lcd->lccr0 &= ~(0<<LEN);	/* disable the LCD */
	while((lcd->lcsr & LDD) == 0)
		sleep(1);

	lcd->dbar1 = framebuf->palette;
	lcd->lccr3 = (pcd << PCD) | (0 << ACB) | (0 << API) | (1 << VSP) | (1 << HSP);
	lcd->lccr2 = ((Ht-1) << LPP) | (vsw << VSW) | (efw << EFW) | (bfw << BFW);
	lcd->lccr1 = (Wid << PPL) | (hsw << HSW) | (elw << ELW) | (blw << BLW);
	lcd->lccr0 = 1<<LEN | 1 << CMS | 0<<SDS | 1<<LDM | 1<<BAM | 1<<ERM | 1<<PAS | 0<<BLE | 0<<PDD;
	lcd->lccr3 = pcd<<PCD | 0<<ACB | 0<<API | 1<<VSP | 1<<HSP | 0<<PCP | 0<<OEP;
	lcd->lccr2 = (Ht-1)<<LPP | vsw<<VSW | efw<<EFW | bfw<<BFW;
	lcd->lccr1 = (Wid-16)<<PPL | hsw<<HSW | elw<<ELW | blw<<BLW;
	lcd->lccr0 = 1<<LEN | 0<<CMS | 0<<SDS | 1<<LDM | 1<<BAM | 1<<ERM | 1<<PAS | 0<<BLE | 0<<DPD | 0<<PDD;

}



@@ 145,9 161,14 @@ screeninit(void)
{
	framebuf = xspanalloc(sizeof *framebuf, 0x10, 0);
	memset(framebuf->palette, 0, sizeof framebuf->palette);
	memset(framebuf->pixel, 0xf8, sizeof framebuf->pixel);
	framebuf->palette[0] = Pal0;

	print("LCD status before power up: 0x%lux\n", lcd->lcsr);
	lcdpower(1);
	print("LCD status after power up: 0x%lux\n", lcd->lcsr);
	lcdinit();
	print("LCD status after lcdinit: 0x%lux\n", lcd->lcsr);

	gscreen = &xgscreen;
	gscreen->data = (struct Memdata *)framebuf->pixel;

M bitsy/screen.h => bitsy/screen.h +1 -0
@@ 1,2 1,3 @@
extern void	blankscreen(int);
extern void	flushmemscreen(Rectangle);


M bitsy/trap.c => bitsy/trap.c +47 -27
@@ 79,23 79,30 @@ trapinit(void)
void
trapdump(char *tag)
{
	iprint("%s: icip %lux icmr %lux iclr %lux iccr %lux icfp %lux\n",
	print("%s: icip %lux icmr %lux iclr %lux iccr %lux icfp %lux\n",
		tag, intrregs->icip, intrregs->icmr, intrregs->iclr,
		intrregs->iccr, intrregs->icfp);
}

void
dumpregs(Ureg *ur)
warnregs(Ureg *ur, char *tag)
{
	iprint("r0  0x%.8lux r1  0x%.8lux r2  0x%.8lux r3  0x%.8lux\n",
	char buf[512];
	char *e = buf+sizeof(buf);
	char *p;

	p = seprint(buf, e, "%s:\n", tag);
	p = seprint(p, e, "r0  0x%.8lux r1  0x%.8lux r2  0x%.8lux r3  0x%.8lux\n",
		ur->r0, ur->r1, ur->r2, ur->r3);
	iprint("r4  0x%.8lux r5  0x%.8lux r6  0x%.8lux r7  0x%.8lux\n",
	p = seprint(p, e, "r4  0x%.8lux r5  0x%.8lux r6  0x%.8lux r7  0x%.8lux\n",
		ur->r4, ur->r5, ur->r6, ur->r7);
	iprint("r8  0x%.8lux r9  0x%.8lux r10 0x%.8lux r11 0x%.8lux\n",
	p = seprint(p, e, "r8  0x%.8lux r9  0x%.8lux r10 0x%.8lux r11 0x%.8lux\n",
		ur->r8, ur->r9, ur->r10, ur->r11);
	iprint("r12 0x%.8lux r13 0x%.8lux r14 0x%.8lux\n",
	p = seprint(p, e, "r12 0x%.8lux r13 0x%.8lux r14 0x%.8lux\n",
		ur->r12, ur->r13, ur->r14);
	iprint("type %.8lux psr %.8lux pc %.8lux\n", ur->type, ur->psr, ur->pc);
	seprint(p, e, "type %.8lux psr %.8lux pc %.8lux\n",
		ur->type, ur->psr, ur->pc);
	print("%s", buf);
}

/*


@@ 131,29 138,36 @@ faultarm(Ureg *ureg, ulong va, int user, int read)

	insyscall = up->insyscall;
	up->insyscall = 1;
//peekmmu(va);
	n = fault(va, read);
//iprint("fault returns %d\n", n);
	if(n < 0){
		if(!user){
			dumpregs(ureg);
			panic("fault: 0x%lux\n", va);
			warnregs(ureg, "kernel fault");
			panic("fault: kernel accessing 0x%lux\n", va);
		}
		dumpregs(ureg);
		sprint(buf, "sys: trap: fault %s va=0x%lux",
			read? "read" : "write", va);
//		warnregs(ureg, "user fault");
		sprint(buf, "sys: trap: fault %s va=0x%lux", read ? "read" : "write", va);
		postnote(up, 1, buf, NDebug);
	}
	up->insyscall = insyscall;
}

/* all Pabt+1 faults are caused by loads or stores.  The Lbit of
 * the instruction distinquishes between them.
/*
 *  returns 1 if the instruction writes memory, 0 otherwise
 */
enum
int
writetomem(ulong inst)
{
	Lbit = 1<<20,	/* load instruction */
};
	/* swap always write memory */
	if((inst & 0x0FC00000) == 0x01000000)
		return 1;

	/* loads and stores are distinguished by bit 20 */
	if(inst & (1<<20))
		return 0;

	return 1;
}


/*
 *  here on all exceptions other than syscall (SWI)


@@ 179,18 193,21 @@ trap(Ureg *ureg)
	else
		ureg->pc -= 4;

	if((user && (ureg->r13 & 0xf0000000)) || (ureg->psr & 0x10) != 0x10){
		warnregs(ureg, "wierd ureg");
		panic("bad ureg\n");
	}

	switch(ureg->type){
	default:
		panic("unknown trap");
		break;
	case PsrMabt:	/* prefetch fault */
print("%d: prefetch abort at 0x%lux\n", m->lastpid, ureg->pc);
		faultarm(ureg, ureg->pc, user, 1);
		break;
	case PsrMabt+1:	/* data fault */
		va = getfar();
		inst = *(ulong*)(ureg->pc);
print("%d: data fault pc 0x%lux(0x%lux) va 0x%lux fsr 0x%lux\n", m->lastpid, ureg->pc, inst, va, getfsr());
		switch(getfsr() & 0xf){
		case 0x0:
			panic("vector exception at %lux\n", ureg->pc);


@@ 218,21 235,23 @@ print("%d: data fault pc 0x%lux(0x%lux) va 0x%lux fsr 0x%lux\n", m->lastpid, ure
		case 0x5:
		case 0x7:
			/* translation fault, i.e., no pte entry */
			faultarm(ureg, va, user, inst & Lbit);
			faultarm(ureg, va, user, !writetomem(inst));
			break;
		case 0x9:
		case 0xb:
			/* domain fault, accessing something we shouldn't */
			if(user){
				sprint(buf, "sys: access violation: pc 0x%lux va 0x%lux\n", ureg->pc, va);
				sprint(buf, "sys: access violation: pc 0x%lux va 0x%lux\n",
					ureg->pc, va);
				postnote(up, 1, buf, NDebug);
			} else
				panic("kernel access violation: pc 0x%lux va 0x%lux\n", ureg->pc, va);
				panic("kernel access violation: pc 0x%lux va 0x%lux\n",
					ureg->pc, va);
			break;
		case 0xd:
		case 0xf:
			/* permission error, copy on write or real permission error */
			faultarm(ureg, va, user, inst & Lbit);
			faultarm(ureg, va, user, !writetomem(inst));
			break;
		}
		break;


@@ 552,10 571,11 @@ forkchild(Proc *p, Ureg *ureg)
{
	Ureg *cureg;

//print("%lud setting up for forking child %lud\n", up->pid, p->pid);
	p->sched.sp = (ulong)p->kstack+KSTACK-sizeof(Ureg);
	p->sched.pc = (ulong)forkret;

	cureg = (Ureg*)(p->sched.sp+2*BY2WD);
	cureg = (Ureg*)(p->sched.sp);
	memmove(cureg, ureg, sizeof(Ureg));

	/* syscall returns 0 for child */


@@ 582,7 602,7 @@ execregs(ulong entry, ulong ssize, ulong nargs)
	memset(ureg, 0, 15*sizeof(ulong));
	ureg->r13 = (ulong)sp;
	ureg->pc = entry;
print("execregs pc 0x%lux sp 0x%lux\n", ureg->pc, ureg->r13);
//print("%lud: EXECREGS pc 0x%lux sp 0x%lux\n", up->pid, ureg->pc, ureg->r13);
	return USTKTOP-BY2WD;		/* address of user-level clock */
}


M boot/local.c => boot/local.c +18 -8
@@ 4,6 4,7 @@

static char diskname[2*NAMELEN];
static char *disk;
static char **args;

void
configlocal(Method *mp)


@@ 56,12 57,12 @@ authlocal(void)
int
connectlocal(void)
{
	int p[2];
	int i, p[2];
	Dir dir;
	char d[DIRLEN];
	char partition[2*NAMELEN];
	char *dev;
	char *args[16], **argp;
	char **arg, **argp;

	if(stat("/kfs", d) < 0)
		return -1;


@@ 87,17 88,26 @@ connectlocal(void)
	case -1:
		fatal("fork");
	case 0:
		dup(p[0], 0);
		dup(p[1], 1);
		close(p[0]);
		close(p[1]);
		argp = args;
		arg = malloc((bargc+5)*sizeof(char*));
		argp = arg;
		*argp++ = "kfs";
		*argp++ = "-f";
		*argp++ = partition;
		*argp++ = "-s";
		for(i=1; i<bargc; i++)
			*argp++ = bargv[i];
		*argp = 0;
		exec("/kfs", args);

		print("kfs");
		for(argp=arg; *argp; argp++)
			print(" %s", *argp);
		print("\n");

		dup(p[0], 0);
		dup(p[1], 1);
		close(p[0]);
		close(p[1]);
		exec("/kfs", arg);
		fatal("can't exec kfs");
	default:
		break;

A pc/apm.c => pc/apm.c +160 -0
@@ 0,0 1,160 @@
/*
 * Advanced Power Management 1.2 driver
 */

#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"ureg.h"

extern int apmfarcall(ushort, ulong, Ureg*);		/* apmjump.s */

static int
getreg(ulong *reg, ISAConf *isa, char *name)
{
	int i;
	int nl;

	nl = strlen(name);
	for(i=0; i<isa->nopt; i++){
		if(cistrncmp(isa->opt[i], name, nl)==0 && isa->opt[i][nl] == '='){
			*reg = strtoul(isa->opt[i]+nl+1, nil, 16);
			return 0;
		}
	}
	return -1;
}

/*
 * Segment descriptors look like this.
 *
 * d1: [base 31:24] [gran] [is32bit] [0] [unused] [limit 19:16] 
		[present] [privlev] [type 3:0] [base 23:16]
 * d0: [base 15:00] [limit 15:00]
 *
 * gran is 0 for 1-byte granularity, 1 for 4k granularity
 * type is 0 for system segment, 1 for code/data.
 *
 * clearly we know way too much about the memory unit.
 *
 * what a crock.
 */
static void
setgdt(int sel, ulong base, ulong limit, int flag)
{
	if(sel < 0 || sel >= NGDT)
		panic("setgdt");

	base = (ulong)KADDR(base);
	m->gdt[sel].d0 = (base<<16) | (limit&0xFFFF);
	m->gdt[sel].d1 = (base&0xFF000000) | (limit&0x000F0000) |
			((base>>16)&0xFF) | SEGP | SEGPL(0) | flag;
}

static void
loadgdt(void)
{
	ulong x;
	ushort ptr[3];

	ptr[0] = sizeof(m->gdt);
	x = (ulong)m->gdt;
	ptr[1] = x & 0xFFFF;
	ptr[2] = (x>>16) & 0xFFFF;
	lgdt(ptr);
}

/*
 * Must run before mmuinit, since we modify the GDT that
 * we want the processor to inherit.  I think (but am not sure)
 * that we could run after mmuinit on processor 0 and just
 * modify m->gdt and then call lgdt() as mmuinit() does,
 * but this is a bit simpler and safer.
 */
static	ulong ax, cx, dx, di, ebx, esi;
static Ureg apmu;
static long
apmread(Chan*, void *a, long n, vlong off)
{
	if(off < 0)
		error("badarg");

	if(n+off > sizeof apmu)
		n = sizeof apmu - off;
	if(n <= 0)
		return 0;
	memmove(a, (char*)&apmu+off, n);
	return n;
}

static long
apmwrite(Chan*, void *a, long n, vlong off)
{
	int s;
	if(off || n != sizeof apmu){
//		if(n == 5 && strncmp(a, "ether", 5) == 0){
//			ether589reset();
//			return 5;
//		}
		error("write a Ureg");
	}

	memmove(&apmu, a, sizeof apmu);
	s = splhi();
	apmfarcall(APMCSEL, ebx, &apmu);
	splx(s);
	return n;
}

void
apmlink(void)
{
	ISAConf isa;
	char *s;

	if(isaconfig("apm", 0, &isa) == 0)
		return;

	/*
	 * APM info passed from boot loader.
	 * Now we need to set up the GDT entries for APM.
	 *
	 * AX = 32-bit code segment base address
	 * EBX = 32-bit code segment offset
	 * CX = 16-bit code segment base address
	 * DX = 32-bit data segment base address
	 * ESI = <16-bit code segment length> <32-bit code segment length> (hi then lo)
	 * DI = 32-bit data segment length
	 */

	if(getreg(&ax, &isa, s="ax") < 0
	|| getreg(&ebx, &isa, s="ebx") < 0
	|| getreg(&cx, &isa, s="cx") < 0
	|| getreg(&dx, &isa, s="dx") < 0
	|| getreg(&esi, &isa, s="esi") < 0
	|| getreg(&di, &isa, s="di") < 0){
		print("apm: missing register %s\n", s);
		return;
	}

	/*
	 * We are required by the BIOS to set up three consecutive segments,
	 * one for the APM 32-bit code, one for the APM 16-bit code, and 
	 * one for the APM data.  The BIOS handler uses the code segment it
	 * get called with to determine the other two segment selector.
	 */
	setgdt(APMCSEG, ax<<4, ((esi&0xFFFF)-1)&0xFFFF, SEGEXEC|SEGR|SEGD);
	setgdt(APMCSEG16, cx<<4, ((esi>>16)-1)&0xFFFF, SEGEXEC|SEGR);
	setgdt(APMDSEG, dx<<4, (di-1)&0xFFFF, SEGDATA|SEGW|SEGD);
	loadgdt();

	addarchfile("apm", 0660, apmread, apmwrite);

print("apm0: configured cbase %.8lux off %.8lux\n", ax<<4, ebx);

	return;
}


A pc/apmjump.s => pc/apmjump.s +98 -0
@@ 0,0 1,98 @@
/*
 * Far call, absolute indirect.
 * The argument is the offset.
 * We use a global structure for the jump params,
 * so this is *not* reentrant or thread safe.
 */

#include "mem.h"

#define SSOVERRIDE		BYTE $0x36
#define CSOVERRIDE	BYTE $0x2E
#define RETF			BYTE $0xCB

GLOBL	apmjumpstruct+0(SB), $8

TEXT fortytwo(SB), $0
	MOVL	$42, AX
	RETF

TEXT getcs(SB), $0
	PUSHL	CS
	POPL		AX
	RET

TEXT apmfarcall(SB), $0
	/*
	 * We call push and pop ourselves.
	 * As soon as we do the first push or pop,
	 * we can't use FP anymore.
	 */
	MOVL	off+4(FP), BX
	MOVL	seg+0(FP), CX
	MOVL	BX, apmjumpstruct+0(SB)
	MOVL	CX, apmjumpstruct+4(SB)

	/* load necessary registers from Ureg */
	MOVL	ureg+8(FP), DI
	MOVL	28(DI), AX
	MOVL	16(DI), BX
	MOVL	24(DI), CX
	MOVL	20(DI), DX

	/* save registers, segments */
	PUSHL	DS
	PUSHL	ES
	PUSHL	FS
	PUSHL	GS
	PUSHL	BP
	PUSHL	DI

	/*
	 * paranoia: zero the segments, since it's the
	 * BIOS's responsibility to initialize them.
	 * (trick picked up from Linux driver).
	PUSHL	DX
	XORL	DX, DX
	PUSHL	DX
	POPL		DS
	PUSHL	DX
	POPL		ES
	PUSHL	DX
	POPL		FS
	PUSHL	DX
	POPL		GS
	POPL		DX
	 */

	PUSHL	$APMDSEG
	POPL	DS

	/*
	 * The actual call.
	 */
	CSOVERRIDE; BYTE $0xFF; BYTE $0x1D
	LONG $apmjumpstruct+0(SB)

	/* restore segments, registers */
	POPL	DI
	POPL	BP
	POPL	GS
	POPL	FS
	POPL	ES
	POPL	DS

	PUSHFL
	POPL		64(DI)

	/* store interesting registers back in Ureg */
	MOVL	AX, 28(DI)
	MOVL	BX, 16(DI)
	MOVL	CX, 24(DI)
	MOVL	DX, 20(DI)
	MOVL	SI, 4(DI)

	PUSHFL
	POPL		AX
	ANDL	$1, AX	/* carry flag */
	RET

M pc/dat.h => pc/dat.h +1 -1
@@ 148,7 148,7 @@ struct Mach

	ulong*	pdb;			/* page directory base for this processor (va) */
	Tss*	tss;			/* tss for this processor */
	Segdesc	gdt[6];			/* gdt for this processor */
	Segdesc	gdt[NGDT];			/* gdt for this processor */

	Proc*	proc;			/* current process on this processor */
	Proc*	externup;		/* extern register Proc *up */

M pc/devarch.c => pc/devarch.c +71 -28
@@ 7,7 7,6 @@
#include "ureg.h"
#include "../port/error.h"


typedef struct IOMap IOMap;
struct IOMap
{


@@ 28,23 27,68 @@ static struct
} iomap;

enum {
	Qdir,
	Qcputype,
	Qioalloc,
	Qdir = CHDIR,
	Qioalloc = 0,
	Qiob,
	Qiow,
	Qiol,
	Qirqalloc,
	Qbase,

	Qmax = 16,
};

static Dirtab ioallocdir[] = {
	"cputype",	{ Qcputype, 0 },	0,	0444,
typedef long Rdwrfn(Chan*, void*, long, vlong);

static Rdwrfn *readfn[Qmax];
static Rdwrfn *writefn[Qmax];

static Dirtab archdir[Qmax] = {
	"ioalloc",	{ Qioalloc, 0 },	0,	0444,
	"iob",		{ Qiob, 0 },		0,	0660,
	"iow",		{ Qiow, 0 },		0,	0660,
	"iol",		{ Qiol, 0 },		0,	0660,
	"irqalloc",	{ Qirqalloc, 0},	0,	0444,
};
Lock archwlock;	/* the lock is only for changing archdir */
int narchdir = Qbase;

/*
 * Add a file to the #P listing.  Once added, you can't delete it.
 * You can't add a file with the same name as one already there,
 * and you get a pointer to the Dirtab entry so you can do things
 * like change the Qid version.  Changing the Qid path is disallowed.
 */
Dirtab*
addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
{
	int i;
	Dirtab d;
	Dirtab *dp;

	memset(&d, 0, sizeof d);
	strcpy(d.name, name);
	d.perm = perm;

	lock(&archwlock);
	if(narchdir >= Qmax){
		unlock(&archwlock);
		return nil;
	}

	for(i=0; i<narchdir; i++)
		if(strcmp(archdir[i].name, name) == 0){
			unlock(&archwlock);
			return nil;
		}

	d.qid.path = narchdir;
	archdir[narchdir] = d;
	readfn[narchdir] = rdfn;
	writefn[narchdir] = wrfn;
	dp = &archdir[narchdir++];
	unlock(&archwlock);

	return dp;
}

void
ioinit(void)


@@ 60,8 104,6 @@ ioinit(void)
	ioalloc(0x10000, 1, 0, "dummy");
}

static long cputyperead(char*, int, ulong);

//
//	alloc some io port space and remember who it was
//	alloced to.  if port < 0, find a free region.


@@ 116,7 158,7 @@ ioalloc(int port, int size, int align, char *tag)
	m->tag[sizeof(m->tag)-1] = 0;
	*l = m;

	ioallocdir[0].qid.vers++;
	archdir[0].qid.vers++;

	unlock(&iomap);
	return m->start;


@@ 139,7 181,7 @@ iofree(int port)
		if((*l)->start > port)
			break;
	}
	ioallocdir[0].qid.vers++;
	archdir[0].qid.vers++;
	unlock(&iomap);
}



@@ 179,19 221,19 @@ archattach(char* spec)
int
archwalk(Chan* c, char* name)
{
	return devwalk(c, name, ioallocdir, nelem(ioallocdir), devgen);
	return devwalk(c, name, archdir, narchdir, devgen);
}

static void
archstat(Chan* c, char* dp)
{
	devstat(c, dp, ioallocdir, nelem(ioallocdir), devgen);
	devstat(c, dp, archdir, narchdir, devgen);
}

static Chan*
archopen(Chan* c, int omode)
{
	return devopen(c, omode, ioallocdir, nelem(ioallocdir), devgen);
	return devopen(c, omode, archdir, narchdir, devgen);
}

static void


@@ 207,17 249,17 @@ enum
static long
archread(Chan *c, void *a, long n, vlong offset)
{
	char *p;
	IOMap *m;
	char buf[Linelen+1];
	char buf[Linelen+1], *p;
	int port;
	ushort *sp;
	ulong *lp;
	IOMap *m;
	Rdwrfn *fn;

	switch(c->qid.path & ~CHDIR){
	switch(c->qid.path){

	case Qdir:
		return devdirread(c, a, n, ioallocdir, nelem(ioallocdir), devgen);
		return devdirread(c, a, n, archdir, narchdir, devgen);

	case Qiob:
		port = offset;


@@ 249,13 291,9 @@ archread(Chan *c, void *a, long n, vlong offset)
	case Qioalloc:
		break;

	case Qirqalloc:
		return irqallocread(a, n, offset);

	case Qcputype:
		return cputyperead(a, n, offset);

	default:
		if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
			return fn(c, a, n, offset);
		error(Eperm);
		break;
	}


@@ 282,10 320,11 @@ archread(Chan *c, void *a, long n, vlong offset)
static long
archwrite(Chan *c, void *a, long n, vlong offset)
{
	char *p;
	int port;
	ushort *sp;
	ulong *lp;
	char *p;
	Rdwrfn *fn;

	switch(c->qid.path & ~CHDIR){



@@ 317,6 356,8 @@ archwrite(Chan *c, void *a, long n, vlong offset)
		return n*4;

	default:
		if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
			return fn(c, a, n, offset);
		error(Eperm);
		break;
	}


@@ 537,7 578,7 @@ cpuidentify(void)
}

static long
cputyperead(char *a, int n, ulong offset)
cputyperead(Chan*, void *a, long n, vlong offset)
{
	char str[32];
	ulong mhz;


@@ 592,6 633,8 @@ archinit(void)

	if(X86FAMILY(m->cpuidax) >= 5)
		coherence = wbflush;

	addarchfile("cputype", 0444, cputyperead, nil);
}

void

M pc/fns.h => pc/fns.h +1 -1
@@ 2,6 2,7 @@

void	aamloop(int);
void	addconf(char*, char*);
Dirtab*	addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,void*,long,vlong));
//void	addscsilink(char*, Scsiio (*)(int, ISAConf*));
void	archinit(void);
void	bootargs(ulong);


@@ 59,7 60,6 @@ void	ioinit(void);
int	iounused(int, int);
int	ioalloc(int, int, int, char*);
int	iprint(char*, ...);
int	irqallocread(char*, long, vlong);
int	isaconfig(char*, int, ISAConf*);
void	kbdinit(void);
void	lgdt(ushort[3]);

M pc/mem.h => pc/mem.h +9 -0
@@ 63,6 63,11 @@
#define	UDSEG	3	/* user data/stack */
#define	UESEG	4	/* user executable */
#define TSSSEG	5	/* task segment */
#define	APMCSEG		6	/* APM code segment */
#define	APMCSEG16	7	/* APM 16-bit code segment */
#define	APMDSEG		8	/* APM data segment */
#define NGDT		10	/* number of GDT entries required */
/* #define	APM40SEG	8	/* APM segment 0x40 */

#define SELGDT	(0<<2)	/* selector is in gdt */
#define	SELLDT	(1<<2)	/* selector is in ldt */


@@ 75,6 80,10 @@
#define UESEL	SELECTOR(UESEG, SELGDT, 3)
#define UDSEL	SELECTOR(UDSEG, SELGDT, 3)
#define TSSSEL	SELECTOR(TSSSEG, SELGDT, 0)
#define APMCSEL 	SELECTOR(APMCSEG, SELGDT, 0)
#define APMCSEL16	SELECTOR(APMCSEG16, SELGDT, 0)
#define APMDSEL		SELECTOR(APMDSEG, SELGDT, 0)
/* #define APM40SEL	SELECTOR(APM40SEG, SELGDT, 0) */

/*
 *  fields in segment descriptors

M pc/trap.c => pc/trap.c +8 -6
@@ 50,19 50,19 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
	iunlock(&vctllock);
}

int
irqallocread(char *buf, long n, vlong offset)
static long
irqallocread(Chan*, void *vbuf, long n, vlong offset)
{
	int vno;
	Vctl *v;
	char *buf, *p, str[11+1+NAMELEN+1];
	int m, vno;
	long oldn;
	char str[11+1+NAMELEN+1], *p;
	int m;
	Vctl *v;

	if(n < 0 || offset < 0)
		error(Ebadarg);

	oldn = n;
	buf = vbuf;
	for(vno=0; vno<nelem(vctl); vno++){
		for(v=vctl[vno]; v; v=v->next){
			m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, NAMELEN, v->name);


@@ 164,6 164,8 @@ trapinit(void)
	trapenable(VectorPF, fault386, 0, "fault386");

	nmienable();

	addarchfile("irqalloc", 0444, irqallocread, nil);
}

static char* excname[32] = {

M port/log.c => port/log.c +47 -18
@@ 7,10 7,6 @@

static char Ebadlogctl[] = "unknown log ctl message";

enum {
	Nlog		= 4*1024,
};

void
logopen(Log *alog)
{


@@ 20,10 16,15 @@ logopen(Log *alog)
		nexterror();
	}
	if(alog->opens == 0){
		if(alog->nlog == 0)
			alog->nlog = 4*1024;
		if(alog->minread == 0)
			alog->minread = 1;
		if(alog->buf == nil)
			alog->buf = malloc(Nlog);
			alog->buf = malloc(alog->nlog);
		alog->rptr = alog->buf;
		alog->end = alog->buf + Nlog;
		alog->end = alog->buf + alog->nlog;
		alog->len = 0;
	}
	alog->opens++;
	unlock(alog);


@@ 52,7 53,7 @@ logready(void *a)
{
	Log *alog = a;

	return alog->len;
	return alog->len >= alog->minread;
}

long


@@ 69,7 70,7 @@ logread(Log *alog, void *a, ulong, long n)

	for(;;){
		lock(alog);
		if(alog->len){
		if(alog->len >= alog->minread || alog->len >= n){
			if(n > alog->len)
				n = alog->len;
			d = 0;


@@ 132,24 133,22 @@ logctl(Log *alog, int argc, char *argv[], Logflag *flags)
}

void
log(Log *alog, int mask, char *fmt, ...)
logn(Log *alog, int mask, void *buf, int n)
{
	char buf[128], *t, *fp;
	int i, n;
	va_list arg;
	char *fp, *t;
	int dowake, i;

	if(!(alog->logmask & mask))
		return;

	va_start(arg, fmt);
	n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf;
	va_end(arg);

	if(alog->opens == 0)
		return;

	if(n > alog->nlog)
		return;

	lock(alog);
	i = alog->len + n - Nlog;
	i = alog->len + n - alog->nlog;
	if(i > 0){
		alog->len -= i;
		alog->rptr += i;


@@ 164,7 163,37 @@ log(Log *alog, int mask, char *fmt, ...)
			t = alog->buf + (t - alog->end);
		*t++ = *fp++;
	}
	dowake = alog->len >= alog->minread;
	unlock(alog);

	wakeup(&alog->readr);
	if(dowake)
		wakeup(&alog->readr);
}

void
vlog(Log *alog, int mask, char *fmt, va_list arg)
{
	char buf[128];
	int n;

	if(!(alog->logmask & mask))
		return;

	if(alog->opens == 0)
		return;

	n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf;

	logn(alog, mask, buf, n);
}

void
log(Log *alog, int mask, char *fmt, ...)
{
	va_list arg;

	va_start(arg, fmt);
	vlog(alog, mask, fmt, arg);
	va_end(arg);
}


M port/portdat.h => port/portdat.h +2 -0
@@ 698,6 698,8 @@ struct Log {
	char	*end;
	char	*rptr;
	int	len;
	int	nlog;
	int	minread;

	int	logmask;	/* mask of things to debug */


M port/portfns.h => port/portfns.h +2 -0
@@ 153,8 153,10 @@ void		lockinit(void);
void		logopen(Log*);
void		logclose(Log*);
char*		logctl(Log*, int, char**, Logflag*);
void		logn(Log*, int, void*, int);
long		logread(Log*, void*, ulong, long);
void		log(Log*, int, char*, ...);
void		vlog(Log*, int, char*, va_list);
Page*		lookpage(Image*, ulong);
void		machinit(void);
void*		mallocz(ulong, int);

M port/proc.c => port/proc.c +1 -0
@@ 1056,6 1056,7 @@ kproc(char *name, void (*func)(void *), void *arg)
	 *  any mmu info about this process is now stale
	 *  and has to be discarded.
	 */
	p->newtlb = 1;
	flushmmu();
}