~kris/9p

9hist

9875fbff1f23d4f6d27c8cfe77000c3b80e2e1c5 — David du Colombier 28 years ago beae2ba
Plan 9 from Bell Labs 1997-11-01
M carrera/fns.h => carrera/fns.h +1 -0
@@ 76,6 76,7 @@ void		iomapinit(void);
void		enetaddr(uchar*);

#define	waserror()		setlabel(&up->errlab[up->nerrlab++])
#define	kmapperm(x)		kmap(x)

#define KADDR(a)	((void*)((ulong)(a)|KSEG0))
#define KADDR1(a)	((void*)((ulong)(a)|KSEG1))

M carrera/kbd.c => carrera/kbd.c +2 -1
@@ 6,7 6,8 @@
#include	"io.h"
#include	"../port/error.h"

#include	<libg.h>
#define	Image	IMAGE
#include	<draw.h>
#include	"screen.h"

enum

M carrera/main.c => carrera/main.c +6 -2
@@ 5,6 5,7 @@
#include	"fns.h"
#include	"io.h"
#include	"init.h"
#include	"pool.h"

/*
 *  args passed by boot process


@@ 58,7 59,6 @@ main(void)
	pageinit();
	procinit0();
	initseg();
	links();
	chandevreset();
	swapinit();
	userinit();


@@ 456,7 456,11 @@ confinit(void)
	conf.npage1 = 0;
	conf.base1 = 0;

	conf.upages = (conf.npage*70)/100;
	if(top > 16*MB){
		conf.upages = (conf.npage*60)/100;
		poolsetparam("Image", 0, 0, 4*1024*1024);
	}else
		conf.upages = (conf.npage*40)/100;
	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;

	conf.nmach = 1;

M carrera/memmove.s => carrera/memmove.s +142 -148
@@ 1,16 1,9 @@
/*
 * R4000 double-word version.  Only works in kernel mode.
 * Requires low-core support to save R5 and R6 in a 64-bit hole.
 * R4000-compatible memmove uses V instructions.
 * The kernel uses the 3000 compilers, but we can
 * use this procedure for speed.
 */

/*
 *  R4000 instructions
 */
#define	LD(offset, base, rt)		WORD	$((067<<26)|((base)<<21)|((rt)<<16)|((offset)&0xFFFF))
#define	STD(rt, offset, base)		WORD	$((077<<26)|((base)<<21)|((rt)<<16)|((offset)&0xFFFF))

	TEXT	memmove(SB), $0

	JMP	move

	TEXT	memcpy(SB), $0


@@ 19,141 12,140 @@ move:

	MOVW	n+8(FP), R3		/* R3 is count */
	MOVW	R1, R4			/* R4 is to-pointer */
	SGT	R0, R3, R10
	BEQ	R10, ok
	SGT	R0, R3, R5
	BEQ	R5, ok
	MOVW	(R0), R0		/* abort if negative count */
ok:
	MOVW	s2+4(FP), R10		/* R10 is from-pointer */
	ADDU	R3,R10, R7		/* R7 is end from-pointer */
	ADDU	R3,R4, R11		/* R11 is end to-pointer */
	MOVW	s2+4(FP), R5		/* R5 is from-pointer */
	ADDU	R3,R5, R7		/* R7 is end from-pointer */
	ADDU	R3,R4, R6		/* R6 is end to-pointer */

/*
 * easiest test is copy backwards if
 * destination string has higher mem address
 */
	SGT	$8,R3, R2
	SGTU	R4,R10, R1
	SGT	$15,R3, R2
	SGTU	R4,R5, R1
	BNE	R1, back

/*
 * if not at least 8 chars,
 * dont even mess around.
 * if not at least 15 chars,
 * don't even mess around.
 * 7 chars to guarantee any
 * rounding up to a doubleword
 * boundary and 8 characters
 * to get at least maybe one
 * full doubleword store.
 * doubleword store.
 */
	BNE	R2, fout

/*
 * test if both pointers
 * are similarly word aligned
 */
	XOR	R4,R10, R1
	AND	$3, R1
	BNE	R1, fout

/*
 * test if both pointers
 * are similarly double-word aligned
 * byte at a time to doubleword align destination
 */
	XOR	R4,R10, R1
	AND	$7, R1
	BNE	R1, f1

/*
 * double-word aligned; start by byte at a time until aligned
 */
fd1:
f1:
	AND	$7,R4, R1
	BEQ	R1, fd2
	MOVB	0(R10), R8
	ADDU	$1, R10
	BEQ	R1, f2
	MOVB	0(R5), R8
	ADDU	$1, R5
	MOVB	R8, 0(R4)
	ADDU	$1, R4
	JMP	fd1
	JMP	f1

/*
 * test if source is now doubleword aligned
 */
f2:
	AND	$7, R5, R1
	BNE	R1, fun2

/*
 * turn R3 into to-end pointer-31
 * copy 32 at a time while there's room.
 * R11 is smaller than R7 --
 * copy 32 at a time while theres room.
 * R6 is smaller than R7 --
 * there are problems if R7 is 0.
 */
fd2:
	ADDU	$-31,R11, R3
fd3:
	ADDU	$-31,R6, R3
f3:
	SGTU	R3,R4, R1
	BEQ	R1, f4
	LD	(0,(10), 5)			/* MOVW	0(R10), R8 */
	LD	(8,(10), 6)			/* MOVW	4(R10), R9 */
	STD	(5, 0,(4))			/* MOVW	R8, 0(R4) */
	LD	(16,(10), 5)		/* MOVW	8(R10), R8 */
	STD	(6, 8,(4))			/* MOVW	R9, 4(R4) */
	LD	(24,(10), 6)		/* MOVW	12(R10), R9 */
	ADDU	$32, R10
	STD	(5, 16,(4))			/* MOVW	R8, 8(R4) */
	STD	(6, 24,(4))			/* MOVW	R9, 12(R4) */
	MOVV	0(R5), R8
	MOVV	8(R5), R9
	MOVV	R8, 0(R4)
	MOVV	16(R5), R8
	MOVV	R9, 8(R4)
	MOVV	24(R5), R9
	ADDU	$32, R5
	MOVV	R8, 16(R4)
	MOVV	R9, 24(R4)
	ADDU	$32, R4
	JMP	fd3
	JMP	f3

/*
 * byte at a time to word align
 * turn R3 into to-end pointer-3
 * copy 4 at a time while theres room
 */
f1:
	AND	$3,R4, R1
	BEQ	R1, f2
	MOVB	0(R10), R8
	ADDU	$1, R10
	MOVB	R8, 0(R4)
	ADDU	$1, R4
	JMP	f1
f4:
	ADDU	$-3,R6, R3
f5:
	SGTU	R3,R4, R1
	BEQ	R1, fout
	MOVW	0(R5), R8
	ADDU	$4, R5
	MOVW	R8, 0(R4)
	ADDU	$4, R4
	JMP	f5

/*
 * turn R3 into to-end pointer-15
 * copy 16 at a time while there's room.
 * R11 is smaller than R7 --
 * forward copy, unaligned
 * turn R3 into to-end pointer-31
 * copy 32 at a time while theres room.
 * R6 is smaller than R7 --
 * there are problems if R7 is 0.
 */
f2:
	ADDU	$-15,R11, R3
f3:
fun2:
	ADDU	$-31,R6, R3
fun3:
	SGTU	R3,R4, R1
	BEQ	R1, f4
	MOVW	0(R10), R8
	MOVW	4(R10), R9
	MOVW	R8, 0(R4)
	MOVW	8(R10), R8
	MOVW	R9, 4(R4)
	MOVW	12(R10), R9
	ADDU	$16, R10
	MOVW	R8, 8(R4)
	MOVW	R9, 12(R4)
	ADDU	$16, R4
	JMP	f3
	BEQ	R1, fun4
	MOVVL	0(R5), R8
	MOVVR	7(R5), R8
	MOVVL	8(R5), R9
	MOVVR	15(R5), R9
	MOVV	R8, 0(R4)
	MOVVL	16(R5), R8
	MOVVR	23(R5), R8
	MOVV	R9, 8(R4)
	MOVVL	24(R5), R9
	MOVVR	31(R5), R9
	ADDU	$32, R5
	MOVV	R8, 16(R4)
	MOVV	R9, 24(R4)
	ADDU	$32, R4
	JMP	fun3

/*
 * turn R3 into to-end pointer-3
 * copy 4 at a time while theres room
 */
f4:
	ADDU	$-3,R11, R3
f5:
fun4:
	ADDU	$-3,R6, R3
fun5:
	SGTU	R3,R4, R1
	BEQ	R1, fout
	MOVW	0(R10), R8
	ADDU	$4, R10
	MOVWL	0(R5), R8
	MOVWR	3(R5), R8
	ADDU	$4, R5
	MOVW	R8, 0(R4)
	ADDU	$4, R4
	JMP	f5
	JMP	fun5

/*
 * last loop, copy byte at a time
 */
fout:
	BEQ	R7,R10, ret
	MOVB	0(R10), R8
	ADDU	$1, R10
	BEQ	R7,R5, ret
	MOVB	0(R5), R8
	ADDU	$1, R5
	MOVB	R8, 0(R4)
	ADDU	$1, R4
	JMP	fout


@@ 163,82 155,84 @@ fout:
 */
back:
	BNE	R2, bout
	XOR	R11,R7, R1
	AND	$3, R1
	BNE	R1, bout

	XOR	R11,R7, R1
	AND	$7, R1
	BNE	R1, b1

	/* double words */
bd1:
	AND	$7,R7, R1
	BEQ	R1, bd2
	MOVB	-1(R7), R8
	ADDU	$-1, R7
	MOVB	R8, -1(R11)
	ADDU	$-1, R11
	JMP	bd1
bd2:
	ADDU	$31,R10, R3
bd3:
	SGTU	R7,R3, R1
	BEQ	R1, b4
	LD	(-8,(7), 5)				/* MOVW	-4(R7), R8 */
	LD	(-16,(7), 6)			/* MOVW	-8(R7), R9 */
	STD	(5, -8,(11))			/* MOVW	R8, -4(R11) */
	LD	(-24,(7), 5)			/* MOVW	-12(R7), R8 */
	STD	(6, -16,(11))			/* MOVW	R9, -8(R11) */
	LD	(-32,(7), 6)			/* MOVW	-16(R7), R9 */
	ADDU	$-32, R7
	STD	(5, -24,(11))			/* MOVW	R8, -12(R11) */
	STD	(6, -32,(11))			/* MOVW	R9, -16(R11) */
	ADDU	$-32, R11
	JMP	bd3

	/* regular words */
b1:
	AND	$3,R7, R1
	AND	$7,R6, R1
	BEQ	R1, b2
	MOVB	-1(R7), R8
	ADDU	$-1, R7
	MOVB	R8, -1(R11)
	ADDU	$-1, R11
	MOVB	R8, -1(R6)
	ADDU	$-1, R6
	JMP	b1

b2:
	ADDU	$15,R10, R3
	AND	$7, R7, R1
	BNE	R1, bun2

	ADDU	$31,R5, R3
b3:
	SGTU	R7,R3, R1
	BEQ	R1, b4
	MOVW	-4(R7), R8
	MOVW	-8(R7), R9
	MOVW	R8, -4(R11)
	MOVW	-12(R7), R8
	MOVW	R9, -8(R11)
	MOVW	-16(R7), R9
	ADDU	$-16, R7
	MOVW	R8, -12(R11)
	MOVW	R9, -16(R11)
	ADDU	$-16, R11
	MOVV	-8(R7), R8
	MOVV	-16(R7), R9
	MOVV	R8, -8(R6)
	MOVV	-24(R7), R8
	MOVV	R9, -16(R6)
	MOVV	-32(R7), R9
	ADDU	$-32, R7
	MOVV	R8, -24(R6)
	MOVV	R9, -32(R6)
	ADDU	$-32, R6
	JMP	b3
b4:
	ADDU	$3,R10, R3
	ADDU	$3,R5, R3
b5:
	SGTU	R7,R3, R1
	BEQ	R1, bout
	MOVW	-4(R7), R8
	ADDU	$-4, R7
	MOVW	R8, -4(R11)
	ADDU	$-4, R11
	MOVW	R8, -4(R6)
	ADDU	$-4, R6
	JMP	b5

bun2:
	ADDU	$31,R5, R3
bun3:
	SGTU	R7,R3, R1
	BEQ	R1, bun4
	MOVVL	-8(R7), R8
	MOVVR	-1(R7), R8
	MOVVL	-16(R7), R9
	MOVVR	-9(R7), R9
	MOVV	R8, -8(R6)
	MOVVL	-24(R7), R8
	MOVVR	-17(R7), R8
	MOVV	R9, -16(R6)
	MOVVL	-32(R7), R9
	MOVVR	-25(R7), R9
	ADDU	$-32, R7
	MOVV	R8, -24(R6)
	MOVV	R9, -32(R6)
	ADDU	$-32, R6
	JMP	bun3

bun4:
	ADDU	$3,R5, R3
bun5:
	SGTU	R7,R3, R1
	BEQ	R1, bout
	MOVWL	-4(R7), R8
	MOVWR	-1(R7), R8
	ADDU	$-4, R7
	MOVW	R8, -4(R6)
	ADDU	$-4, R6
	JMP	bun5

bout:
	BEQ	R7,R10, ret
	BEQ	R7,R5, ret
	MOVB	-1(R7), R8
	ADDU	$-1, R7
	MOVB	R8, -1(R11)
	ADDU	$-1, R11
	MOVB	R8, -1(R6)
	ADDU	$-1, R6
	JMP	bout

ret:

M carrera/memset.s => carrera/memset.s +21 -32
@@ 1,16 1,10 @@
/*
 * R4000 double-word version.  Only works in kernel mode.
 * Requires low-core support to save R5 in a 64-bit hole.
 * R4000-compatible memset uses V instructions.
 * The kernel uses the 3000 compilers, but we can
 * use this procedure for speed.
 */

/*
 *  R4000 instructions
 */
#define	LD(base, rt)		WORD	$((067<<26)|((base)<<21)|((rt)<<16))
#define	STD(rt, offset, base)		WORD	$((077<<26)|((base)<<21)|((rt)<<16)|((offset)&0xFFFF))

	TEXT	memset(SB),$16	/* $16 for hole to build temporary */
	MOVW R1, 0(FP)
	TEXT	memset(SB),$16
	MOVW	R1, 0(FP)

	MOVW	n+8(FP), R3		/* R3 is count */
	MOVW	p+0(FP), R4		/* R4 is pointer */


@@ 19,35 13,30 @@

/*
 * if not at least 8 chars,
 * don't even mess around.
 * dont even mess around.
 * 7 chars to guarantee any
 * rounding up to a doubleword
 * rounding up to a word
 * boundary and 8 characters
 * to get at least maybe one
 * full doubleword store.
 * full word store.
 */
	SGT	$8,R3, R1
	BNE	R1, out

/*
 * turn R5 into a doubleword of characters.
 * build doubleword on stack; can't use OR on 64-bit registers
 * turn R5 into a doubleword of characters
 */
	AND	$0xff, R5
	SLL	$8,R5, R1
	SLLV	$8,R5, R1
	OR	R1, R5
	SLLV	$16,R5, R1
	OR	R1, R5
	SLL	$16,R5, R1
	SLLV	$32,R5, R1
	OR	R1, R5
	MOVW	R29, R1
	ADD	$8, R1
	AND	$~7, R1
	MOVW	R5, 0(R1)
	MOVW	R5, 4(R1)
	LD		(1, 5)
	

/*
 * store one byte at a time until pointer
 * is aligned on a doubleword boundary
 * is alligned on a doubleword boundary
 */
l1:
	AND	$7,R4, R1


@@ 58,23 47,23 @@ l1:

/*
 * turn R3 into end pointer-31
 * store 32 at a time while there's room
 * store 32 at a time while theres room
 */
l2:
	ADDU	$-31,R6, R3
l3:
	SGTU	R3,R4, R1
	BEQ	R1, l4
	STD	(5, 0, 4)
	STD	(5, 8, 4)
	MOVV	R5, 0(R4)
	MOVV	R5, 8(R4)
	ADDU	$32, R4
	STD	(5, -16, 4)
	STD	(5, -8, 4)
	MOVV	R5, -16(R4)
	MOVV	R5, -8(R4)
	JMP	l3

/*
 * turn R3 into end pointer-3
 * store 4 at a time while there's room
 * store 4 at a time while theres room
 */
l4:
	ADDU	$-3,R6, R3

M carrera/screen.c => carrera/screen.c +186 -55
@@ 7,7 7,9 @@
#include	"ureg.h"
#include	"../port/error.h"

#include	<libg.h>
#define	Image	IMAGE
#include	<draw.h>
#include	<memdraw.h>
#include	"screen.h"

#define	MINX	8


@@ 27,8 29,9 @@ struct Dac
};

char s1[] = { 0x00, 0x00, 0xC0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
#define	Backgnd		0x00

extern	Subfont	defont0;
		Memsubfont	*memdefont;
static	ulong		rep(ulong, int);

struct{


@@ 38,28 41,108 @@ struct{

Lock	screenlock;

Bitmap	gscreen =
Point	ZP = {0, 0};

static Memdata	hwcursordata;

static Memdata gscreendata =
{
	{ 0, 0, 1597, 1234 },
	{ 0, 0, 1597, 1234 },
	3,
	Screenvirt+0x000178D0,
	0,
	512,
	0
	nil,
	(ulong*)(Screenvirt+0x000178D0),
	1,
};

Memimage gscreen =
{
	{ 0, 0, 1597, 1234 },	/* r */
	{ 0, 0, 1597, 1234 },	/* clipr */
	3,	/* ldepth */
	0,	/* repl */
	&gscreendata,	/* data */
	0,	/* zero */
	512,	/* width */
	0,	/* layer */
};

static Bitmap hwcursor=
static Memimage hwcursor=
{
	{0, 0, 64, 64},
	{0, 0, 64, 64},
	1,
	0,		/* base filled in by malloc when needed */
	0,
	&hwcursordata,		/* base filled in by malloc when needed */
	0,
	4,
	0,
};

ulong	consbits = ~0;
Memdata	consdata = {
	nil,
	&consbits
};
Memimage conscol =
{
	{ 0, 0, 1, 1 },
	{ -100000, -100000, 100000, 100000 },
	3,
	1,
	&consdata,
	0,
	1
};

ulong	onesbits = ~0;
Memdata	onesdata = {
	nil,
	&onesbits,
};
Memimage	xones =
{
	{ 0, 0, 1, 1 },
	{ -100000, -100000, 100000, 100000 },
	3,
	1,
	&onesdata,
	0,
	1
};
Memimage *memones = &xones;

ulong	zerosbits = 0;
Memdata	zerosdata = {
	nil,
	&zerosbits,
};
Memimage	xzeros =
{
	{ 0, 0, 1, 1 },
	{ -100000, -100000, 100000, 100000 },
	3,
	1,
	&zerosdata,
	0,
	1
};
Memimage *memzeros = &xzeros;

ulong	backbits = (Backgnd<<24)|(Backgnd<<16)|(Backgnd<<8)|Backgnd;
Memdata	backdata = {
	nil,
	&backbits
};
Memimage	xback =
{
	{ 0, 0, 1, 1 },
	{ -100000, -100000, 100000, 100000 },
	3,
	1,
	&backdata,
	0,
	1
};
Memimage *back = &xback;

static Rectangle window;
static Point curpos;
static int h, w;


@@ 68,31 151,35 @@ void
screenwin(void)
{
	Dac *d;
	Point p;
	int i, y;
	Point p, q;
	int y;
	Cursor zero;
	char *greet;

	memset((void*)Screenvirt, 0xff, 3*1024*1024);
	for(y=gscreen.r.min.y; y<gscreen.r.max.y; y++)
		memset(byteaddr(&gscreen, Pt(gscreen.r.min.x, y)), 0xa0, Dx(gscreen.r));
		memset(byteaddr(&gscreen, Pt(gscreen.r.min.x, y)), 0xba, Dx(gscreen.r));

	w = defont0.info[' '].width;
	h = defont0.height;
	w = memdefont->info[' '].width;
	h = memdefont->height;

	window.min = Pt(100, 100);
	window.max = add(window.min, Pt(10+w*120, 10+h*60));

	bitblt(&gscreen, add(window.min, Pt(5, 5)), &gscreen, window, F);
	bitblt(&gscreen, window.min, &gscreen, window, Zero);
	border(&gscreen, window, 4, F);
	window = inset(window, 5);
	for(i = 0; i < h+6; i += 2) {
		y = window.min.y+i;
		bitblt(&gscreen, Pt(window.min.x, y),
			&gscreen, Rect(window.min.x, y, window.max.x, y+1), F);
	}
	p = add(window.min, Pt(10, 2));
	subfstring(&gscreen, p, &defont0, "Brazil Console ", S);
	window.max = addpt(window.min, Pt(10+w*120, 10+h*60));

	memimagedraw(&gscreen, window, memones, ZP, memones, ZP);
	window = insetrect(window, 4);
	memimagedraw(&gscreen, window, back, ZP, memones, ZP);
	/* hack to get a grey color */
	memzeros->data->data[0] = 0x33333333;
	memimagedraw(&gscreen, Rect(window.min.x, window.min.y,
			window.max.x, window.min.y+h+5+6), memzeros, ZP, memones, ZP);
	memzeros->data->data[0] = 0;
	window = insetrect(window, 5);

	greet = " Brazil Console: Draw version ";
	p = addpt(window.min, Pt(10, 0));
	q = memsubfontwidth(memdefont, greet);
	memimagestring(&gscreen, p, &conscol, memdefont, greet);
	window.min.y += h+6;
	curpos = window.min;
	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;


@@ 152,7 239,7 @@ dacinit(void)
	for(i = 0; i < 0x400; i++)
		d->cr2 = 0xff;

	graphicscmap(0);
	drawcmap(0);

	/* Overlay Palette Ram */
	d->cr0 = 0x00;


@@ 178,10 265,11 @@ screeninit(void)
{
	dacinit();

	bitblt(&gscreen, Pt(0, 0), &gscreen, gscreen.r, 0);
	memdefont = getmemdefont();

	out.pos.x = MINX;
	out.pos.y = 0;
	out.bwid = defont0.info[' '].width;
	out.bwid = memdefont->info[' '].width;

	screenwin();
}


@@ 190,21 278,51 @@ static void
scroll(void)
{
	int o;
	Point p;
	Rectangle r;

	o = 5*h;
	r = Rpt(Pt(window.min.x, window.min.y+o), window.max);
	bitblt(&gscreen, window.min, &gscreen, r, S);
	o = 8*h;
	r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
	p = Pt(window.min.x, window.min.y+o);
	memimagedraw(&gscreen, r, &gscreen, p, memones, p);
	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
	bitblt(&gscreen, r.min, &gscreen, r, Zero);
	memimagedraw(&gscreen, r, back, ZP, memones, ZP);

	curpos.y -= o;
}

/* 
 * export screen to devdraw
 */
ulong*
attachscreen(Rectangle *r, int *ld, int *width)
{
	*r = gscreen.r;
	*ld = gscreen.ldepth;
	*width = gscreen.width;

	return gscreendata.data;
}

/*
 * update screen (no-op: frame buffer is direct-mapped)
 */
void
flushmemscreen(Rectangle)
{
}

static void
screenputc(char *buf)
{
	int pos;
	Point p;
	int w, pos;
	Rectangle r;
	static int *xp;
	static int xbuf[256];

	if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
		xp = xbuf;

	switch(buf[0]) {
	case '\n':


@@ 214,27 332,39 @@ screenputc(char *buf)
		screenputc("\r");
		break;
	case '\r':
		xp = xbuf;
		curpos.x = window.min.x;
		break;
	case '\t':
		p = memsubfontwidth(memdefont, " ");
		w = p.x;
		*xp++ = curpos.x;
		pos = (curpos.x-window.min.x)/w;
		pos = 8-(pos%8);
		r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
		memimagedraw(&gscreen, r, back, back->r.min, memones, back->r.min);
		curpos.x += pos*w;
		break;
	case '\b':
		if(curpos.x-w >= 0){
			r.min.x = curpos.x-w;
			r.max.x = curpos.x;
			r.min.y = curpos.y;
			r.max.y = curpos.y+defont0.height;
			bitblt(&gscreen, r.min, &gscreen, r, Zero);
			curpos.x -= w;
		}
		if(xp <= xbuf)
			break;
		xp--;
		r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
		memimagedraw(&gscreen, r, back, back->r.min, memones, back->r.min);
		curpos.x = *xp;
		break;
	default:
		p = memsubfontwidth(memdefont, buf);
		w = p.x;

		if(curpos.x >= window.max.x-w)
			screenputc("\n");
		curpos = subfstring(&gscreen, curpos, &defont0, buf, S);

		*xp++ = curpos.x;
		r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y + h);
		memimagedraw(&gscreen, r, back, back->r.min, memones, back->r.min);
		memimagestring(&gscreen, curpos, &conscol, memdefont, buf);
		curpos.x += w;
	}
}



@@ 381,17 511,18 @@ setcursor(Cursor *curs)
		*p = curs->clr[2*i];
		*(p+1) = curs->clr[2*i+1];
	}
	hwcursor.base = (ulong *)malloc(1024);
	if(hwcursor.base == 0)
	hwcursor.data->data = (ulong *)malloc(1024);
	if(hwcursor.data->data == 0)
		error(Enomem);
	/* hw cursor is 64x64 with hot point at (32,32) */
	org = add(Pt(32,32), curs->offset); 
	for(x = 0; x < 16; x++)
		for(y = 0; y < 16; y++) {
	org = addpt(Pt(32,32), curs->offset); 
	for(y = 0; y < 16; y++)
		for(x = 0; x < 16; x++) {
			spix = (s[y]>>(31-(x&0x1F)))&1;
			cpix = (c[y]>>(31-(x&0x1F)))&1;
			dpix = (spix<<1) | cpix;
			point(&hwcursor, add(Pt(x,y), org), dpix, S);
			/* point(&hwcursor, addpt(Pt(x,y), org), dpix, S), by hand */
			*byteaddr(&hwcursor, Pt(x+org.x, y+org.y)) |= dpix<<(6-(2*((x+org.x)&3)));
		}

	d = DAC;


@@ 409,14 540,14 @@ setcursor(Cursor *curs)
	d->cr1 = 0x04;
	d->cr0 = 0x00;
	for(x = 0; x < 1024; x++)
		d->cr2 = ((uchar *)hwcursor.base)[x];
		d->cr2 = ((uchar *)hwcursor.data->data)[x];
	/* set y back */
	d->cr1 = 0x03;
	d->cr0 = 0x03;
	d->cr2 = ylow;
	d->cr2 = yhigh;
	
	free(hwcursor.base);
	free(hwcursor.data->data);
}

int

M carrera/trap.c => carrera/trap.c +55 -24
@@ 60,26 60,49 @@ char	*fpexcname(Ureg*, ulong, char*);
void (*eisadma[8])(void);			/* Eisa dma chain vectors */


char *regname[]={
	"STATUS",	"PC",
	"SP",		"CAUSE",
	"BADADDR",	"TLBVIRT",
	"HI",		"LO",
	"R31",		"R30",
	"R28",		"R27",
	"R26",		"R25",
	"R24",		"R23",
	"R22",		"R21",
	"R20",		"R19",
	"R18",		"R17",
	"R16",		"R15",
	"R14",		"R13",
	"R12",		"R11",
	"R10",		"R9",
	"R8",		"R7",
	"R6",		"R5",
	"R4",		"R3",
	"R2",		"R1",
struct
{
	char	*name;
	int	off;
} regname[]={
	"STATUS",	Ureg_status,
	"PC",		Ureg_pc,
	"SP",		Ureg_sp,
	"CAUSE",	Ureg_cause,
	"BADADDR",	Ureg_badvaddr,
	"TLBVIRT",	Ureg_tlbvirt,
	"HI",		Ureg_hi,
	"LO",		Ureg_lo,
	"R31",		Ureg_r31,
	"R30",		Ureg_r30,
	"R28",		Ureg_r28,
	"R27",		Ureg_r27,
	"R26",		Ureg_r26,
	"R25",		Ureg_r25,
	"R24",		Ureg_r24,
	"R23",		Ureg_r23,
	"R22",		Ureg_r22,
	"R21",		Ureg_r21,
	"R20",		Ureg_r20,
	"R19",		Ureg_r19,
	"R18",		Ureg_r18,
	"R17",		Ureg_r17,
	"R16",		Ureg_r16,
	"R15",		Ureg_r15,
	"R14",		Ureg_r14,
	"R13",		Ureg_r13,
	"R12",		Ureg_r12,
	"R11",		Ureg_r11,
	"R10",		Ureg_r10,	
	"R9",		Ureg_r9,
	"R8",		Ureg_r8,
	"R7",		Ureg_r7,
	"R6",		Ureg_r6,
	"R5",		Ureg_r5,
	"R4",		Ureg_r4,
	"R3",		Ureg_r3,
	"R2",		Ureg_r2,
	"R1",		Ureg_r1,
};

static char *


@@ 470,21 493,29 @@ dumpstack(void)
	print("\n");
}

ulong
R(Ureg *ur, int i)
{
	uchar *s;

	s = (uchar*)ur;
	return *(ulong*)(s+regname[i].off-Uoffset);
}

void
dumpregs(Ureg *ur)
{
	int i;
	ulong *l;

	if(up)
		print("registers for %s %d\n", up->text, up->pid);
	else
		print("registers for kernel\n");

	l = &ur->status;
	for(i=0; i<nelem(regname); i+=2, l+=2)
	for(i=0; i<nelem(regname); i+=2)
		print("%s\t0x%.8lux\t%s\t0x%.8lux\n",
				regname[i], l[0], regname[i+1], l[1]);
				regname[i].name, R(ur, i),
				regname[i+1].name, R(ur, i+1));
}

int

M pc/cga.c => pc/cga.c +31 -49
@@ 3,7 3,6 @@
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

enum {


@@ 15,10 14,9 @@ enum {

#define CGASCREENBASE	((uchar*)KADDR(0xB8000))

static int pos;
static int cgapos;
static int screeninitdone;
QLock screenlock;
void (*vgascreenputc)(char*);
static Lock cgascreenlock;

static uchar
cgaregr(int index)


@@ 37,9 35,9 @@ cgaregw(int index, int data)
static void
movecursor(void)
{
	cgaregw(0x0E, (pos/2>>8) & 0xFF);
	cgaregw(0x0F, pos/2 & 0xFF);
	CGASCREENBASE[pos+1] = Attr;
	cgaregw(0x0E, (cgapos/2>>8) & 0xFF);
	cgaregw(0x0F, cgapos/2 & 0xFF);
	CGASCREENBASE[cgapos+1] = Attr;
}

static void


@@ 48,28 46,28 @@ cgascreenputc(int c)
	int i;

	if(c == '\n'){
		pos = pos/Width;
		pos = (pos+1)*Width;
		cgapos = cgapos/Width;
		cgapos = (cgapos+1)*Width;
	}
	else if(c == '\t'){
		i = 8 - ((pos/2)&7);
		i = 8 - ((cgapos/2)&7);
		while(i-->0)
			cgascreenputc(' ');
	}
	else if(c == '\b'){
		if(pos >= 2)
			pos -= 2;
		if(cgapos >= 2)
			cgapos -= 2;
		cgascreenputc(' ');
		pos -= 2;
		cgapos -= 2;
	}
	else{
		CGASCREENBASE[pos++] = c;
		CGASCREENBASE[pos++] = Attr;
		CGASCREENBASE[cgapos++] = c;
		CGASCREENBASE[cgapos++] = Attr;
	}
	if(pos >= Width*Height){
	if(cgapos >= Width*Height){
		memmove(CGASCREENBASE, &CGASCREENBASE[Width], Width*(Height-1));
		memset(&CGASCREENBASE[Width*(Height-1)], 0, Width);
		pos = Width*(Height-1);
		cgapos = Width*(Height-1);
	}
	movecursor();
}


@@ 77,46 75,30 @@ cgascreenputc(int c)
void
screeninit(void)
{
	pos = cgaregr(0x0E)<<8;
	pos |= cgaregr(0x0F);
	pos *= 2;
	cgapos = cgaregr(0x0E)<<8;
	cgapos |= cgaregr(0x0F);
	cgapos *= 2;
	screeninitdone = 1;
}

void
screenputs(char* s, int n)
static void
cgascreenputs(char* s, int n)
{
	int i;
	Rune r;
	char buf[4];

	if(!islo()){
		if(!canqlock(&screenlock))
		/*
		 * Don't deadlock trying to
		 * print in an interrupt.
		 */
		if(!canlock(&cgascreenlock))
			return;
	}
	else
		qlock(&screenlock);
		lock(&cgascreenlock);

	if(vgascreenputc == nil){
		while(n-- > 0)
			cgascreenputc(*s++);
		qunlock(&screenlock);
		return;
	}

	while(n > 0) {
		i = chartorune(&r, s);
		if(i == 0){
			s++;
			--n;
			continue;
		}
		memmove(buf, s, i);
		buf[i] = 0;
		n -= i;
		s += i;
		vgascreenputc(buf);
	}
	while(n-- > 0)
		cgascreenputc(*s++);

	qunlock(&screenlock);
	unlock(&cgascreenlock);
}

void (*screenputs)(char*, int) = cgascreenputs;

M pc/dat.h => pc/dat.h +1 -1
@@ 144,7 144,7 @@ struct Mach
	int	machno;			/* physical id of processor */
	ulong	splpc;			/* pc of last caller to splhi */

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


M pc/devether.c => pc/devether.c +15 -9
@@ 230,13 230,15 @@ etherwrite(Chan* chan, void* buf, long n, ulong)
	Ether *ether;
	Block *bp;

	if(n > ETHERMAXTU)
		error(Ebadarg);

	ether = etherxx[chan->dev];
	if(NETTYPE(chan->qid.path) != Ndataqid)
		return netifwrite(ether, chan, buf, n);

	if(n > ETHERMAXTU)
		error(Etoobig);
	if(n < ETHERMINTU)
		error(Etoosmall);

	bp = allocb(n);
	if(waserror()){
		freeb(bp);


@@ 257,11 259,6 @@ etherbwrite(Chan* chan, Block* bp, ulong)
	long n;

	n = BLEN(bp);
	if(n > ETHERMAXTU){
		freeb(bp);
		error(Ebadarg);
	}

	ether = etherxx[chan->dev];
	if(NETTYPE(chan->qid.path) != Ndataqid){
		n = netifwrite(ether, chan, bp->rp, n);


@@ 269,6 266,15 @@ etherbwrite(Chan* chan, Block* bp, ulong)
		return n;
	}

	if(n > ETHERMAXTU){
		freeb(bp);
		error(Ebadarg);
	}
	if(n < ETHERMINTU){
		freeb(bp);
		error(Etoosmall);
	}

	return etheroq(ether, bp);
}



@@ 352,7 358,7 @@ etherreset(void)
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
				ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
			if(ether->mem)
				i += sprint(buf+i, " addr 0x%luX", ether->mem & ~KZERO);
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
			if(ether->size)
				i += sprint(buf+i, " size 0x%luX", ether->size);
			i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX",

M pc/devi82365.c => pc/devi82365.c +1 -0
@@ 357,6 357,7 @@ pcmmap(int slotno, ulong offset, int len, int attr)
			m->len = 0;
		}
		m->isa = umbmalloc(0, len, Mgran)&~KZERO;
print("m->isa = 0x%uX, %d\n", m->isa, len);
		if(m->isa == 0){
			print("pcmmap: out of isa space\n");
			unlock(&pp->mlock);

M pc/devvga.c => pc/devvga.c +162 -1139
@@ 1,129 1,40 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"../port/error.h"

#include	<libg.h>
#include	"screen.h"
#include	"vga.h"

enum
{
	/* default footprint is 64k */
	Footshift=	16,
	Footprint=	1<<Footshift,
}; 
/*
 *  screen memory addresses
 */
#define SCREENMEM	(0xA0000 | KZERO)

static	ulong	screenmem = SCREENMEM;
static	int	footprint = Footprint;
static	int	footshift = Footshift;
static	int	screendisabled;

/* imported */
extern	Subfont defont0;
extern Cursor curs;			/* barf */

/* exported */
Bitmap	gscreen;
Lock palettelock;			/* access to DAC registers */
Cursor curcursor;			/* current cursor */
static Lock vgaxlock;			/* access to index registers */

/* vga screen */
extern	QLock	screenlock;
static	ulong	colormap[Pcolours][3];
static	Lock	myscreenlock;

/* system window */
static	Rectangle window;
static	int	h, w;
static	Point	curpos;

static void nopage(int);

static Vgac vga = {
	"vga",
	nopage,

	0,
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"

#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"

enum {
	Qdir,
	Qvgaiob,
	Qvgaiow,
	Qvgaiol,
	Qvgactl,
};

static Vgac *vgactlr = &vga;			/* available VGA ctlrs */
static Vgac *vgac = &vga;			/* current VGA ctlr */
static Hwgc *hwgctlr;				/* available HWGC's */
Hwgc *hwgc;					/* current HWGC */

static char interlaced[2];

/*
 *  work areas for bitblting screen characters, scrolling, and cursor redraw
 */
Bitmap chwork;
Bitmap scrollwork;
Bitmap cursorwork;

/* predefined for the stupid compiler */
static void	setscreen(int, int, int);
static void	screenputc(char*);
static void	scroll(void);
static void	workinit(Bitmap*, int, int);
extern void	screenload(Rectangle, uchar*, int, int, int);
extern void	screenunload(Rectangle, uchar*, int, int, int);
static void	cursorlock(Rectangle);
static void	cursorunlock(void);
static void	cursorinit(void);

extern void	(*vgascreenputc)(char*);
extern int	graphicssubtile(uchar*, int, int, Rectangle, Rectangle, uchar**);

/*
 *  vga device
 */
enum
{
	Qdir		= 0,
	Qvgaiob		= 1,
	Qvgaiow		= 2,
	Qvgaiol		= 3,
	Qvgactl		= 4,
};
Dirtab vgadir[]={
	"vgaiob",	{ Qvgaiob },	0,	0666,
	"vgaiow",	{ Qvgaiow },	0,	0666,
	"vgaiol",	{ Qvgaiol },	0,	0666,
	"vgactl",	{ Qvgactl },	0,	0666,
static Dirtab vgadir[] = {
	"vgaiob",	{ Qvgaiob, 0 },		0,	0660,
	"vgaiow",	{ Qvgaiow, 0 },		0,	0660,
	"vgaiol",	{ Qvgaiol, 0 },		0,	0660,
	"vgactl",	{ Qvgactl, 0 },		0,	0660,
};

static void
vgareset(void)
{
	cursor.disable++;
	conf.monitor = 1;
}

static void
vgainit(void)
{
	int i;
	ulong *l;

	/*
	 *  swizzle the font longs.
	 */
	l = defont0.bits->base;
	for(i = defont0.bits->width*Dy(defont0.bits->r); i > 0; i--, l++)
		*l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24);
}

static Chan*
vgaattach(char *spec)
vgaattach(char* spec)
{
	if(*spec && strcmp(spec, "0"))
		error(Eio);


@@ 131,19 42,19 @@ vgaattach(char *spec)
}

int
vgawalk(Chan *c, char *name)
vgawalk(Chan* c, char* name)
{
	return devwalk(c, name, vgadir, nelem(vgadir), devgen);
}

static void
vgastat(Chan *c, char *dp)
vgastat(Chan* c, char* dp)
{
	devstat(c, dp, vgadir, nelem(vgadir), devgen);
}

static Chan*
vgaopen(Chan *c, int omode)
vgaopen(Chan* c, int omode)
{
	return devopen(c, omode, vgadir, nelem(vgadir), devgen);
}


@@ 153,223 64,181 @@ vgaclose(Chan*)
{
}

static int
checkvgaport(int port, int len)
{
	if((port == 0x102 || port == 0x46E8) && len == 1)
		return 0;
	if(port >= 0x3B0 && port+len < 0x3E0)
		return 0;
	return -1;
}

static long
vgaread(Chan *c, void *buf, long n, ulong offset)
vgaread(Chan* c, void* a, long n, ulong offset)
{
	int port;
	uchar *cp;
	char cbuf[128];
	int len, port;
	char *p, *s;
	ushort *sp;
	ulong *lp;
	Vgac *vgacp;
	VGAscr *scr;

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

	switch(c->qid.path&~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, vgadir, nelem(vgadir), devgen);
		return devdirread(c, a, n, vgadir, nelem(vgadir), devgen);

	case Qvgactl:
		if(vgascreenputc == nil)
			return readstr(offset, buf, n, "type: cga\n");
		vgacp = vgac;
		port = sprint(cbuf, "type: %s\n", vgacp->name);
		port += sprint(cbuf+port, "size: %dx%dx%d%s\n",
			gscreen.r.max.x, gscreen.r.max.y,
			1<<gscreen.ldepth, interlaced);
		port += sprint(cbuf+port, "hwgc: ");
		if(hwgc)
			port += sprint(cbuf+port, "%s\n", hwgc->name);
		scr = &vgascreen[0];

		p = malloc(READSTR);
		if(waserror()){
			free(p);
			nexterror();
		}
		if(scr->dev)
			s = scr->dev->name;
		else
			s = "cga";
		len = snprint(p, READSTR, "type: %s\n", s);
		if(scr->gscreen)
			len += snprint(p+len, READSTR-len, "size: %dx%dx%d\n",
				scr->gscreen->r.max.x, scr->gscreen->r.max.y,
				1<<scr->gscreen->ldepth);
		if(scr->cur)
			s = scr->cur->name;
		else
			port += sprint(cbuf+port, "off\n");
		sprint(cbuf+port, "addr: 0x%lux\n", screenmem&~KZERO);
		return readstr(offset, buf, n, cbuf);
			s = "off";
		len += snprint(p+len, READSTR-len, "hwgc: %s\n", s);
		snprint(p+len, READSTR-len, "addr: 0x%lux\n", scr->aperture);

		n = readstr(offset, a, n, p);
		poperror();
		free(p);

		return n;

	case Qvgaiob:
		port = offset;
		/*if(checkvgaport(port, n))
			error(Eperm);*/
		for(cp = buf; port < offset+n; port++)
			*cp++ = vgai(port);
		for(p = a; port < offset+n; port++)
			*p++ = inb(port);
		return n;

	case Qvgaiow:
		if((n & 01) || (offset & 01))
		if((n & 0x01) || (offset & 0x01))
			error(Ebadarg);
		n /= 2;
		for (sp = buf, port=offset; port<offset+n; port+=2)
		sp = a;
		for(port = offset; port < offset+n; port += 2)
			*sp++ = ins(port);
		return n*2;

	case Qvgaiol:
		if((n & 03) || (offset & 03))
		if((n & 0x03) || (offset & 0x03))
			error(Ebadarg);
		n /= 4;
		for (lp = buf, port=offset; port<offset+n; port+=4)
		lp = a;
		for(port = offset; port < offset+n; port += 4)
			*lp++ = inl(port);
		return n*4;

	default:
		error(Egreg);
		break;
	}
	error(Eperm);

	return 0;
}

static void
vgactl(char *arg)
vgactl(char* a)
{
	int n;
	ulong x, y, z;
	char *cp, *field[4];
	Hwgc *hwgcp;
	Vgac *vgacp;
	ulong mem, size, align;
	int align, i, n, size, x, y, z;
	char *field[4], *p;
	VGAscr *scr;
	extern VGAdev *vgadev[];
	extern VGAcur *vgacur[];

	n = parsefields(arg, field, 4, " ");
	n = parsefields(a, field, 4, " ");
	if(n < 2)
		error(Ebadarg);

	if(strcmp(field[0], "disable") == 0){
		screendisabled = 1;
	}
	else if(strcmp(field[0], "enable") == 0){
		screendisabled = 0;
	}
	else if(strcmp(field[0], "hwgc") == 0){
	scr = &vgascreen[0];
	if(strcmp(field[0], "hwgc") == 0){
		if(n < 2)
			error(Ebadarg);
		if(strcmp(field[1], "off") == 0){
			if(hwgc){
				hwgc->disable();
				hwgc = 0;
				cursoron(1);
			lock(&cursor);
			if(scr->cur){
				if(scr->cur->disable)
					scr->cur->disable(scr);
				scr->cur = nil;
			}
			unlock(&cursor);
			return;
		}

		for(hwgcp = hwgctlr; hwgcp; hwgcp = hwgcp->link){
			if(strcmp(field[1], hwgcp->name) == 0){
				if(hwgc)
					hwgc->disable();
				else
					cursoroff(1);
				hwgc = hwgcp;
				hwgc->enable();
				setcursor(&curs);
				cursoron(1);
				return;
			}
		for(i = 0; vgacur[i]; i++){
			if(strcmp(field[1], vgacur[i]->name))
				continue;
			lock(&cursor);
			if(scr->cur && scr->cur->disable)
				scr->cur->disable(scr);
			scr->cur = vgacur[i];
			if(scr->cur->enable)
				scr->cur->enable(scr);
			unlock(&cursor);
			return;
		}
	}
	else if(strcmp(field[0], "type") == 0){
		if(n < 2)
			error(Ebadarg);
		for(vgacp = vgactlr; vgacp; vgacp = vgacp->link){
			if(strcmp(field[1], vgacp->name) == 0){
				vgac = vgacp;
				return;
			}

		for(i = 0; vgadev[i]; i++){
			if(strcmp(field[1], vgadev[i]->name))
				continue;
			if(scr->dev && scr->dev->disable)
				scr->dev->disable(scr);
			scr->dev = vgadev[i];
			if(scr->dev->enable)
				scr->dev->enable(scr);
			return;
		}
	}
	else if(strcmp(field[0], "size") == 0){
		if(n < 2)
			error(Ebadarg);
		x = strtoul(field[1], &cp, 0);
		x = strtoul(field[1], &p, 0);
		if(x == 0 || x > 2048)
			error(Ebadarg);
		if(*p)
			p++;

		if(*cp)
			cp++;
		y = strtoul(cp, &cp, 0);
		y = strtoul(p, &p, 0);
		if(y == 0 || y > 2048)
			error(Ebadarg);
		if(*p)
			p++;

		if(*cp)
			cp++;
		switch(strtoul(cp, &cp, 0)){
		switch(strtoul(p, &p, 0)){
		case 8:
			z = 3; break;
		case 1:
			z = 0; break;
			z = 3;
			break;

		default:
			z = 0;
			error(Ebadarg);
		}
		interlaced[0] = *cp;

		cursoroff(1);
		setscreen(x, y, z);
		if(screensize(x, y, z))
			error(Egreg);
		vgascreenwin(scr);
		cursoron(1);
		return;
	}
	else if(strcmp(field[0], "linear") == 0){
		if(n < 2)
			error(Ebadarg);

		size = strtoul(field[1], 0, 0);
		if(n < 3)
			align = 0;
		else
			align = strtoul(field[2], 0, 0);

		/* see if it fits in the usual place */
		if(size <= Footprint){
			if(screenmem != SCREENMEM)
				upafree(screenmem, footprint);
			screenmem = SCREENMEM;
			if(size == 0){
				footprint = Footprint;
				footshift = Footshift;
			} else {
				footprint = size;
				for(n = 0; n < 31; n++)
					if((1<<n) >= footprint)
						break;
				footshift = n;
			}
			gscreen.base = (void*)screenmem;
			return;
		}

		/* grab new space */
		if(align == 0 || (screenmem % (align-1)) == 0){
			if(footprint >= size)
				return;
		} else {
			int s, e;

			s = screenmem & ~KZERO;
			e = s + footprint;
			s = ROUND(s, align);
			if(e >= s + size)
				return;
		}

		mem = 0;
		if(vgac->linear)
			vgac->linear(&mem, &size, &align);
		else
			mem = upamalloc(0, size, align);
		if(mem == 0)
		if(screenaperture(size, align))
			error("not enough free address space");

		/*
		 * Be very careful here, upamalloc now returns a
		 * PHYSICAL address. This won't work once devices
		 * start mapping PCI framebuffers at the address
		 * the BIOS sets, but that hopefully will be after
		 * conversion to the Draw kernel.
		 */
		if(screenmem != SCREENMEM)
			upafree(screenmem, footprint);
		screenmem = (ulong)KADDR(mem);
		gscreen.base = (void*)screenmem;
		footprint = size;
		for(n = 0; n < 31; n++)
			if((1<<n) >= footprint)
				break;
		footshift = n;
		return;
	}



@@ 377,47 246,62 @@ vgactl(char *arg)
}

static long
vgawrite(Chan *c, void *buf, long n, ulong offset)
vgawrite(Chan* c, void* a, long n, ulong offset)
{
	int port;
	uchar *cp;
	char cbuf[64];
	char *p;
	ushort *sp;
	ulong *lp;

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

	case Qdir:
		error(Eperm);

	case Qvgactl:
		if(offset != 0 || n >= sizeof(cbuf))
		if(offset || n >= READSTR)
			error(Ebadarg);
		memmove(cbuf, buf, n);
		cbuf[n] = 0;
		vgactl(cbuf);
		p = malloc(READSTR);
		if(waserror()){
			free(p);
			nexterror();
		}
		memmove(p, a, n);
		p[n] = 0;
		vgactl(p);
		poperror();
		free(p);
		return n;

	case Qvgaiob:
		port = offset;
		/*if(checkvgaport(port, n))
			error(Eperm);*/
		for(cp = buf; port < offset+n; port++)
			vgao(port, *cp++);
		p = a;
		for(port = offset; port < offset+n; port++)
			outb(port, *p++);
		return n;

	case Qvgaiow:
		if((n & 01) || (offset & 01))
			error(Ebadarg);
		n /= 2;
		for (sp = buf, port=offset; port<offset+n; port+=2)
		sp = a;
		for(port = offset; port < offset+n; port += 2)
			outs(port, *sp++);
		return n*2;

	case Qvgaiol:
		if((n & 03) || (offset & 03))
		if((n & 0x03) || (offset & 0x03))
			error(Ebadarg);
		n /= 4;
		for (lp = buf, port=offset; port<offset+n; port+=4)
		lp = a;
		for(port = offset; port < offset+n; port += 4)
			outl(port, *lp++);
		return n*4;

	default:
		error(Egreg);
		break;
	}
	error(Eperm);

	return 0;
}



@@ 426,7 310,7 @@ Dev vgadevtab = {
	"vga",

	vgareset,
	vgainit,
	devinit,
	vgaattach,
	devclone,
	vgawalk,


@@ 441,864 325,3 @@ Dev vgadevtab = {
	devremove,
	devwstat,
};

int
vgaxi(long port, uchar index)
{
	uchar data;

	ilock(&vgaxlock);
	switch(port){

	case Seqx:
	case Crtx:
	case Grx:
		outb(port, index);
		data = inb(port+1);
		break;

	case Attrx:
		/*
		 * Allow processor access to the colour
		 * palette registers. Writes to Attrx must
		 * be preceded by a read from Status1 to
		 * initialise the register to point to the
		 * index register and not the data register.
		 * Processor access is allowed by turning
		 * off bit 0x20.
		 */
		inb(Status1);
		if(index < 0x10){
			outb(Attrx, index);
			data = inb(Attrx+1);
			inb(Status1);
			outb(Attrx, 0x20|index);
		}
		else{
			outb(Attrx, 0x20|index);
			data = inb(Attrx+1);
		}
		break;

	default:
		iunlock(&vgaxlock);
		return -1;
	}
	iunlock(&vgaxlock);

	return data & 0xFF;
}

int
vgaxo(long port, uchar index, uchar data)
{
	ilock(&vgaxlock);
	switch(port){

	case Seqx:
	case Crtx:
	case Grx:
		/*
		 * We could use an outport here, but some chips
		 * (e.g. 86C928) have trouble with that for some
		 * registers.
		 */
		outb(port, index);
		outb(port+1, data);
		break;

	case Attrx:
		inb(Status1);
		if(index < 0x10){
			outb(Attrx, index);
			outb(Attrx, data);
			inb(Status1);
			outb(Attrx, 0x20|index);
		}
		else{
			outb(Attrx, 0x20|index);
			outb(Attrx, data);
		}
		break;

	default:
		iunlock(&vgaxlock);
		return -1;
	}
	iunlock(&vgaxlock);

	return 0;
}

static ulong
xnto32(uchar x, int n)
{
	int s;
	ulong y;

	x &= (1<<n)-1;
	y = 0;
	for(s = 32 - n; s > 0; s -= n)
		y |= x<<s;
	if(s < 0)
		y |= x>>(-s);
	return y;
}

/*
 *  reconfigure screen shape
 */
static void
setscreen(int maxx, int maxy, int ldepth)
{
	int i, x, l, tl;
	uchar *a;
	Rectangle r;

	if(waserror()){
		qunlock(&screenlock);
		nexterror();
	}

	qlock(&screenlock);

	/* setup a bitmap for the new size */
	gscreen.ldepth = ldepth;
	gscreen.width = (maxx*(1<<gscreen.ldepth)+31)/32;
	gscreen.base = (void*)screenmem;
	gscreen.r.min = Pt(0, 0);
	gscreen.r.max = Pt(maxx, maxy);
	gscreen.clipr = gscreen.r;
	for(i = 0; i < gscreen.width*BY2WD*maxy; i += footprint){
		vgac->page(i>>footshift);
		memset(gscreen.base, 0xff, footprint);
	}

	/* get size for a system window */
	h = defont0.height;
	w = defont0.info[' '].width;
	window.min = Pt(48, 48);
	window.max = add(window.min, Pt(10+w*80, 50*h));
	if(window.max.y >= gscreen.r.max.y)
		window.max.y = gscreen.r.max.y-1;
	if(window.max.x >= gscreen.r.max.x)
		window.max.x = gscreen.r.max.x-1;
	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
	curpos = window.min;

	/* work areas change when dimensions change */
	workinit(&chwork, w, h);
	workinit(&scrollwork, 80*w, 1);
	workinit(&scrollwork, Dx(window), 1);
	cursorinit();

	/* clear the system window */
	l = scrollwork.width * BY2WD;
	memset(scrollwork.base, 0, l);
	tl = graphicssubtile(0, l, gscreen.ldepth, gscreen.r, window, &a);
	for(i = window.min.y; i < window.max.y; i++){
		r = Rect(window.min.x, i, window.max.x, i + 1);
		screenload(r, (uchar*)scrollwork.base, tl, l, 1);
	}

	/* switch software to graphics mode */
	if(vgascreenputc == nil)
		vgascreenputc = screenputc;

	qunlock(&screenlock);
	poperror();

	/* default color map (has to be outside the lock) */
	switch(ldepth){
	case 3:
		graphicscmap(0);
		break;
	case 2:
	case 1:
	case 0:
		for(i = 0; i < 16; i++){
			x = xnto32((i*63)/15, 6);
			setcolor(i, x, x, x);
		}
		break;
	}
}

/*
 *  init a bitblt work area
 */
static void
workinit(Bitmap *bm, int maxx, int maxy)
{
	bm->ldepth = gscreen.ldepth;
	bm->r = Rect(0, 0, maxx, maxy);
	if(gscreen.ldepth != 3)
		bm->r.max.x += 1<<(3-gscreen.ldepth);
	bm->clipr = bm->r;
	bm->width = ((bm->r.max.x << gscreen.ldepth) + 31) >> 5;
	if(bm->base == 0)
		bm->base = xalloc(maxx*maxy);
}

/*
 *  Load a byte into screen memory.  Assume that if the page
 *  is wrong we just need to increment it.
 */
static int
byteload(uchar *q, uchar *data, int m, int *page, uchar *e)
{
	int pg;
	int diff;

	diff = 0;
	if(q >= e){
		pg = ++*page;
		vgac->page(pg);
		q -= footprint;
		diff -= footprint;
	}
	*q ^= (*data^*q) & m;
	return diff;
}

/*
 *  Load adjacent bytes into a screen memory.  Assume that if the page
 *  is wrong we just need to increment it.
 */
static int
lineload(uchar *q, uchar *data, int len, int *page, uchar *e)
{
	int rem, pg;
	int diff;

	diff = 0;
	if(q >= e){
		pg = ++*page;
		vgac->page(pg);
		q -= footprint;
		diff -= footprint;
	}

	rem = e - q;

	if(rem < len){
		memmove(q, data, rem);
		pg = ++*page;
		vgac->page(pg);
		q -= footprint;
		diff -= footprint;
		memmove(q+rem, data+rem, len-rem);
	} else
		memmove(q, data, len);

	return diff;
}

/*
 *   paste tile into hard screen.
 *   tile is at location r, first pixel in *data.  tl is length of scan line to insert,
 *   l is amount to advance data after each scan line.
 */
void
screenload(Rectangle r, uchar *data, int tl, int l, int dolock)
{
	int y, lpart, rpart, mx, m, mr, page, sw;
	ulong off;
	uchar *q, *e;

	if(screendisabled || vgascreenputc == nil || !rectclip(&r, gscreen.r) || tl<=0)
		return;

	if(dolock && hwgc == 0)
		cursorlock(r);

	lock(&myscreenlock);
	q = byteaddr(&gscreen, r.min);
	mx = 7>>gscreen.ldepth;
	lpart = (r.min.x & mx) << gscreen.ldepth;
	rpart = (r.max.x & mx) << gscreen.ldepth;
	m = 0xFF >> lpart;
	mr = 0xFF ^ (0xFF >> rpart);

	off = q - (uchar*)gscreen.base;
	page = off>>footshift;
	vgac->page(page);
	q = ((uchar*)gscreen.base) + (off&(footprint-1));

	sw = gscreen.width*sizeof(ulong);
	e = ((uchar*)gscreen.base) + footprint;

	/* may need to do bit insertion on edges */
	if(tl <= 0){
		;
	}else if(tl == 1){	/* all in one byte */
		if(rpart)
			m &= mr;
		for(y=r.min.y; y<r.max.y; y++){
			if(q < e)
				*q ^= (*data^*q) & m;
			else
				q += byteload(q, data, m, &page, e);
			q += sw;
			data += l;
		}
	}else if(lpart==0 && rpart==0){	/* easy case */
		for(y=r.min.y; y<r.max.y; y++){
			if(q + tl <= e)
				memmove(q, data, tl);
			else
				q += lineload(q, data, tl, &page, e);
			q += sw;
			data += l;
		}
	}else if(rpart==0){
		for(y=r.min.y; y<r.max.y; y++){
			if(q + tl <= e){
				*q ^= (*data^*q) & m;
				memmove(q+1, data+1, tl-1);
			} else {
				q += byteload(q, data, m, &page, e);
				q += lineload(q+1, data+1, tl-1, &page, e);
			}
			q += sw;
			data += l;
		}
	}else if(lpart == 0){
		for(y=r.min.y; y<r.max.y; y++){
			if(q + tl <= e){
				memmove(q, data, tl-1);
				q[tl-1] ^= (data[tl-1]^q[tl-1]) & mr;
			} else {	/* new page */
				q += lineload(q, data, tl-1, &page, e);
				q += byteload(q+tl-1, data+tl-1, mr, &page, e);
			}
			q += sw;
			data += l;
		}
	}else for(y=r.min.y; y<r.max.y; y++){
		if(q + tl <= e){
			*q ^= (*data^*q) & m;
			if(tl > 2)
				memmove(q+1, data+1, tl-2);
			q[tl-1] ^= (data[tl-1]^q[tl-1]) & mr;
		} else {	/* new page */
			q += byteload(q, data, m, &page, e);
			if(tl > 2)
				q += lineload(q+1, data+1, tl-2, &page, e);
			q += byteload(q+tl-1, data+tl-1, mr, &page, e);
		}
		q += sw;
		data += l;
	}

	unlock(&myscreenlock);
	if(dolock && hwgc == 0)
		cursorunlock();
}

/*
 *  Get a byte from screen memory.  Assume that if the page
 *  is wrong we just need to increment it.
 */
static int
byteunload(uchar *q, uchar *data, int m, int *page, uchar *e)
{
	int pg;
	int diff;

	diff = 0;
	if(q >= e){
		pg = ++*page;
		vgac->page(pg);
		q -= footprint;
		diff -= footprint;
	}
	*data ^= (*q^*data) & m;
	return diff;
}

/*
 *  Get a vector of bytes from screen memory.  Assume that if the page
 *  is wrong we just need to increment it.
 */
static int
lineunload(uchar *q, uchar *data, int len, int *page, uchar *e)
{
	int rem, pg;
	int diff;

	diff = 0;
	if(q >= e){
		pg = ++*page;
		vgac->page(pg);
		q -= footprint;
		diff -= footprint;
	}

	rem = e - q;

	if(rem < len){
		memmove(data, q, rem);
		pg = ++*page;
		vgac->page(pg);
		q -= footprint;
		diff -= footprint;
		memmove(data+rem, q+rem, len-rem);
	} else
		memmove(data, q, len);

	return diff;
}

/*
 * get a tile from screen memory.
 * tile is at location r, first pixel in *data. 
 * tl is length of scan line to insert,
 * l is amount to advance data after each scan line.
 */
void
screenunload(Rectangle r, uchar *data, int tl, int l, int dolock)
{
	int y, lpart, rpart, mx, m, mr, page, sw;
	ulong off;
	uchar *q, *e;

	if(screendisabled || vgascreenputc == nil || !rectclip(&r, gscreen.r) || tl<=0)
		return;

	if(dolock && hwgc == 0)
		cursorlock(r);

	lock(&myscreenlock);
	q = byteaddr(&gscreen, r.min);
	mx = 7>>gscreen.ldepth;
	lpart = (r.min.x & mx) << gscreen.ldepth;
	rpart = (r.max.x & mx) << gscreen.ldepth;
	m = 0xFF >> lpart;
	mr = 0xFF ^ (0xFF >> rpart);

	off = q - (uchar*)gscreen.base;
	page = off>>footshift;
	vgac->page(page);
	q = ((uchar*)gscreen.base) + (off&(footprint-1));

	sw = gscreen.width*sizeof(ulong);
	e = ((uchar*)gscreen.base) + footprint;

	/* may need to do bit insertion on edges */
	if(tl <= 0){
		;
	}else if(tl == 1){	/* all in one byte */
		if(rpart)
			m &= mr;
		for(y=r.min.y; y<r.max.y; y++){
			if(q < e)
				*data ^= (*q^*data) & m;
			else
				q += byteunload(q, data, m, &page, e);
			q += sw;
			data += l;
		}
	}else if(lpart==0 && rpart==0){	/* easy case */
		for(y=r.min.y; y<r.max.y; y++){
			if(q + tl <= e)
				memmove(data, q, tl);
			else
				q += lineunload(q, data, tl, &page, e);
			q += sw;
			data += l;
		}
	}else if(rpart==0){
		for(y=r.min.y; y<r.max.y; y++){
			if(q + tl <= e){
				*data ^= (*q^*data) & m;
				memmove(data+1, q+1, tl-1);
			} else {
				q += byteunload(q, data, m, &page, e);
				q += lineunload(q+1, data+1, tl-1, &page, e);
			}
			q += sw;
			data += l;
		}
	}else if(lpart == 0){
		for(y=r.min.y; y<r.max.y; y++){
			if(q + tl <= e){
				memmove(data, q, tl-1);
				data[tl-1] ^= (q[tl-1]^data[tl-1]) & mr;
			} else {	/* new page */
				q += lineunload(q, data, tl-1, &page, e);
				q += byteunload(q+tl-1, data+tl-1, mr, &page, e);
			}
			q += sw;
			data += l;
		}
	}else for(y=r.min.y; y<r.max.y; y++){
		if(q + tl <= e){
			*data ^= (*q^*data) & m;
			if(tl > 2)
				memmove(data+1, q+1, tl-2);
			data[tl-1] ^= (q[tl-1]^data[tl-1]) & mr;
		} else {	/* new page */
			q += byteunload(q, data, m, &page, e);
			if(tl > 2)
				q += lineunload(q+1, data+1, tl-2, &page, e);
			q += byteunload(q+tl-1, data+tl-1, mr, &page, e);
		}
		q += sw;
		data += l;
	}

	unlock(&myscreenlock);
	if(dolock && hwgc == 0)
		cursorunlock();
}

static void
nopage(int)
{
}

/*
 *  graphics mode console
 */
#define LINE2SCROLL 4
static void
scroll(void)
{
	int from, tl, l, diff;
	uchar *a;
	Rectangle r;

	diff = h*LINE2SCROLL;
	l = scrollwork.width * BY2WD;
	tl = graphicssubtile(0, l, gscreen.ldepth, gscreen.r, window, &a);

	/* move lines up */
	for(from = window.min.y + diff; from < window.max.y; from++){
		r = Rect(window.min.x, from, window.max.x, from + 1);
		screenunload(r, (uchar*)scrollwork.base, tl, l, 1);
		r = Rect(window.min.x, from - diff, window.max.x, from - diff + 1);
		screenload(r, (uchar*)scrollwork.base, tl, l, 1);
	}

	/* clear bottom */
	memset(scrollwork.base, 0, l);
	for(from = window.max.y - diff; from < window.max.y; from++){
		r = Rect(window.min.x, from, window.max.x, from + 1);
		screenload(r, (uchar*)scrollwork.base, tl, l, 1);
	}
	
	curpos.y -= diff;
}

static void
screenputc(char *buf)
{
	int pos, l, tl, off;
	uchar *a;
	Rectangle r;

	switch(buf[0]) {
	case '\n':
		if(curpos.y+h >= window.max.y)
			scroll();
		curpos.y += h;
		screenputc("\r");
		break;
	case '\r':
		curpos.x = window.min.x;
		break;
	case '\t':
		pos = (curpos.x-window.min.x)/w;
		pos = 8-(pos%8);
		curpos.x += pos*w;
		break;
	case '\b':
		if(curpos.x-w >= window.min.x){
			curpos.x -= w;
			screenputc(" ");
			curpos.x -= w;
		}
		break;
	default:
		if(curpos.x >= window.max.x-w)
			screenputc("\n");

		/* tile width */
		r.min = curpos;
		r.max = add(r.min, Pt(w, h));
		off = ((1<<gscreen.ldepth)*r.min.x) & 7;
		l = chwork.width*BY2WD;
		tl = graphicssubtile(0, l, gscreen.ldepth, gscreen.r, r, &a);

		/* add char into work area */
		subfstring(&chwork, Pt(off, 0), &defont0, buf, S);

		/* move work area to screen */
		screenload(r, (uchar*)chwork.base, tl, l, 1);

		curpos.x += w;
	}
}

int
screenbits(void)
{
	return 1<<gscreen.ldepth;	/* bits per pixel */
}

void
getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
{
	ulong x;

	switch(gscreen.ldepth){
	default:
		x = 0xF;
		break;
	case 3:
		x = 0xFF;
		break;
	}
	p &= x;
	p ^= x;
	lock(&palettelock);
	*pr = colormap[p][Pred];
	*pg = colormap[p][Pgreen];
	*pb = colormap[p][Pblue];
	unlock(&palettelock);
}

int
setcolor(ulong p, ulong r, ulong g, ulong b)
{
	ulong x;

	switch(gscreen.ldepth){
	default:
		x = 0xF;
		break;
	case 3:
		x = 0xFF;
		break;
	}
	p &= x;
	p ^= x;
	lock(&palettelock);
	colormap[p][Pred] = r;
	colormap[p][Pgreen] = g;
	colormap[p][Pblue] = b;
	vgao(PaddrW, p);
	vgao(Pdata, r>>(32-6));
	vgao(Pdata, g>>(32-6));
	vgao(Pdata, b>>(32-6));
	unlock(&palettelock);
	return ~0;
}

/*
 *  software cursor
 *  and hacks for hardware cursor
 */

/*
 *  area to store the bits that are behind the cursor
 */
static ulong backbits[16*4];
static ulong clrbits[16];
static ulong setbits[16];

/*
 *  the white border around the cursor
 */
Bitmap	clr =
{
	{0, 0, 16, 16},
	{0, 0, 16, 16},
	0,
	clrbits,
	0,
	1,
};

/*
 *  the black center of the cursor
 */
Bitmap	set =
{
	{0, 0, 16, 16},
	{0, 0, 16, 16},
	0,
	setbits,
	0,
	1,
};

static void
cursorinit(void)
{
	static int already;

	lock(&cursor);

	workinit(&cursorwork, 16, 16);
	cursor.l = cursorwork.width*BY2WD;

	if(!already){
		cursor.disable--;
		already = 1;
	}

	unlock(&cursor);
}

void
setcursor(Cursor *curs)
{
	uchar *p;
	int i;

	if(hwgc)
		hwgc->load(curs);
	else for(i=0; i<16; i++){
		p = (uchar*)&set.base[i];
		*p = curs->set[2*i];
		*(p+1) = curs->set[2*i+1];
		p = (uchar*)&clr.base[i];
		*p = curs->clr[2*i];
		*(p+1) = curs->clr[2*i+1];
	}
}

int
cursoron(int dolock)
{
	int xoff, yoff, s, ret;
	Rectangle r;
	uchar *a;
	struct {
		Bitmap *dm;
		Point p;
		Bitmap *sm;
		Rectangle r;
		Fcode f;
	} xx;

	if(cursor.disable)
		return 0;
	if(dolock){
		s = 0;		/* to avoid compiler warning */
		lock(&cursor);
	} /*else
		s = spllo();	/* to avoid freezing out the eia ports */

	ret = 0;
	if(hwgc)
		ret = hwgc->move(mousexy());
	else if(cursor.visible++ == 0){
		cursor.r.min = mousexy();
		cursor.r.max = add(cursor.r.min, Pt(16, 16));
		cursor.r = raddp(cursor.r, cursor.offset);
	
		/* offsets into backup area and clr/set bitmaps */
		r.min = Pt(0, 0);
		if(cursor.r.min.x < 0){
			xoff = cursor.r.min.x;
			r.min.x = -xoff;
		} else
			xoff = ((1<<gscreen.ldepth)*cursor.r.min.x) & 7;
		if(cursor.r.min.y < 0){
			yoff = cursor.r.min.y;
			r.min.y = -yoff;
		} else
			yoff = 0;
		r.max = add(r.min, Pt(16, 16));
	
		/* clip the cursor rectangle */
		xx.dm = &cursorwork;
		xx.p = Pt(xoff, yoff);
		xx.sm = &gscreen;
		xx.r = cursor.r;
		bitbltclip(&xx);
	
		/* tile width */
		cursor.tl = graphicssubtile(0, cursor.l, gscreen.ldepth,
				gscreen.r, xx.r, &a);
		if(cursor.tl > 0){
			/* get tile */
			screenunload(xx.r, (uchar*)cursorwork.base, cursor.tl, cursor.l, 0);
	
			/* save for cursoroff */
			memmove(backbits, cursorwork.base, cursor.l*16);
	
			/* add mouse into work area */
			bitblt(&cursorwork, xx.p, &clr, r, D&~S);
			bitblt(&cursorwork, xx.p, &set, r, S|D);
	
			/* put back tile */
			cursor.clipr = xx.r;
			screenload(xx.r, (uchar*)cursorwork.base, cursor.tl, cursor.l, 0);
		}
	}

	if(dolock)
		unlock(&cursor);
	/*else
		splx(s);*/

	return ret;
}

void
cursoroff(int dolock)
{
	if(hwgc)
		return;
	if(cursor.disable)
		return;
	if(dolock)
		lock(&cursor);

	if(--cursor.visible == 0 && cursor.tl > 0)
		screenload(cursor.clipr, (uchar*)backbits, cursor.tl, cursor.l, 0);

	if(dolock)
		unlock(&cursor);
}

static void
cursorlock(Rectangle r)
{
	lock(&cursor);
	if(rectXrect(cursor.r, r)){
		cursoroff(0);
		cursor.frozen = 1;
	}
	cursor.disable++;
	unlock(&cursor);
}

static void
cursorunlock(void)
{
	lock(&cursor);
	cursor.disable--;
	if(cursor.frozen)
		cursoron(0);
	cursor.frozen = 0;
	unlock(&cursor);
}

void
addhwgclink(Hwgc *hwgcp)
{
	hwgcp->link = hwgctlr;
	hwgctlr = hwgcp;
}

void
addvgaclink(Vgac *vgacp)
{
	vgacp->link = vgactlr;
	vgactlr = vgacp;
}

M pc/ether8003.c => pc/ether8003.c +2 -2
@@ 122,7 122,7 @@ reset8003(Ether* ether, uchar ea[Eaddrlen], uchar ic[8])
			ctlr->width = 1;
	}

	ether->mem = KZERO|((ic[Msr] & 0x3F)<<13);
	ether->mem = (ulong)KADDR((ic[Msr] & 0x3F)<<13);
	if(ctlr->width == 2)
		ether->mem |= (ic[Laar] & 0x1F)<<19;
	else


@@ 163,7 163,7 @@ reset8216(Ether* ether, uchar[8])
	irq = inb(port+0x0D);
	outb(port+Hcr, hcr);

	ether->mem = KZERO|(0xC0000+((((addr>>2) & 0x30)|(addr & 0x0F))<<13));
	ether->mem = (ulong)KADDR(0xC0000+((((addr>>2) & 0x30)|(addr & 0x0F))<<13));
	ether->size = 8192*(1<<((addr>>4) & 0x03));
	ether->irq = irq8216[((irq>>4) & 0x04)|((irq>>2) & 0x03)];


M pc/fns.h => pc/fns.h +2 -2
@@ 60,7 60,7 @@ void	mmuinit(void);
ulong	mmukmap(ulong, ulong, int);
int	mmukmapsync(ulong);
#define	mmunewpage(x)
ulong*	mmuwalk(ulong*, ulong, int);
ulong*	mmuwalk(ulong*, ulong, int, int);
void	ns16552install(void);
void	ns16552special(int, int, Queue**, Queue**, int (*)(Queue*, int));
uchar	nvramread(int);


@@ 94,7 94,7 @@ void	putcr4(ulong);
void	rdmsr(int, ulong*, ulong*);
void	screeninit(void);
int	screenprint(char*, ...);			/* debugging */
void	screenputs(char*, int);
void	(*screenputs)(char*, int);
void	touser(void*);
void	trapinit(void);
int	tas(void*);

M pc/kbd.c => pc/kbd.c +1 -1
@@ 149,7 149,7 @@ inready(void)
void
i8042reset(void)
{
	ushort *s = (ushort*)(KZERO|0x472);
	ushort *s = KADDR(0x472);
	int i, x;

	*s = 0x1234;		/* BIOS warm-boot flag */

M pc/l.s => pc/l.s +269 -274
@@ 66,13 66,7 @@ _setpte:
	ADDL	$4, AX
	LOOP	_setpte

	MOVL	$CPU0PDB, AX
	ADDL	$PDO(MACHADDR), AX		/* page directory offset for MACHADDR */
	MOVL	$PADDR(CPU0MACHPTE), (AX)	/* PTE's for 4MB containing MACHADDR */
	MOVL	$(PTEWRITE|PTEVALID), BX	/* page permissions */
	ORL	BX, (AX)

	MOVL	$CPU0MACHPTE, AX
	MOVL	$CPU0PTE, AX
	ADDL	$PTO(MACHADDR), AX		/* page table entry offset for MACHADDR */
	MOVL	$PADDR(CPU0MACH), (AX)		/* PTE for Mach */
	MOVL	$(PTEWRITE|PTEVALID), BX	/* page permissions */


@@ 436,22 430,23 @@ TEXT splhi(SB), $0
	CLI
	RET

TEXT spllo(SB), $0
	PUSHFL
	POPL	AX
	STI
	RET

TEXT splx(SB), $0
	MOVL	$(MACHADDR+0x04), AX 		/* save PC in m->splpc */
	MOVL	(SP), BX
	MOVL	BX, (AX)

TEXT _splx(SB), $0				/* for iunlock */
	MOVL	s+0(FP), AX
	PUSHL	AX
	POPFL
	RET

TEXT spllo(SB), $0
	PUSHFL
	POPL	AX
	STI
	RET

TEXT spldone(SB), $0
	RET



@@ 509,21 504,21 @@ TEXT setlabel(SB), $0

/*
 * Interrupt/exception handling.
 * Each entry in the vector table calls either strayintr or strayintrx depending
 * Each entry in the vector table calls either _strayintr or _strayintrx depending
 * on whether an error code has beemn automatically pushed onto the stack
 * (strayintrx) or not, in which case a dummy entry must be pushed before retrieving
 * (_strayintrx) or not, in which case a dummy entry must be pushed before retrieving
 * the trap type from the vector table entry and placing it on the stack as part
 * of the Ureg structure.
 * The size of each entry in the vector table (6 bytes) is known in trapinit().
 */
TEXT strayintr(SB), $0
TEXT _strayintr(SB), $0
	PUSHL	AX				/* save AX */
	MOVL	4(SP), AX			/* return PC from vectortable(SB) */
	MOVBLZX	(AX), AX			/* trap type */
	XCHGL	AX, (SP)			/* restore AX and put the type on the stack */
	JMP	intrcommon

TEXT strayintrx(SB), $0
TEXT _strayintrx(SB), $0
	XCHGL	AX, (SP)			/* exchange AX with pointer to trap type */
	MOVBLZX	(AX), AX			/* trap type -> AX */
	XCHGL	AX, (SP)			/* exchange trap type with AX */


@@ 534,7 529,7 @@ intrcommon:
	PUSHL	FS
	PUSHL	GS
	PUSHAL
	MOVL	$(KDSEL),AX
	MOVL	$(KDSEL), AX
	MOVW	AX, DS
	MOVW	AX, ES
	PUSHL	SP


@@ 551,259 546,259 @@ TEXT forkret(SB), $0
	IRETL

TEXT vectortable(SB), $0
	CALL strayintr(SB); BYTE $0x00		/* divide error */
	CALL strayintr(SB); BYTE $0x01		/* debug exception */
	CALL strayintr(SB); BYTE $0x02		/* NMI interrupt */
	CALL strayintr(SB); BYTE $0x03		/* breakpoint */
	CALL strayintr(SB); BYTE $0x04		/* overflow */
	CALL strayintr(SB); BYTE $0x05		/* bound */
	CALL strayintr(SB); BYTE $0x06		/* invalid opcode */
	CALL strayintr(SB); BYTE $0x07		/* no coprocessor available */
	CALL strayintrx(SB); BYTE $0x08		/* double fault */
	CALL strayintr(SB); BYTE $0x09		/* coprocessor segment overflow */
	CALL strayintrx(SB); BYTE $0x0A		/* invalid TSS */
	CALL strayintrx(SB); BYTE $0x0B		/* segment not available */
	CALL strayintrx(SB); BYTE $0x0C		/* stack exception */
	CALL strayintrx(SB); BYTE $0x0D		/* general protection error */
	CALL strayintrx(SB); BYTE $0x0E		/* page fault */
	CALL strayintr(SB); BYTE $0x0F		/*  */
	CALL strayintr(SB); BYTE $0x10		/* coprocessor error */
	CALL strayintrx(SB); BYTE $0x11		/* alignment check */
	CALL strayintr(SB); BYTE $0x12		/* machine check */
	CALL strayintr(SB); BYTE $0x13
	CALL strayintr(SB); BYTE $0x14
	CALL strayintr(SB); BYTE $0x15
	CALL strayintr(SB); BYTE $0x16
	CALL strayintr(SB); BYTE $0x17
	CALL strayintr(SB); BYTE $0x18
	CALL strayintr(SB); BYTE $0x19
	CALL strayintr(SB); BYTE $0x1A
	CALL strayintr(SB); BYTE $0x1B
	CALL strayintr(SB); BYTE $0x1C
	CALL strayintr(SB); BYTE $0x1D
	CALL strayintr(SB); BYTE $0x1E
	CALL strayintr(SB); BYTE $0x1F
	CALL strayintr(SB); BYTE $0x20		/* VectorLAPIC */
	CALL strayintr(SB); BYTE $0x21
	CALL strayintr(SB); BYTE $0x22
	CALL strayintr(SB); BYTE $0x23
	CALL strayintr(SB); BYTE $0x24
	CALL strayintr(SB); BYTE $0x25
	CALL strayintr(SB); BYTE $0x26
	CALL strayintr(SB); BYTE $0x27
	CALL strayintr(SB); BYTE $0x28
	CALL strayintr(SB); BYTE $0x29
	CALL strayintr(SB); BYTE $0x2A
	CALL strayintr(SB); BYTE $0x2B
	CALL strayintr(SB); BYTE $0x2C
	CALL strayintr(SB); BYTE $0x2D
	CALL strayintr(SB); BYTE $0x2E
	CALL strayintr(SB); BYTE $0x2F
	CALL strayintr(SB); BYTE $0x30
	CALL strayintr(SB); BYTE $0x31
	CALL strayintr(SB); BYTE $0x32
	CALL strayintr(SB); BYTE $0x33
	CALL strayintr(SB); BYTE $0x34
	CALL strayintr(SB); BYTE $0x35
	CALL strayintr(SB); BYTE $0x36
	CALL strayintr(SB); BYTE $0x37
	CALL strayintr(SB); BYTE $0x38
	CALL strayintr(SB); BYTE $0x39
	CALL strayintr(SB); BYTE $0x3A
	CALL strayintr(SB); BYTE $0x3B
	CALL strayintr(SB); BYTE $0x3C
	CALL strayintr(SB); BYTE $0x3D
	CALL strayintr(SB); BYTE $0x3E
	CALL strayintr(SB); BYTE $0x3F
	CALL strayintr(SB); BYTE $0x40		/* VectorSYSCALL */
	CALL strayintr(SB); BYTE $0x41
	CALL strayintr(SB); BYTE $0x42
	CALL strayintr(SB); BYTE $0x43
	CALL strayintr(SB); BYTE $0x44
	CALL strayintr(SB); BYTE $0x45
	CALL strayintr(SB); BYTE $0x46
	CALL strayintr(SB); BYTE $0x47
	CALL strayintr(SB); BYTE $0x48
	CALL strayintr(SB); BYTE $0x49
	CALL strayintr(SB); BYTE $0x4A
	CALL strayintr(SB); BYTE $0x4B
	CALL strayintr(SB); BYTE $0x4C
	CALL strayintr(SB); BYTE $0x4D
	CALL strayintr(SB); BYTE $0x4E
	CALL strayintr(SB); BYTE $0x4F
	CALL strayintr(SB); BYTE $0x50
	CALL strayintr(SB); BYTE $0x51
	CALL strayintr(SB); BYTE $0x52
	CALL strayintr(SB); BYTE $0x53
	CALL strayintr(SB); BYTE $0x54
	CALL strayintr(SB); BYTE $0x55
	CALL strayintr(SB); BYTE $0x56
	CALL strayintr(SB); BYTE $0x57
	CALL strayintr(SB); BYTE $0x58
	CALL strayintr(SB); BYTE $0x59
	CALL strayintr(SB); BYTE $0x5A
	CALL strayintr(SB); BYTE $0x5B
	CALL strayintr(SB); BYTE $0x5C
	CALL strayintr(SB); BYTE $0x5D
	CALL strayintr(SB); BYTE $0x5E
	CALL strayintr(SB); BYTE $0x5F
	CALL strayintr(SB); BYTE $0x60
	CALL strayintr(SB); BYTE $0x61
	CALL strayintr(SB); BYTE $0x62
	CALL strayintr(SB); BYTE $0x63
	CALL strayintr(SB); BYTE $0x64
	CALL strayintr(SB); BYTE $0x65
	CALL strayintr(SB); BYTE $0x66
	CALL strayintr(SB); BYTE $0x67
	CALL strayintr(SB); BYTE $0x68
	CALL strayintr(SB); BYTE $0x69
	CALL strayintr(SB); BYTE $0x6A
	CALL strayintr(SB); BYTE $0x6B
	CALL strayintr(SB); BYTE $0x6C
	CALL strayintr(SB); BYTE $0x6D
	CALL strayintr(SB); BYTE $0x6E
	CALL strayintr(SB); BYTE $0x6F
	CALL strayintr(SB); BYTE $0x70
	CALL strayintr(SB); BYTE $0x71
	CALL strayintr(SB); BYTE $0x72
	CALL strayintr(SB); BYTE $0x73
	CALL strayintr(SB); BYTE $0x74
	CALL strayintr(SB); BYTE $0x75
	CALL strayintr(SB); BYTE $0x76
	CALL strayintr(SB); BYTE $0x77
	CALL strayintr(SB); BYTE $0x78
	CALL strayintr(SB); BYTE $0x79
	CALL strayintr(SB); BYTE $0x7A
	CALL strayintr(SB); BYTE $0x7B
	CALL strayintr(SB); BYTE $0x7C
	CALL strayintr(SB); BYTE $0x7D
	CALL strayintr(SB); BYTE $0x7E
	CALL strayintr(SB); BYTE $0x7F
	CALL strayintr(SB); BYTE $0x80		/* Vector[A]PIC */
	CALL strayintr(SB); BYTE $0x81
	CALL strayintr(SB); BYTE $0x82
	CALL strayintr(SB); BYTE $0x83
	CALL strayintr(SB); BYTE $0x84
	CALL strayintr(SB); BYTE $0x85
	CALL strayintr(SB); BYTE $0x86
	CALL strayintr(SB); BYTE $0x87
	CALL strayintr(SB); BYTE $0x88
	CALL strayintr(SB); BYTE $0x89
	CALL strayintr(SB); BYTE $0x8A
	CALL strayintr(SB); BYTE $0x8B
	CALL strayintr(SB); BYTE $0x8C
	CALL strayintr(SB); BYTE $0x8D
	CALL strayintr(SB); BYTE $0x8E
	CALL strayintr(SB); BYTE $0x8F
	CALL strayintr(SB); BYTE $0x90
	CALL strayintr(SB); BYTE $0x91
	CALL strayintr(SB); BYTE $0x92
	CALL strayintr(SB); BYTE $0x93
	CALL strayintr(SB); BYTE $0x94
	CALL strayintr(SB); BYTE $0x95
	CALL strayintr(SB); BYTE $0x96
	CALL strayintr(SB); BYTE $0x97
	CALL strayintr(SB); BYTE $0x98
	CALL strayintr(SB); BYTE $0x99
	CALL strayintr(SB); BYTE $0x9A
	CALL strayintr(SB); BYTE $0x9B
	CALL strayintr(SB); BYTE $0x9C
	CALL strayintr(SB); BYTE $0x9D
	CALL strayintr(SB); BYTE $0x9E
	CALL strayintr(SB); BYTE $0x9F
	CALL strayintr(SB); BYTE $0xA0
	CALL strayintr(SB); BYTE $0xA1
	CALL strayintr(SB); BYTE $0xA2
	CALL strayintr(SB); BYTE $0xA3
	CALL strayintr(SB); BYTE $0xA4
	CALL strayintr(SB); BYTE $0xA5
	CALL strayintr(SB); BYTE $0xA6
	CALL strayintr(SB); BYTE $0xA7
	CALL strayintr(SB); BYTE $0xA8
	CALL strayintr(SB); BYTE $0xA9
	CALL strayintr(SB); BYTE $0xAA
	CALL strayintr(SB); BYTE $0xAB
	CALL strayintr(SB); BYTE $0xAC
	CALL strayintr(SB); BYTE $0xAD
	CALL strayintr(SB); BYTE $0xAE
	CALL strayintr(SB); BYTE $0xAF
	CALL strayintr(SB); BYTE $0xB0
	CALL strayintr(SB); BYTE $0xB1
	CALL strayintr(SB); BYTE $0xB2
	CALL strayintr(SB); BYTE $0xB3
	CALL strayintr(SB); BYTE $0xB4
	CALL strayintr(SB); BYTE $0xB5
	CALL strayintr(SB); BYTE $0xB6
	CALL strayintr(SB); BYTE $0xB7
	CALL strayintr(SB); BYTE $0xB8
	CALL strayintr(SB); BYTE $0xB9
	CALL strayintr(SB); BYTE $0xBA
	CALL strayintr(SB); BYTE $0xBB
	CALL strayintr(SB); BYTE $0xBC
	CALL strayintr(SB); BYTE $0xBD
	CALL strayintr(SB); BYTE $0xBE
	CALL strayintr(SB); BYTE $0xBF
	CALL strayintr(SB); BYTE $0xC0
	CALL strayintr(SB); BYTE $0xC1
	CALL strayintr(SB); BYTE $0xC2
	CALL strayintr(SB); BYTE $0xC3
	CALL strayintr(SB); BYTE $0xC4
	CALL strayintr(SB); BYTE $0xC5
	CALL strayintr(SB); BYTE $0xC6
	CALL strayintr(SB); BYTE $0xC7
	CALL strayintr(SB); BYTE $0xC8
	CALL strayintr(SB); BYTE $0xC9
	CALL strayintr(SB); BYTE $0xCA
	CALL strayintr(SB); BYTE $0xCB
	CALL strayintr(SB); BYTE $0xCC
	CALL strayintr(SB); BYTE $0xCD
	CALL strayintr(SB); BYTE $0xCE
	CALL strayintr(SB); BYTE $0xCF
	CALL strayintr(SB); BYTE $0xD0
	CALL strayintr(SB); BYTE $0xD1
	CALL strayintr(SB); BYTE $0xD2
	CALL strayintr(SB); BYTE $0xD3
	CALL strayintr(SB); BYTE $0xD4
	CALL strayintr(SB); BYTE $0xD5
	CALL strayintr(SB); BYTE $0xD6
	CALL strayintr(SB); BYTE $0xD7
	CALL strayintr(SB); BYTE $0xD8
	CALL strayintr(SB); BYTE $0xD9
	CALL strayintr(SB); BYTE $0xDA
	CALL strayintr(SB); BYTE $0xDB
	CALL strayintr(SB); BYTE $0xDC
	CALL strayintr(SB); BYTE $0xDD
	CALL strayintr(SB); BYTE $0xDE
	CALL strayintr(SB); BYTE $0xDF
	CALL strayintr(SB); BYTE $0xE0
	CALL strayintr(SB); BYTE $0xE1
	CALL strayintr(SB); BYTE $0xE2
	CALL strayintr(SB); BYTE $0xE3
	CALL strayintr(SB); BYTE $0xE4
	CALL strayintr(SB); BYTE $0xE5
	CALL strayintr(SB); BYTE $0xE6
	CALL strayintr(SB); BYTE $0xE7
	CALL strayintr(SB); BYTE $0xE8
	CALL strayintr(SB); BYTE $0xE9
	CALL strayintr(SB); BYTE $0xEA
	CALL strayintr(SB); BYTE $0xEB
	CALL strayintr(SB); BYTE $0xEC
	CALL strayintr(SB); BYTE $0xED
	CALL strayintr(SB); BYTE $0xEE
	CALL strayintr(SB); BYTE $0xEF
	CALL strayintr(SB); BYTE $0xF0
	CALL strayintr(SB); BYTE $0xF1
	CALL strayintr(SB); BYTE $0xF2
	CALL strayintr(SB); BYTE $0xF3
	CALL strayintr(SB); BYTE $0xF4
	CALL strayintr(SB); BYTE $0xF5
	CALL strayintr(SB); BYTE $0xF6
	CALL strayintr(SB); BYTE $0xF7
	CALL strayintr(SB); BYTE $0xF8
	CALL strayintr(SB); BYTE $0xF9
	CALL strayintr(SB); BYTE $0xFA
	CALL strayintr(SB); BYTE $0xFB
	CALL strayintr(SB); BYTE $0xFC
	CALL strayintr(SB); BYTE $0xFD
	CALL strayintr(SB); BYTE $0xFE
	CALL strayintr(SB); BYTE $0xFF
	CALL _strayintr(SB); BYTE $0x00		/* divide error */
	CALL _strayintr(SB); BYTE $0x01		/* debug exception */
	CALL _strayintr(SB); BYTE $0x02		/* NMI interrupt */
	CALL _strayintr(SB); BYTE $0x03		/* breakpoint */
	CALL _strayintr(SB); BYTE $0x04		/* overflow */
	CALL _strayintr(SB); BYTE $0x05		/* bound */
	CALL _strayintr(SB); BYTE $0x06		/* invalid opcode */
	CALL _strayintr(SB); BYTE $0x07		/* no coprocessor available */
	CALL _strayintrx(SB); BYTE $0x08	/* double fault */
	CALL _strayintr(SB); BYTE $0x09		/* coprocessor segment overflow */
	CALL _strayintrx(SB); BYTE $0x0A	/* invalid TSS */
	CALL _strayintrx(SB); BYTE $0x0B	/* segment not available */
	CALL _strayintrx(SB); BYTE $0x0C	/* stack exception */
	CALL _strayintrx(SB); BYTE $0x0D	/* general protection error */
	CALL _strayintrx(SB); BYTE $0x0E	/* page fault */
	CALL _strayintr(SB); BYTE $0x0F		/*  */
	CALL _strayintr(SB); BYTE $0x10		/* coprocessor error */
	CALL _strayintrx(SB); BYTE $0x11	/* alignment check */
	CALL _strayintr(SB); BYTE $0x12		/* machine check */
	CALL _strayintr(SB); BYTE $0x13
	CALL _strayintr(SB); BYTE $0x14
	CALL _strayintr(SB); BYTE $0x15
	CALL _strayintr(SB); BYTE $0x16
	CALL _strayintr(SB); BYTE $0x17
	CALL _strayintr(SB); BYTE $0x18
	CALL _strayintr(SB); BYTE $0x19
	CALL _strayintr(SB); BYTE $0x1A
	CALL _strayintr(SB); BYTE $0x1B
	CALL _strayintr(SB); BYTE $0x1C
	CALL _strayintr(SB); BYTE $0x1D
	CALL _strayintr(SB); BYTE $0x1E
	CALL _strayintr(SB); BYTE $0x1F
	CALL _strayintr(SB); BYTE $0x20		/* VectorLAPIC */
	CALL _strayintr(SB); BYTE $0x21
	CALL _strayintr(SB); BYTE $0x22
	CALL _strayintr(SB); BYTE $0x23
	CALL _strayintr(SB); BYTE $0x24
	CALL _strayintr(SB); BYTE $0x25
	CALL _strayintr(SB); BYTE $0x26
	CALL _strayintr(SB); BYTE $0x27
	CALL _strayintr(SB); BYTE $0x28
	CALL _strayintr(SB); BYTE $0x29
	CALL _strayintr(SB); BYTE $0x2A
	CALL _strayintr(SB); BYTE $0x2B
	CALL _strayintr(SB); BYTE $0x2C
	CALL _strayintr(SB); BYTE $0x2D
	CALL _strayintr(SB); BYTE $0x2E
	CALL _strayintr(SB); BYTE $0x2F
	CALL _strayintr(SB); BYTE $0x30
	CALL _strayintr(SB); BYTE $0x31
	CALL _strayintr(SB); BYTE $0x32
	CALL _strayintr(SB); BYTE $0x33
	CALL _strayintr(SB); BYTE $0x34
	CALL _strayintr(SB); BYTE $0x35
	CALL _strayintr(SB); BYTE $0x36
	CALL _strayintr(SB); BYTE $0x37
	CALL _strayintr(SB); BYTE $0x38
	CALL _strayintr(SB); BYTE $0x39
	CALL _strayintr(SB); BYTE $0x3A
	CALL _strayintr(SB); BYTE $0x3B
	CALL _strayintr(SB); BYTE $0x3C
	CALL _strayintr(SB); BYTE $0x3D
	CALL _strayintr(SB); BYTE $0x3E
	CALL _strayintr(SB); BYTE $0x3F
	CALL _syscallintr(SB); BYTE $0x40	/* VectorSYSCALL */
	CALL _strayintr(SB); BYTE $0x41
	CALL _strayintr(SB); BYTE $0x42
	CALL _strayintr(SB); BYTE $0x43
	CALL _strayintr(SB); BYTE $0x44
	CALL _strayintr(SB); BYTE $0x45
	CALL _strayintr(SB); BYTE $0x46
	CALL _strayintr(SB); BYTE $0x47
	CALL _strayintr(SB); BYTE $0x48
	CALL _strayintr(SB); BYTE $0x49
	CALL _strayintr(SB); BYTE $0x4A
	CALL _strayintr(SB); BYTE $0x4B
	CALL _strayintr(SB); BYTE $0x4C
	CALL _strayintr(SB); BYTE $0x4D
	CALL _strayintr(SB); BYTE $0x4E
	CALL _strayintr(SB); BYTE $0x4F
	CALL _strayintr(SB); BYTE $0x50
	CALL _strayintr(SB); BYTE $0x51
	CALL _strayintr(SB); BYTE $0x52
	CALL _strayintr(SB); BYTE $0x53
	CALL _strayintr(SB); BYTE $0x54
	CALL _strayintr(SB); BYTE $0x55
	CALL _strayintr(SB); BYTE $0x56
	CALL _strayintr(SB); BYTE $0x57
	CALL _strayintr(SB); BYTE $0x58
	CALL _strayintr(SB); BYTE $0x59
	CALL _strayintr(SB); BYTE $0x5A
	CALL _strayintr(SB); BYTE $0x5B
	CALL _strayintr(SB); BYTE $0x5C
	CALL _strayintr(SB); BYTE $0x5D
	CALL _strayintr(SB); BYTE $0x5E
	CALL _strayintr(SB); BYTE $0x5F
	CALL _strayintr(SB); BYTE $0x60
	CALL _strayintr(SB); BYTE $0x61
	CALL _strayintr(SB); BYTE $0x62
	CALL _strayintr(SB); BYTE $0x63
	CALL _strayintr(SB); BYTE $0x64
	CALL _strayintr(SB); BYTE $0x65
	CALL _strayintr(SB); BYTE $0x66
	CALL _strayintr(SB); BYTE $0x67
	CALL _strayintr(SB); BYTE $0x68
	CALL _strayintr(SB); BYTE $0x69
	CALL _strayintr(SB); BYTE $0x6A
	CALL _strayintr(SB); BYTE $0x6B
	CALL _strayintr(SB); BYTE $0x6C
	CALL _strayintr(SB); BYTE $0x6D
	CALL _strayintr(SB); BYTE $0x6E
	CALL _strayintr(SB); BYTE $0x6F
	CALL _strayintr(SB); BYTE $0x70
	CALL _strayintr(SB); BYTE $0x71
	CALL _strayintr(SB); BYTE $0x72
	CALL _strayintr(SB); BYTE $0x73
	CALL _strayintr(SB); BYTE $0x74
	CALL _strayintr(SB); BYTE $0x75
	CALL _strayintr(SB); BYTE $0x76
	CALL _strayintr(SB); BYTE $0x77
	CALL _strayintr(SB); BYTE $0x78
	CALL _strayintr(SB); BYTE $0x79
	CALL _strayintr(SB); BYTE $0x7A
	CALL _strayintr(SB); BYTE $0x7B
	CALL _strayintr(SB); BYTE $0x7C
	CALL _strayintr(SB); BYTE $0x7D
	CALL _strayintr(SB); BYTE $0x7E
	CALL _strayintr(SB); BYTE $0x7F
	CALL _strayintr(SB); BYTE $0x80		/* Vector[A]PIC */
	CALL _strayintr(SB); BYTE $0x81
	CALL _strayintr(SB); BYTE $0x82
	CALL _strayintr(SB); BYTE $0x83
	CALL _strayintr(SB); BYTE $0x84
	CALL _strayintr(SB); BYTE $0x85
	CALL _strayintr(SB); BYTE $0x86
	CALL _strayintr(SB); BYTE $0x87
	CALL _strayintr(SB); BYTE $0x88
	CALL _strayintr(SB); BYTE $0x89
	CALL _strayintr(SB); BYTE $0x8A
	CALL _strayintr(SB); BYTE $0x8B
	CALL _strayintr(SB); BYTE $0x8C
	CALL _strayintr(SB); BYTE $0x8D
	CALL _strayintr(SB); BYTE $0x8E
	CALL _strayintr(SB); BYTE $0x8F
	CALL _strayintr(SB); BYTE $0x90
	CALL _strayintr(SB); BYTE $0x91
	CALL _strayintr(SB); BYTE $0x92
	CALL _strayintr(SB); BYTE $0x93
	CALL _strayintr(SB); BYTE $0x94
	CALL _strayintr(SB); BYTE $0x95
	CALL _strayintr(SB); BYTE $0x96
	CALL _strayintr(SB); BYTE $0x97
	CALL _strayintr(SB); BYTE $0x98
	CALL _strayintr(SB); BYTE $0x99
	CALL _strayintr(SB); BYTE $0x9A
	CALL _strayintr(SB); BYTE $0x9B
	CALL _strayintr(SB); BYTE $0x9C
	CALL _strayintr(SB); BYTE $0x9D
	CALL _strayintr(SB); BYTE $0x9E
	CALL _strayintr(SB); BYTE $0x9F
	CALL _strayintr(SB); BYTE $0xA0
	CALL _strayintr(SB); BYTE $0xA1
	CALL _strayintr(SB); BYTE $0xA2
	CALL _strayintr(SB); BYTE $0xA3
	CALL _strayintr(SB); BYTE $0xA4
	CALL _strayintr(SB); BYTE $0xA5
	CALL _strayintr(SB); BYTE $0xA6
	CALL _strayintr(SB); BYTE $0xA7
	CALL _strayintr(SB); BYTE $0xA8
	CALL _strayintr(SB); BYTE $0xA9
	CALL _strayintr(SB); BYTE $0xAA
	CALL _strayintr(SB); BYTE $0xAB
	CALL _strayintr(SB); BYTE $0xAC
	CALL _strayintr(SB); BYTE $0xAD
	CALL _strayintr(SB); BYTE $0xAE
	CALL _strayintr(SB); BYTE $0xAF
	CALL _strayintr(SB); BYTE $0xB0
	CALL _strayintr(SB); BYTE $0xB1
	CALL _strayintr(SB); BYTE $0xB2
	CALL _strayintr(SB); BYTE $0xB3
	CALL _strayintr(SB); BYTE $0xB4
	CALL _strayintr(SB); BYTE $0xB5
	CALL _strayintr(SB); BYTE $0xB6
	CALL _strayintr(SB); BYTE $0xB7
	CALL _strayintr(SB); BYTE $0xB8
	CALL _strayintr(SB); BYTE $0xB9
	CALL _strayintr(SB); BYTE $0xBA
	CALL _strayintr(SB); BYTE $0xBB
	CALL _strayintr(SB); BYTE $0xBC
	CALL _strayintr(SB); BYTE $0xBD
	CALL _strayintr(SB); BYTE $0xBE
	CALL _strayintr(SB); BYTE $0xBF
	CALL _strayintr(SB); BYTE $0xC0
	CALL _strayintr(SB); BYTE $0xC1
	CALL _strayintr(SB); BYTE $0xC2
	CALL _strayintr(SB); BYTE $0xC3
	CALL _strayintr(SB); BYTE $0xC4
	CALL _strayintr(SB); BYTE $0xC5
	CALL _strayintr(SB); BYTE $0xC6
	CALL _strayintr(SB); BYTE $0xC7
	CALL _strayintr(SB); BYTE $0xC8
	CALL _strayintr(SB); BYTE $0xC9
	CALL _strayintr(SB); BYTE $0xCA
	CALL _strayintr(SB); BYTE $0xCB
	CALL _strayintr(SB); BYTE $0xCC
	CALL _strayintr(SB); BYTE $0xCD
	CALL _strayintr(SB); BYTE $0xCE
	CALL _strayintr(SB); BYTE $0xCF
	CALL _strayintr(SB); BYTE $0xD0
	CALL _strayintr(SB); BYTE $0xD1
	CALL _strayintr(SB); BYTE $0xD2
	CALL _strayintr(SB); BYTE $0xD3
	CALL _strayintr(SB); BYTE $0xD4
	CALL _strayintr(SB); BYTE $0xD5
	CALL _strayintr(SB); BYTE $0xD6
	CALL _strayintr(SB); BYTE $0xD7
	CALL _strayintr(SB); BYTE $0xD8
	CALL _strayintr(SB); BYTE $0xD9
	CALL _strayintr(SB); BYTE $0xDA
	CALL _strayintr(SB); BYTE $0xDB
	CALL _strayintr(SB); BYTE $0xDC
	CALL _strayintr(SB); BYTE $0xDD
	CALL _strayintr(SB); BYTE $0xDE
	CALL _strayintr(SB); BYTE $0xDF
	CALL _strayintr(SB); BYTE $0xE0
	CALL _strayintr(SB); BYTE $0xE1
	CALL _strayintr(SB); BYTE $0xE2
	CALL _strayintr(SB); BYTE $0xE3
	CALL _strayintr(SB); BYTE $0xE4
	CALL _strayintr(SB); BYTE $0xE5
	CALL _strayintr(SB); BYTE $0xE6
	CALL _strayintr(SB); BYTE $0xE7
	CALL _strayintr(SB); BYTE $0xE8
	CALL _strayintr(SB); BYTE $0xE9
	CALL _strayintr(SB); BYTE $0xEA
	CALL _strayintr(SB); BYTE $0xEB
	CALL _strayintr(SB); BYTE $0xEC
	CALL _strayintr(SB); BYTE $0xED
	CALL _strayintr(SB); BYTE $0xEE
	CALL _strayintr(SB); BYTE $0xEF
	CALL _strayintr(SB); BYTE $0xF0
	CALL _strayintr(SB); BYTE $0xF1
	CALL _strayintr(SB); BYTE $0xF2
	CALL _strayintr(SB); BYTE $0xF3
	CALL _strayintr(SB); BYTE $0xF4
	CALL _strayintr(SB); BYTE $0xF5
	CALL _strayintr(SB); BYTE $0xF6
	CALL _strayintr(SB); BYTE $0xF7
	CALL _strayintr(SB); BYTE $0xF8
	CALL _strayintr(SB); BYTE $0xF9
	CALL _strayintr(SB); BYTE $0xFA
	CALL _strayintr(SB); BYTE $0xFB
	CALL _strayintr(SB); BYTE $0xFC
	CALL _strayintr(SB); BYTE $0xFD
	CALL _strayintr(SB); BYTE $0xFE
	CALL _strayintr(SB); BYTE $0xFF

M pc/main.c => pc/main.c +17 -4
@@ 6,6 6,7 @@
#include	"io.h"
#include	"ureg.h"
#include	"init.h"
#include	"pool.h"

Mach *m;



@@ 128,7 129,7 @@ main(void)
	 */
	conf.nmach = 1;
	MACHP(0) = (Mach*)CPU0MACH;
	m->pdb = (void*)CPU0PDB;
	m->pdb = (ulong*)CPU0PDB;
	machinit();
	active.machs = 1;
	active.exiting = 0;


@@ 155,6 156,7 @@ main(void)
	procinit0();
	initseg();
	links();
conf.monitor = 1;
	chandevreset();
	swapinit();
	userinit();


@@ 165,7 167,7 @@ void
machinit(void)
{
	int machno;
	void *pdb;
	ulong *pdb;

	machno = m->machno;
	pdb = m->pdb;


@@ 388,8 390,19 @@ confinit(void)
	meminit(maxmem);

	conf.npage = conf.npage0 + conf.npage1;
	if(pcnt < 10)
		pcnt = 70;
	if(cpuserver) {
		if(pcnt < 10)
			pcnt = 70;
	} else {
		if(pcnt < 10) {
			if(conf.npage*BY2PG < 16*MB)
				pcnt = 40;
			else
				pcnt = 60;
		}
		if(conf.npage*BY2PG < 16*MB)
			poolsetparam("Image", 0, 0, 4*1024*1024);
	}
	conf.upages = (conf.npage*pcnt)/100;
	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;


M pc/mem.h => pc/mem.h +4 -7
@@ 16,8 16,7 @@
#define PGROUND(s)	ROUND(s, BY2PG)

#define	MAXMACH		8			/* max # cpus system can run */
#define KSTACK		4096-16			/* Size of kernel stack */
						/* the -16 is room for the 2n allocator header */
#define KSTACK		4096			/* Size of kernel stack */

/*
 * Time


@@ 35,12 34,10 @@
#define APBOOTSTRAP	0x80001000		/* AP bootstrap code */
#define CONFADDR	0x80001200		/* info passed from boot loader */
#define CPU0PDB		0x80002000		/* bootstrap processor PDB */
#define CPU0PTE		0x80003000		/* bootstrap processor PTE's for 0-2MB */
#define CPU0MACHPTE	0x80004000		/* bootstrap processor PTE for MACHADDR */
#define CPU0PTE		0x80003000		/* bootstrap processor PTE's for 0-4MB */
#define MACHADDR	0x80004000		/* as seen by current processor */
#define CPU0MACH	0x80005000		/* Mach for bootstrap processor */

#define MACHADDR	0xFEF00000		/* as seen by current processor */
#define	MACHSIZE	4096
#define	MACHSIZE	BY2PG

/*
 *  Address spaces

M pc/memory.c => pc/memory.c +9 -6
@@ 74,6 74,7 @@ static RMap rmapumbrw = {
	&mapumbrw[7],
};

#define notdef
#ifdef notdef
void
dumpmembank(void)


@@ 302,7 303,7 @@ ramscan(ulong maxmem)
		 * pool later if it isn't needed.
		 */
		va = KADDR(pa);
		table = &((ulong*)m->pdb)[PDX(va)];
		table = &m->pdb[PDX(va)];
		if(*table == 0){
			if(map == 0 && (map = mapalloc(&rmapram, 0, BY2PG, BY2PG)) == 0)
				break;


@@ 365,7 366,7 @@ ramscan(ulong maxmem)
		 *    initialised space for the page table.
		 */
		if((pa % (4*MB)) == 0){
			table = &((ulong*)m->pdb)[PDX(va)];
			table = &m->pdb[PDX(va)];
			if(nvalid[MemUPA] == (4*MB)/BY2PG)
				*table = 0;
			else if(nvalid[MemRAM] == (4*MB)/BY2PG && (m->cpuiddx & 0x08))


@@ 383,8 384,9 @@ ramscan(ulong maxmem)
		mapfree(&rmapram, map, BY2PG);
	if(pa < maxmem)
		mapfree(&rmapupa, pa, maxmem-pa);
	if(maxmem < 0xFEC00000)
		mapfree(&rmapupa, maxmem, 0xFEC00000-maxmem);
	if(maxmem < 0xFFE00000)
		mapfree(&rmapupa, maxmem, 0xFFE00000-maxmem);
print("maxmem %uX %uX\n", maxmem, 0xFFE00000-maxmem);
	*k0 = kzero;
}



@@ 401,11 403,11 @@ meminit(ulong maxmem)
	 * then scan for useful memory.
	 */
	for(pa = 0xA0000; pa < 0xC0000; pa += BY2PG){
		pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 0);
		pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0);
		*pte |= PTEWT;
	}
	for(pa = 0xC0000; pa < 0x100000; pa += BY2PG){
		pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 0);
		pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0);
		*pte |= PTEUNCACHED;
	}
	mmuflushtlb(PADDR(m->pdb));


@@ 432,6 434,7 @@ meminit(ulong maxmem)
		conf.base1 = xmp->addr;
		conf.npage1 = xmp->size/BY2PG;
	}
dumpmembank();
}

ulong

M pc/mmu.c => pc/mmu.c +116 -27
@@ 111,7 111,7 @@ mmuswitch(Proc* p)

	if(p->mmupdb){
		top = (ulong*)p->mmupdb->va;
		top[PDX(MACHADDR)] = ((ulong*)m->pdb)[PDX(MACHADDR)];
		top[PDX(MACHADDR)] = m->pdb[PDX(MACHADDR)];
		taskswitch(p->mmupdb->pa, (ulong)(p->kstack+KSTACK));
	}
	else


@@ 224,34 224,50 @@ putmmu(ulong va, ulong pa, Page* pg)
		up->mmuused = pg;
	}

	pt = (ulong*)(PPN(pdb[pdbx])|KZERO);
	pt = KADDR(PPN(pdb[pdbx]));
	pt[PTX(va)] = pa|PTEUSER;

	s = splhi();
	pdb[PDX(MACHADDR)] = ((ulong*)m->pdb)[PDX(MACHADDR)];
	pdb[PDX(MACHADDR)] = m->pdb[PDX(MACHADDR)];
	mmuflushtlb(up->mmupdb->pa);
	splx(s);
}

ulong*
mmuwalk(ulong* pdb, ulong va, int create)
mmuwalk(ulong* pdb, ulong va, int level, int create)
{
	ulong pa, *table;

	/*
	 * Walk the page-table pointed to by pdb and return a pointer
	 * to the entry for virtual address va at the requested level.
	 * If the entry is invalid and create isn't requested then bail
	 * out early. Otherwise, for the 2nd level walk, allocate a new
	 * page-table page and register it in the 1st level.
	 */
	table = &pdb[PDX(va)];
	if(*table == 0){
		if(create == 0)
			return 0;
		pa = PADDR((ulong)xspanalloc(BY2PG, BY2PG, 0));
		*table = pa|PTEWRITE|PTEVALID;
	}
	if(*table & PTESIZE)
	if(!(*table & PTEVALID) && create == 0)
		return 0;

	switch(level){

	default:
		return 0;

	case 1:
		return table;

	table = (ulong*)(KZERO|PPN(*table));
	va = PTX(va);
	case 2:
		if(*table & PTESIZE)
			panic("mmuwalk2: va %uX entry %uX\n", va, *table);
		if(!(*table & PTEVALID)){
			pa = PADDR(xspanalloc(BY2PG, BY2PG, 0));
			*table = pa|PTEWRITE|PTEVALID;
		}
		table = KADDR(PPN(*table));

	return &table[va];
		return &table[PTX(va)];
	}
}

static Lock mmukmaplock;


@@ 260,20 276,24 @@ int
mmukmapsync(ulong va)
{
	Mach *mach0;
	ulong entry;
	ulong entry, *pte;

	mach0 = MACHP(0);

	lock(&mmukmaplock);

	if(mmuwalk(mach0->pdb, va, 0) == nil){
	if((pte = mmuwalk(mach0->pdb, va, 1, 0)) == nil){
		unlock(&mmukmaplock);
		return 0;
	}
	if(!(*pte & PTESIZE) && mmuwalk(mach0->pdb, va, 2, 0) == nil){
		unlock(&mmukmaplock);
		return 0;
	}
	entry = ((ulong*)mach0->pdb)[PDX(va)];
	entry = *pte;

	if(!(((ulong*)m->pdb)[PDX(va)] & PTEVALID))
		((ulong*)m->pdb)[PDX(va)] = entry;
	if(!(m->pdb[PDX(va)] & PTEVALID))
		m->pdb[PDX(va)] = entry;

	if(up && up->mmupdb){
		((ulong*)up->mmupdb->va)[PDX(va)] = entry;


@@ 291,34 311,103 @@ ulong
mmukmap(ulong pa, ulong va, int size)
{
	Mach *mach0;
	ulong ova, pae, *table, pgsz, *pte;
	ulong ova, pae, *table, pgsz, *pte, x;
	int pse, sync;

	mach0 = MACHP(0);
	if((mach0->cpuiddx & 0x08) && (getcr4() & 0x10))
		pse = 1;
	else
		pse = 0;
	sync = 0;

	pa &= ~(BY2PG-1);
	pa = PPN(pa);
	if(va == 0)
		va = (ulong)KADDR(pa);
	va &= ~(BY2PG-1);
	else
		va = PPN(va);
	ova = va;

	pae = pa + size;
	mach0 = MACHP(0);
	lock(&mmukmaplock);
	while(pa < pae){
		table = &((ulong*)mach0->pdb)[PDX(va)];
		if((pa % (4*MB)) == 0 && (mach0->cpuiddx & 0x08)){
		table = &mach0->pdb[PDX(va)];
		/*
		 * Possibly already mapped.
		 */
		if(*table & PTEVALID){
			if(*table & PTESIZE){
				/*
				 * Big page. Does it fit within?
				 * If it does, adjust pgsz so the correct end can be
				 * returned and get out.
				 * If not, adjust pgsz up to the next 4MB boundary
				 * and continue.
				 */
				x = PPN(*table);
				if(x != pa)
					panic("mmukmap1: pa %ux  entry %uX\n",
						pa, *table);
				x += 4*MB;
				if(pae <= x){
					pa = pae;
					break;
				}
				pgsz = x - pa;
				pa += pgsz;
				va += pgsz;

				continue;
			}
			else{
				/*
				 * Little page. Walk to the entry.
				 * If the entry is valid, set pgsz and continue.
				 * If not, make it so, set pgsz, sync and continue.
				 */
				pte = mmuwalk(mach0->pdb, va, 2, 0);
				if(pte && *pte & PTEVALID){
					x = PPN(*pte);
					if(x != pa)
						panic("mmukmap2: pa %ux entry %uX\n",
							pa, *pte);
					pgsz = BY2PG;
					pa += pgsz;
					va += pgsz;
					sync++;

					continue;
				}
			}
		}

		/*
		 * Not mapped. Check if it can be mapped using a big page -
		 * starts on a 4MB boundary, size >= 4MB and processor can do it.
		 * If not a big page, walk the walk, talk the talk.
		 * Sync is set.
		 */
		if(pse && (pa % (4*MB)) == 0 && (pae >= pa+4*MB)){
			*table = pa|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID;
			pgsz = 4*MB;
		}
		else{
			pte = mmuwalk(mach0->pdb, va, 1);
			pte = mmuwalk(mach0->pdb, va, 2, 1);
			*pte = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
			pgsz = BY2PG;
		}
		pa += pgsz;
		va += pgsz;
		sync++;
	}
	unlock(&mmukmaplock);

	mmukmapsync(ova);
	/*
	 * If something was added
	 * then need to sync up.
	 */
	if(sync)
		mmukmapsync(ova);

	return pa;
}

M pc/mouse.c => pc/mouse.c +14 -1
@@ 6,10 6,23 @@
#include "../port/error.h"
#include "io.h"

#include <libg.h>
#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"

/*
 *  mouse types
 */
enum
{
	Mouseother=	0,
	Mouseserial=	1,
	MousePS2=	2,
};
static int mousetype;

/*
 *  setup a serial mouse
 */
static void

M pc/mp.c => pc/mp.c +23 -31
@@ 124,27 124,20 @@ static Apic*
mkioapic(PCMPioapic* p)
{
	Apic *apic;
	ulong addr, *pte;

	if(!(p->flags & PcmpEN) || p->apicno > MaxAPICNO)
		return 0;

	/*
	 * Map the I/O APIC. This should be in the same 4MB segment
	 * as MACHADDR so no new 2nd level table will be allocated.
	 * Map the I/O APIC.
	 */
	addr = p->addr;
	if((pte = mmuwalk(m->pdb, addr, 1)) == 0)
	if(mmukmap(p->addr, 0, 1024) == 0)
		return 0;
	if(!(*pte & PTEVALID)){
		*pte = addr|PTEWRITE|PTEUNCACHED|PTEVALID;
		mmuflushtlb(PADDR(m->pdb));
	}

	apic = &mpapic[p->apicno];
	apic->type = PcmpIOAPIC;
	apic->apicno = p->apicno;
	apic->addr = KADDR(addr);
	apic->addr = KADDR(p->addr);
	apic->flags = p->flags;

	return apic;


@@ 290,8 283,7 @@ squidboy(Apic* apic)
{
	int clkin;

	/*iprint("Hello Squidboy\n");*/

//	iprint("Hello Squidboy\n");
	machinit();
	mmuinit();



@@ 322,25 314,31 @@ static void
mpstartap(Apic* apic)
{
	ulong *apbootp, *pdb, *pte;
	Mach *mach;
	Mach *mach, *mach0;
	int i, machno;
	uchar *p;

	mach0 = MACHP(0);

	/*
	 * Initialise the AP page-tables and Mach structure. These are
	 * the same as for the bootstrap processor with the exception of
	 * Initialise the AP page-tables and Mach structure. The page-tables
	 * are the same as for the bootstrap processor with the exception of
	 * the PTE for the Mach structure.
	 * Xspanalloc will panic if an allocation can't be made.
	 */
	pdb = xspanalloc(3*BY2PG, BY2PG, 0);
	memmove(pdb, (void*)CPU0PDB, BY2PG);
	p = xspanalloc(3*BY2PG, BY2PG, 0);
	pdb = (ulong*)p;
	memmove(pdb, mach0->pdb, BY2PG);
	p += BY2PG;

	pte = (ulong*)(((uchar*)pdb)+BY2PG);
	memmove(pte, (void*)CPU0MACHPTE, BY2PG);
	pdb[PDX(MACHADDR)] = PADDR(pte)|PTEWRITE|PTEVALID;
	if((pte = mmuwalk(pdb, MACHADDR, 1, 0)) == nil)
		return;
	memmove(p, KADDR(PPN(*pte)), BY2PG);
	*pte = PADDR(p)|PTEWRITE|PTEVALID;
	p += BY2PG;

	mach = (Mach*)(((uchar*)pdb)+2*BY2PG);
	if((pte = mmuwalk(pdb, MACHADDR, 0)) == 0)
	mach = (Mach*)p;
	if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil)
		return;
	*pte = PADDR(mach)|PTEWRITE|PTEVALID;



@@ 386,7 384,6 @@ void
mpinit(void)
{
	PCMP *pcmp;
	ulong *pte;
	uchar *e, *p;
	Apic *apic, *bpapic;
	int clkin;


@@ 398,15 395,10 @@ mpinit(void)
	pcmp = KADDR(_mp_->physaddr);

	/*
	 * Map the local APIC. This should be in the same 4MB segment
	 * as MACHADDR so no new 2nd level table will be allocated.
	 * Map the local APIC.
	 */
	if((pte = mmuwalk(m->pdb, pcmp->lapicbase, 1)) == 0)
	if(mmukmap(pcmp->lapicbase, 0, 1024) == 0)
		return;
	if(!(*pte & PTEVALID)){
		*pte = pcmp->lapicbase|PTEWRITE|PTEUNCACHED|PTEVALID;
		mmuflushtlb(PADDR(m->pdb));
	}

	bpapic = 0;



@@ 633,7 625,7 @@ mpshutdown(void)
	 * warm-boot sequence is tried. The following is Intel specific and
	 * seems to perform a cold-boot, but at least it comes back.
	 */
	*(ushort*)(KZERO|0x472) = 0x1234;		/* BIOS warm-boot flag */
	*(ushort*)KADDR(0x472) = 0x1234;		/* BIOS warm-boot flag */
	outb(0xCF9, 0x02);
	outb(0xCF9, 0x06);
#else

M pc/pci.c => pc/pci.c +7 -2
@@ 29,6 29,7 @@ static int pcicfgmode = -1;
static int pcimaxdno;
static Pcidev* pciroot;
static Pcidev* pcilist;
static Pcidev* pcitail;

static int pcicfgrw8(int, int, int, int);
static int pcicfgrw16(int, int, int, int);


@@ 62,8 63,12 @@ pciscan(int bno, Pcidev** list)
			p->tbdf = tbdf;
			p->vid = l;
			p->did = l>>16;
			p->list = pcilist;
			pcilist = p;

			if(pcilist != nil)
				pcitail->list = p;
			else
				pcilist = p;
			pcitail = p;

			p->intl = pcicfgrw8(tbdf, PciINTL, 0, 1);
			p->ccru = pcicfgrw16(tbdf, PciCCRu, 0, 1);

M pc/screen.c => pc/screen.c +244 -255
@@ 4,306 4,295 @@
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
#include "../port/error.h"

#include <libg.h>
#include <gnot.h>
#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"
#include "vga.h"

/*
 * CGA-only hack.
 */
/* imported */
extern	GSubfont defont0;
extern	Cursor arrow;
extern	GBitmap cursorback;

/* exported */
GSubfont *defont;
int islittle = 1;		/* little endian bit ordering in bytes */
GBitmap	gscreen;

/* local */
static	Lock vgalock;
static	ulong colormap[256][3];
static	Rectangle mbb;

/*
 *  reverse pixels into little endian order
 */
uchar revtab0[] = {
 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};
uchar revtab1[] = {
 0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0,
 0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0,
 0x04, 0x44, 0x84, 0xc4, 0x14, 0x54, 0x94, 0xd4,
 0x24, 0x64, 0xa4, 0xe4, 0x34, 0x74, 0xb4, 0xf4,
 0x08, 0x48, 0x88, 0xc8, 0x18, 0x58, 0x98, 0xd8,
 0x28, 0x68, 0xa8, 0xe8, 0x38, 0x78, 0xb8, 0xf8,
 0x0c, 0x4c, 0x8c, 0xcc, 0x1c, 0x5c, 0x9c, 0xdc,
 0x2c, 0x6c, 0xac, 0xec, 0x3c, 0x7c, 0xbc, 0xfc,
 0x01, 0x41, 0x81, 0xc1, 0x11, 0x51, 0x91, 0xd1,
 0x21, 0x61, 0xa1, 0xe1, 0x31, 0x71, 0xb1, 0xf1,
 0x05, 0x45, 0x85, 0xc5, 0x15, 0x55, 0x95, 0xd5,
 0x25, 0x65, 0xa5, 0xe5, 0x35, 0x75, 0xb5, 0xf5,
 0x09, 0x49, 0x89, 0xc9, 0x19, 0x59, 0x99, 0xd9,
 0x29, 0x69, 0xa9, 0xe9, 0x39, 0x79, 0xb9, 0xf9,
 0x0d, 0x4d, 0x8d, 0xcd, 0x1d, 0x5d, 0x9d, 0xdd,
 0x2d, 0x6d, 0xad, 0xed, 0x3d, 0x7d, 0xbd, 0xfd,
 0x02, 0x42, 0x82, 0xc2, 0x12, 0x52, 0x92, 0xd2,
 0x22, 0x62, 0xa2, 0xe2, 0x32, 0x72, 0xb2, 0xf2,
 0x06, 0x46, 0x86, 0xc6, 0x16, 0x56, 0x96, 0xd6,
 0x26, 0x66, 0xa6, 0xe6, 0x36, 0x76, 0xb6, 0xf6,
 0x0a, 0x4a, 0x8a, 0xca, 0x1a, 0x5a, 0x9a, 0xda,
 0x2a, 0x6a, 0xaa, 0xea, 0x3a, 0x7a, 0xba, 0xfa,
 0x0e, 0x4e, 0x8e, 0xce, 0x1e, 0x5e, 0x9e, 0xde,
 0x2e, 0x6e, 0xae, 0xee, 0x3e, 0x7e, 0xbe, 0xfe,
 0x03, 0x43, 0x83, 0xc3, 0x13, 0x53, 0x93, 0xd3,
 0x23, 0x63, 0xa3, 0xe3, 0x33, 0x73, 0xb3, 0xf3,
 0x07, 0x47, 0x87, 0xc7, 0x17, 0x57, 0x97, 0xd7,
 0x27, 0x67, 0xa7, 0xe7, 0x37, 0x77, 0xb7, 0xf7,
 0x0b, 0x4b, 0x8b, 0xcb, 0x1b, 0x5b, 0x9b, 0xdb,
 0x2b, 0x6b, 0xab, 0xeb, 0x3b, 0x7b, 0xbb, 0xfb,
 0x0f, 0x4f, 0x8f, 0xcf, 0x1f, 0x5f, 0x9f, 0xdf,
 0x2f, 0x6f, 0xaf, 0xef, 0x3f, 0x7f, 0xbf, 0xff,

static ulong onesbits = ~0;
static Memdata onesdata = {
	nil,
	&onesbits,
};
uchar revtab2[] = {
 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
 0x81, 0x91, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1, 0xf1,
 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
 0x82, 0x92, 0xa2, 0xb2, 0xc2, 0xd2, 0xe2, 0xf2,
 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
 0x83, 0x93, 0xa3, 0xb3, 0xc3, 0xd3, 0xe3, 0xf3,
 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
 0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4,
 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
 0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5,
 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6,
 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7,
 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8,
 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9,
 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a,
 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa,
 0x0b, 0x1b, 0x2b, 0x3b, 0x4b, 0x5b, 0x6b, 0x7b,
 0x8b, 0x9b, 0xab, 0xbb, 0xcb, 0xdb, 0xeb, 0xfb,
 0x0c, 0x1c, 0x2c, 0x3c, 0x4c, 0x5c, 0x6c, 0x7c,
 0x8c, 0x9c, 0xac, 0xbc, 0xcc, 0xdc, 0xec, 0xfc,
 0x0d, 0x1d, 0x2d, 0x3d, 0x4d, 0x5d, 0x6d, 0x7d,
 0x8d, 0x9d, 0xad, 0xbd, 0xcd, 0xdd, 0xed, 0xfd,
 0x0e, 0x1e, 0x2e, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e,
 0x8e, 0x9e, 0xae, 0xbe, 0xce, 0xde, 0xee, 0xfe,
 0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f,
 0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff,
static Memimage xones = {
	{ 0, 0, 1, 1 },
	{ -100000, -100000, 100000, 100000 },
	3,
	1,
	&onesdata,
	0,
	1
};
Memimage *memones = &xones;

void
pixreverse(uchar *p, int len, int ldepth)
{
	uchar *e;
	uchar *tab;
Point ZP = {0, 0};

	switch(ldepth){
	case 0:
		tab = revtab0;
		break;
	case 1:
		tab = revtab1;
		break;
	case 2:
		tab = revtab2;
		break;
	default:
		return;
	}
Memdata gscreendata;
Memimage gscreen;

	for(e = p + len; p < e; p++)
		*p = tab[*p];
}
VGAscr vgascreen[1];

static void
crout(int reg, int val)
int
screensize(int x, int y, int z)
{
	outb(CRX, reg);
	outb(CR, val);
}
	VGAscr *scr;

void
screeninit(void)
{
	int i;
	ulong *l;
	scr = &vgascreen[0];

	/*
	 *  arrow is defined as a big endian
	 * BUG: need to check if any xalloc'ed memory needs to
	 * be given back if aperture is set.
	 */
	pixreverse(arrow.set, 2*16, 0);
	pixreverse(arrow.clr, 2*16, 0);
	if(scr->aperture == 0){
		int width = (x*(1<<z))/BI2WD;

	/*
	 *  swizzle the font longs.  we do both byte and bit swizzling
	 *  since the font is initialized with big endian longs.
	 */
	defont = &defont0;
	l = defont->bits->base;
	for(i = defont->bits->width*Dy(defont->bits->r); i > 0; i--, l++)
		*l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24);
	pixreverse((uchar*)defont->bits->base,
		defont->bits->width*BY2WD*Dy(defont->bits->r), 0);

	crout(0x0a, 0xff);		/* turn off cursor */
	memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT);
		gscreendata.data = xalloc(width*BY2WD*y);
		if(gscreendata.data == 0)
			error("screensize: vga soft memory");
		memset(gscreendata.data, Backgnd, width*BY2WD*y);
		scr->useflush = 1;

		scr->aperture = 0xA0000;
		scr->apsize = 1<<16;
	}
	else
		gscreendata.data = KADDR(scr->aperture);

	gscreen.data = &gscreendata;
	gscreen.ldepth = z;
	gscreen.width = (x*(1<<gscreen.ldepth)+31)/32;
	gscreen.r.min = ZP;
	gscreen.r.max = Pt(x, y);
	gscreen.clipr = gscreen.r;
	gscreen.repl = 0;

	scr->gscreendata = gscreen.data;
	scr->memdefont = getmemdefont();
	scr->gscreen = &gscreen;

//	memset(gscreen.data->data, Backgnd, scr->apsize);

	drawcmap(0);

	return 0;
}

static void
cgascreenputc(int c)
int
screenaperture(int size, int align)
{
	int i;
	static int color;
	static int pos;

	if(c == '\n'){
		pos = pos/CGAWIDTH;
		pos = (pos+1)*CGAWIDTH;
	} else if(c == '\t'){
		i = 8 - ((pos/2)&7);
		while(i-->0)
			cgascreenputc(' ');
	} else if(c == '\b'){
		if(pos >= 2)
			pos -= 2;
		cgascreenputc(' ');
		pos -= 2;
	} else {
		CGASCREEN[pos++] = c;
		CGASCREEN[pos++] = 2;	/* green on black */
	VGAscr *scr;
	ulong aperture;

	scr = &vgascreen[0];

	if(size == 0){
		if(scr->aperture && scr->isupamem)
			upafree(scr->aperture, scr->apsize);
		scr->aperture = 0;
		scr->isupamem = 0;
		return 0;
	}
	if(scr->dev && scr->dev->linear){
		aperture = scr->dev->linear(scr, &size, &align);
		if(aperture == 0)
			return 1;
	}
	if(pos >= CGAWIDTH*CGAHEIGHT){
		memmove(CGASCREEN, &CGASCREEN[CGAWIDTH], CGAWIDTH*(CGAHEIGHT-1));
		memset(&CGASCREEN[CGAWIDTH*(CGAHEIGHT-1)], 0, CGAWIDTH);
		pos = CGAWIDTH*(CGAHEIGHT-1);
	else{
		aperture = upamalloc(0, size, align);
		if(aperture == 0)
			return 1;

		if(scr->aperture && scr->isupamem)
			upafree(scr->aperture, scr->apsize);
		scr->isupamem = 1;
	}

	scr->aperture = aperture;
	scr->apsize = size;

	return 0;
}

void
screenputs(char *s, int n)
ulong*
attachscreen(Rectangle* r, int* ld, int* width)
{
	while(n-- > 0)
		cgascreenputc(*s++);
	VGAscr *scr;

	scr = &vgascreen[0];
	if(scr->gscreen == nil || scr->gscreendata == nil)
		return nil;

	*r = scr->gscreen->r;
	*ld = scr->gscreen->ldepth;
	*width = scr->gscreen->width;

	return scr->gscreendata->data;
}

/*
 *  collect changes to the 'soft' screen
 */
void
mbbrect(Rectangle r)
flushmemscreen(Rectangle r)
{
	if (r.min.x < mbb.min.x)
		mbb.min.x = r.min.x;
	if (r.min.y < mbb.min.y)
		mbb.min.y = r.min.y;
	if (r.max.x > mbb.max.x)
		mbb.max.x = r.max.x;
	if (r.max.y > mbb.max.y)
		mbb.max.y = r.max.y;
	mousescreenupdate();
	VGAscr *scr;
	uchar *sp, *disp, *sdisp, *edisp;
	int y, len, incs, off, page;

	scr = &vgascreen[0];
	if(scr->gscreen == nil || scr->useflush == 0)
		return;
	if(scr->dev == nil || scr->dev->page == nil)
		return;

	if(rectclip(&r, scr->gscreen->r) == 0)
		return;

	incs = scr->gscreen->width * BY2WD;

	switch(scr->gscreen->ldepth){
	default:
		len = 0;
		panic("flushmemscreen: ldepth\n");
		break;
	case 3:
		len = Dx(r);
		break;
	}
	if(len < 1)
		return;

	off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x>>(3-scr->gscreen->ldepth));
	page = off/scr->apsize;
	off %= scr->apsize;
	disp = KADDR(scr->aperture);
	sdisp = disp+off;
	edisp = disp+scr->apsize;

	off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x>>(3-scr->gscreen->ldepth));
	sp = ((uchar*)scr->gscreendata->data) + off;

	scr->dev->page(scr, page);
	for(y = r.min.y; y < r.max.y; y++) {
		if(sdisp + incs < edisp) {
			memmove(sdisp, sp, len);
			sp += incs;
			sdisp += incs;
		}
		else {
			off = edisp - sdisp;
			page++;
			if(off <= len){
				if(off > 0)
					memmove(sdisp, sp, off);
				scr->dev->page(scr, page);
				if(len - off > 0)
					memmove(disp, sp+off, len - off);
			}
			else {
				memmove(sdisp, sp, len);
				scr->dev->page(scr, page);
			}
			sp += incs;
			sdisp += incs - scr->apsize;
		}
	}
}

void
hwcursset(ulong *s, ulong *c, int ox, int oy)
getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
{
	USED(s, c, ox, oy);
	VGAscr *scr;
	ulong x;

	scr = &vgascreen[0];
	if(scr->gscreen == nil)
		return;

	switch(scr->gscreen->ldepth){
	default:
		x = 0x0F;
		break;
	case 3:
		x = 0xFF;
		break;
	}
	p &= x;
	p ^= x;

	lock(&cursor);
	*pr = scr->colormap[p][0];
	*pg = scr->colormap[p][1];
	*pb = scr->colormap[p][2];
	unlock(&cursor);
}

void
hwcursmove(int x, int y)
int
setcolor(ulong p, ulong r, ulong g, ulong b)
{
	USED(x, y);
	VGAscr *scr;
	ulong x;

	scr = &vgascreen[0];
	if(scr->gscreen == nil)
		return 0;

	switch(scr->gscreen->ldepth){
	default:
		x = 0x0F;
		break;
	case 3:
		x = 0xFF;
		break;
	}
	p &= x;
	p ^= x;

	lock(&cursor);
	scr->colormap[p][0] = r;
	scr->colormap[p][1] = g;
	scr->colormap[p][2] = b;
	vgao(PaddrW, p);
	vgao(Pdata, r>>(32-6));
	vgao(Pdata, g>>(32-6));
	vgao(Pdata, b>>(32-6));
	unlock(&cursor);

	return ~0;
}

void
screenload(Rectangle r, uchar *data, int tl, int l)
int
cursoron(int dolock)
{
	USED(r, data, tl, l);
	VGAscr *scr;
	int v;

	scr = &vgascreen[0];
	if(scr->cur == nil || scr->cur->move == nil)
		return 0;

	if(dolock)
		lock(&cursor);
	v = scr->cur->move(scr, mousexy());
	if(dolock)
		unlock(&cursor);

	return v;
}

void
getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
cursoroff(int)
{
	p &= (1<<(1<<gscreen.ldepth))-1;
	lock(&vgalock);
	*pr = colormap[p][0];
	*pg = colormap[p][1];
	*pb = colormap[p][2];
	unlock(&vgalock);
}

void
mousescreenupdate(void)
setcursor(Cursor* curs)
{
}
	VGAscr *scr;

/*
 *  a fatter than usual cursor for the safari
 */
Cursor fatarrow = {
	{ -1, -1 },
	{
		0xff, 0xff, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0c, 
		0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, 
		0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8c, 0x04, 
		0x92, 0x08, 0x91, 0x10, 0xa0, 0xa0, 0xc0, 0x40, 
	},
	{
		0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf0, 
		0x7f, 0xe0, 0x7f, 0xe0, 0x7f, 0xf0, 0x7f, 0xf8, 
		0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfc, 0x73, 0xf8, 
		0x61, 0xf0, 0x60, 0xe0, 0x40, 0x40, 0x00, 0x00, 
	},
};
	scr = &vgascreen[0];
	if(scr->cur == nil || scr->cur->load == nil)
		return;

void
bigcursor(void)
{
	memmove(&arrow, &fatarrow, sizeof(fatarrow));
	pixreverse(arrow.set, 2*16, 0);
	pixreverse(arrow.clr, 2*16, 0);
	scr->cur->load(scr, curs);
}

M pc/screen.h => pc/screen.h +104 -30
@@ 1,40 1,114 @@
typedef struct Cursorinfo	Cursorinfo;

struct Cursorinfo
{
typedef struct Cursorinfo Cursorinfo;
struct Cursorinfo {
	Cursor;
	Lock;
	int	visible;	/* on screen */
	int	disable;	/* from being used */
	int	frozen;		/* from being used */
	Rectangle r;		/* location */
	Rectangle clipr;	/* r clipped into screen */
	int	l;		/* width of cursorwork (in bytes) */
	int	tl;		/* scan line byte width of mouse at r */
};

Cursorinfo	cursor;
Cursor		curs;
extern int	cursoron(int);
extern void	cursoroff(int);
extern void	setcursor(Cursor*);
/* devmouse.c */
extern void mousetrack(int, int, int);
extern Point mousexy(void);

extern void mouseaccelerate(char*);
extern int m3mouseputc(void*, int);
extern int mouseputc(void*, int);
extern int mouseswap;

extern Cursorinfo cursor;

/* mouse.c */
extern void mousectl(char*);

/* screen.c */
extern void flushmemscreen(Rectangle);
extern int cursoron(int);
extern void cursoroff(int);
extern void setcursor(Cursor*);

/*
 * Generic VGA registers.
 */
enum {
	MiscW		= 0x03C2,	/* Miscellaneous Output (W) */
	MiscR		= 0x03CC,	/* Miscellaneous Output (R) */
	Status0		= 0x03C2,	/* Input status 0 (R) */
	Status1		= 0x03DA,	/* Input Status 1 (R) */
	FeatureR	= 0x03CA,	/* Feature Control (R) */
	FeatureW	= 0x03DA,	/* Feature Control (W) */

	Seqx		= 0x03C4,	/* Sequencer Index, Data at Seqx+1 */
	Crtx		= 0x03D4,	/* CRT Controller Index, Data at Crtx+1 */
	Grx		= 0x03CE,	/* Graphics Controller Index, Data at Grx+1 */
	Attrx		= 0x03C0,	/* Attribute Controller Index and Data */

	PaddrW		= 0x03C8,	/* Palette Address Register, write */
	Pdata		= 0x03C9,	/* Palette Data Register */
	Pixmask		= 0x03C6,	/* Pixel Mask Register */
	PaddrR		= 0x03C7,	/* Palette Address Register, read */
	Pstatus		= 0x03C7,	/* DAC Status (RO) */

	Pcolours	= 256,		/* Palette */
	Pred		= 0,
	Pgreen		= 1,
	Pblue		= 2,

	Pblack		= 0x00,
	Pwhite		= 0xFF,
};

#define vgai(port)		inb(port)
#define vgao(port, data)	outb(port, data)

extern int vgaxi(long, uchar);
extern int vgaxo(long, uchar, uchar);

/*
 *  mouse types
 */
enum
{
	Mouseother=	0,
	Mouseserial=	1,
	MousePS2=	2,
typedef struct VGAdev VGAdev;
typedef struct VGAcur VGAcur;
typedef struct VGAscr VGAscr;

struct VGAdev {
	char*	name;

	void	(*enable)(VGAscr*);
	void	(*disable)(VGAscr*);
	void	(*page)(VGAscr*, int);
	ulong	(*linear)(VGAscr*, int*, int*);
};

struct VGAcur {
	char*	name;

	void	(*enable)(VGAscr*);
	void	(*disable)(VGAscr*);
	void	(*load)(VGAscr*, Cursor*);
	int	(*move)(VGAscr*, Point);
};
extern int	mousetype;

extern void	mousectl(char*);
extern void	mousetrack(int, int, int);
extern Point	mousexy(void);
/*
 */
struct VGAscr {
	Lock	devlock;
	VGAdev*	dev;

extern void	mouseaccelerate(char*);
extern int	m3mouseputc(void*, int);
extern int	mouseputc(void*, int);
extern int	mouseswap;
	VGAcur*	cur;
	ulong	storage;
	Cursor;

	int	useflush;

	ulong	aperture;			/* physical address */
	int	isupamem;
	int	apsize;

	ulong	colormap[Pcolours][3];

	Memimage* gscreen;
	Memdata* gscreendata;
	Memsubfont* memdefont;
};
extern VGAscr vgascreen[];

enum {
	Backgnd		= Pwhite,
};

M pc/scsi.c => pc/scsi.c +1 -1
@@ 82,7 82,7 @@ scsireset(void)
				ctlrno, ctlr->type, ctlr->port,
				ctlr->irq, ctlr->mem, ctlr->size);
			if(ctlr->mem)
				print(" addr 0x%luX", ctlr->mem & ~KZERO);
				print(" addr 0x%luX", PADDR(ctlr->mem));
			if(ctlr->size)
				print(" size 0x%luX", ctlr->size);
			print("\n");

M pc/trap.c => pc/trap.c +68 -60
@@ 11,7 11,6 @@ void	noted(Ureg*, ulong);

static void debugbpt(Ureg*, void*);
static void fault386(Ureg*, void*);
static void syscall(Ureg*, void*);

static Lock irqctllock;
static Irqctl *irqctl[256];


@@ 63,25 62,39 @@ nmienable(void)
void
trapinit(void)
{
	int v, pri;
	int d1, v;
	ulong vaddr;
	Segdesc *idt;

	idt = (Segdesc*)IDTADDR;
	vaddr = (ulong)vectortable;
	for(v = 0; v < 256; v++){
		if(v == VectorBPT || v == VectorSYSCALL)
			pri = 3;
		else
			pri = 0;
		d1 = (vaddr & 0xFFFF0000)|SEGP;
		switch(v){

		case VectorBPT:
			d1 |= SEGPL(3)|SEGIG;
			break;

		case VectorSYSCALL:
			d1 |= SEGPL(3)|SEGTG;
			break;

		default:
			d1 |= SEGPL(0)|SEGIG;
			break;
		}
		idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16);
		idt[v].d1 = (vaddr & 0xFFFF0000)|SEGP|SEGPL(pri)|SEGIG;
		idt[v].d1 = d1;
		vaddr += 6;
	}

	/*
	 * Special traps.
	 * Syscall() is called directly without going through trap().
	 */
	intrenable(VectorBPT, debugbpt, 0, BUSUNKNOWN);
	intrenable(VectorPF, fault386, 0, BUSUNKNOWN);
	intrenable(VectorSYSCALL, syscall, 0, BUSUNKNOWN);

	nmienable();
}


@@ 113,7 126,8 @@ static int nspuriousintr;
/*
 *  All traps come here.  It is slower to have all traps call trap() rather than
 *  directly vectoring the handler.  However, this avoids a lot of code duplication
 *  and possible bugs.  trap is called splhi().
 *  and possible bugs.  The only exception is VectorSYSCALL.
 *  Trap is called with interrupts disabled via interrupt-gates.
 */
void
trap(Ureg* ureg)


@@ 123,16 137,19 @@ trap(Ureg* ureg)
	Irqctl *ctl;
	Irq *irq;

	user = (ureg->cs & 0xFFFF) == UESEL;
	if(user)
	user = 0;
	if((ureg->cs & 0xFFFF) == UESEL){
		user = 1;
		up->dbgreg = ureg;
	}

	v = ureg->trap;
	if(ctl = irqctl[v]){
		if(ctl->isintr)
		if(ctl->isintr){
			m->intr++;
		if(ctl->isr)
			ctl->isr(v);
			if(ctl->isr)
				ctl->isr(v);
		}

		for(irq = ctl->irq; irq; irq = irq->next)
			irq->f(ureg, irq->a);


@@ 171,12 188,10 @@ trap(Ureg* ureg)
		panic("unknown trap/intr: %d\n", v);
	}

	/*
	 *  check user since syscall does its own notifying
	 */
	splhi();
	if(v != VectorSYSCALL && user && (up->procctl || up->nnote))
	if(user && (up->procctl || up->nnote)){
		splhi();
		notify(ureg);
	}
}

/*


@@ 185,12 200,6 @@ trap(Ureg* ureg)
void
dumpregs2(Ureg* ureg)
{
	ureg->cs &= 0xFFFF;
	ureg->ds &= 0xFFFF;
	ureg->es &= 0xFFFF;
	ureg->fs &= 0xFFFF;
	ureg->gs &= 0xFFFF;

	if(up)
		print("cpu%d: registers for %s %d\n", m->machno, up->text, up->pid);
	else


@@ 203,7 212,8 @@ dumpregs2(Ureg* ureg)
	print("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",
		ureg->si, ureg->di, ureg->bp);
	print("  CS %4.4uX  DS %4.4uX  ES %4.4uX  FS %4.4uX  GS %4.4uX\n",
		ureg->cs, ureg->ds, ureg->es, ureg->fs, ureg->gs);
		ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF,
		ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);
}

void


@@ 248,8 258,12 @@ dumpstack(void)
	for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){
		v = *(ulong*)l;
		if(KTZERO < v && v < (ulong)&etext){
			/*
			 * Pick off general CALL (0xE8) and CALL indirect
			 * through AX (0xFFD0).
			 */
			p = (uchar*)v;
			if(*(p-5) == 0xE8){
			if(*(p-5) == 0xE8 || (*(p-2) == 0xFF && *(p-1) == 0xD0)){
				print("%lux ", p-5);
				i++;
			}


@@ 309,59 323,53 @@ fault386(Ureg* ureg, void*)
#include "../port/systab.h"

/*
 *  syscall is called splhi()
 *  Syscall is called directly from assembler without going through trap().
 */
static void
syscall(Ureg* ureg, void*)
void
syscall(Ureg* ureg)
{
	ulong	sp;
	long	ret;
	int	i;
	int	i, scallnr;

	if((ureg->cs & 0xFFFF) != UESEL)
		panic("syscall: cs 0x%4.4uX\n", ureg->cs);

	m->syscall++;
	up->insyscall = 1;
	up->pc = ureg->pc;
	up->dbgreg = ureg;

	if((ureg->cs)&0xffff == KESEL)
		panic("recursive system call");

	up->scallnr = ureg->ax;
	if(up->scallnr == RFORK && up->fpstate == FPactive){
		/*
		 *  so that the child starts out with the
		 *  same registers as the parent.
		 *  this must be atomic relative to this CPU, hence
		 *  the spl's.
		 */
		if(up->fpstate == FPactive){
			fpsave(&up->fpsave);
			up->fpstate = FPinactive;
		}
	scallnr = ureg->ax;
	up->scallnr = scallnr;
	if(scallnr == RFORK && up->fpstate == FPactive){
		splhi();
		fpsave(&up->fpsave);
		up->fpstate = FPinactive;
		spllo();
	}
	spllo();

	sp = ureg->usp;
	up->nerrlab = 0;
	ret = -1;
	if(!waserror()){
		if(up->scallnr >= nsyscall){
			pprint("bad sys call number %d pc %lux\n", up->scallnr, ureg->pc);
		if(scallnr >= nsyscall){
			pprint("bad sys call number %d pc %lux\n", scallnr, ureg->pc);
			postnote(up, 1, "sys: bad sys call", NDebug);
			error(Ebadarg);
		}

		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-(1+MAXSYSARG)*BY2WD))
			validaddr(sp, (1+MAXSYSARG)*BY2WD, 0);
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
			validaddr(sp, sizeof(Sargs)+BY2WD, 0);

		up->s = *((Sargs*)(sp+1*BY2WD));
		up->psstate = sysctab[up->scallnr];
		up->s = *((Sargs*)(sp+BY2WD));
		up->psstate = sysctab[scallnr];

		ret = systab[up->scallnr](up->s.args);
		ret = systab[scallnr](up->s.args);
		poperror();
	}
	if(up->nerrlab){
		print("bad errstack [%d]: %d extra\n", up->scallnr, up->nerrlab);
		print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
		for(i = 0; i < NERR; i++)
			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
		panic("error stack");


@@ 371,20 379,20 @@ syscall(Ureg* ureg, void*)
	up->psstate = 0;

	/*
	 *  Put return value in frame.  On the safari the syscall is
	 *  Put return value in frame.  On the x86 the syscall is
	 *  just another trap and the return value from syscall is
	 *  ignored.  On other machines the return value is put into
	 *  the results register by caller of syscall.
	 */
	ureg->ax = ret;

	if(up->scallnr == NOTED)
	if(scallnr == NOTED)
		noted(ureg, *(ulong*)(sp+BY2WD));
	splhi();

	if(up->scallnr!=RFORK && (up->procctl || up->nnote))
	if(scallnr!=RFORK && (up->procctl || up->nnote)){
		splhi();
		notify(ureg);

	}
}

/*

M pc/vga.c => pc/vga.c +137 -726
@@ 1,567 1,158 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"

#include	<libg.h>
#include	<gnot.h>
#include	"screen.h"
#include	"vga.h"

#define	MINX	8

struct{
	Point	pos;
	int	bwid;
}out;

/* imported */
extern	GSubfont defont0;
extern	Cursor arrow;
extern	GBitmap cursorback;

/* exported */
GSubfont *defont;
int islittle = 1;		/* little endian bit ordering in bytes */
GBitmap	gscreen;

/* local */
static	Lock vgalock;
static	GBitmap	vgascreen;
static	ulong colormap[256][3];
static	int cga = 1;		/* true if in cga mode */

/*
 *  screen dimensions
 */
#define MAXX	640
#define MAXY	480

/*
 *  'soft' screen bitmap
 */

typedef struct VGAmode	VGAmode;
struct VGAmode
{
	uchar	general[2];
	uchar	sequencer[5];
	uchar	crt[0x19];
	uchar	graphics[9];
	uchar	attribute[0x15];
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"

#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"

static ulong backbits = (Backgnd<<24)|(Backgnd<<16)|(Backgnd<<8)|Backgnd;
static Memdata backdata = {
	nil,
	&backbits
};

/*
 *  640x480 display, 1, 2, or 4 bit color.
 */
VGAmode mode12 = 
{
	/* general */
	0xe7, 0x00,
	/* sequence */
	0x03, 0x01, 0x0f, 0x00, 0x06,
	/* crt */
	0x65, 0x4f, 0x50, 0x88, 0x55, 0x9a, 0x09, 0x3e,
	0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xe8, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
	0xff,
	/* graphics */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
	0xff,
	/* attribute */
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
	0x01, 0x10, 0x0f, 0x00, 0x00,
static Memimage xback = {
	{ 0, 0, 1, 1 },
	{ -100000, -100000, 100000, 100000 },
	3,
	1,
	&backdata,
	0,
	1
};
static Memimage* back = &xback;

/*
 *  320x200 display, 8 bit color.
 */
VGAmode mode13 = 
{
	/* general */
	0x63, 0x00,
	/* sequence */
	0x03, 0x01, 0x0f, 0x00, 0x0e,
	/* crt */
	0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
	0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28,
	0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
	0xff,
	/* graphics */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
	0xff,
	/* attribute */
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
	0x41, 0x10, 0x0f, 0x00, 0x00,
static ulong consbits = 0;
static Memdata consdata = {
	nil,
	&consbits
};
static Memimage conscol = {
	{ 0, 0, 1, 1 },
	{ -100000, -100000, 100000, 100000 },
	3,
	1,
	&consdata,
	0,
	1
};

static Rectangle mbb;
static Rectangle NULLMBB = {10000, 10000, -10000, -10000};

void
genout(int reg, int val)
{
	if(reg == 0)
		outb(EMISCW, val);
	else if (reg == 1)
		outb(EFCW, val);
}
void
srout(int reg, int val)
{
	outb(SRX, reg);
	outb(SR, val);
}
void
grout(int reg, int val)
{
	outb(GRX, reg);
	outb(GR, val);
}
void
arout(int reg, int val)
{
	inb(0x3DA);
	if (reg <= 0xf) {
		outb(ARW, reg | 0x0);
		outb(ARW, val);
		inb(0x3DA);
		outb(ARW, reg | 0x20);
	} else {
		outb(ARW, reg | 0x20);
		outb(ARW, val);
	}
}

void
crout(int reg, int val)
{
	outb(CRX, reg);
	outb(CR, val);
}

void
setmode(VGAmode *v)
{
	int i;

	/* turn screen off (to avoid damage) */
	srout(1, 0x21);

	for(i = 0; i < sizeof(v->general); i++)
		genout(i, v->general[i]);

	for(i = 0; i < sizeof(v->sequencer); i++)
		if(i == 1)
			srout(i, v->sequencer[i]|0x20);		/* avoid enabling screen */
		else
			srout(i, v->sequencer[i]);

	crout(Cvre, 0);	/* allow writes to CRT registers 0-7 */
	for(i = 0; i < sizeof(v->crt); i++)
		crout(i, v->crt[i]);

	for(i = 0; i < sizeof(v->graphics); i++)
		grout(i, v->graphics[i]);

	for(i = 0; i < sizeof(v->attribute); i++)
		arout(i, v->attribute[i]);

	/* turn screen on */
	srout(1, v->sequencer[1]);
}

void
getmode(VGAmode *v) {
	int i;
	v->general[0] = inb(0x3cc);
	v->general[1] = inb(0x3ca);
	for(i = 0; i < sizeof(v->sequencer); i++) {
		outb(SRX, i);
		v->sequencer[i] = inb(SR);
	}
	for(i = 0; i < sizeof(v->crt); i++) {
		outb(CRX, i);
		v->crt[i] = inb(CR);
	}
	for(i = 0; i < sizeof(v->graphics); i++) {
		outb(GRX, i);
		v->graphics[i] = inb(GR);
	}
	for(i = 0; i < sizeof(v->attribute); i++) {
		inb(0x3DA);
		outb(ARW, i | 0x20);
		v->attribute[i] = inb(ARR);
	}
}

void
printmode(VGAmode *v) {
	int i;
	print("g %2.2x %2x\n",
		v->general[0], v->general[1]);

	print("s ");
	for(i = 0; i < sizeof(v->sequencer); i++) {
		print(" %2.2x", v->sequencer[i]);
	}

	print("\nc ");
	for(i = 0; i < sizeof(v->crt); i++) {
		print(" %2.2x", v->crt[i]);
	}

	print("\ng ");
	for(i = 0; i < sizeof(v->graphics); i++) {
		print(" %2.2x", v->graphics[i]);
	}

	print("\na ");
	for(i = 0; i < sizeof(v->attribute); i++) {
		print(" %2.2x", v->attribute[i]);
	}
	print("\n");
}

/*
 *  expand 3 and 6 bits of color to 32
 */
static ulong
x3to32(uchar x)
{
	ulong y;

	x = x&7;
	x= (x<<3)|x;
	y = (x<<(32-6))|(x<<(32-12))|(x<<(32-18))|(x<<(32-24))|(x<<(32-30));
	return y;
}
static ulong
x6to32(uchar x)
{
	ulong y;

	x = x&0x3f;
	y = (x<<(32-6))|(x<<(32-12))|(x<<(32-18))|(x<<(32-24))|(x<<(32-30));
	return y;
}

void
setscreen(int maxx, int maxy, int ldepth)
{
	int len, vgamaxy, width, i, x;
	uchar *p;

	if(ldepth == 3)
		setmode(&mode13);
	else
		setmode(&mode12);

	/* allocate a new soft bitmap area */
	width = (maxx*(1<<ldepth))/32;
	len = width * BY2WD * maxy;
	p = xalloc(len);
	if(p == 0)
		panic("can't alloc screen bitmap");
	mbb = NULLMBB;

	/*
	 *  zero hard screen and setup a bitmap for the new size
	 */
	if(ldepth == 3)
		vgascreen.ldepth = 3;
	else
		vgascreen.ldepth = 0;
	vgascreen.width = (maxx*(1<<vgascreen.ldepth))/32;
	if(maxy > (64*1024)/(vgascreen.width*BY2WD))
		vgamaxy = (64*1024)/(vgascreen.width*BY2WD);
	else
		vgamaxy = maxy;
	vgascreen.base = (void*)SCREENMEM;
	vgascreen.r.min = Pt(0, 0);
	vgascreen.r.max = Pt(maxx, vgamaxy);
	vgascreen.clipr = vgascreen.r;
	memset(vgascreen.base, 0xff, vgascreen.width * BY2WD * vgamaxy);

	/*
	 *  setup new soft screen, free memory for old screen
	 */
	if(gscreen.base)
		xfree(gscreen.base);
	gscreen.ldepth = ldepth;
	gscreen.width = width;
	gscreen.r.min = Pt(0, 0);
	gscreen.r.max = Pt(maxx, maxy);
	gscreen.clipr = gscreen.r;
	gscreen.base = (ulong*)p;
	memset(gscreen.base, 0xff, len);

	/*
	 *  set depth of cursor backup area
	 */
	bitdepth();

	/*
	 *  set string pointer to upper left
	 */
	out.pos.x = MINX;
	out.pos.y = 0;
	out.bwid = defont0.info[' '].width;

	/*
	 *  default color map
	 */
	switch(ldepth){
	case 3:
		for(i = 0; i < 256; i++)
			setcolor(i, x3to32(i>>5), x3to32(i>>2), x3to32(i<<1));
		break;
	case 2:
	case 1:
	case 0:
		gscreen.ldepth = 3;
		for(i = 0; i < 16; i++){
			x = x6to32((i*63)/15);
			setcolor(i, x, x, x);
		}
		gscreen.ldepth = ldepth;
		break;
	}
	cga = 0;
}
static Point curpos;
static Rectangle window;
static int *xp;
static int xbuf[256];
static Lock vgascreenlock;

void
screeninit(void)
static void
vgascroll(VGAscr* scr)
{
	int i;
	ulong *l;

	/*
	 *  arrow is defined as a big endian
	 */
	pixreverse(arrow.set, 2*16, 0);
	pixreverse(arrow.clr, 2*16, 0);

	/*
	 *  swizzle the font longs.  we do both byte and bit swizzling
	 *  since the font is initialized with big endian longs.
	 */
	defont = &defont0;
	l = defont->bits->base;
	for(i = defont->bits->width*Dy(defont->bits->r); i > 0; i--, l++)
		*l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24);
	pixreverse((uchar*)defont->bits->base,
		defont->bits->width*BY2WD*Dy(defont->bits->r), 0);

	cga = 1;
	crout(0x0a, 0xff);		/* turn off cursor */
	memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT);
}
	int h, o;
	Point p;
	Rectangle r;

/*
 *  collect changes to the 'soft' screen
 */
void
mbbrect(Rectangle r)
{
	if (r.min.x < mbb.min.x)
		mbb.min.x = r.min.x;
	if (r.min.y < mbb.min.y)
		mbb.min.y = r.min.y;
	if (r.max.x > mbb.max.x)
		mbb.max.x = r.max.x;
	if (r.max.y > mbb.max.y)
		mbb.max.y = r.max.y;
	if (Dy(mbb) > 32 || Dx(mbb) > 32)
		mousescreenupdate();
}
	h = scr->memdefont->height;
	o = 8*h;
	r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
	p = Pt(window.min.x, window.min.y+o);
	memimagedraw(scr->gscreen, r, scr->gscreen, p, memones, p);
	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
	memimagedraw(scr->gscreen, r, back, ZP, memones, ZP);

void
mbbpt(Point p)
{
	if (p.x < mbb.min.x)
		mbb.min.x = p.x;
	if (p.y < mbb.min.y)
		mbb.min.y = p.y;
	if (p.x >= mbb.max.x)
		mbb.max.x = p.x+1;
	if (p.y >= mbb.max.y)
		mbb.max.y = p.y+1;
	curpos.y -= o;
}

/*
 *  copy litte endian soft screen to big endian hard screen
 */
static void
vgaupdate(void)
vgascreenputc(VGAscr* scr, char* buf, Rectangle *flushr)
{
	uchar *sp, *hp, *edisp;
	int y, len, incs, inch, off, page;
	Point p;
	int h, w, pos;
	Rectangle r;
	void* (*f)(void*, void*, long);

	r = mbb;
	mbb = NULLMBB;

	if(Dy(r) < 0)
		return;

	if(r.min.x < 0)
		r.min.x = 0;
	if(r.min.y < 0)
		r.min.y = 0;
	if(r.max.x > gscreen.r.max.x)
		r.max.x = gscreen.r.max.x;
	if(r.max.y > gscreen.r.max.y)
		r.max.y = gscreen.r.max.y;
	if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
		xp = xbuf;

	incs = gscreen.width * BY2WD;
	inch = vgascreen.width * BY2WD;
	h = scr->memdefont->height;
	switch(buf[0]){

	off = r.min.y * vgascreen.width * BY2WD + (r.min.x>>(3 - vgascreen.ldepth));
	page = off>>16;
	off &= (1<<16)-1;
	hp = ((uchar*)vgascreen.base) + off;
	off = r.min.y * gscreen.width * BY2WD + (r.min.x>>(3 - gscreen.ldepth));
	sp = ((uchar*)gscreen.base) + off;

	switch(gscreen.ldepth){
	case 0:
		f = l0update;
		len = (r.max.x + 7)/8 - r.min.x/8;
	case '\n':
		if(curpos.y+h >= window.max.y){
			vgascroll(scr);
			*flushr = window;
		}
		curpos.y += h;
		vgascreenputc(scr, "\r", flushr);
		break;
	case 1:
		f = l1update;
		len = (r.max.x + 15)/8 - r.min.x/8;

	case '\r':
		xp = xbuf;
		curpos.x = window.min.x;
		break;
	case 2:
		f = l2update;
		len = (r.max.x + 7)/8 - r.min.x/8;

	case '\t':
		p = memsubfontwidth(scr->memdefont, " ");
		w = p.x;
		*xp++ = curpos.x;
		pos = (curpos.x-window.min.x)/w;
		pos = 4-(pos%4);
		r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y+h);
		memimagedraw(scr->gscreen, r, back, back->r.min, memones, back->r.min);
		bbox(flushr, r);
		curpos.x += pos*w;
		break;
	case 3:
		f = memmove;
		len = r.max.x - r.min.x;

	case '\b':
		if(xp <= xbuf)
			break;
		xp--;
		r = Rect(*xp, curpos.y, curpos.x, curpos.y+h);
		memimagedraw(scr->gscreen, r, back, back->r.min, memones, back->r.min);
		bbox(flushr, r);
		curpos.x = *xp;
		break;
	default:
		return;
	}
	if(len < 1)
		return;

	edisp = ((uchar*)vgascreen.base) + 64*1024;
	outb(0x3cd, (page<<4)|page);
	for(y = r.min.y; y < r.max.y; y++){
		if(hp + inch < edisp){
			f(hp, sp, len);
			sp += incs;
			hp += inch;
		} else {
			off = edisp - hp;
			if(off <= len){
				if(off > 0)
					f(hp, sp, off);
				page++;
				outb(0x3cd, (page<<4)|page);
				if(len - off > 0)
					f(vgascreen.base, sp+off, len - off);
			} else {
				f(hp, sp, len);
				page++;
				outb(0x3cd, (page<<4)|page);
			}
			sp += incs;
			hp += inch - 64*1024;
		}
	}
}
	default:
		p = memsubfontwidth(scr->memdefont, buf);
		w = p.x;

void
screenupdate(void)
{
	lock(&vgalock);
	vgaupdate();
	unlock(&vgalock);
}
		if(curpos.x >= window.max.x-w)
			vgascreenputc(scr, "\n", flushr);

void
mousescreenupdate(void)
{
	if(canlock(&vgalock)){
		vgaupdate();
		unlock(&vgalock);
		*xp++ = curpos.x;
		r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y+h);
		memimagedraw(scr->gscreen, r, back, back->r.min, memones, back->r.min);
		memimagestring(scr->gscreen, curpos, &conscol, scr->memdefont, buf);
		bbox(flushr, r);
		curpos.x += w;
	}
}

static void
cgascreenputc(int c)
vgascreenputs(char* s, int n)
{
	int i;
	static int color;
	static int pos;

	if(c == '\n'){
		pos = pos/CGAWIDTH;
		pos = (pos+1)*CGAWIDTH;
	} else if(c == '\t'){
		i = 8 - ((pos/2)&7);
		while(i-->0)
			cgascreenputc(' ');
	} else if(c == '\b'){
		if(pos >= 2)
			pos -= 2;
		cgascreenputc(' ');
		pos -= 2;
	} else {
		CGASCREEN[pos++] = c;
		CGASCREEN[pos++] = 2;	/* green on black */
	}
	if(pos >= CGAWIDTH*CGAHEIGHT){
		memmove(CGASCREEN, &CGASCREEN[CGAWIDTH], CGAWIDTH*(CGAHEIGHT-1));
		memset(&CGASCREEN[CGAWIDTH*(CGAHEIGHT-1)], 0, CGAWIDTH);
		pos = CGAWIDTH*(CGAHEIGHT-1);
	}
}

void
cgascreenputs(char *s, int n)
{
	while(n-- > 0)
		cgascreenputc(*s++);
}

void
screenputnl(void)
{
	Rectangle r;

	out.pos.x = MINX;
	out.pos.y += defont0.height;
	if(out.pos.y > gscreen.r.max.y-defont0.height){
		vgaupdate();
		out.pos.y = gscreen.r.min.y;
	}
	r = Rect(0, out.pos.y, gscreen.r.max.x, out.pos.y+2*defont0.height);
	gbitblt(&gscreen, r.min, &gscreen, r, flipD[0]);
	mbbrect(r);
	vgaupdate();
}

void
screenputs(char *s, int n)
{
	Rune r;
	int i;
	char buf[4];
	Rectangle rect;
	VGAscr *scr;
	Rectangle flushr;

	scr = &vgascreen[0];

	if(cga) {
		cgascreenputs(s, n);
		return;
	if(!islo()){
		/*
		 * Don't deadlock trying to
		 * print in an interrupt.
		 */
		if(!canlock(&vgascreenlock))
			return;
	}
	else
		lock(&vgascreenlock);

	flushr = Rect(10000, 10000, -10000, -10000);

	while(n > 0){
		i = chartorune(&r, s);


@@ 574,209 165,29 @@ screenputs(char *s, int n)
		buf[i] = 0;
		n -= i;
		s += i;
		if(r == '\n')
			screenputnl();
		else if(r == '\t'){
			out.pos.x += (8-((out.pos.x-MINX)/out.bwid&7))*out.bwid;
			if(out.pos.x >= gscreen.r.max.x)
				screenputnl();
		}else if(r == '\b'){
			if(out.pos.x >= out.bwid+MINX){
				out.pos.x -= out.bwid;
				gsubfstring(&gscreen, out.pos, defont, " ", flipD[S]);
			}
			rect.min = Pt(out.pos.x, out.pos.y);
			rect.max = Pt(out.pos.x+out.bwid, out.pos.y+defont0.height);
			mbbrect(rect);
		}else{
			if(out.pos.x >= gscreen.r.max.x-out.bwid)
				screenputnl();
			rect.min = Pt(out.pos.x, out.pos.y);
			rect.max = Pt(out.pos.x+out.bwid, out.pos.y+defont0.height);
			out.pos = gsubfstring(&gscreen, out.pos, defont, buf, flipD[S]);
			mbbrect(rect);
		}
		vgascreenputc(scr, buf, &flushr);
	}
	vgaupdate();
}
	flushmemscreen(flushr);

int
screenbits(void)
{
	return 1<<gscreen.ldepth;	/* bits per pixel */
	unlock(&vgascreenlock);
}

void
getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
vgascreenwin(VGAscr* scr)
{
	p &= (1<<(1<<gscreen.ldepth))-1;
	lock(&vgalock);
	*pr = colormap[p][0];
	*pg = colormap[p][1];
	*pb = colormap[p][2];
	unlock(&vgalock);
}

int
setcolor(ulong p, ulong r, ulong g, ulong b)
{
	p &= (1<<(1<<gscreen.ldepth))-1;
	lock(&vgalock);
	colormap[p][0] = r;
	colormap[p][1] = g;
	colormap[p][2] = b;
	outb(CMWX, p);
	outb(CM, r>>(32-6));
	outb(CM, g>>(32-6));
	outb(CM, b>>(32-6));
	unlock(&vgalock);
	return ~0;
}

int
hwcursset(uchar *s, uchar *c, int ox, int oy)
{
	USED(s, c, ox, oy);
	return 0;
}

int
hwcursmove(int x, int y)
{
	USED(x, y);
	return 0;
}
	int h, w;

void
mouseclock(void)
{
	spllo();	/* so we don't cause lost chars on the uart */
	mouseupdate(1);
}
	h = scr->memdefont->height;
	w = scr->memdefont->info[' '].width;

/*
 *  a fatter than usual cursor for the safari
 */
Cursor fatarrow = {
	{ -1, -1 },
	{
		0xff, 0xff, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0c, 
		0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, 
		0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8c, 0x04, 
		0x92, 0x08, 0x91, 0x10, 0xa0, 0xa0, 0xc0, 0x40, 
	},
	{
		0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf0, 
		0x7f, 0xe0, 0x7f, 0xe0, 0x7f, 0xf0, 0x7f, 0xf8, 
		0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfc, 0x73, 0xf8, 
		0x61, 0xf0, 0x60, 0xe0, 0x40, 0x40, 0x00, 0x00, 
	},
};
	window.min = Pt(48, 48);
	window.max = addpt(window.min, Pt(10+w*80, 10+h*50));
	if(window.max.y >= scr->gscreen->r.max.y)
		window.max.y = scr->gscreen->r.max.y-1;
	if(window.max.x >= scr->gscreen->r.max.x)
		window.max.x = scr->gscreen->r.max.x-1;
	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
	curpos = window.min;

void
bigcursor(void)
{
	memmove(&arrow, &fatarrow, sizeof(fatarrow));
	pixreverse(arrow.set, 2*16, 0);
	pixreverse(arrow.clr, 2*16, 0);
	screenputs = vgascreenputs;
}

/*
 *  Table for separating and reversing bits in a ldepth 1 bitmap.
 *  This aids in coverting a little endian ldepth 1 bitmap into the
 *  2 big-endian ldepth 0 bitmaps used for the VGA bit planes.
 *
 *	if the bits in uchar x are labeled
 *		76543210
 *	then l1revsep[x] yields a ushort with bits
 *		________1357________0246
 *	where _ represents a bit whose value is 0.
 *
 *  This table is used by l1update() in l.s.  l1update is implemented
 *  in assembler for speed.
 *
 */
ulong l1revsep[] = {
 0x00000, 0x00008, 0x80000, 0x80008, 0x00004, 0x0000c, 0x80004, 0x8000c,
 0x40000, 0x40008, 0xc0000, 0xc0008, 0x40004, 0x4000c, 0xc0004, 0xc000c,
 0x00002, 0x0000a, 0x80002, 0x8000a, 0x00006, 0x0000e, 0x80006, 0x8000e,
 0x40002, 0x4000a, 0xc0002, 0xc000a, 0x40006, 0x4000e, 0xc0006, 0xc000e,
 0x20000, 0x20008, 0xa0000, 0xa0008, 0x20004, 0x2000c, 0xa0004, 0xa000c,
 0x60000, 0x60008, 0xe0000, 0xe0008, 0x60004, 0x6000c, 0xe0004, 0xe000c,
 0x20002, 0x2000a, 0xa0002, 0xa000a, 0x20006, 0x2000e, 0xa0006, 0xa000e,
 0x60002, 0x6000a, 0xe0002, 0xe000a, 0x60006, 0x6000e, 0xe0006, 0xe000e,
 0x00001, 0x00009, 0x80001, 0x80009, 0x00005, 0x0000d, 0x80005, 0x8000d,
 0x40001, 0x40009, 0xc0001, 0xc0009, 0x40005, 0x4000d, 0xc0005, 0xc000d,
 0x00003, 0x0000b, 0x80003, 0x8000b, 0x00007, 0x0000f, 0x80007, 0x8000f,
 0x40003, 0x4000b, 0xc0003, 0xc000b, 0x40007, 0x4000f, 0xc0007, 0xc000f,
 0x20001, 0x20009, 0xa0001, 0xa0009, 0x20005, 0x2000d, 0xa0005, 0xa000d,
 0x60001, 0x60009, 0xe0001, 0xe0009, 0x60005, 0x6000d, 0xe0005, 0xe000d,
 0x20003, 0x2000b, 0xa0003, 0xa000b, 0x20007, 0x2000f, 0xa0007, 0xa000f,
 0x60003, 0x6000b, 0xe0003, 0xe000b, 0x60007, 0x6000f, 0xe0007, 0xe000f,
 0x10000, 0x10008, 0x90000, 0x90008, 0x10004, 0x1000c, 0x90004, 0x9000c,
 0x50000, 0x50008, 0xd0000, 0xd0008, 0x50004, 0x5000c, 0xd0004, 0xd000c,
 0x10002, 0x1000a, 0x90002, 0x9000a, 0x10006, 0x1000e, 0x90006, 0x9000e,
 0x50002, 0x5000a, 0xd0002, 0xd000a, 0x50006, 0x5000e, 0xd0006, 0xd000e,
 0x30000, 0x30008, 0xb0000, 0xb0008, 0x30004, 0x3000c, 0xb0004, 0xb000c,
 0x70000, 0x70008, 0xf0000, 0xf0008, 0x70004, 0x7000c, 0xf0004, 0xf000c,
 0x30002, 0x3000a, 0xb0002, 0xb000a, 0x30006, 0x3000e, 0xb0006, 0xb000e,
 0x70002, 0x7000a, 0xf0002, 0xf000a, 0x70006, 0x7000e, 0xf0006, 0xf000e,
 0x10001, 0x10009, 0x90001, 0x90009, 0x10005, 0x1000d, 0x90005, 0x9000d,
 0x50001, 0x50009, 0xd0001, 0xd0009, 0x50005, 0x5000d, 0xd0005, 0xd000d,
 0x10003, 0x1000b, 0x90003, 0x9000b, 0x10007, 0x1000f, 0x90007, 0x9000f,
 0x50003, 0x5000b, 0xd0003, 0xd000b, 0x50007, 0x5000f, 0xd0007, 0xd000f,
 0x30001, 0x30009, 0xb0001, 0xb0009, 0x30005, 0x3000d, 0xb0005, 0xb000d,
 0x70001, 0x70009, 0xf0001, 0xf0009, 0x70005, 0x7000d, 0xf0005, 0xf000d,
 0x30003, 0x3000b, 0xb0003, 0xb000b, 0x30007, 0x3000f, 0xb0007, 0xb000f,
 0x70003, 0x7000b, 0xf0003, 0xf000b, 0x70007, 0x7000f, 0xf0007, 0xf000f,
};

/*
 *  Table for separating and reversing bits in a ldepth 2 bitmap.
 *  This aids in coverting a little endian ldepth 1 bitmap into the
 *  4 big-endian ldepth 0 bitmaps used for the VGA bit planes.
 *
 *	if the bits in uchar x are labeled
 *		76543210
 *	then l1revsep[x] yields a ushort with bits
 *		______37______26______15______04
 *	where _ represents a bit whose value is 0.
 *
 *  This table is used by l2update() in l.s.  l2update is implemented
 *  in assembler for speed.
 *
 */
ulong l2revsep[] = {
 0x0000000, 0x0000002, 0x0000200, 0x0000202, 0x0020000, 0x0020002, 0x0020200, 0x0020202,
 0x2000000, 0x2000002, 0x2000200, 0x2000202, 0x2020000, 0x2020002, 0x2020200, 0x2020202,
 0x0000001, 0x0000003, 0x0000201, 0x0000203, 0x0020001, 0x0020003, 0x0020201, 0x0020203,
 0x2000001, 0x2000003, 0x2000201, 0x2000203, 0x2020001, 0x2020003, 0x2020201, 0x2020203,
 0x0000100, 0x0000102, 0x0000300, 0x0000302, 0x0020100, 0x0020102, 0x0020300, 0x0020302,
 0x2000100, 0x2000102, 0x2000300, 0x2000302, 0x2020100, 0x2020102, 0x2020300, 0x2020302,
 0x0000101, 0x0000103, 0x0000301, 0x0000303, 0x0020101, 0x0020103, 0x0020301, 0x0020303,
 0x2000101, 0x2000103, 0x2000301, 0x2000303, 0x2020101, 0x2020103, 0x2020301, 0x2020303,
 0x0010000, 0x0010002, 0x0010200, 0x0010202, 0x0030000, 0x0030002, 0x0030200, 0x0030202,
 0x2010000, 0x2010002, 0x2010200, 0x2010202, 0x2030000, 0x2030002, 0x2030200, 0x2030202,
 0x0010001, 0x0010003, 0x0010201, 0x0010203, 0x0030001, 0x0030003, 0x0030201, 0x0030203,
 0x2010001, 0x2010003, 0x2010201, 0x2010203, 0x2030001, 0x2030003, 0x2030201, 0x2030203,
 0x0010100, 0x0010102, 0x0010300, 0x0010302, 0x0030100, 0x0030102, 0x0030300, 0x0030302,
 0x2010100, 0x2010102, 0x2010300, 0x2010302, 0x2030100, 0x2030102, 0x2030300, 0x2030302,
 0x0010101, 0x0010103, 0x0010301, 0x0010303, 0x0030101, 0x0030103, 0x0030301, 0x0030303,
 0x2010101, 0x2010103, 0x2010301, 0x2010303, 0x2030101, 0x2030103, 0x2030301, 0x2030303,
 0x1000000, 0x1000002, 0x1000200, 0x1000202, 0x1020000, 0x1020002, 0x1020200, 0x1020202,
 0x3000000, 0x3000002, 0x3000200, 0x3000202, 0x3020000, 0x3020002, 0x3020200, 0x3020202,
 0x1000001, 0x1000003, 0x1000201, 0x1000203, 0x1020001, 0x1020003, 0x1020201, 0x1020203,
 0x3000001, 0x3000003, 0x3000201, 0x3000203, 0x3020001, 0x3020003, 0x3020201, 0x3020203,
 0x1000100, 0x1000102, 0x1000300, 0x1000302, 0x1020100, 0x1020102, 0x1020300, 0x1020302,
 0x3000100, 0x3000102, 0x3000300, 0x3000302, 0x3020100, 0x3020102, 0x3020300, 0x3020302,
 0x1000101, 0x1000103, 0x1000301, 0x1000303, 0x1020101, 0x1020103, 0x1020301, 0x1020303,
 0x3000101, 0x3000103, 0x3000301, 0x3000303, 0x3020101, 0x3020103, 0x3020301, 0x3020303,
 0x1010000, 0x1010002, 0x1010200, 0x1010202, 0x1030000, 0x1030002, 0x1030200, 0x1030202,
 0x3010000, 0x3010002, 0x3010200, 0x3010202, 0x3030000, 0x3030002, 0x3030200, 0x3030202,
 0x1010001, 0x1010003, 0x1010201, 0x1010203, 0x1030001, 0x1030003, 0x1030201, 0x1030203,
 0x3010001, 0x3010003, 0x3010201, 0x3010203, 0x3030001, 0x3030003, 0x3030201, 0x3030203,
 0x1010100, 0x1010102, 0x1010300, 0x1010302, 0x1030100, 0x1030102, 0x1030300, 0x1030302,
 0x3010100, 0x3010102, 0x3010300, 0x3010302, 0x3030100, 0x3030102, 0x3030300, 0x3030302,
 0x1010101, 0x1010103, 0x1010301, 0x1010303, 0x1030101, 0x1030103, 0x1030301, 0x1030303,
 0x3010101, 0x3010103, 0x3010301, 0x3010303, 0x3030101, 0x3030103, 0x3030301, 0x3030303,
};

D pc/vga.h => pc/vga.h +0 -69
@@ 1,69 0,0 @@
/*
 * Generic VGA registers.
 */
enum {
	MiscW		= 0x03C2,	/* Miscellaneous Output (W) */
	MiscR		= 0x03CC,	/* Miscellaneous Output (R) */
	Status0		= 0x03C2,	/* Input status 0 (R) */
	Status1		= 0x03DA,	/* Input Status 1 (R) */
	FeatureR	= 0x03CA,	/* Feature Control (R) */
	FeatureW	= 0x03DA,	/* Feature Control (W) */

	Seqx		= 0x03C4,	/* Sequencer Index, Data at Seqx+1 */
	Crtx		= 0x03D4,	/* CRT Controller Index, Data at Crtx+1 */
	Grx		= 0x03CE,	/* Graphics Controller Index, Data at Grx+1 */
	Attrx		= 0x03C0,	/* Attribute Controller Index and Data */

	PaddrW		= 0x03C8,	/* Palette Address Register, write */
	Pdata		= 0x03C9,	/* Palette Data Register */
	Pixmask		= 0x03C6,	/* Pixel Mask Register */
	PaddrR		= 0x03C7,	/* Palette Address Register, read */
	Pstatus		= 0x03C7,	/* DAC Status (RO) */

	Pcolours	= 256,		/* Palette */
	Pred		= 0,
	Pgreen		= 1,
	Pblue		= 2,

	Pblack		= 0x00,
	Pwhite		= 0xFF,
};

#define vgai(port)		inb(port)
#define vgao(port, data)	outb(port, data)

extern int vgaxi(long, uchar);
extern int vgaxo(long, uchar, uchar);

/*
 * Definitions of known VGA controllers.
 */
typedef struct Vgac Vgac;
struct Vgac {
	char	*name;
	void	(*page)(int);
	int	(*linear)(ulong*, ulong*, ulong*);

	Vgac*	link;
};

/*
 * Definition of known hardware graphics cursors.
 */
typedef struct Hwgc Hwgc;
struct Hwgc {
	char*	name;
	void	(*enable)(void);
	void	(*load)(Cursor*);
	int	(*move)(Point);
	void	(*disable)(void);

	Hwgc*	link;
};

extern void addvgaclink(Vgac*);
extern void addhwgclink(Hwgc*);

extern Hwgc *hwgc;

extern Lock palettelock;

M pc/vgaark2000pv.c => pc/vgaark2000pv.c +55 -80
@@ 5,43 5,45 @@
#include "fns.h"
#include "../port/error.h"

#include <libg.h>
#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"
#include "vga.h"

extern Bitmap gscreen;
extern Cursor curcursor;
static int
ark2000pvpageset(VGAscr*, int page)
{
	uchar seq15;

	seq15 = vgaxi(Seqx, 0x15);
	vgaxo(Seqx, 0x15, page);
	vgaxo(Seqx, 0x16, page);

static Lock ark2000pvlock;
static ulong storage;
static Point hotpoint;
	return seq15;
}

static void
setark2000pvpage(int page)
ark2000pvpage(VGAscr* scr, int page)
{
	vgaxo(Seqx, 0x15, page);
	vgaxo(Seqx, 0x16, page);
	lock(&scr->devlock);
	ark2000pvpageset(scr, page);
	unlock(&scr->devlock);
}

static void
disable(void)
ark2000pvdisable(VGAscr*)
{
	uchar seq20;

	lock(&ark2000pvlock);

	seq20 = vgaxi(Seqx, 0x20) & ~0x08;
	vgaxo(Seqx, 0x20, seq20);

	unlock(&ark2000pvlock);
}

static void
enable(void)
ark2000pvenable(VGAscr* scr)
{
	uchar seq20;

	lock(&ark2000pvlock);
	ulong storage;

	/*
	 * Disable the cursor then configure for X-Windows style,


@@ 66,46 68,34 @@ enable(void)
	storage = (vgaxi(Seqx, 0x10)>>6) & 0x03;
	storage = (1024*1024)<<storage;
	storage -= 256;
	scr->storage = storage;
	vgaxo(Seqx, 0x25, 0x3F);

	/*
	 * Enable the cursor.
	 */
	vgaxo(Seqx, 0x20, seq20);

	unlock(&ark2000pvlock);
}

static void
load(Cursor *c)
ark2000pvload(VGAscr* scr, Cursor* curs)
{
	uchar *p;
	int x, y;

	/*
	 * Lock the display memory so we can update the
	 * cursor bitmap if necessary.
	 * If it's the same as the last cursor we loaded,
	 * just make sure it's enabled.
	 */
	lock(&ark2000pvlock);
	if(memcmp(c, &curcursor, sizeof(Cursor)) == 0){
		vgaxo(Seqx, 0x20, vgaxi(Seqx, 0x20)|0x08);
		unlock(&ark2000pvlock);
		return;
	}
	memmove(&curcursor, c, sizeof(Cursor));
	uchar *p, seq10;
	int opage, x, y;

	/*
	 * Is linear addressing turned on? This will determine
	 * how we access the cursor storage.
	 */
	if(vgaxi(Seqx, 0x10) & 0x10)
		p = ((uchar*)gscreen.base) + storage;
	else {
		setark2000pvpage(storage>>16);
		p = ((uchar*)gscreen.base) + (storage & 0xFFFF);
	seq10 = vgaxi(Seqx, 0x10);
	opage = 0;
	p = KADDR(scr->aperture);
	if(!(seq10 & 0x10)){
		opage = ark2000pvpageset(scr, scr->storage>>16);
		p += (scr->storage & 0xFFFF);
	}
	else
		p += scr->storage;

	/*
	 * The cursor is set in X11 mode which gives the following


@@ 122,8 112,8 @@ load(Cursor *c)
	for(y = 0; y < 32; y++){
		for(x = 0; x < 32/8; x++){
			if(x < 16/8 && y < 16){
				*p++ = c->clr[2*y + x]|c->set[2*y + x];
				*p++ = c->set[2*y + x];
				*p++ = curs->clr[2*y + x]|curs->set[2*y + x];
				*p++ = curs->set[2*y + x];
			}
			else {
				*p++ = 0x00;


@@ 132,34 122,34 @@ load(Cursor *c)
		}
	}

	if(!(seq10 & 0x10)){
		ark2000pvpageset(scr, opage);
		unlock(&scr->devlock);
	}

	/*
	 * Set the cursor hotpoint and enable the cursor.
	 * Save the cursor hotpoint.
	 */
	hotpoint = c->offset;

	unlock(&ark2000pvlock);
	scr->offset = curs->offset;
}

static int
move(Point p)
ark2000pvmove(VGAscr* scr, Point p)
{
	int x, xo, y, yo;

	if(canlock(&ark2000pvlock) == 0)
		return 1;

	/*
	 * Mustn't position the cursor offscreen even partially,
	 * or it might disappear. Therefore, if x or y is -ve, adjust the
	 * cursor origins instead.
	 */
	if((x = p.x+hotpoint.x) < 0){
	if((x = p.x+scr->offset.x) < 0){
		xo = -x;
		x = 0;
	}
	else
		xo = 0;
	if((y = p.y+hotpoint.y) < 0){
	if((y = p.y+scr->offset.y) < 0){
		yo = -y;
		y = 0;
	}


@@ 176,38 166,23 @@ move(Point p)
	vgaxo(Seqx, 0x23, (y>>8) & 0x0F);
	vgaxo(Seqx, 0x24, y & 0xFF);

	unlock(&ark2000pvlock);
	return 0;
}

static Hwgc ark2000pvhwgc = {
	"ark2000pvhwgc",
	enable,
	load,
	move,
	disable,
VGAdev vgaark2000pvdev = {
	"ark2000pv",

	0,
};

static void
ark2000pvpage(int page)
{
	lock(&ark2000pvlock);
	setark2000pvpage(page);
	unlock(&ark2000pvlock);
}

static Vgac ark2000pv = {
	"ark2000pv",
	0,
	ark2000pvpage,

	0,
};

void
vgaark2000pvlink(void)
{
	addvgaclink(&ark2000pv);
	addhwgclink(&ark2000pvhwgc);
}
VGAcur vgaark2000pvcur = {
	"ark2000pvhwgc",

	ark2000pvenable,
	ark2000pvdisable,
	ark2000pvload,
	ark2000pvmove,
};

M pc/vgabt485.c => pc/vgabt485.c +74 -97
@@ 5,9 5,10 @@
#include "fns.h"
#include "../port/error.h"

#include <libg.h>
#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"
#include "vga.h"

/*
 * Hardware graphics cursor support for


@@ 103,16 104,71 @@ bt485o(uchar reg, uchar data)
	vgaxo(Crtx, 0x55, crt55);
}

static Point hotpoint;
static void
bt485disable(VGAscr*)
{
	uchar r;

	/*
	 * Disable 
	 *	cursor mode 3;
	 *	cursor control enable for Bt485 DAC;
	 *	the hardware cursor external operation mode.
	 */
	r = bt485i(Cmd2) & ~0x03;
	bt485o(Cmd2, r);

	r = vgaxi(Crtx, 0x45) & ~0x20;
	vgaxo(Crtx, 0x45, r);

	r = vgaxi(Crtx, 0x55) & ~0x20;
	vgaxo(Crtx, 0x55, r);
}

static void
load(Cursor *c)
bt485enable(VGAscr*)
{
	uchar r;
	int x, y;

	/*
	 * Turn cursor off.
	 */
	r = bt485i(Cmd2) & 0xFC;
	bt485o(Cmd2, r);

	lock(&palettelock);
	/*
	 * Overscan colour,
	 * cursor colour 1 (white),
	 * cursor colour 2, 3 (black).
	 */
	bt485o(ColorW, 0x00);
	bt485o(Color, Pwhite); bt485o(Color, Pwhite); bt485o(Color, Pwhite);

	bt485o(Color, Pwhite); bt485o(Color, Pwhite); bt485o(Color, Pwhite);

	bt485o(Color, Pblack); bt485o(Color, Pblack); bt485o(Color, Pblack);
	bt485o(Color, Pblack); bt485o(Color, Pblack); bt485o(Color, Pblack);

	/*
	 * Finally, enable
	 *	the hardware cursor external operation mode;
	 *	cursor control enable for Bt485 DAC.
	 * The #9GXE cards seem to need the 86C928 Bt485 support
	 * enabled in order to work at all in enhanced mode.
	 */

	r = vgaxi(Crtx, 0x55)|0x20;
	vgaxo(Crtx, 0x55, r);

	r = vgaxi(Crtx, 0x45)|0x20;
	vgaxo(Crtx, 0x45, r);
}

static void
bt485load(VGAscr* scr, Cursor* curs)
{
	uchar r;
	int x, y;

	/*
	 * Turn cursor off;


@@ 137,7 193,7 @@ load(Cursor *c)
	for(y = 0; y < 64; y++){
		for(x = 0; x < 64/8; x++){
			if(x < 16/8 && y < 16)
				bt485o(Cram, c->clr[x+y*2]);
				bt485o(Cram, curs->clr[x+y*2]);
			else
				bt485o(Cram, 0x00);
		}


@@ 145,7 201,7 @@ load(Cursor *c)
	for(y = 0; y < 64; y++){
		for(x = 0; x < 64/8; x++){
			if(x < 16/8 && y < 16)
				bt485o(Cram, c->set[x+y*2]);
				bt485o(Cram, curs->set[x+y*2]);
			else
				bt485o(Cram, 0x00);
		}


@@ 155,113 211,34 @@ load(Cursor *c)
	 * Initialise the cursor hot-point
	 * and enable the cursor.
	 */
	hotpoint.x = 64+c->offset.x;
	hotpoint.y = 64+c->offset.y;
	scr->offset.x = 64+curs->offset.x;
	scr->offset.y = 64+curs->offset.y;

	r = (bt485i(Cmd2) & 0xFC)|0x01;
	bt485o(Cmd2, r);

	unlock(&palettelock);
}

static void
enable(void)
{
	uchar r;

	lock(&palettelock);

	/*
	 * Turn cursor off.
	 */
	r = bt485i(Cmd2) & 0xFC;
	bt485o(Cmd2, r);

	/*
	 * Overscan colour,
	 * cursor colour 1 (white),
	 * cursor colour 2, 3 (black).
	 */
	bt485o(ColorW, 0x00);
	bt485o(Color, Pwhite); bt485o(Color, Pwhite); bt485o(Color, Pwhite);

	bt485o(Color, Pwhite); bt485o(Color, Pwhite); bt485o(Color, Pwhite);

	bt485o(Color, Pblack); bt485o(Color, Pblack); bt485o(Color, Pblack);
	bt485o(Color, Pblack); bt485o(Color, Pblack); bt485o(Color, Pblack);

	unlock(&palettelock);

	/*
	 * Finally, enable
	 *	the hardware cursor external operation mode;
	 *	cursor control enable for Bt485 DAC.
	 * The #9GXE cards seem to need the 86C928 Bt485 support
	 * enabled in order to work at all in enhanced mode.
	 */

	r = vgaxi(Crtx, 0x55)|0x20;
	vgaxo(Crtx, 0x55, r);

	r = vgaxi(Crtx, 0x45)|0x20;
	vgaxo(Crtx, 0x45, r);
}

static int
move(Point p)
bt485move(VGAscr* scr, Point p)
{
	int x, y;

	if(canlock(&palettelock) == 0)
		return 1;

	x = p.x+hotpoint.x;
	y = p.y+hotpoint.y;
	x = p.x+scr->offset.x;
	y = p.y+scr->offset.y;

	bt485o(Cxlr, x & 0xFF);
	bt485o(Cxhr, (x>>8) & 0x0F);
	bt485o(Cylr, y & 0xFF);
	bt485o(Cyhr, (y>>8) & 0x0F);

	unlock(&palettelock);
	return 0;
}

static void
disable(void)
{
	uchar r;

	/*
	 * Disable 
	 *	cursor mode 3;
	 *	cursor control enable for Bt485 DAC;
	 *	the hardware cursor external operation mode.
	 */
	lock(&palettelock);
	r = bt485i(Cmd2) & ~0x03;
	bt485o(Cmd2, r);
	unlock(&palettelock);

	r = vgaxi(Crtx, 0x45) & ~0x20;
	vgaxo(Crtx, 0x45, r);

	r = vgaxi(Crtx, 0x55) & ~0x20;
	vgaxo(Crtx, 0x55, r);
}

Hwgc bt485hwgc = {
VGAcur vgabt485cur = {
	"bt485hwgc",
	enable,
	load,
	move,
	disable,

	0,
	bt485enable,
	bt485disable,
	bt485load,
	bt485move,
};

void
vgabt485link(void)
{
	addhwgclink(&bt485hwgc);
}

M pc/vgaclgd542x.c => pc/vgaclgd542x.c +58 -82
@@ 6,58 6,51 @@
#include "io.h"
#include "../port/error.h"

#include <libg.h>
#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"
#include "vga.h"

extern Bitmap gscreen;
extern Cursor curcursor;

static Lock clgd542xlock;
static ulong storage;

static int
setclgd542xpage(int page)
clgd542xpageset(VGAscr*, int page)
{
	uchar gr9;
	uchar gr09;
	int opage;

	
	if(vgaxi(Seqx, 0x07) & 0xF0)
		page = 0;
	gr9 = vgaxi(Grx, 0x09);
	gr09 = vgaxi(Grx, 0x09);
	if(vgaxi(Grx, 0x0B) & 0x20){
		vgaxo(Grx, 0x09, page<<2);
		opage = gr9>>2;
		opage = gr09>>2;
	}
	else{
		vgaxo(Grx, 0x09, page<<4);
		opage = gr9>>4;
		opage = gr09>>4;
	}

	return opage;
}

static void
clgd542xpage(int page)
clgd542xpage(VGAscr* scr, int page)
{
	lock(&clgd542xlock);
	setclgd542xpage(page);
	unlock(&clgd542xlock);
	lock(&scr->devlock);
	clgd542xpageset(scr, page);
	unlock(&scr->devlock);
}

static void
disable(void)
clgd542xdisable(VGAscr*)
{
	uchar sr12;

	lock(&clgd542xlock);
	sr12 = vgaxi(Seqx, 0x12);
	vgaxo(Seqx, 0x12, sr12 & ~0x01);
	unlock(&clgd542xlock);
}

static void
enable(void)
clgd542xenable(VGAscr* scr)
{
	uchar sr12;
	int mem, x;


@@ 65,16 58,22 @@ enable(void)
	/*
	 * Disable the cursor.
	 */
	lock(&clgd542xlock);
	sr12 = vgaxi(Seqx, 0x12);
	vgaxo(Seqx, 0x12, sr12 & ~0x01);

	/*
	 * Cursor colours.  
	 * Cursor colours.
	 * Can't call setcolor here as cursor is already locked.
	 */
	vgaxo(Seqx, 0x12, sr12|0x02);
	setcolor(0x00, Pblack<<(32-6), Pblack<<(32-6), Pblack<<(32-6));
	setcolor(0x0F, Pwhite<<(32-6), Pwhite<<(32-6), Pwhite<<(32-6));
	vgao(PaddrW, 0x00);
	vgao(Pdata, Pwhite);
	vgao(Pdata, Pwhite);
	vgao(Pdata, Pwhite);
	vgao(PaddrW, 0x0F);
	vgao(Pdata, Pblack);
	vgao(Pdata, Pblack);
	vgao(Pdata, Pblack);
	vgaxo(Seqx, 0x12, sr12);

	mem = 0;


@@ 114,7 113,7 @@ enable(void)
	default:				/* uh, ah dunno */
		break;
	}
	storage = ((256<<mem)-16)*1024;
	scr->storage = ((256<<mem)-16)*1024;

	/*
	 * Set the current cursor to index 0


@@ 122,12 121,10 @@ enable(void)
	 */
	vgaxo(Seqx, 0x13, 0);
	vgaxo(Seqx, 0x12, sr12|0x05);

	unlock(&clgd542xlock);
}

static void
initcursor(Cursor* c, int xo, int yo, int index)
clgd542xinitcursor(VGAscr* scr, int xo, int yo, int index)
{
	uchar *p, seq07;
	uint p0, p1;


@@ 139,18 136,19 @@ initcursor(Cursor* c, int xo, int yo, int index)
	 */
	seq07 = vgaxi(Seqx, 0x07);
	opage = 0;
	p = ((uchar*)gscreen.base);
	p = KADDR(scr->aperture);
	if(!(seq07 & 0xF0)){
		opage = setclgd542xpage(storage>>16);
		p += (storage & 0xFFFF);
		lock(&scr->devlock);
		opage = clgd542xpageset(scr, scr->storage>>16);
		p += (scr->storage & 0xFFFF);
	}
	else
		p += storage;
		p += scr->storage;
	p += index*1024;

	for(y = yo; y < 16; y++){
		p0 = c->set[2*y];
		p1 = c->set[2*y+1];
		p0 = scr->set[2*y];
		p1 = scr->set[2*y+1];
		if(xo){
			p0 = (p0<<xo)|(p1>>(8-xo));
			p1 <<= xo;


@@ 161,8 159,8 @@ initcursor(Cursor* c, int xo, int yo, int index)
		for(x = 16; x < 64; x += 8)
			*p++ = 0x00;

		p0 = c->clr[2*y]|c->set[2*y];
		p1 = c->clr[2*y+1]|c->set[2*y+1];
		p0 = scr->clr[2*y]|scr->set[2*y];
		p1 = scr->clr[2*y+1]|scr->set[2*y+1];
		if(xo){
			p0 = (p0<<xo)|(p1>>(8-xo));
			p1 <<= xo;


@@ 181,60 179,46 @@ initcursor(Cursor* c, int xo, int yo, int index)
		y++;
	}

	if(!(seq07 & 0xF0))
		setclgd542xpage(opage);
	if(!(seq07 & 0xF0)){
		clgd542xpageset(scr, opage);
		unlock(&scr->devlock);
	}
}

static void
load(Cursor* c)
clgd542xload(VGAscr* scr, Cursor* curs)
{
	uchar sr12;

	/*
	 * Lock the display memory so we can update the
	 * cursor bitmap if necessary.
	 * Disable the cursor.
	 * If it's the same as the last cursor loaded,
	 * just make sure it's enabled and index 0.
	 */
	lock(&clgd542xlock);
	sr12 = vgaxi(Seqx, 0x12);
	vgaxo(Seqx, 0x12, sr12 & ~0x01);

	if(memcmp(c, &curcursor, sizeof(Cursor)) == 0){
		vgaxo(Seqx, 0x13, 0);
		vgaxo(Seqx, 0x12, sr12|0x05);
		unlock(&clgd542xlock);
		return;
	}
	memmove(&curcursor, c, sizeof(Cursor));
	initcursor(c, 0, 0, 0);
	memmove(&scr->Cursor, curs, sizeof(Cursor));
	clgd542xinitcursor(scr, 0, 0, 0);

	/*
	 * Enable the cursor.
	 */
	vgaxo(Seqx, 0x13, 0);
	vgaxo(Seqx, 0x12, sr12|0x05);

	unlock(&clgd542xlock);
}

static int
move(Point p)
clgd542xmove(VGAscr* scr, Point p)
{
	int index, x, xo, y, yo;

	if(canlock(&clgd542xlock) == 0)
		return 1;

	index = 0;
	if((x = p.x+curcursor.offset.x) < 0){
	if((x = p.x+scr->offset.x) < 0){
		xo = -x;
		x = 0;
	}
	else
		xo = 0;
	if((y = p.y+curcursor.offset.y) < 0){
	if((y = p.y+scr->offset.y) < 0){
		yo = -y;
		y = 0;
	}


@@ 242,7 226,7 @@ move(Point p)
		yo = 0;

	if(xo || yo){
		initcursor(&curcursor, xo, yo, 1);
		clgd542xinitcursor(scr, xo, yo, 1);
		index = 1;
	}
	vgaxo(Seqx, 0x13, index<<2);


@@ 250,31 234,23 @@ move(Point p)
	vgaxo(Seqx, 0x10|((x & 0x07)<<5), (x>>3) & 0xFF);
	vgaxo(Seqx, 0x11|((y & 0x07)<<5), (y>>3) & 0xFF);

	unlock(&clgd542xlock);
	return 0;
}

static Hwgc clgd542xhwgc = {
	"clgd542xhwgc",
	enable,
	load,
	move,
	disable,
VGAdev vgaclgd542xdev = {
	"clgd542x",

	0,
};

static Vgac clgd542x = {
	"clgd542x",
	clgd542xpage,
	0,

	clgd542xpage,
	0,
};

void
vgaclgd542xlink(void)
{
	addvgaclink(&clgd542x);
	addhwgclink(&clgd542xhwgc);
}
VGAcur vgaclgd542xcur = {
	"clgd542xhwgc",

	clgd542xenable,
	clgd542xdisable,
	clgd542xload,
	clgd542xmove,
};

A pc/vgact65545.c => pc/vgact65545.c +147 -0
@@ 0,0 1,147 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"

#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"

static void
ct65545page(VGAscr*, int page)
{
	outb(0x3D6, 0x10);
	outb(0x3D7, page<<6);
}

static void
ct65545disable(VGAscr*)
{
	outl(0xA3D0, 0);
}

static void
ct65545enable(VGAscr* scr)
{
	ulong storage;

	/*
	 * Find a place for the cursor data in display memory.
	 * Must be on a 1024-byte boundary.
	 */
	storage = ROUND(scr->gscreen->width*BY2WD*scr->gscreen->r.max.y, 1024);
	outl(0xB3D0, storage);
	scr->storage = storage;

	/*
	 * Set the colours.
	 * Enable the cursor.
	 */
	outl(0xA7D0, 0xFFFF0000);
	outl(0xA3D0, 2);
}

static void
ct65545initcursor(VGAscr* scr, int xo, int yo, int index)
{
	uchar *mem;
	uint and, clr, set, xor;
	int i, x, y;

	mem = KADDR(scr->aperture);
	mem += scr->storage + index*1024;

	for(y = yo; y < 16; y++){
		clr = (scr->clr[2*y]<<8)|scr->clr[2*y+1];
		set = (scr->set[2*y]<<8)|scr->set[2*y+1];
		if(xo){
			clr <<= xo;
			set <<= xo;
		}

		and = 0;
		xor = 0;
		for(i = 0; i < 16; i++){
			if(set & (1<<i))
				;
			else if(clr & (1<<i))
				xor |= 1<<i;
			else
				and |= 1<<i;
		}
		*mem++ = and>>8;
		*mem++ = xor>>8;
		*mem++ = and;
		*mem++ = xor;

		for(x = 16; x < 64; x += 8){
			*mem++ = 0xFF;
			*mem++ = 0x00;
		}
	}
	while(y < 64+yo){
		for(x = 0; x < 64; x += 8){
			*mem++ = 0xFF;
			*mem++ = 0x00;
		}
		y++;
	}
}

static void
ct65545load(VGAscr* scr, Cursor* curs)
{
	memmove(&scr->Cursor, curs, sizeof(Cursor));
	ct65545initcursor(scr, 0, 0, 0);
}

static int
ct65545move(VGAscr* scr, Point p)
{
	int index, x, xo, y, yo;

	index = 0;
	if((x = p.x+scr->offset.x) < 0){
		xo = -x;
		x = 0;
	}
	else
		xo = 0;
	if((y = p.y+scr->offset.y) < 0){
		yo = -y;
		y = 0;
	}
	else
		yo = 0;

	if(xo || yo){
		ct65545initcursor(scr, xo, yo, 1);
		index = 1;
	}
	outl(0xB3D0, scr->storage + index*1024);

	outl(0xAFD0, (y<<16)|x);

	return 0;
}

VGAdev vgact65545dev = {
	"ct65540",				/* BUG: really 65545 */

	0,
	0,
	ct65545page,
	0,
};

VGAcur vgact65545cur = {
	"ct65545hwgc",

	ct65545enable,
	ct65545disable,
	ct65545load,
	ct65545move,
};

D pc/vgamach32.c => pc/vgamach32.c +0 -47
@@ 1,47 0,0 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"

#include <libg.h>
#include "screen.h"
#include "vga.h"

static Lock mach32lock;

static void
mach32page(int page)
{
	uchar ae, p;

	lock(&mach32lock);

	p = (page & 0x0F)<<1;
	p |= (page & 0x07)<<5;
	outs(0x1CE, (p<<8)|0xB2);

	outb(0x1CE, 0xAE);
	ae = inb(0x1CE+1);

	p = (page>>4) & 0x03;
	p |= p<<2;
	p |= ae & 0xF0;
	outs(0x1CE, (p<<8)|0xAE);

	unlock(&mach32lock);
}

static Vgac mach32 = {
	"mach32",
	mach32page,

	0,
};

void
vgamach32link(void)
{
	addvgaclink(&mach32);
}

M pc/vgargb524.c => pc/vgargb524.c +53 -92
@@ 5,11 5,10 @@
#include "fns.h"
#include "../port/error.h"

#include <libg.h>
#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"
#include "vga.h"

extern Cursor curcursor;

/*
 * IBM RGB524.


@@ 55,7 54,7 @@ static ushort dacxreg[4] = {
};

static uchar
setrs2(void)
rgb524setrs2(void)
{
	uchar rs2;



@@ 70,37 69,54 @@ rgb524xo(int index, uchar data)
{
	vgao(dacxreg[IndexLo], index & 0xFF);
	vgao(dacxreg[IndexHi], (index>>8) & 0xFF);

	vgao(dacxreg[Data], data);
}

static void
restorers2(uchar rs2)
rgb524disable(VGAscr*)
{
	uchar rs2;

	rs2 = rgb524setrs2();
	rgb524xo(CursorCtl, 0x00);
	vgaxo(Crtx, 0x55, rs2);
}

static void
load(Cursor *c)
rgb524enable(VGAscr*)
{
	uchar p, p0, p1, rs2;
	int x, y;
	uchar rs2;

	rs2 = rgb524setrs2();

	/*
	 * Lock the DAC registers so we can update the
	 * cursor bitmap if necessary.
	 * If it's the same as the last cursor we loaded,
	 * just make sure it's enabled.
	 * Make sure cursor is off by initialising the cursor
	 * control to defaults.
	 */
	lock(&palettelock);
	rs2 = setrs2();
	if(memcmp(c, &curcursor, sizeof(Cursor)) == 0){
		rgb524xo(CursorCtl, 0x23);
		restorers2(rs2);
		unlock(&palettelock);
		return;
	}
	memmove(&curcursor, c, sizeof(Cursor));
	rgb524xo(CursorCtl, 0x00);

	/*
	 * Cursor colour 1 (white),
	 * cursor colour 2 (black).
	 */
	rgb524xo(CursorR1, Pwhite); rgb524xo(CursorG1, Pwhite); rgb524xo(CursorB1, Pwhite);
	rgb524xo(CursorR2, Pblack); rgb524xo(CursorG2, Pblack); rgb524xo(CursorB2, Pblack);

	/*
	 * Enable the cursor, 32x32, mode 2.
	 */
	rgb524xo(CursorCtl, 0x23);

	vgaxo(Crtx, 0x55, rs2);
}

static void
rgb524load(VGAscr*, Cursor* curs)
{
	uchar p, p0, p1, rs2;
	int x, y;

	rs2 = rgb524setrs2();

	/*
	 * Make sure cursor is off by initialising the cursor


@@ 132,8 148,8 @@ load(Cursor *c)
	for(y = 0; y < 32; y++){
		for(x = 0; x < 32/8; x++){
			if(x < 16/8 && y < 16){
				p0 = c->clr[x+y*2];
				p1 = c->set[x+y*2];
				p0 = curs->clr[x+y*2];
				p1 = curs->set[x+y*2];

				p = 0x00;
				if(p1 & 0x80)


@@ 181,94 197,39 @@ load(Cursor *c)
	}

	/*
	 * Initialise the cursor hot-point,
	 * Initialise the cursor hotpoint,
	 * enable the cursor and restore state.
	 */
	rgb524xo(CursorHotX, -c->offset.x);
	rgb524xo(CursorHotY, -c->offset.y);
	rgb524xo(CursorHotX, -curs->offset.x);
	rgb524xo(CursorHotY, -curs->offset.y);

	rgb524xo(CursorCtl, 0x23);

	restorers2(rs2);
	unlock(&palettelock);
}

static void
enable(void)
{
	uchar rs2;

	lock(&palettelock);
	rs2 = setrs2();

	/*
	 * Make sure cursor is off by initialising the cursor
	 * control to defaults.
	 */
	rgb524xo(CursorCtl, 0x00);

	/*
	 * Cursor colour 1 (white),
	 * cursor colour 2 (black).
	 */
	rgb524xo(CursorR1, Pwhite); rgb524xo(CursorG1, Pwhite); rgb524xo(CursorB1, Pwhite);
	rgb524xo(CursorR2, Pblack); rgb524xo(CursorG2, Pblack); rgb524xo(CursorB2, Pblack);

	/*
	 * Enable the cursor, 32x32, mode 2.
	 */
	rgb524xo(CursorCtl, 0x23);

	restorers2(rs2);
	unlock(&palettelock);
	vgaxo(Crtx, 0x55, rs2);
}

static int
move(Point p)
rgb524move(VGAscr*, Point p)
{
	uchar rs2;

	if(canlock(&palettelock) == 0)
		return 1;
	rs2 = setrs2();
	rs2 = rgb524setrs2();

	rgb524xo(CursorXLo, p.x & 0xFF);
	rgb524xo(CursorXHi, (p.x>>8) & 0x0F);
	rgb524xo(CursorYLo, p.y & 0xFF);
	rgb524xo(CursorYHi, (p.y>>8) & 0x0F);

	restorers2(rs2);
	unlock(&palettelock);
	vgaxo(Crtx, 0x55, rs2);

	return 0;
}

static void
disable(void)
{
	uchar rs2;

	lock(&palettelock);
	rs2 = setrs2();

	rgb524xo(CursorCtl, 0x00);

	restorers2(rs2);
	unlock(&palettelock);
}

Hwgc rgb524hwgc = {
VGAcur vgargb524cur = {
	"rgb524hwgc",
	enable,
	load,
	move,
	disable,

	0,
	rgb524enable,
	rgb524disable,
	rgb524load,
	rgb524move,
};

void
vgargb524link(void)
{
	addhwgclink(&rgb524hwgc);
}

M pc/vgas3.c => pc/vgas3.c +102 -106
@@ 3,30 3,22 @@
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

#include <libg.h>
#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"
#include "vga.h"

/*
 * Hardware graphics cursor support for
 * generic S3 chipset.
 * Assume we're in enhanced mode.
 */
static Lock s3lock;
static ulong storage;
static Point hotpoint;

extern Bitmap gscreen;
extern Cursor curcursor;

static void
sets3page(int page)
static int
s3pageset(VGAscr* scr, int page)
{
	uchar crt51;
	uchar crt35, crt51;
	int opage;

	if(gscreen.ldepth == 3){
	crt35 = vgaxi(Crtx, 0x35);
	if(scr->gscreen->ldepth == 3){
		/*
		 * The S3 registers need to be unlocked for this.
		 * Let's hope they are already:


@@ 37,15 29,60 @@ sets3page(int page)
		 * the upper 2 in Crt51<3:2>.
		 */
		vgaxo(Crtx, 0x35, page & 0x0F);
		crt51 = vgaxi(Crtx, 0x51) & 0xF3;
		vgaxo(Crtx, 0x51, crt51|((page & 0x30)>>2));
		crt51 = vgaxi(Crtx, 0x51);
		vgaxo(Crtx, 0x51, (crt51 & ~0x0C)|((page & 0x30)>>2));
		opage = ((crt51 & 0x0C)<<2)|(crt35 & 0x0F);
	}
	else
	else{
		vgaxo(Crtx, 0x35, (page<<2) & 0x0C);
		opage = (crt35>>2) & 0x03;
	}

	return opage;
}

static void
s3page(VGAscr* scr, int page)
{
	lock(&scr->devlock);
	s3pageset(scr, page);
	unlock(&scr->devlock);
}

static ulong
s3linear(VGAscr* scr, int* size, int* align)
{
	ulong aperture, oaperture;
	int oapsize, wasupamem;
	Pcidev *p;

	oaperture = scr->aperture;
	oapsize = scr->apsize;
	wasupamem = scr->isupamem;
	if(wasupamem)
		upafree(oaperture, oapsize);
	scr->isupamem = 0;

	if(p = pcimatch(nil, 0x5333, 0)){
		aperture = p->mem[0].bar & ~0x0F;
		*size = p->mem[0].size;
	}
	else
		aperture = 0;

	aperture = upamalloc(aperture, *size, *align);
	if(aperture == 0){
		if(wasupamem && upamalloc(oaperture, oapsize, 0))
			scr->isupamem = 1;
	}
	else
		scr->isupamem = 1;

	return aperture;
}

static void
vsyncactive(void)
s3vsyncactive(void)
{
	/*
	 * Hardware cursor information is fetched from display memory


@@ 57,7 94,7 @@ vsyncactive(void)
}

static void
_disable(void)
s3disable(VGAscr*)
{
	uchar crt45;



@@ 65,26 102,17 @@ _disable(void)
	 * Turn cursor off.
	 */
	crt45 = vgaxi(Crtx, 0x45) & 0xFE;
	vsyncactive();
	s3vsyncactive();
	vgaxo(Crtx, 0x45, crt45);
}

static void
disable(void)
{
	lock(&s3lock);
	_disable();
	unlock(&s3lock);
}

static void
enable(void)
s3enable(VGAscr* scr)
{
	int i;
	ulong storage;

	lock(&s3lock);

	_disable();
	s3disable(scr);

	/*
	 * Cursor colours. Set both the CR0[EF] and the colour


@@ 104,53 132,38 @@ enable(void)
	 * Find a place for the cursor data in display memory.
	 * Must be on a 1024-byte boundary.
	 */
	storage = (gscreen.width*BY2WD*gscreen.r.max.y+1023)/1024;
	storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+1023)/1024;
	vgaxo(Crtx, 0x4C, (storage>>8) & 0x0F);
	vgaxo(Crtx, 0x4D, storage & 0xFF);
	storage *= 1024;
	scr->storage = storage;

	/*
	 * Enable the cursor in X11 mode.
	 */
	vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55)|0x10);
	vsyncactive();
	s3vsyncactive();
	vgaxo(Crtx, 0x45, 0x01);

	unlock(&s3lock);
}

static void
load(Cursor *c)
s3load(VGAscr* scr, Cursor* curs)
{
	uchar *p;
	int x, y;

	/*
	 * Lock the display memory so we can update the
	 * cursor bitmap if necessary.
	 * If it's the same as the last cursor we loaded,
	 * just make sure it's enabled.
	 */
	lock(&s3lock);
	if(memcmp(c, &curcursor, sizeof(Cursor)) == 0){
		vsyncactive();
		vgaxo(Crtx, 0x45, 0x01);
		unlock(&s3lock);
		return;
	}
	memmove(&curcursor, c, sizeof(Cursor));
	int opage, x, y;

	/*
	 * Disable the cursor.
	 * Set the display page (do we need to restore
	 * the current contents when done?) and the
	 * pointer to the two planes. What if this crosses
	 * into a new page?
	 * Disable the cursor and
	 * set the pointer to the two planes.
	 * Is linear addressing turned on? This will determine
	 * how we access the cursor storage.
	 */
	_disable();
	s3disable(scr);

	sets3page(storage>>16);
	p = ((uchar*)gscreen.base) + (storage & 0xFFFF);
	p = KADDR(scr->aperture);
	lock(&scr->devlock);
	opage = s3pageset(scr, scr->storage>>16);
	p += (scr->storage & 0xFFFF);

	/*
	 * The cursor is set in X11 mode which gives the following


@@ 168,10 181,10 @@ load(Cursor *c)
	for(y = 0; y < 64; y++){
		for(x = 0; x < 64/8; x += 2){
			if(x < 16/8 && y < 16){
				*p++ = c->clr[2*y + x]|c->set[2*y + x];
				*p++ = c->clr[2*y + x+1]|c->set[2*y + x+1];
				*p++ = c->set[2*y + x];
				*p++ = c->set[2*y + x+1];
				*p++ = curs->clr[2*y + x]|curs->set[2*y + x];
				*p++ = curs->clr[2*y + x+1]|curs->set[2*y + x+1];
				*p++ = curs->set[2*y + x];
				*p++ = curs->set[2*y + x+1];
			}
			else {
				*p++ = 0x00;


@@ 182,24 195,22 @@ load(Cursor *c)
		}
	}

	s3pageset(scr, opage);
	unlock(&scr->devlock);

	/*
	 * Set the cursor hotpoint and enable the cursor.
	 * Save the cursor hotpoint and enable the cursor.
	 */
	hotpoint = c->offset;
	vsyncactive();
	scr->offset = curs->offset;
	s3vsyncactive();
	vgaxo(Crtx, 0x45, 0x01);

	unlock(&s3lock);
}

static int
move(Point p)
s3move(VGAscr* scr, Point p)
{
	int x, xo, y, yo;

	if(canlock(&s3lock) == 0)
		return 1;

	/*
	 * Mustn't position the cursor offscreen even partially,
	 * or it disappears. Therefore, if x or y is -ve, adjust the


@@ 208,14 219,14 @@ move(Point p)
	 * cursor doesn't disappear off the left edge properly, so
	 * round it up to be even.
	 */
	if((x = p.x+hotpoint.x) < 0){
	if((x = p.x+scr->offset.x) < 0){
		xo = -x;
		xo = ((xo+1)/2)*2;
		x = 0;
	}
	else
		xo = 0;
	if((y = p.y+hotpoint.y) < 0){
	if((y = p.y+scr->offset.y) < 0){
		yo = -y;
		y = 0;
	}


@@ 229,38 240,23 @@ move(Point p)
	vgaxo(Crtx, 0x4F, yo);
	vgaxo(Crtx, 0x48, (y>>8) & 0x07);

	unlock(&s3lock);
	return 0;
}

Hwgc s3hwgc = {
	"s3hwgc",
	enable,
	load,
	move,
	disable,
VGAdev vgas3dev = {
	"s3",

	0,
	0,
	s3page,
	s3linear,
};

static void
s3page(int page)
{
	lock(&s3lock);
	sets3page(page);
	unlock(&s3lock);
}

static Vgac s3 = {
	"s3",
	s3page,
VGAcur vgas3cur = {
	"s3hwgc",

	0,
	s3enable,
	s3disable,
	s3load,
	s3move,
};

void
vgas3link(void)
{
	addvgaclink(&s3);
	addhwgclink(&s3hwgc);
}

M pc/vgatvp3020.c => pc/vgatvp3020.c +68 -107
@@ 5,24 5,18 @@
#include "fns.h"
#include "../port/error.h"

#include <libg.h>
#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"
#include "vga.h"

extern Cursor curcursor;

/*
 * TVP3020 Viewpoint Video Interface Pallette.
 * Assumes hooked up to an S3 86C928.
 */
enum {
	AddrW		= 0x00,		/* Palette address register - write mode */
	Palette		= 0x01,		/* Color palette holding register */
	Pmask		= 0x02,		/* Pixel read mask */
	AddrR		= 0x03,		/* Palette address register - read mode */

	Index		= 0x06,		/* Index register */
	Data		= 0x07,		/* Data register */
	Index		= 0x06,				/* Index register */
	Data		= 0x07,				/* Data register */
};

/*


@@ 56,24 50,62 @@ tvp3020xo(uchar index, uchar data)
}

static void
load(Cursor *c)
tvp3020disable(VGAscr*)
{
	uchar p, p0, p1;
	int x, y;
	uchar r;

	/*
	 * Lock the DAC registers so we can update the
	 * cursor bitmap if necessary.
	 * If it's the same as the last cursor we loaded,
	 * just make sure it's enabled.
	 * Disable 
	 *	cursor;
	 *	cursor control enable for Bt485 DAC (!);
	 *	the hardware cursor external operation mode.
	 */
	lock(&palettelock);
	if(memcmp(c, &curcursor, sizeof(Cursor)) == 0){
		tvp3020xo(0x06, 0x40|0x10);		/* Cursor Control Register */
		unlock(&palettelock);
		return;
	}
	memmove(&curcursor, c, sizeof(Cursor));
	tvp3020xo(0x06, 0x10);				/* Cursor Control Register */

	r = vgaxi(Crtx, 0x45) & ~0x20;
	vgaxo(Crtx, 0x45, r);

	r = vgaxi(Crtx, 0x55) & ~0x20;
	vgaxo(Crtx, 0x55, r);
}

static void
tvp3020enable(VGAscr*)
{
	uchar r;

	/*
	 * Make sure cursor is off by initialising the cursor
	 * control to defaults + X-Windows cursor mode.
	 */
	tvp3020xo(0x06, 0x10);				/* Cursor Control Register */

	/*
	 * Overscan colour,
	 * cursor colour 1 (white),
	 * cursor colour 2 (black).
	 */
	tvp3020xo(0x20, Pwhite); tvp3020xo(0x21, Pwhite); tvp3020xo(0x22, Pwhite);
	tvp3020xo(0x23, Pwhite); tvp3020xo(0x24, Pwhite); tvp3020xo(0x25, Pwhite);
	tvp3020xo(0x26, Pblack); tvp3020xo(0x27, Pblack); tvp3020xo(0x28, Pblack);

	/*
	 * Finally, enable
	 *	the hardware cursor external operation mode;
	 *	cursor control enable for Bt485 DAC (!).
	 */
	r = vgaxi(Crtx, 0x55)|0x20;
	vgaxo(Crtx, 0x55, r);

	r = vgaxi(Crtx, 0x45)|0x20;
	vgaxo(Crtx, 0x45, r);
}

static void
tvp3020load(VGAscr*, Cursor* curs)
{
	uchar p, p0, p1;
	int x, y;

	/*
	 * Make sure cursor is off by initialising the cursor


@@ 104,8 136,8 @@ load(Cursor *c)
	for(y = 0; y < 64; y++){
		for(x = 0; x < 64/8; x++){
			if(x < 16/8 && y < 16){
				p0 = c->clr[x+y*2];
				p1 = c->set[x+y*2];
				p0 = curs->clr[x+y*2];
				p1 = curs->set[x+y*2];

				p = 0x00;
				if(p1 & 0x10)


@@ 153,102 185,31 @@ load(Cursor *c)
	}

	/*
	 * Initialise the cursor hot-point
	 * Initialise the cursor hotpoint
	 * and enable the cursor.
	 */
	tvp3020xo(0x04, -c->offset.x);			/* Sprite Origin X */
	tvp3020xo(0x05, -c->offset.y);			/* Sprite Origin Y */
	tvp3020xo(0x04, -curs->offset.x);		/* Sprite Origin X */
	tvp3020xo(0x05, -curs->offset.y);		/* Sprite Origin Y */

	tvp3020xo(0x06, 0x40|0x10);			/* Cursor Control Register */

	unlock(&palettelock);
}

static void
enable(void)
{
	uchar r;

	lock(&palettelock);

	/*
	 * Make sure cursor is off by initialising the cursor
	 * control to defaults + X-Windows cursor mode.
	 */
	tvp3020xo(0x06, 0x10);				/* Cursor Control Register */

	/*
	 * Overscan colour,
	 * cursor colour 1 (white),
	 * cursor colour 2 (black).
	 */
	tvp3020xo(0x20, Pwhite); tvp3020xo(0x21, Pwhite); tvp3020xo(0x22, Pwhite);
	tvp3020xo(0x23, Pwhite); tvp3020xo(0x24, Pwhite); tvp3020xo(0x25, Pwhite);
	tvp3020xo(0x26, Pblack); tvp3020xo(0x27, Pblack); tvp3020xo(0x28, Pblack);

	unlock(&palettelock);

	/*
	 * Finally, enable
	 *	the hardware cursor external operation mode;
	 *	cursor control enable for Bt485 DAC (!).
	 */
	r = vgaxi(Crtx, 0x55)|0x20;
	vgaxo(Crtx, 0x55, r);

	r = vgaxi(Crtx, 0x45)|0x20;
	vgaxo(Crtx, 0x45, r);
}

static int
move(Point p)
tvp3020move(VGAscr*, Point p)
{
	if(canlock(&palettelock) == 0)
		return 1;

	tvp3020xo(0x00, p.x & 0xFF);			/* Cursor Position X LSB */
	tvp3020xo(0x01, (p.x>>8) & 0x0F);		/* Cursor Position X MSB */
	tvp3020xo(0x02, p.y & 0xFF);			/* Cursor Position Y LSB */
	tvp3020xo(0x03, (p.y>>8) & 0x0F);		/* Cursor Position Y MSB */

	unlock(&palettelock);
	return 0;
}

static void
disable(void)
{
	uchar r;

	/*
	 * Disable 
	 *	cursor;
	 *	cursor control enable for Bt485 DAC (!);
	 *	the hardware cursor external operation mode.
	 */
	lock(&palettelock);
	tvp3020xo(0x06, 0x10);				/* Cursor Control Register */
	unlock(&palettelock);

	r = vgaxi(Crtx, 0x45) & ~0x20;
	vgaxo(Crtx, 0x45, r);

	r = vgaxi(Crtx, 0x55) & ~0x20;
	vgaxo(Crtx, 0x55, r);
}

Hwgc tvp3020hwgc = {
VGAcur vgatvp3020cur = {
	"tvp3020hwgc",
	enable,
	load,
	move,
	disable,

	0,
	tvp3020enable,
	tvp3020disable,
	tvp3020load,
	tvp3020move,
};

void
vgatvp3020link(void)
{
	addhwgclink(&tvp3020hwgc);
}

M pc/vgatvp3026.c => pc/vgatvp3026.c +48 -86
@@ 5,11 5,10 @@
#include "fns.h"
#include "../port/error.h"

#include <libg.h>
#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"
#include "vga.h"

extern Cursor curcursor;

/*
 * TVP3026 Viewpoint Video Interface Pallette.


@@ 40,8 39,6 @@ static ushort dacxreg[4] = {
	PaddrW, Pdata, Pixmask, PaddrR
};

static Point hotpoint;

static uchar
tvp3026io(uchar reg, uchar data)
{


@@ 75,23 72,42 @@ tvp3026xo(uchar index, uchar data)
}

static void
load(Cursor *c)
tvp3026disable(VGAscr*)
{
	int x, y;
	tvp3026xo(Icctl, 0x90);
	tvp3026o(Cctl, 0x00);
}

static void
tvp3026enable(VGAscr*)
{
	/*
	 * Lock the DAC registers so we can update the
	 * cursor bitmap if necessary.
	 * If it's the same as the last cursor we loaded,
	 * just make sure it's enabled.
	 * Make sure cursor is off and direct control enabled.
	 */
	lock(&palettelock);
	if(memcmp(c, &curcursor, sizeof(Cursor)) == 0){
		tvp3026o(Cctl, 0x01);
		unlock(&palettelock);
		return;
	}
	memmove(&curcursor, c, sizeof(Cursor));
	tvp3026xo(Icctl, 0x90);
	tvp3026o(Cctl, 0x00);

	/*
	 * Overscan colour,
	 * cursor colour 1 (white),
	 * cursor colour 2, 3 (black).
	 */
	tvp3026o(CaddrW, 0x00);
	tvp3026o(Cdata, Pwhite); tvp3026o(Cdata, Pwhite); tvp3026o(Cdata, Pwhite);
	tvp3026o(Cdata, Pwhite); tvp3026o(Cdata, Pwhite); tvp3026o(Cdata, Pwhite);
	tvp3026o(Cdata, Pblack); tvp3026o(Cdata, Pblack); tvp3026o(Cdata, Pblack);
	tvp3026o(Cdata, Pblack); tvp3026o(Cdata, Pblack); tvp3026o(Cdata, Pblack);

	/*
	 * Enable the cursor in 3-colour mode.
	 */
	tvp3026o(Cctl, 0x01);
}

static void
tvp3026load(VGAscr* scr, Cursor* curs)
{
	int x, y;

	/*
	 * Make sure cursor is off by initialising the cursor


@@ 123,7 139,7 @@ load(Cursor *c)
	for(y = 0; y < 64; y++){
		for(x = 0; x < 64/8; x++){
			if(x < 16/8 && y < 16)
				tvp3026o(Cram, c->clr[x+y*2]);
				tvp3026o(Cram, curs->clr[x+y*2]);
			else
				tvp3026o(Cram, 0x00);
		}


@@ 131,96 147,42 @@ load(Cursor *c)
	for(y = 0; y < 64; y++){
		for(x = 0; x < 64/8; x++){
			if(x < 16/8 && y < 16)
				tvp3026o(Cram, c->set[x+y*2]);
				tvp3026o(Cram, curs->set[x+y*2]);
			else
				tvp3026o(Cram, 0x00);
		}
	}

	/*
	 * Initialise the cursor hot-point
	 * Initialise the cursor hotpoint
	 * and enable the cursor in 3-colour mode.
	 */
	hotpoint.x = 64+c->offset.x;
	hotpoint.y = 64+c->offset.y;

	tvp3026o(Cctl, 0x01);

	unlock(&palettelock);
}

static void
enable(void)
{
	lock(&palettelock);

	/*
	 * Make sure cursor is off and direct control enabled.
	 */
	tvp3026xo(Icctl, 0x90);
	tvp3026o(Cctl, 0x00);

	/*
	 * Overscan colour,
	 * cursor colour 1 (white),
	 * cursor colour 2, 3 (black).
	 */
	tvp3026o(CaddrW, 0x00);
	tvp3026o(Cdata, Pwhite); tvp3026o(Cdata, Pwhite); tvp3026o(Cdata, Pwhite);
	tvp3026o(Cdata, Pwhite); tvp3026o(Cdata, Pwhite); tvp3026o(Cdata, Pwhite);
	tvp3026o(Cdata, Pblack); tvp3026o(Cdata, Pblack); tvp3026o(Cdata, Pblack);
	tvp3026o(Cdata, Pblack); tvp3026o(Cdata, Pblack); tvp3026o(Cdata, Pblack);

	/*
	 * Enable the cursor in 3-colour mode.
	 */
	scr->offset.x = 64+curs->offset.x;
	scr->offset.y = 64+curs->offset.y;
	tvp3026o(Cctl, 0x01);

	unlock(&palettelock);
}

static int
move(Point p)
tvp3026move(VGAscr* scr, Point p)
{
	int x, y;

	if(canlock(&palettelock) == 0)
		return 1;

	x = p.x+hotpoint.x;
	y = p.y+hotpoint.y;
	x = p.x+scr->offset.x;
	y = p.y+scr->offset.y;

	tvp3026o(Cxlsb, x & 0xFF);
	tvp3026o(Cxmsb, (x>>8) & 0x0F);
	tvp3026o(Cylsb, y & 0xFF);
	tvp3026o(Cymsb, (y>>8) & 0x0F);

	unlock(&palettelock);

	return 0;
}

static void
disable(void)
{
	lock(&palettelock);
	tvp3026xo(Icctl, 0x90);
	tvp3026o(Cctl, 0x00);
	unlock(&palettelock);
}

Hwgc tvp3026hwgc = {
VGAcur vgatvp3026cur = {
	"tvp3026hwgc",
	enable,
	load,
	move,
	disable,

	0,
	tvp3026enable,
	tvp3026disable,
	tvp3026load,
	tvp3026move,
};

void
vgatvp3026link(void)
{
	addhwgclink(&tvp3026hwgc);
}

A pc/vgax.c => pc/vgax.c +101 -0
@@ 0,0 1,101 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"

#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include "screen.h"

static Lock vgaxlock;			/* access to index registers */

int
vgaxi(long port, uchar index)
{
	uchar data;

	ilock(&vgaxlock);
	switch(port){

	case Seqx:
	case Crtx:
	case Grx:
		outb(port, index);
		data = inb(port+1);
		break;

	case Attrx:
		/*
		 * Allow processor access to the colour
		 * palette registers. Writes to Attrx must
		 * be preceded by a read from Status1 to
		 * initialise the register to point to the
		 * index register and not the data register.
		 * Processor access is allowed by turning
		 * off bit 0x20.
		 */
		inb(Status1);
		if(index < 0x10){
			outb(Attrx, index);
			data = inb(Attrx+1);
			inb(Status1);
			outb(Attrx, 0x20|index);
		}
		else{
			outb(Attrx, 0x20|index);
			data = inb(Attrx+1);
		}
		break;

	default:
		iunlock(&vgaxlock);
		return -1;
	}
	iunlock(&vgaxlock);

	return data & 0xFF;
}

int
vgaxo(long port, uchar index, uchar data)
{
	ilock(&vgaxlock);
	switch(port){

	case Seqx:
	case Crtx:
	case Grx:
		/*
		 * We could use an outport here, but some chips
		 * (e.g. 86C928) have trouble with that for some
		 * registers.
		 */
		outb(port, index);
		outb(port+1, data);
		break;

	case Attrx:
		inb(Status1);
		if(index < 0x10){
			outb(Attrx, index);
			outb(Attrx, data);
			inb(Status1);
			outb(Attrx, 0x20|index);
		}
		else{
			outb(Attrx, 0x20|index);
			outb(Attrx, data);
		}
		break;

	default:
		iunlock(&vgaxlock);
		return -1;
	}
	iunlock(&vgaxlock);

	return 0;
}

M port/alloc.c => port/alloc.c +519 -327
@@ 1,411 1,603 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"pool.h"
#include	"dat.h"
#include	"fns.h"
#include	"error.h"

#define left	u.s.bhl
#define right	u.s.bhr
#define fwd	u.s.bhf
#define prev	u.s.bhv
#define parent	u.s.bhp

/*
 * Plan 9 has two kernel allocators, the x... routines provide a first
 * fit hole allocator which should be used for permanent or large structures.
 * Routines are provided to allocate aligned memory which does not cross
 * arbitrary 2^n boundaries. A second allocator malloc, smalloc, free is
 * a 2n bucket allocator which steals from the x routines. This should
 * be used for small frequently used structures.
 */

#define datoff		((ulong)((Xhdr*)0)->data)
#define bdatoff		((ulong)((Bucket*)0)->data)

enum
struct Pool
{
	Maxpow		= 19,
	CUTOFF		= 12,
	Nhole		= 128,
	Magichole	= 0xDeadBabe,
	Magic2n		= 0xFeedBeef,
	Spanlist	= 64,
	char*	name;
	ulong	maxsize;
	int	quanta;
	int	chunk;
	ulong	cursize;
	ulong	arenasize;
	ulong	hw;
	Lock	l;
	Bhdr*	root;
	Bhdr*	chain;
	int	nalloc;
	int	nfree;
	int	nbrk;
	int	lastfree;
	void	(*move)(void*, void*);
};

typedef struct Hole Hole;
typedef struct Xalloc Xalloc;
typedef struct Xhdr Xhdr;
typedef struct Bucket Bucket;
typedef struct Arena Arena;

struct Hole
struct
{
	ulong	addr;
	ulong	size;
	ulong	top;
	Hole	*link;
	int	n;
	Pool	pool[MAXPOOL];
	Lock	l;
} table = {
	2,
	{
		{ "Main",	 4*1024*1024, 31,  128*1024 },
		{ "Image",	 8*1024*1024, 31, 2*1024*1024 },
	}
};

struct Xhdr
{
	ulong	size;
	ulong	magix;
	char	data[1];
};
Pool*	mainmem = &table.pool[0];
Pool*	imagmem = &table.pool[1];

struct Xalloc
{
	Lock;
	Hole	hole[Nhole];
	Hole	*flist;
	Hole	*table;
};
int	poolcompact(Pool*);

struct Bucket
Bhdr*
poolchain(Pool *p)
{
	int	size;
	int	magic;
	Bucket	*next;
	ulong	pc;
	char	data[1];
};
	return p->chain;
}

struct Arena
void
pooldel(Pool *p, Bhdr *t)
{
	Lock;
	Bucket	*btab[Maxpow];
	int	nbuck[Maxpow];
	QLock	rq;
	Rendez	r;
};
	Bhdr *s, *f, *rp, *q;

static Arena	arena;
static Xalloc	xlists;
	if(t->parent == nil && p->root != t) {
		t->prev->fwd = t->fwd;
		t->fwd->prev = t->prev;
		return;
	}
 
	if(t->fwd != t) {
		f = t->fwd;
		s = t->parent;
		f->parent = s;
		if(s == nil)
			p->root = f;
		else {
			if(s->left == t)
				s->left = f;
			else
				s->right = f;
		}
 
		rp = t->left;
		f->left = rp;
		if(rp != nil)
			rp->parent = f;
		rp = t->right;
		f->right = rp;
		if(rp != nil)
			rp->parent = f;
 
		t->prev->fwd = t->fwd;
		t->fwd->prev = t->prev;
		return;
	}

void
xinit(void)
{
	Hole *h, *eh;
	int upages, np0, np1;

	eh = &xlists.hole[Nhole-1];
	for(h = xlists.hole; h < eh; h++)
		h->link = h+1;

	xlists.flist = xlists.hole;

	upages = conf.upages;
	np1 = upages;
	if(np1 > conf.npage1)
		np1 = conf.npage1;

	palloc.p1 = conf.base1 + (conf.npage1 - np1)*BY2PG;
	conf.npage1 -= np1;
	xhole(conf.base1, conf.npage1*BY2PG);
	conf.npage1 = conf.base1+(conf.npage1*BY2PG);
	upages -= np1;

	np0 = upages;
	if(np0 > conf.npage0)
		np0 = conf.npage0;

	palloc.p0 = conf.base0 + (conf.npage0 - np0)*BY2PG;
	conf.npage0 -= np0;
	xhole(conf.base0, conf.npage0*BY2PG);
	conf.npage0 = conf.base0+(conf.npage0*BY2PG);

	palloc.np0 = np0;
	palloc.np1 = np1;
	/* Save the bounds of kernel alloc memory for kernel mmu mapping */
	conf.base0 = (ulong)KADDR(conf.base0);
	conf.base1 = (ulong)KADDR(conf.base1);
	conf.npage0 = (ulong)KADDR(conf.npage0);
	conf.npage1 = (ulong)KADDR(conf.npage1);
	if(t->left == nil)
		rp = t->right;
	else {
		if(t->right == nil) 
			rp = t->left;
		else {
			f = t;
			rp = t->right;
			s = rp->left;
			while(s != nil) {
				f = rp;
				rp = s;
				s = rp->left;
			}
			if(f != t) {
				s = rp->right;
				f->left = s;
				if(s != nil)
					s->parent = f;
				s = t->right;
				rp->right = s;
				if(s != nil)
					s->parent = rp;
			}
			s = t->left;
			rp->left = s;
			s->parent = rp;
		}
	}
	q = t->parent;
	if(q == nil)
		p->root = rp;
	else {
		if(t == q->left)
			q->left = rp;
		else
			q->right = rp;
	}
	if(rp != nil)
		rp->parent = q;
}

/*
 * NB. spanalloc memory will cause a panic if free'd
 */
void*
xspanalloc(ulong size, int align, ulong span)
void
pooladd(Pool *p, Bhdr *q)
{
	ulong a, v, t;

	a = (ulong)xalloc(size+align+span);
	if(a == 0)
		panic("xspanalloc: %d %d %lux\n", size, align, span);

	if(span > 2) {
		v = (a + span) & ~(span-1);
		t = v - a;
		if(t > 0)
			xhole(PADDR(a), t);
		t = a + span - v;
		if(t > 0)
			xhole(PADDR(v+size+align), t);
	int size;
	Bhdr *tp, *t;

	q->magic = MAGIC_F;

	q->left = nil;
	q->right = nil;
	q->parent = nil;
	q->fwd = q;
	q->prev = q;

	t = p->root;
	if(t == nil) {
		p->root = q;
		return;
	}
	else
		v = a;

	if(align > 1)
		v = (v + align) & ~(align-1);
	size = q->size;

	return (void*)v;
	tp = nil;
	while(t != nil) {
		if(size == t->size) {
			q->fwd = t->fwd;
			q->fwd->prev = q;
			q->prev = t;
			t->fwd = q;
			return;
		}
		tp = t;
		if(size < t->size)
			t = t->left;
		else
			t = t->right;
	}

	q->parent = tp;
	if(size < tp->size)
		tp->left = q;
	else
		tp->right = q;
}

void*
xallocz(ulong size, int zero)
poolalloc(Pool *p, int size)
{
	Xhdr *p;
	Hole *h, **l;

	size += BY2V + sizeof(Xhdr);
	size &= ~(BY2V-1);

	ilock(&xlists);
	l = &xlists.table;
	for(h = *l; h; h = h->link) {
		if(h->size >= size) {
			p = (Xhdr*)h->addr;
			h->addr += size;
			h->size -= size;
			if(h->size == 0) {
				*l = h->link;
				h->link = xlists.flist;
				xlists.flist = h;
			}
			iunlock(&xlists);
			p = KADDR(p);
			if(zero)
				memset(p, 0, size);
			p->magix = Magichole;
			p->size = size;
			return p->data;
	Bhdr *q, *t;
	int alloc, ldr, ns, frag;

	size = (size + BHDRSIZE + p->quanta) & ~(p->quanta);

	ilock(&p->l);
	p->nalloc++;

	t = p->root;
	q = nil;
	while(t) {
		if(t->size == size) {
			pooldel(p, t);
			t->magic = MAGIC_A;
			p->cursize += t->size;
			if(p->cursize > p->hw)
				p->hw = p->cursize;
			iunlock(&p->l);
			return B2D(t);
		}
		if(size < t->size) {
			q = t;
			t = t->left;
		}
		l = &h->link;
		else
			t = t->right;
	}
	if(q != nil) {
		pooldel(p, q);
		q->magic = MAGIC_A;
		frag = q->size - size;
		if(frag < (size>>2)) {
			p->cursize += q->size;
			if(p->cursize > p->hw)
				p->hw = p->cursize;
			iunlock(&p->l);
			return B2D(q);
		}
		/* Split */
		ns = q->size - size;
		q->size = size;
		B2T(q)->hdr = q;
		t = B2NB(q);
		t->size = ns;
		B2T(t)->hdr = t;
		pooladd(p, t);				
		p->cursize += q->size;
		if(p->cursize > p->hw)
			p->hw = p->cursize;
		iunlock(&p->l);
		return B2D(q);
	}
	iunlock(&xlists);
	return nil;
}

void
xfree(void *p)
{
	Xhdr *x;
	ns = p->chunk;
	if(size > ns)
		ns = size;
	ldr = p->quanta+1;

	alloc = ns+ldr+sizeof(t->magic);
	p->arenasize += alloc;
	if(p->arenasize > p->maxsize) {
		p->arenasize -= alloc;

		if(poolcompact(p)) {
			iunlock(&p->l);
			return poolalloc(p, size);
		}

		iunlock(&p->l);
		print("arena too large: size %d cursize %d arenasize %d maxsize %d\n",
			 size, p->cursize, p->arenasize, p->maxsize);
		return nil;
	}

	x = (Xhdr*)((ulong)p - datoff);
	if(x->magix != Magichole) {
		xsummary();
		panic("xfree(0x%lux) 0x%lux!=0x%lux", p, Magichole, x->magix);
	p->nbrk++;
	t = xalloc(alloc);
	if(t == nil) {
		iunlock(&p->l);
		return nil;
	}
	xhole(PADDR(x), x->size);

	t->magic = MAGIC_E;		/* Make a leader */
	t->size = ldr;
	t->csize = ns+ldr;
	t->clink = p->chain;
	p->chain = t;
	B2T(t)->hdr = t;
	t = B2NB(t);

	t->magic = MAGIC_A;		/* Make the block we are going to return */
	t->size = size;
	B2T(t)->hdr = t;
	q = t;

	ns -= size;			/* Free the rest */
	if(ns > 0) {
		q = B2NB(t);
		q->size = ns;
		B2T(q)->hdr = q;
		pooladd(p, q);
	}
	B2NB(q)->magic = MAGIC_E;	/* Mark the end of the chunk */

	p->cursize += t->size;
	if(p->cursize > p->hw)
		p->hw = p->cursize;
	iunlock(&p->l);
	return B2D(t);
}

void
xhole(ulong addr, ulong size)
poolfree(Pool *p, void *v)
{
	ulong top;
	Hole *h, *c, **l;
	Bhdr *b, *c;

	if(size == 0)
		return;
	D2B(b, v);

	top = addr + size;
	ilock(&xlists);
	l = &xlists.table;
	for(h = *l; h; h = h->link) {
		if(h->top == addr) {
			h->size += size;
			h->top = h->addr+h->size;
			c = h->link;
			if(c && h->top == c->addr) {
				h->top += c->size;
				h->size += c->size;
				h->link = c->link;
				c->link = xlists.flist;
				xlists.flist = c;
			}
			iunlock(&xlists);
			return;
		}
		if(h->addr > addr)
			break;
		l = &h->link;
	}
	if(h && top == h->addr) {
		h->addr -= size;
		h->size += size;
		iunlock(&xlists);
		return;
	ilock(&p->l);
	p->nfree++;
	p->cursize -= b->size;

	c = B2NB(b);
	if(c->magic == MAGIC_F) {	/* Join forward */
		pooldel(p, c);
		c->magic = 0;
		b->size += c->size;
		B2T(b)->hdr = b;
	}

	if(xlists.flist == nil) {
		iunlock(&xlists);
		print("xfree: no free holes, leaked %d bytes\n", size);
		return;
	c = B2PT(b)->hdr;
	if(c->magic == MAGIC_F) {	/* Join backward */
		pooldel(p, c);
		b->magic = 0;
		c->size += b->size;
		b = c;
		B2T(b)->hdr = b;
	}

	h = xlists.flist;
	xlists.flist = h->link;
	h->addr = addr;
	h->top = top;
	h->size = size;
	h->link = *l;
	*l = h;
	iunlock(&xlists);
	pooladd(p, b);
	iunlock(&p->l);
}

int
poolread(char *va, int count, ulong offset)
{
	Pool *p;
	int n, i, signed_off;

	n = 0;
	signed_off = offset;
	for(i = 0; i < table.n; i++) {
		p = &table.pool[i];
		n += snprint(va+n, count-n, "%11d %11d %11d %11d %11d %11d %s\n",
			p->cursize,
			p->maxsize,
			p->hw,
			p->nalloc,
			p->nfree,
			p->nbrk,
			p->name);

		if(signed_off > 0) {
			signed_off -= n;
			if(signed_off < 0) {
				memmove(va, va+n+signed_off, -signed_off);
				n = -signed_off;
			}
			else
				n = 0;
		}

	}
	return n;
}

void*
mallocz(ulong size, int zero)
malloc(ulong size)
{
	int pow, n;
	Bucket *bp, **l;
	void *v;

	for(pow = 3; pow <= Maxpow; pow++)
		if(size <= (1<<pow))
			goto good;
	v = poolalloc(mainmem, size);
	if(v != nil)
		memset(v, 0, size);
	return v;
}

	return nil;
good:
void*
smalloc(ulong size)
{
	void *v;

	/* Allocate off this list */
	ilock(&arena);
	bp = arena.btab[pow];
	if(bp) {
		arena.btab[pow] = bp->next;
		iunlock(&arena);
	for(;;) {
		v = poolalloc(mainmem, size);
		if(v != nil)
			break;
		tsleep(&up->sleep, return0, 0, 100);
	}
	memset(v, 0, size);
	return v;
}

		if(bp->magic != 0)
			panic("malloc %lux %lux", bp->magic, bp->pc);
void*
mallocz(ulong size, int clr)
{
	void *v;

		bp->magic = Magic2n;
	v = poolalloc(mainmem, size);
	if(clr && v != nil)
		memset(v, 0, size);
	return v;
}

		if(zero)
			memset(bp->data, 0,  size);
		return  bp->data;
	}
	iunlock(&arena);

	size = sizeof(Bucket)+(1<<pow);
	size += BY2V;
	size &= ~(BY2V-1);

	if(pow < CUTOFF) {
		n = (CUTOFF-pow)+2;
		bp = xalloc(size*n);
		if(bp == nil)
			return nil;

		ilock(&arena);
		arena.nbuck[pow] += n;
		l = &arena.btab[pow];
		/* add all but the last to the free list */
		while(--n){
			bp->size = pow;
			bp->next = *l;
			*l = bp;
			bp = (Bucket*)((ulong)bp+size);
		}
		iunlock(&arena);
void
free(void *v)
{
	Bhdr *b;

	if(v != nil) {
		D2B(b, v);
		poolfree(mainmem, v);
	}
	else {
		bp = xalloc(size);
		if(bp == nil)
			return nil;
}

void*
realloc(void *v, ulong size)
{
	Bhdr *b;
	void *nv;
	int osize;

		arena.nbuck[pow]++;
	if(v == nil)
		return malloc(size);

	D2B(b, v);

	osize = b->size - BHDRSIZE;
	if(osize >= size)
		return v;

	nv = poolalloc(mainmem, size);
	if(nv != nil) {
		memmove(nv, v, osize);
		free(v);
	}
	return nv;
}

	bp->size = pow;
	bp->magic = Magic2n;
int
msize(void *v)
{
	Bhdr *b;

	return bp->data;
	D2B(b, v);
	return b->size - BHDRSIZE;
}

void*
malloc(ulong size)
calloc(ulong n, ulong szelem)
{
	return mallocz(size, 1);
	return malloc(n*szelem);
}

void*
smalloc(ulong size)
/*
void
pooldump(Bhdr *b, int d, int c)
{
	char *s;
	void *p;
	int attempt;

	for(attempt = 0; attempt < 1000; attempt++) {
		p = malloc(size);
		if(p != nil)
			return p;
		s = up->psstate;
		up->psstate = "Malloc";
		qlock(&arena.rq);
		while(waserror())
			;
		sleep(&arena.r, return0, nil);
		poperror();
		qunlock(&arena.rq);
		up->psstate = s;
	Bhdr *t;

	if(b == nil)
		return;

	print("%.8lux %.8lux %.8lux %c %4d %d (f %.8lux p %.8lux)\n",
		b, b->left, b->right, c, d, b->size, b->fwd, b->prev);
	d++;
	for(t = b->fwd; t != b; t = t->fwd)
		print("\t%.8lux %.8lux %.8lux\n", t, t->prev, t->fwd);
	pooldump(b->left, d, 'l');
	pooldump(b->right, d, 'r');
}


void
poolshow(void)
{
	int i;

	for(i = 0; i < table.n; i++) {
		print("Arena: %s root=%.8lux\n", table.pool[i].name, table.pool[i].root);
		pooldump(table.pool[i].root, 0, 'R');
	}
	pexit(Enomem, 1);
	return 0;
}
*/

int
msize(void *ptr)
void
poolsummary(void)
{
	Bucket *bp;
	int i;

	bp = (Bucket*)((ulong)ptr - bdatoff);
	if(bp->magic != Magic2n)
		panic("msize");
	return 1<<bp->size;
	for(i = 0; i < table.n; i++)
		print("Arena: %s cursize=%d; maxsize=%d\n", table.pool[i].name, table.pool[i].cursize, table.pool[i].maxsize);
}

/*
void
free(void *ptr)
pooldump(Pool *p)
{
	Bucket *bp, **l;

	bp = (Bucket*)((ulong)ptr - bdatoff);
	if(bp->magic != Magic2n)
		panic("free %lux %lux %lux", bp->magic, bp->pc, getcallerpc(ptr));

	bp->magic = 0;
	ilock(&arena);
	l = &arena.btab[bp->size];
	bp->next = *l;
	*l = bp;
	iunlock(&arena);
	if(arena.r.p)
		wakeup(&arena.r);
	Bhdr *b, *base, *limit, *ptr;

	b = p->chain;
	if(b == nil)
		return;
	base = b;
	ptr = b;
	limit = B2LIMIT(b);

	while(base != nil) {
		print("\tbase #%.8lux ptr #%.8lux", base, ptr);
		if(ptr->magic == MAGIC_A)
			print("\tA%.5d\n", ptr->size);
		else if(ptr->magic == MAGIC_E)
			print("\tE\tL#%.8lux\tS#%.8lux\n", ptr->clink, ptr->csize);
		else
			print("\tF%.5d\tL#%.8lux\tR#%.8lux\tF#%.8lux\tP#%.8lux\tT#%.8lux\n",
				ptr->size, ptr->left, ptr->right, ptr->fwd, ptr->prev, ptr->parent);
		ptr = B2NB(ptr);
		if(ptr >= limit) {
			print("link to #%.8lux\n", base->clink);
			base = base->clink;
			if(base == nil)
				break;
			ptr = base;
			limit = B2LIMIT(base);
		}
	}
	return;
}
*/

void
poolsetcompact(Pool *p, void (*move)(void*, void*))
{
	p->move = move;
}

void
xsummary(void)
poolsetparam(char *name, ulong maxsize, int quanta, int chunk)
{
	Hole *h;
	Bucket *k;
	int i, nfree, nused;

	i = 0;
	for(h = xlists.flist; h; h = h->link)
		i++;

	print("%d holes free\n", i);
	i = 0;
	for(h = xlists.table; h; h = h->link) {
		print("%.8lux %.8lux %d\n", h->addr, h->top, h->size);
		i += h->size;
	Pool *p;
	int i;

	for(i=0; i<table.n; i++){
		p = &table.pool[i];
		if(strcmp(name, p->name) == 0){
			if(maxsize)
				p->maxsize = maxsize;
			if(quanta)
				p->quanta = quanta;
			if(chunk)
				p->chunk = chunk;
			return;
		}
	}
	print("%d bytes free\n", i);
	nused = 0;
	for(i = 3; i < Maxpow; i++) {
		if(arena.btab[i] == 0 && arena.nbuck[i] == 0)
			continue;
		nused += arena.nbuck[i]*(1<<i);
		nfree = 0;
		for(k = arena.btab[i]; k; k = k->next)
			nfree++;
		print("%8d %4d %4d\n", 1<<i, arena.nbuck[i], nfree);
}

int
poolcompact(Pool *pool)
{
	Bhdr *base, *limit, *ptr, *end, *next;
	int compacted, recov, nb;

	if(pool->move == nil || pool->lastfree == pool->nfree)
		return 0;

	pool->lastfree = pool->nfree;

	base = pool->chain;
	ptr = B2NB(base);	/* First Block in arena has clink */
	limit = B2LIMIT(base);
	compacted = 0;

	pool->root = nil;
	end = ptr;
	recov = 0;
	while(base != nil) {
		next = B2NB(ptr);
		if(ptr->magic == MAGIC_A) {
			if(ptr != end) {
				memmove(end, ptr, ptr->size);
				pool->move(B2D(ptr), B2D(end));
				recov = (uchar*)ptr - (uchar*)end;
				compacted = 1;
			}
			end = B2NB(end);
		}
		if(next >= limit) {
			nb = (uchar*)limit - (uchar*)end;
			//print("recovered %d bytes\n", recov);
			//print("%d bytes at end\n", nb);
			USED(recov);
			if(nb > 0){
				if(nb < pool->quanta+1)
					panic("poolcompact: leftover too small\n");
				end->size = nb;
				pooladd(pool, end);
			}
			base = base->clink;
			if(base == nil)
				break;
			ptr = B2NB(base);
			end = ptr;	/* could do better by copying between chains */
			limit = B2LIMIT(base);
			recov = 0;
		} else
			ptr = next;
	}
	print("%d bytes in pool\n", nused);

	return compacted;
}

D port/devXXX.c => port/devXXX.c +0 -150
@@ 1,150 0,0 @@
/*
 *  template for making a new device
 */

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


enum{
	Qdir,
	Qdata,
};
Dirtab XXXtab[]={
	"data",		{Qdata, 0},	0,	0600,
};

static void
XXXreset(void)						/* default in dev.c */
{
}

static void
XXXinit(void)						/* default in dev.c */
{
}

static Chan*
XXXattach(char* spec)
{
	return devattach('X', spec);
}

static Chan*
XXXclone(Chan* c, Chan* nc)				/* default in dev.c */
{
	return devclone(c, nc);
}

static int
XXXwalk(Chan* c, char* name)
{
	return devwalk(c, name, XXXtab, nelem(XXXtab), devgen);
}

static void
XXXstat(Chan* c, char* db)
{
	devstat(c, db, XXXtab, nelem(XXXtab), devgen);
}

static Chan*
XXXopen(Chan* c, int omode)
{
	return devopen(c, omode, XXXtab, nelem(XXXtab), devgen);
}

static void
XXXcreate(Chan* c, char* name, int omode, ulong perm)	/* default in dev.c */
{
	USED(c, name, omode, perm);
	error(Eperm);
}

static void
XXXremove(Chan* c)					/* default in dev.c */
{
	USED(c);
	error(Eperm);
}

static void
XXXwstat(Chan* c, char* dp)				/* default in dev.c */
{
	USED(c, dp);
	error(Eperm);
}

static void
XXXclose(Chan* c)
{
	USED(c);
}

static long
XXXread(Chan* c, void* a, long n, ulong offset)
{
	USED(offset);

	switch(c->qid.path & ~CHDIR){
	case Qdir:
		return devdirread(c, a, n, XXXtab, nelem(XXXtab), devgen);
	case Qdata:
		break;
	default:
		n=0;
		break;
	}
	return n;
}

static Block*
XXXbread(Chan* c, long n, ulong offset)			/* default in dev.c */
{
	return devbread(c, n, offset);
}

static long
XXXwrite(Chan* c, char* a, long n, ulong offset)
{
	USED(a, offset);

	switch(c->qid.path & ~CHDIR){
	case Qdata:
		break;
	default:
		error(Ebadusefd);
	}
	return n;
}

static long
XXXbwrite(Chan* c, Block* bp, ulong offset)		/* default in dev.c */
{
	return devbwrite(c, bp, offset);
}

Dev XXXdevtab = {					/* defaults in dev.c */
	'X',
	"XXX",

	XXXreset,					/* devreset */
	XXXinit,					/* devinit */
	XXXattach,
	XXXclone,					/* devclone */
	XXXwalk,
	XXXstat,
	XXXopen,
	XXXcreate,					/* devcreate */
	XXXclose,
	XXXread,
	XXXbread,					/* devbread */
	XXXwrite,
	XXXbwrite,					/* devbwrite */
	XXXremove,					/* devremove */
	XXXwstat,					/* devwstat */
};

M port/devcons.c => port/devcons.c +2 -15
@@ 1,6 1,7 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"pool.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"


@@ 149,21 150,6 @@ print(char *fmt, ...)
	return n;
}

int
fprint(int, char *fmt, ...)	/* needed so we can use user-level libg */
{
	int n;
	va_list arg;
	char buf[PRINTSIZE];

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

	return n;
}

void
panic(char *fmt, ...)
{


@@ 244,6 230,7 @@ echo(Rune r, char *buf, int n)
		case 'x':
			xsummary();
			ixsummary();
			poolsummary();
			break;
		case 'd':
			if(consdebug != nil)

A port/devdraw.c => port/devdraw.c +1782 -0
@@ 0,0 1,1782 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"

#define	Image	IMAGE
#include	<draw.h>
#include	<memdraw.h>
#include	<memlayer.h>

enum
{
	Qtopdir		= 1,
	Q2nd,
	Qnew,
	Q3rd,
	Qcolormap,
	Qctl,
	Qdata,
	Qrefresh,
};

/*
 * Qid path is:
 *	 4 bits of file type (qids above)
 *	24 bits of mux slot number +1; 0 means not attached to client
 */
#define	QSHIFT	4	/* location in qid of client # */

#define	QID(q)		(((q).path&0x0000000F)>>0)
#define	CLIENTPATH(q)	((q&0x07FFFFFF0)>>QSHIFT)
#define	CLIENT(q)	CLIENTPATH((q).path)

#define	NHASH		(1<<5)
#define	HASHMASK	(NHASH-1)

typedef struct Client Client;
typedef struct Draw Draw;
typedef struct DImage DImage;
typedef struct DScreen DScreen;
typedef struct CScreen CScreen;
typedef struct FChar FChar;
typedef struct Refresh Refresh;
typedef struct Refx Refx;
typedef struct DName DName;

#define	BLANKTIME	30*60*1000	/* half hour */

struct Draw
{
	QLock;
	int		clientid;
	int		nclient;
	Client**	client;
	int		nname;
	DName*	name;
	int		vers;
	int		blanked;	/* screen turned off */
	ulong		blanktime;	/* time of last operation */
	ulong		savemap[3*256];
};

struct Client
{
	Ref		r;
	DImage*		dimage[NHASH];
	CScreen*	cscreen;
	Refresh*	refresh;
	Rendez		refrend;
	uchar*		readdata;
	int		nreaddata;
	int		busy;
	int		clientid;
	int		slot;
	int		refreshme;
	int		infoid;
};

struct Refresh
{
	DImage*		dimage;
	Rectangle	r;
	Refresh*	next;
};

struct Refx
{
	Client*		client;
	DImage*		dimage;
};

struct DName
{
	char			*name;
	Client	*client;
	DImage*		dimage;
	int			vers;
};

struct FChar
{
	int		minx;	/* left edge of bits */
	int		maxx;	/* right edge of bits */
	uchar		miny;	/* first non-zero scan-line */
	uchar		maxy;	/* last non-zero scan-line + 1 */
	schar		left;	/* offset of baseline */
	uchar		width;	/* width of baseline */
};

/*
 * Reference counts in DImages:
 *	one per open by original client
 *	one per screen image or fill
 * Images published by name are not ref'ed, but protected by
 * comparing version number with the DName entry.
 */
struct DImage
{
	int		id;
	int		ref;
	char		*name;
	int		vers;
	Memimage*	image;
	int		ascent;
	int		nfchar;
	FChar*		fchar;
	DScreen*	dscreen;	/* 0 if not a window */
	DImage*		next;
};

struct CScreen
{
	DScreen*	dscreen;
	CScreen*	next;
};

struct DScreen
{
	int		id;
	int		public;
	int		ref;
	DImage	*dimage;
	DImage	*dfill;
	Memscreen*	screen;
	Client*		owner;
	DScreen*	next;
};

static	Draw		sdraw;
static	Memimage	screenimage;
static	Memdata	screendata;
static	Rectangle	flushrect;
static	DScreen*	dscreen;
extern	void		flushmemscreen(Rectangle);
	void		drawmesg(Client*, void*, int);
	void		drawuninstall(Client*, int);
	void		drawfreedimage(DImage*);

static	char Enodrawimage[] =	"unknown id for draw image";
static	char Enodrawscreen[] =	"unknown id for draw screen";
static	char Eshortdraw[] =	"short draw message";
static	char Eshortread[] =	"draw read too short";
static	char Eimageexists[] =	"image id in use";
static	char Escreenexists[] =	"screen id in use";
static	char Edrawmem[] =	"image memory allocation failed";
static	char Ereadoutside[] =	"readimage outside image";
static	char Ewriteoutside[] =	"writeimage outside image";
static	char Enotfont[] =	"image not a font";
static	char Eindex[] =		"character index out of range";
static	char Enoclient[] =	"no such draw client";
static	char Eldepth[] =	"image has bad ldepth";
static	char Enameused[] =	"image name in use";
static	char Enoname[] =	"no image with that name";
static	char Eoldname[] =	"named image no longer valid";
static	char Enamed[] = 	"image already has name";
static	char Ewrongname[] = 	"wrong name for image";

static int
drawgen(Chan *c, Dirtab *tab, int x, int s, Dir *dp)
{
	int t;
	Qid q;
	ulong path;
	Client *cl;
	char buf[NAMELEN];

	USED(tab, x);
	q.vers = 0;

	/*
	 * Top level directory contains the name of the device.
	 */
	if(c->qid.path == CHDIR){
		switch(s){
		case 0:
			q = (Qid){CHDIR|Q2nd, 0};
			devdir(c, q, "draw", 0, eve, 0555, dp);
			break;
		default:
			return -1;
		}
		return 1;
	}

	/*
	 * Second level contains "new" plus all the clients.
	 */
	t = QID(c->qid);
	if(t == Q2nd || t == Qnew){
		if(s == 0){
			q = (Qid){Qnew, 0};
			devdir(c, q, "new", 0, eve, 0666, dp);
		}
		else if(s <= sdraw.nclient){
			cl = sdraw.client[s-1];
			if(cl == 0)
				return 0;
			sprint(buf, "%d", cl->clientid);
			q = (Qid){CHDIR|(s<<QSHIFT)|Q3rd, 0};
			devdir(c, q, buf, 0, eve, 0555, dp);
			return 1;
		}
		else
			return -1;
		return 1;
	}

	/*
	 * Third level.
	 */
	path = c->qid.path&~(CHDIR|((1<<QSHIFT)-1));	/* slot component */
	q.vers = c->qid.vers;
	switch(s){
	case 0:
		q = (Qid){path|Qcolormap, c->qid.vers};
		devdir(c, q, "colormap", 0, eve, 0600, dp);
		break;
	case 1:
		q = (Qid){path|Qctl, c->qid.vers};
		devdir(c, q, "ctl", 0, eve, 0600, dp);
		break;
	case 2:
		q = (Qid){path|Qdata, c->qid.vers};
		devdir(c, q, "data", 0, eve, 0600, dp);
		break;
	case 3:
		q = (Qid){path|Qrefresh, c->qid.vers};
		devdir(c, q, "refresh", 0, eve, 0400, dp);
		break;
	default:
		return -1;
	}
	return 1;
}

static
int
drawrefactive(void *a)
{
	Client *c;

	c = a;
	return c->refreshme || c->refresh!=0;
}

static
void
drawrefresh(Memimage *l, Rectangle r, void *v)
{
	Refx *x;
	DImage *d;
	Client *c;
	Refresh *ref;

	USED(l);
	if(v == 0)
		return;
	x = v;
	c = x->client;
	d = x->dimage;
	for(ref=c->refresh; ref; ref=ref->next)
		if(ref->dimage == d){
			bbox(&ref->r, r);
			return;
		}
	ref = malloc(sizeof(Refresh));
	if(ref){
		ref->dimage = d;
		ref->r = r;
		ref->next = c->refresh;
		c->refresh = ref;
	}
}

static
void
addflush(Rectangle r)
{
	bbox(&flushrect, r);
}

static
void
dstflush(int dstid, Memimage *dst, Rectangle r)
{
	if(dstid == 0){
		bbox(&flushrect, r);
		return;
	}
	if(dst->layer == nil)
		return;
	if(dst->layer->screen->image->data != screenimage.data)
		return;
	r = rectaddpt(r, dst->layer->delta);
	bbox(&flushrect, r);
}

static
void
drawflush(void)
{
	flushmemscreen(flushrect);
	flushrect = Rect(10000, 10000, -10000, -10000);
}

static
int
drawcmp(char *a, char *b, int n)
{
	if(strlen(a) != n)
		return 1;
	return memcmp(a, b, n);
}

DName*
drawlookupname(int n, char *str)
{
	DName *name, *ename;

	name = sdraw.name;
	ename = &name[sdraw.nname];
	for(; name<ename; name++)
		if(drawcmp(name->name, str, n) == 0)
			return name;
	error(Enoname);
	return 0;
}

int
drawgoodname(DImage *d)
{
	DName *n;

	if(d->name == nil)
		return 1;
	n = drawlookupname(strlen(d->name), d->name);
	if(n==nil || n->vers!=d->vers)
		return 0;
	/* if window, validate the screen's own images */
	if(d->dscreen == nil)
		return 1;
	if(drawgoodname(d->dscreen->dimage) && drawgoodname(d->dscreen->dfill))
		return 1;
	return 0;
}

DImage*
drawlookup(Client *client, int id, int checkname)
{
	DImage *d;

	d = client->dimage[id&HASHMASK];
	while(d){
		if(d->id == id){
			if(checkname && !drawgoodname(d))
				error("Eoldname");
			return d;
		}
		d = d->next;
	}
	return 0;
}

DScreen*
drawlookupdscreen(int id)
{
	DScreen *s;

	s = dscreen;
	while(s){
		if(s->id == id)
			return s;
		s = s->next;
	}
	return 0;
}

DScreen*
drawlookupscreen(Client *client, int id, CScreen **cs)
{
	CScreen *s;

	s = client->cscreen;
	while(s){
		if(s->dscreen->id == id){
			*cs = s;
			return s->dscreen;
		}
		s = s->next;
	}
	error(Enodrawscreen);
	return 0;
}

Memimage*
drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
{
	DImage *d;

	d = malloc(sizeof(DImage));
	if(d == 0)
		return 0;
	d->id = id;
	d->ref = 1;
	d->name = 0;
	d->image = i;
	d->nfchar = 0;
	d->fchar = 0;
	d->dscreen = dscreen;
	d->next = client->dimage[id&HASHMASK];
	client->dimage[id&HASHMASK] = d;
	return i;
}

Memscreen*
drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
{
	Memscreen *s;
	CScreen *c;

	c = malloc(sizeof(CScreen));
	if(c == 0)
		return 0;
	if(d == 0){
		d = malloc(sizeof(DScreen));
		if(d == 0){
			free(c);
			return 0;
		}
		s = malloc(sizeof(Memscreen));
		if(s == 0){
			free(c);
			free(d);
			return 0;
		}
		s->frontmost = 0;
		s->rearmost = 0;
		d->dimage = dimage;
		if(dimage){
			s->image = dimage->image;
			dimage->ref++;
		}
		d->dfill = dfill;
		if(dfill){
			s->fill = dfill->image;
			dfill->ref++;
		}
		d->ref = 0;
		d->id = id;
		d->screen = s;
		d->public = public;
		d->next = dscreen;
		d->owner = client;
		dscreen = d;
	}
	c->dscreen = d;
	d->ref++;
	c->next = client->cscreen;
	client->cscreen = c;
	return d->screen;
}

void
drawdelname(DName *name)
{
	int i;

	i = name-sdraw.name;
	memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
	sdraw.nname--;
}

void
drawfreedscreen(DScreen *this)
{
	DScreen *ds, *next;

	this->ref--;
	if(this->ref < 0)
		print("negative ref in drawfreedscreen\n");
	if(this->ref > 0)
		return;
	ds = dscreen;
	if(ds == this){
		dscreen = this->next;
		goto Found;
	}
	while(next = ds->next){	/* assign = */
		if(next == this){
			ds->next = this->next;
			goto Found;
		}
		ds = next;
	}
	error(Enodrawimage);

    Found:
	if(this->dimage)
		drawfreedimage(this->dimage);
	if(this->dfill)
		drawfreedimage(this->dfill);
	free(this->screen);
	free(this);
}

void
drawfreedimage(DImage *dimage)
{
	int i;
	Memimage *l;
	DScreen *ds;

	dimage->ref--;
	if(dimage->ref < 0)
		print("negative ref in drawfreedimage\n");
	if(dimage->ref > 0)
		return;

	/* any names? */
	for(i=0; i<sdraw.nname; )
		if(sdraw.name[i].dimage == dimage)
			drawdelname(sdraw.name+i);
		else
			i++;
	if(dimage->vers != 0)	/* acquired by name; owned by someone else*/
		goto Return;
	if(dimage->image == &screenimage)	/* don't free the display */
		goto Return;
	ds = dimage->dscreen;
	if(ds){
		l = dimage->image;
		if(l->data == screenimage.data)
			addflush(l->layer->screenr);
		if(l->layer->refreshfn == drawrefresh)	/* else true owner will clean up */
			free(l->layer->refreshptr);
		l->layer->refreshptr = nil;
		if(drawgoodname(dimage))
			memldelete(l);
		else
			memlfree(l);
		drawfreedscreen(ds);
	}else
		freememimage(dimage->image);
    Return:
	free(dimage->fchar);
	free(dimage);
}

void
drawuninstallscreen(Client *client, CScreen *this)
{
	CScreen *cs, *next;

	cs = client->cscreen;
	if(cs == this){
		client->cscreen = this->next;
		drawfreedscreen(this->dscreen);
		free(this);
		return;
	}
	while(next = cs->next){	/* assign = */
		if(next == this){
			cs->next = this->next;
			drawfreedscreen(this->dscreen);
			free(this);
			return;
		}
		cs = next;
	}
}

void
drawuninstall(Client *client, int id)
{
	DImage *d, *next;

	/*
	 * If this image is a screen fill or image, don't drop it yet; save it
	 * in the DScreen and drawfreedscreen will ask again later.
	 */
	d = client->dimage[id&HASHMASK];
	if(d == 0)
		error(Enodrawimage);
	if(d->id == id){
		client->dimage[id&HASHMASK] = d->next;
		drawfreedimage(d);
		return;
	}
	while(next = d->next){	/* assign = */
		if(next->id == id){
			d->next = next->next;
			drawfreedimage(next);
			return;
		}
		d = next;
	}
	error(Enodrawimage);
}

void
drawaddname(Client *client, DImage *di, int n, char *str)
{
	DName *name, *ename, *new, *t;

	name = sdraw.name;
	ename = &name[sdraw.nname];
	for(; name<ename; name++)
		if(drawcmp(name->name, str, n) == 0)
			error(Enameused);
	t = smalloc((sdraw.nname+1)*sizeof(DName));
	memmove(t, sdraw.name, sdraw.nname*sizeof(DName));
	free(sdraw.name);
	sdraw.name = t;
	new = &sdraw.name[sdraw.nname++];
	new->name = smalloc(n+1);
	memmove(new->name, str, n);
	new->name[n] = 0;
	new->dimage = di;
	new->client = client;
	new->vers = ++sdraw.vers;
}

Client*
drawnewclient(void)
{
	Client *cl, **cp;
	int i;

	for(i=0; i<sdraw.nclient; i++){
		cl = sdraw.client[i];
		if(cl == 0)
			break;
	}
	if(i == sdraw.nclient){
		cp = malloc((sdraw.nclient+1)*sizeof(Client*));
		if(cp == 0)
			return 0;
		memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*));
		free(sdraw.client);
		sdraw.client = cp;
		sdraw.nclient++;
		cp[i] = 0;
	}
	cl = malloc(sizeof(Client));
	if(cl == 0)
		return 0;
	memset(cl, 0, sizeof(Client));
	cl->slot = i;
	cl->clientid = ++sdraw.clientid;
	sdraw.client[i] = cl;
	return cl;
}

Client*
drawclientofpath(ulong path)
{
	Client *cl;
	int slot;

	slot = CLIENTPATH(path);
	if(slot == 0)
		return nil;
	cl = sdraw.client[slot-1];
	if(cl==0 || cl->clientid==0)
		return nil;
	return cl;
}


Client*
drawclient(Chan *c)
{
	Client *client;

	client = drawclientofpath(c->qid.path);
	if(client == nil)
		error(Enoclient);
	return client;
}

Memimage*
drawimage(Client *client, uchar *a)
{
	DImage *d;

	d = drawlookup(client, BGLONG(a), 1);
	if(d == nil)
		error(Enodrawimage);
	return d->image;
}

void
drawrectangle(Rectangle *r, uchar *a)
{
	r->min.x = BGLONG(a+0*4);
	r->min.y = BGLONG(a+1*4);
	r->max.x = BGLONG(a+2*4);
	r->max.y = BGLONG(a+3*4);
}

void
drawpoint(Point *p, uchar *a)
{
	p->x = BGLONG(a+0*4);
	p->y = BGLONG(a+1*4);
}

Point
drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index)
{
	FChar *fc;
	Rectangle r;
	Point sp1;

	fc = &font->fchar[index];
	r.min.x = p.x+fc->left;
	r.min.y = p.y-(font->ascent-fc->miny);
	r.max.x = r.min.x+(fc->maxx-fc->minx);
	r.max.y = r.min.y+(fc->maxy-fc->miny);
	sp1.x = sp->x+fc->left;
	sp1.y = sp->y+fc->miny;
	memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny));
	p.x += fc->width;
	sp->x += fc->width;
	return p;
}

Chan*
drawattach(char *spec)
{
	int width;

	if(screendata.data == nil){
		screendata.base = nil;
		screendata.data = attachscreen(&screenimage.r, &screenimage.ldepth, &width);
		if(screendata.data != nil){
			screendata.ref = 1;
			screenimage.data = &screendata;
			screenimage.width = width;
			screenimage.clipr  = screenimage.r;
		}
	}
	return devattach('i', spec);
}

int
drawwalk(Chan *c, char *name)
{
	if(screendata.data == nil)
		error("no frame buffer");
	if(strcmp(name, "..") == 0){
		switch(QID(c->qid)){
		case Qtopdir:
		case Q2nd:
			c->qid = (Qid){CHDIR|Qtopdir, 0};
			break;
		case Q3rd:
			c->qid = (Qid){CHDIR|Q2nd, 0};
			break;
		default:
			panic("drawwalk %lux", c->qid.path);
		}
		return 1;
	}
	return devwalk(c, name, 0, 0, drawgen);
}

static void
drawstat(Chan *c, char *db)
{
	devstat(c, db, 0, 0, drawgen);
}

static Chan*
drawopen(Chan *c, int omode)
{
	Client *cl;

	if(c->qid.path & CHDIR)
		return devopen(c, omode, 0, 0, drawgen);

	qlock(&sdraw);
	if(waserror()){
		qunlock(&sdraw);
		nexterror();
	}

	if(QID(c->qid) == Qnew){
		cl = drawnewclient();
		if(cl == 0)
			error(Enodev);
		c->qid.path = Qctl|((cl->slot+1)<<QSHIFT);
	}

	switch(QID(c->qid)){
	case Qnew:
		break;

	case Qctl:
		cl = drawclient(c);
		if(cl->busy)
			error(Einuse);
		cl->busy = 1;
		flushrect = Rect(10000, 10000, -10000, -10000);
		drawinstall(cl, 0, &screenimage, 0);
		incref(&cl->r);
		break;
	case Qcolormap:
	case Qdata:
	case Qrefresh:
		cl = drawclient(c);
		incref(&cl->r);
		break;
	}
	qunlock(&sdraw);
	poperror();
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

static void
drawclose(Chan *c)
{
	int i;
	DImage *d, **dp;
	Client *cl;
	Refresh *r;

	if(c->qid.path & CHDIR)
		return;
	qlock(&sdraw);
	if(waserror()){
		qunlock(&sdraw);
		nexterror();
	}

	cl = drawclient(c);
	if(QID(c->qid) == Qctl)
		cl->busy = 0;
	if((c->flag&COPEN) && (decref(&cl->r)==0)){
		while(r = cl->refresh){	/* assign = */
			cl->refresh = r->next;
			free(r);
		}
		/* free names */
		for(i=0; i<sdraw.nname; )
			if(sdraw.name[i].client == cl)
				drawdelname(sdraw.name+i);
			else
				i++;
		while(cl->cscreen)
			drawuninstallscreen(cl, cl->cscreen);
		/* all screens are freed, so now we can free images */
		dp = cl->dimage;
		for(i=0; i<NHASH; i++){
			while(d = *dp){	/* assign = */
				*dp = d->next;
				drawfreedimage(d);
			}
			dp++;
		}
		sdraw.client[cl->slot] = 0;
		drawflush();	/* to erase visible, now dead windows */
		free(cl);
	}
	qunlock(&sdraw);
	poperror();
}

long
drawread(Chan *c, void *a, long n, ulong offset)
{
	int index, m;
	ulong red, green, blue;
	Client *cl;
	uchar *p;
	Refresh *r;
	DImage *di;
	Memimage *i;

	USED(offset);
	if(c->qid.path & CHDIR)
		return devdirread(c, a, n, 0, 0, drawgen);
	cl = drawclient(c);
	qlock(&sdraw);
	if(waserror()){
		qunlock(&sdraw);
		nexterror();
	}
	switch(QID(c->qid)){
	case Qctl:
		if(n <= 12*12)
			error(Eshortread);
		if(cl->infoid < 0)
			error(Enodrawimage);
		if(cl->infoid == 0)
			i = &screenimage;
		else{
			di = drawlookup(cl, cl->infoid, 1);
			if(di == nil)
				error(Enodrawimage);
			i = di->image;
		}
		n = sprint(a, "%11d %11d %11d %11d %11d %11d %11d %11d %11d %11d %11d %11d ",
			cl->clientid, cl->infoid, i->ldepth, i->repl,
			i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
			i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
		cl->infoid = -1;
		break;

	case Qcolormap:
		drawactive(1);	/* to restore map from backup */
		p = malloc(4*12*256);
		if(p == 0)
			error(Enomem);
		m = 0;
		for(index = 0; index < 256; index++){
			getcolor(index, &red, &green, &blue);
			m += sprint((char*)p+m, "%11d %11d %11d %11d\n", index, red>>24, green>>24, blue>>24);
		}
		n = readstr(offset, a, n, (char*)p);
		free(p);
		break;

	case Qdata:
		if(cl->readdata == nil)
			error("no draw data");
		if(n < cl->nreaddata)
			error(Eshortread);
		n = cl->nreaddata;
		memmove(a, cl->readdata, cl->nreaddata);
		free(cl->readdata);
		cl->readdata = nil;
		break;

	case Qrefresh:
		if(n < 5*4)
			error(Ebadarg);
		for(;;){
			if(cl->refreshme || cl->refresh)
				break;
			qunlock(&sdraw);
			sleep(&cl->refrend, drawrefactive, cl);
			qlock(&sdraw);
		}
		p = a;
		while(cl->refresh && n>=5*4){
			r = cl->refresh;
			BPLONG(p+0*4, r->dimage->id);
			BPLONG(p+1*4, r->r.min.x);
			BPLONG(p+2*4, r->r.min.y);
			BPLONG(p+3*4, r->r.max.x);
			BPLONG(p+4*4, r->r.max.y);
			cl->refresh = r->next;
			free(r);
			p += 5*4;
			n -= 5*4;
		}
		cl->refreshme = 0;
		n = p-(uchar*)a;
	}
	qunlock(&sdraw);
	poperror();
	return n;
}

void
drawwakeall(void)
{
	Client *cl;
	int i;

	for(i=0; i<sdraw.nclient; i++){
		cl = sdraw.client[i];
		if(cl && (cl->refreshme || cl->refresh))
			wakeup(&cl->refrend);
	}
}

static long
drawwrite(Chan *c, void *a, long n, ulong offset)
{
	char buf[128], *fields[4], *q;
	Client *cl;
	int i, m, red, green, blue, x;

	USED(offset);
	if(c->qid.path & CHDIR)
		error(Eisdir);
	cl = drawclient(c);
	qlock(&sdraw);
	if(waserror()){
		drawwakeall();
		qunlock(&sdraw);
		nexterror();
	}
	switch(QID(c->qid)){
	case Qctl:
		if(n != 4)
			error("unknown draw control request");
		cl->infoid = BGLONG((uchar*)a);
		break;

	case Qcolormap:
		drawactive(1);	/* to restore map from backup */
		m = n;
		n = 0;
		while(m > 0){
			x = m;
			if(x > sizeof(buf)-1)
				x = sizeof(buf)-1;
			q = memccpy(buf, a, '\n', x);
			if(q == 0)
				break;
			i = q-buf;
			n += i;
			a = (char*)a + i;
			m -= i;
			*q = 0;
			if(parsefields(buf, fields, nelem(fields), " ") != 4)
				error(Ebadarg);
			i = strtoul(fields[0], 0, 0);
			red = strtoul(fields[1], 0, 0);
			green = strtoul(fields[2], 0, 0);
			blue = strtoul(fields[3], &q, 0);
			if(fields[3] == q)
				error(Ebadarg);
			if(red>255 || green>255 || blue>255 || i<0 || i>255)
				error(Ebadarg);
			red |= red<<8;
			red |= red<<16;
			green |= green<<8;
			green |= green<<16;
			blue |= blue<<8;
			blue |= blue<<16;
			setcolor(i, red, green, blue);
		}
		break;

	case Qdata:
		drawmesg(cl, a, n);
		drawwakeall();
		break;

	default:
		error(Ebadusefd);
	}
	qunlock(&sdraw);
	poperror();
	return n;
}

uchar*
drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
{
	int b, x;

	if(p >= maxp)
		error(Eshortdraw);
	b = *p++;
	x = b & 0x7F;
	if(b & 0x80){
		if(p+1 >= maxp)
			error(Eshortdraw);
		x |= *p++ << 7;
		x |= *p++ << 15;
		if(x & (1<<22))
			x |= ~0<<23;
	}else{
		if(b & 0x40)
			x |= ~0<<7;
		x += oldx;
	}
	*newx = x;
	return p;
}

void
drawmesg(Client *client, void *av, int n)
{
	int c, ldepth, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, ox, oy, esize, doflush;
	uchar *u, *a;
	Rectangle r, clipr;
	Point p, q, *pp, sp;
	Memimage *i, *dst, *src, *mask;
	Memimage *l, **lp;
	Memscreen *scrn;
	DImage *font, *ll, *di, *ddst, *dsrc;
	DName *dn;
	DScreen *dscrn;
	FChar *fc;
	Refx *refx;
	CScreen *cs;
	Refreshfn reffn;

	a = av;
	m = 0;
	while((n-=m) > 0){
		a += m;
		switch(*a){
		default:
			error("bad draw command");
		/* allocate: 'a' id[4] screenid[4] refresh[1] ldepth[2] repl[1] R[4*4] clipR[4*4] value[1] */
		case 'a':
			m = 1+4+4+1+2+1+4*4+4*4+1;
			if(n < m)
				error(Eshortdraw);
			dstid = BGLONG(a+1);
			if(drawlookup(client, dstid, 0))
				error(Eimageexists);
			ldepth = BGSHORT(a+10);
			repl = a[12];
			drawrectangle(&r, a+13);
			scrnid = BGSHORT(a+5);
			if(scrnid){
				dscrn = drawlookupscreen(client, scrnid, &cs);
				scrn = dscrn->screen;
				if(repl || ldepth!=scrn->image->ldepth)
					error("image parameters incompatible with screen");
				reffn = nil;
				switch(a[9]){
				case Refbackup:
					break;
				case Refnone:
					reffn = memlnorefresh;
					break;
				case Refmesg:
					reffn = drawrefresh;
					break;
				default:
					error("unknown refresh method");
				}
				l = memlalloc(scrn, r, reffn, 0, a[45]);
				if(l == 0)
					error(Edrawmem);
				addflush(l->layer->screenr);
				drawrectangle(&l->clipr, a+29);
				rectclip(&l->clipr, r);
				if(drawinstall(client, dstid, l, dscrn) == 0){
					memldelete(l);
					error(Edrawmem);
				}
				dscrn->ref++;
				if(reffn){
					refx = nil;
					if(reffn == drawrefresh){
						refx = malloc(sizeof(Refx));
						if(refx == 0){
							drawuninstall(client, dstid);
							error(Edrawmem);
						}
						refx->client = client;
						refx->dimage = drawlookup(client, dstid, 1);
					}
					memlsetrefresh(l, reffn, refx);
				}
				continue;
			}
			i = allocmemimage(r, ldepth);
			if(i == 0)
				error(Edrawmem);
			i->repl = repl;
			drawrectangle(&i->clipr, a+29);
			if(!repl)
				rectclip(&i->clipr, r);
			if(drawinstall(client, dstid, i, 0) == 0){
				freememimage(i);
				error(Edrawmem);
			}
			memfillcolor(i, a[45]);
			continue;

		/* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */
		case 'A':
			m = 1+4+4+4+1;
			if(n < m)
				error(Eshortdraw);
			dstid = BGLONG(a+1);
			if(dstid == 0)
				error(Ebadarg);
			if(drawlookupdscreen(dstid))
				error(Escreenexists);
			ddst = drawlookup(client, BGLONG(a+5), 1);
			dsrc = drawlookup(client, BGLONG(a+9), 1);
			if(ddst==0 || dsrc==0)
				error(Enodrawimage);
			if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0)
				error(Edrawmem);
			continue;

		/* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */
		case 'c':
			m = 1+4+1+4*4;
			if(n < m)
				error(Eshortdraw);
			ddst = drawlookup(client, BGLONG(a+1), 1);
			if(ddst == nil)
				error(Enodrawimage);
			if(ddst->name)
				error("can't change repl/clipr of shared image");
			dst = ddst->image;
			dst->repl = a[5];
			drawrectangle(&dst->clipr, a+6);
			continue;

		/* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */
		case 'd':
			m = 1+4+4+4+4*4+2*4+2*4;
			if(n < m)
				error(Eshortdraw);
			dst = drawimage(client, a+1);
			dstid = BGLONG(a+1);
			src = drawimage(client, a+5);
			mask = drawimage(client, a+9);
			drawrectangle(&r, a+13);
			drawpoint(&p, a+29);
			drawpoint(&q, a+37);
			memdraw(dst, r, src, p, mask, q);
			dstflush(dstid, dst, r);
			continue;

		/* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/
		case 'e':
		case 'E':
			m = 1+4+4+2*4+4+4+4+2*4+2*4;
			if(n < m)
				error(Eshortdraw);
			dst = drawimage(client, a+1);
			dstid = BGLONG(a+1);
			src = drawimage(client, a+5);
			drawpoint(&p, a+9);
			e0 = BGLONG(a+17);
			e1 = BGLONG(a+21);
			if(e0<0 || e1<0)
				error("invalid ellipse semidiameter");
			j = BGLONG(a+25);
			if(j < 0)
				error("negative ellipse thickness");
			drawpoint(&sp, a+29);
			c = j;
			if(*a == 'E')
				c = -1;
			ox = BGLONG(a+37);
			oy = BGLONG(a+41);
			/* high bit indicates arc angles are present */
			if(ox & (1<<31)){
				if((ox & (1<<30)) == 0)
					ox &= ~(1<<31);
				memarc(dst, p, e0, e1, c, src, sp, ox, oy);
			}else
				memellipse(dst, p, e0, e1, c, src, sp);
			dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
			continue;

		/* free: 'f' id[4] */
		case 'f':
			m = 1+4;
			if(n < m)
				error(Eshortdraw);
			ll = drawlookup(client, BGLONG(a+1), 0);
			if(ll && ll->dscreen && ll->dscreen->owner != client)
				ll->dscreen->owner->refreshme = 1;
			drawuninstall(client, BGLONG(a+1));
			continue;

		/* free screen: 'F' id[4] */
		case 'F':
			m = 1+4;
			if(n < m)
				error(Eshortdraw);
			drawlookupscreen(client, BGLONG(a+1), &cs);
			drawuninstallscreen(client, cs);
			continue;

		/* initialize font: 'i' fontid[4] nchars[4] ascent[1] */
		case 'i':
			m = 1+4+4+1;
			if(n < m)
				error(Eshortdraw);
			dstid = BGLONG(a+1);
			if(dstid == 0)
				error("can't use display as font");
			font = drawlookup(client, dstid, 1);
			if(font == 0)
				error(Enodrawimage);
			if(font->image->layer)
				error("can't use window as font");
			free(font->fchar);	/* should we complain if non-zero? */
			ni = BGLONG(a+5);
			font->fchar = malloc(ni*sizeof(FChar));
			if(font->fchar == 0)
				error("no memory for font");
			memset(font->fchar, 0, ni*sizeof(FChar));
			font->nfchar = ni;
			font->ascent = a[9];
			continue;

		/* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
		case 'l':
			m = 1+4+4+2+4*4+2*4+1+1;
			if(n < m)
				error(Eshortdraw);
			font = drawlookup(client, BGLONG(a+1), 1);
			if(font == 0)
				error(Enodrawimage);
			if(font->nfchar == 0)
				error(Enotfont);
			src = drawimage(client, a+5);
			ci = BGSHORT(a+9);
			if(ci >= font->nfchar)
				error(Eindex);
			drawrectangle(&r, a+11);
			drawpoint(&p, a+27);
			memdraw(font->image, r, src, p, memones, p);
			fc = &font->fchar[ci];
			fc->minx = r.min.x;
			fc->maxx = r.max.x;
			fc->miny = r.min.y;
			fc->maxy = r.max.y;
			fc->left = a[35];
			fc->width = a[36];
			continue;

		/* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */
		case 'L':
			m = 1+4+2*4+2*4+4+4+4+4+2*4;
			if(n < m)
				error(Eshortdraw);
			dst = drawimage(client, a+1);
			dstid = BGLONG(a+1);
			drawpoint(&p, a+5);
			drawpoint(&q, a+13);
			e0 = BGLONG(a+21);
			e1 = BGLONG(a+25);
			j = BGLONG(a+29);
			if(j < 0)
				error("negative line width");
			src = drawimage(client, a+33);
			drawpoint(&sp, a+37);
			memline(dst, p, q, e0, e1, j, src, sp);
			/* avoid memlinebbox if possible */
			if(dstid==0 || dst->layer!=nil){
				/* BUG: this is terribly inefficient: update maximal containing rect*/
				r = memlinebbox(p, q, e0, e1, j);
				dstflush(dstid, dst, insetrect(r, -(1+1+j)));
			}
			continue;

		/* attach to a named image: 'n' dstid[4] j[1] name[j] */
		case 'n':
			m = 1+4+1;
			if(n < m)
				error(Eshortdraw);
			j = a[5];
			if(j == 0)	/* give me a non-empty name please */
				error(Eshortdraw);
			m += j;
			if(n < m)
				error(Eshortdraw);
			dstid = BGLONG(a+1);
			if(drawlookup(client, dstid, 0))
				error(Eimageexists);
			dn = drawlookupname(j, (char*)a+6);
			if(drawinstall(client, dstid, dn->dimage->image, 0) == 0)
				error(Edrawmem);
			di = drawlookup(client, dstid, 0);
			if(di == 0)
				error("draw: can't happen");
			di->vers = dn->vers;
			di->name = smalloc(j+1);
			memmove(di->name, a+6, j);
			di->name[j] = 0;
			client->infoid = dstid;
			continue;

		/* name an image: 'N' dstid[4] in[1] j[1] name[j] */
		case 'N':
			m = 1+4+1+1;
			if(n < m)
				error(Eshortdraw);
			c = a[5];
			j = a[6];
			if(j == 0)	/* give me a non-empty name please */
				error(Eshortdraw);
			m += j;
			if(n < m)
				error(Eshortdraw);
			di = drawlookup(client, BGLONG(a+1), 0);
			if(di == 0)
				error(Enodrawimage);
			if(di->name)
				error(Enamed);
			if(c)
				drawaddname(client, di, j, (char*)a+7);
			else{
				dn = drawlookupname(j, (char*)a+7);
				if(dn->dimage != di)
					error(Ewrongname);
				drawdelname(dn);
			}
			continue;

		/* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */
		case 'o':
			m = 1+4+2*4+2*4;
			if(n < m)
				error(Eshortdraw);
			dst = drawimage(client, a+1);
			if(dst->layer){
				drawpoint(&p, a+5);
				drawpoint(&q, a+13);
				r = dst->layer->screenr;
				ni = memlorigin(dst, p, q);
				if(ni < 0)
					error("image origin failed");
				if(ni > 0){
					addflush(r);
					addflush(dst->layer->screenr);
					ll = drawlookup(client, BGLONG(a+1), 1);
					if(ll->dscreen->owner != client)
						ll->dscreen->owner->refreshme = 1;
				}
			}
			continue;

		/* filled polygon: 'P' dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
		/* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
		case 'p':
		case 'P':
			m = 1+4+2+4+4+4+4+2*4;
			if(n < m)
				error(Eshortdraw);
			dstid = BGLONG(a+1);
			dst = drawimage(client, a+1);
			ni = BGSHORT(a+5);
			if(ni < 0)
				error("negative count in polygon");
			e0 = BGLONG(a+7);
			e1 = BGLONG(a+11);
			j = 0;
			if(*a == 'p'){
				j = BGLONG(a+15);
				if(j < 0)
					error("negative polygon line width");
			}
			src = drawimage(client, a+19);
			drawpoint(&sp, a+23);
			drawpoint(&p, a+31);
			ni++;
			pp = malloc(ni*sizeof(Point));
			if(pp == nil)
				error(Enomem);
			doflush = 0;
			if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage.data))
				doflush = 1;	/* simplify test in loop */
			ox = oy = 0;
			u = a+m;
			for(y=0; y<ni; y++){
				u = drawcoord(u, a+n, ox, &p.x);
				u = drawcoord(u, a+n, oy, &p.y);
				ox = p.x;
				oy = p.y;
				if(doflush){
					esize = j;
					if(*a == 'p'){
						if(y == 0){
							c = memlineendsize(e0);
							if(c > esize)
								esize = c;
						}
						if(y == ni-1){
							c = memlineendsize(e1);
							if(c > esize)
								esize = c;
						}
					}
					if(*a=='P' && e0!=1 && e0 !=~0)
						r = dst->clipr;
					else
						r = Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1);
					dstflush(dstid, dst, r);
				}
				pp[y] = p;
			}
			if(*a == 'p')
				mempoly(dst, pp, ni, e0, e1, j, src, sp);
			else
				memfillpoly(dst, pp, ni, e0, src, sp);
			free(pp);
			m = u-a;
			continue;

		/* read: 'r' id[4] R[4*4] */
		case 'r':
			m = 1+4+4*4;
			if(n < m)
				error(Eshortdraw);
			i = drawimage(client, a+1);
			if(i->layer)
				error("readimage from window unimplemented");
			drawrectangle(&r, a+5);
			if(!rectinrect(r, i->r))
				error(Ereadoutside);
			free(client->readdata);
			c = bytesperline(r, i->ldepth);
			c *= Dy(r);
			client->readdata = mallocz(c, 0);
			if(client->readdata == nil)
				error("readimage malloc failed");
			client->nreaddata = unloadmemimage(i, r, client->readdata, c);
			if(client->nreaddata < 0){
				free(client->readdata);
				client->readdata = nil;
				error("bad readimage call");
			}
			continue;

		/* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */
		/* stringbg: 'x' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] bgid[4] bgpt[2*4] ni*(index[2]) */
		case 's':
		case 'x':
			m = 1+4+4+4+2*4+4*4+2*4+2;
			if(*a == 'x')
				m += 4+2*4;
			if(n < m)
				error(Eshortdraw);

		CaseS:
			dst = drawimage(client, a+1);
			dstid = BGLONG(a+1);
			src = drawimage(client, a+5);
			font = drawlookup(client, BGLONG(a+9), 1);
			if(font == 0)
				error(Enodrawimage);
			if(font->nfchar == 0)
				error(Enotfont);
			drawpoint(&p, a+13);
			drawrectangle(&r, a+21);
			drawpoint(&sp, a+37);
			ni = BGSHORT(a+45);
			u = a+m;
			m += ni*2;
			if(n < m)
				error(Eshortdraw);
			clipr = dst->clipr;
			dst->clipr = r;
			if(*a == 'x'){
				/* paint background */
				l = drawimage(client, a+47);
				drawpoint(&q, a+51);
				r.min.x = p.x;
				r.min.y = p.y-font->ascent;
				r.max.x = p.x;
				r.max.y = r.min.y+Dy(font->image->r);
				j = ni;
				while(--j >= 0){
					ci = BGSHORT(u);
					if(ci<0 || ci>=font->nfchar){
						dst->clipr = clipr;
						error(Eindex);
					}
					r.max.x += font->fchar[ci].width;
					u += 2;
				}
				memdraw(dst, r, l, q, memones, ZP);
				u -= 2*ni;
			}
			q = p;
			while(--ni >= 0){
				ci = BGSHORT(u);
				if(ci<0 || ci>=font->nfchar){
					dst->clipr = clipr;
					error(Eindex);
				}
				q = drawchar(dst, q, src, &sp, font, ci);
				u += 2;
			}
			dst->clipr = clipr;
			p.y -= font->ascent;
			dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
			continue;

		/* use public screen: 'S' id[4] ldepth[4] */
		case 'S':
			m = 1+4+4;
			if(n < m)
				error(Eshortdraw);
			dstid = BGLONG(a+1);
			if(dstid == 0)
				error(Ebadarg);
			dscrn = drawlookupdscreen(dstid);
			if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
				error(Enodrawscreen);
			if(dscrn->screen->image->ldepth != BGLONG(a+5))
				error("inconsistent ldepth");
			if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
				error(Edrawmem);
			continue;

		/* top or bottom windows: 't' top[1] nw[2] n*id[4] */
		case 't':
			m = 1+1+2;
			if(n < m)
				error(Eshortdraw);
			nw = BGSHORT(a+2);
			if(nw < 0)
				error(Ebadarg);
			if(nw == 0)
				continue;
			m += nw*4;
			if(n < m)
				error(Eshortdraw);
			lp = malloc(nw*sizeof(Memimage*));
			if(lp == 0)
				error(Enomem);
			if(waserror()){
				free(lp);
				nexterror();
			}
			for(j=0; j<nw; j++)
				lp[j] = drawimage(client, a+1+1+2+j*4);
			if(lp[0]->layer == 0)
				error("images are not windows");
			for(j=1; j<nw; j++)
				if(lp[j]->layer->screen != lp[0]->layer->screen)
					error("images not on same screen");
			if(a[1])
				memltofrontn(lp, nw);
			else
				memltorearn(lp, nw);
			if(lp[0]->layer->screen->image->data == screenimage.data)
				for(j=0; j<nw; j++)
					addflush(lp[j]->layer->screenr);
			ll = drawlookup(client, BGLONG(a+1+1+2), 1);
			if(ll->dscreen->owner != client)
				ll->dscreen->owner->refreshme = 1;
			poperror();
			free(lp);
			continue;

		/* visible: 'v' */
		case 'v':
			m = 1;
			drawflush();
			continue;

		/* write: 'w' id[4] R[4*4] data[x*1] */
		/* write from compressed data: 'W' id[4] R[4*4] data[x*1] */
		case 'w':
		case 'W':
			m = 1+4+4*4;
			if(n < m)
				error(Eshortdraw);
			dstid = BGLONG(a+1);
			dst = drawimage(client, a+1);
			drawrectangle(&r, a+5);
			if(!rectinrect(r, dst->r))
				error(Ewriteoutside);
			y = memload(dst, r, a+m, n-m, *a=='W');
			if(y < 0)
				error("bad writeimage call");
			dstflush(dstid, dst, r);
			m += y;
			continue;
		}
	}
}

Dev drawdevtab = {
	'i',
	"draw",

	devreset,
	devinit,
	drawattach,
	devclone,
	drawwalk,
	drawstat,
	drawopen,
	devcreate,
	drawclose,
	drawread,
	devbread,
	drawwrite,
	devbwrite,
	devremove,
	devwstat,
};

/*
 * On 8 bit displays, load the default color map
 */
void
drawcmap(invert){
	int r, g, b, cr, cg, cb, v;
	int num, den;
	int i, j;
	drawactive(1);	/* to restore map from backup */
	for(r=0,i=0;r!=4;r++) for(v=0;v!=4;v++,i+=16){
		for(g=0,j=v-r;g!=4;g++) for(b=0;b!=4;b++,j++){
			den=r;
			if(g>den) den=g;
			if(b>den) den=b;
			if(den==0)	/* divide check -- pick grey shades */
				cr=cg=cb=v*17;
			else{
				num=17*(4*den+v);
				cr=r*num/den;
				cg=g*num/den;
				cb=b*num/den;
			}
			if(invert)
				setcolor(255-i-(j&15),
					cr*0x01010101, cg*0x01010101, cb*0x01010101);
			else
				setcolor(i+(j&15),
					cr*0x01010101, cg*0x01010101, cb*0x01010101);
		}
	}
}

void
drawblankscreen(int blank)
{
	int i, nc;
	ulong *p;

	if(blank == sdraw.blanked)
		return;
	p = sdraw.savemap;
	nc = 1<<(1<<screenimage.ldepth);
	if(blank == 0)	/* turn screen on */
		for(i=0; i<nc; i++, p+=3)
			setcolor(i, p[0], p[1], p[2]);
	else	/* turn screen off */
		for(i=0; i<nc; i++, p+=3){
			getcolor(i, &p[0], &p[1], &p[2]);
			setcolor(i, 0, 0, 0);
		}
	sdraw.blanked = blank;
}

/*
 * record activity on screen, changing blanking as appropriate
 */
void
drawactive(int active)
{
	if(active){
		drawblankscreen(0);
		sdraw.blanktime = 0;
	}else {
		if(TK2MS(sdraw.blanktime) > BLANKTIME)
			drawblankscreen(1);
		else
			sdraw.blanktime++;
	}
}

D port/devlance.c => port/devlance.c +0 -567
@@ 1,567 0,0 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"../port/netif.h"

enum {
	Ntypes=		9,	/* max number of ethernet packet types */
	Maxrb=		128,	/* max buffers in a ring */
};
#define RSUCC(x) (((x)+1)%l.nrrb)
#define TSUCC(x) (((x)+1)%l.ntrb)

/*
 *  Communication with the lance is via a transmit and receive ring of
 *  message descriptors.  The Initblock contains pointers to and sizes of
 *  these rings.  The rings must be in RAM addressible by the lance
 */
typedef struct {
	ushort	laddr;		/* low order piece of address */
	ushort	flags;		/* flags and high order piece of address */
	short	size;		/* size of buffer */
	ushort	cntflags;	/* (rcv)count of buffer; (xmt) more flags */
} Msg;

/*
 *  lance memory map
 */
struct Lancemem
{
	/*
	 *  initialization block
	 */
	ushort	mode;		/* chip control (see below) */
	ushort	etheraddr[3];	/* the ethernet physical address */
	ushort	multi[4];	/* multicast addresses, 1 bit for each of 64 */
	ushort	rdralow;	/* receive buffer ring */
	ushort	rdrahigh;	/* (top three bits define size of ring) */
	ushort	tdralow;	/* transmit buffer ring */
	ushort	tdrahigh;	/* (top three bits define size of ring) */
	
	/*
	 *  ring buffers
	 *  first receive, then transmit
	 */
	Msg	rmr[Maxrb];		/* recieve message ring */
	Msg	tmr[Maxrb];		/* transmit message ring */
};

/*
 *  Some macros for dealing with lance memory addresses.  The lance splits
 *  its 24 bit addresses across two 16 bit registers.
 */
#define HADDR(a) ((((ulong)(a))>>16)&0xFF)
#define LADDR(a) (((ulong)a)&0xFFFF)

/*
 *  The following functions exist to sidestep a quirk in the SGI IO3 lance
 *  interface.  In all other processors, the lance's initialization block and
 *  descriptor rings look like normal memory.  In the SGI IO3, the CPU sees a
 *  6 byte pad twixt all lance memory shorts.  Therefore, we use the following
 *  macros to compute the address whenever accessing the lance memory to make
 *  the code portable.  Sic transit gloria.
 */
#define LANCEMEM ((Lancemem*)0)
#define MPs(a) (*(short *)(l.lanceram + l.sep*((ushort*)&a - (ushort*)0)))
#define MPus(a) (*(ushort *)(l.lanceram + l.sep*((ushort*)&a - (ushort*)0)))

enum
{
	PROM	= 0x8000,
	INTL	= 0x40,
	DRTY	= 0x20,
	COLL	= 0x10,
	DTCR	= 0x8,
	LOOP	= 0x4,
	DTX	= 0x2,
	DRX	= 0x1,
	ERR0	= 0x8000,
	BABL	= 0x4000,
	CERR	= 0x2000,
	MISS	= 0x1000,
	MERR	= 0x800,
	RINT	= 0x400,
	TINT	= 0x200,
	IDON	= 0x100,
	INTR	= 0x80,
	INEA	= 0x40,
	RXON	= 0x20,
	TXON	= 0x10,
	TDMD	= 0x8,
	STOP	= 0x4,
	STRT	= 0x2,
	INIT	= 0x1,
	/* flag bits from a buffer descriptor in the rcv/xmt rings */
	LANCEOWNER= 0x8000,	/* 1 means buffer can be used by the chip */
	ERR	= 0x4000,	/* error summary, the OR of all error bits */
	FRAM	= 0x2000,	/* CRC error */
	OFLO	= 0x1000,	/* (receive) lost some of the packet */
	MORE	= 0x1000,	/* (transmit) more than 1 retry to tx pkt */
	CRC	= 0x800,	/* (rcv) crc error reading packet */
	ONE	= 0x800,	/* (tx) one retry to transmit the packet */
	BUF	= 0x400,	/* (rcv) out of buffers */
	DEF	= 0x400,	/* (tx) deffered while transmitting packet */
	STP	= 0x200,	/* start of packet */
	ENP	= 0x100,	/* end of packet */
	/* cntflags bits from a buffer descriptor in the rcv/xmt rings */
	BUFF	= 0x8000,	/* buffer error (host screwed up?) */
	UFLO	= 0x4000,	/* underflow from memory */
	LCOL	= 0x1000,	/* late collision (ether too long?) */
	LCAR	= 0x800,	/* loss of carrier (ether broken?) */
	RTRY	= 0x400,	/* couldn't transmit (ether jammed?) */
	TTDR	= 0x3FF,	/* time domain reflectometer */
};

struct Softlance
{
	Lance;			/* host dependent lance params */

	uchar	bcast[6];

	int	wedged;		/* the lance is wedged */

	ushort	rl;		/* first rcv Message belonging to Lance */	
	ushort	tc;		/* next xmt Message CPU will try for */	

	QLock	tlock;		/* lock for grabbing transmitter queue */
	Rendez	tr;		/* wait here for free xmit buffer */

	Netif;
} l;

static void	promiscuous(void*, int);

static void
lancereset(void)
{
	static int inited;

	if(inited == 0){
		inited = 1;
		lancesetup(&l);

		/* general network interface structure */
		netifinit(&l, "ether0", Ntypes, 32*1024);
		l.alen = 6;
		memmove(l.addr, l.ea, Eaddrlen);
		memset(l.bcast, 0xFF, Eaddrlen);

		l.promiscuous = promiscuous;
		l.arg = &l;
	}

	/*
	 *  stop the lance
	 */
	*l.rap = 0;
	*l.rdp = STOP;
	l.wedged = 1;
}

/*
 * Initialize and start the lance. 
 * This routine can be called only from a process.
 * It may be used to restart a dead lance.
 */
static void
lancestart(int mode)
{
	int i;
	Msg *m;
	Lancemem *lm = LANCEMEM;

	/*
	 *   wait till both receiver and transmitter are
	 *   quiescent
	 */
	qlock(&l.tlock);

	lancereset();
	l.rl = 0;
	l.tc = 0;

	/*
	 *  create the initialization block
	 */
	MPus(lm->mode) = mode;

	/*
	 *  set ether addr from the value in the id prom.
	 *  the id prom has them in reverse order, the init
	 *  structure wants them in byte swapped order
	 */
	MPus(lm->etheraddr[0]) = (l.ea[1]<<8) | l.ea[0];
	MPus(lm->etheraddr[1]) = (l.ea[3]<<8) | l.ea[2];
	MPus(lm->etheraddr[2]) = (l.ea[5]<<8) | l.ea[4];

	/*
	 *  ignore multicast addresses
	 */
	MPus(lm->multi[0]) = 0;
	MPus(lm->multi[1]) = 0;
	MPus(lm->multi[2]) = 0;
	MPus(lm->multi[3]) = 0;

	/*
	 *  set up rcv message ring
	 */
	m = lm->rmr;
	for(i = 0; i < l.nrrb; i++, m++){
		MPs(m->size) = -sizeof(Lancepkt);
		MPus(m->cntflags) = 0;
		MPus(m->laddr) = LADDR(&l.lrp[i]);
		MPus(m->flags) = HADDR(&l.lrp[i]);
	}
	MPus(lm->rdralow) = LADDR(l.lm->rmr);
	MPus(lm->rdrahigh) = (l.lognrrb<<13)|HADDR(l.lm->rmr);


	/*
	 *  give the lance all the rcv buffers except one (as a sentinel)
	 */
	m = lm->rmr;
	for(i = 0; i < l.nrrb; i++, m++)
		MPus(m->flags) |= LANCEOWNER;

	/*
	 *  set up xmit message ring
	 */
	m = lm->tmr;
	for(i = 0; i < l.ntrb; i++, m++){
		MPs(m->size) = 0;
		MPus(m->cntflags) = 0;
		MPus(m->laddr) = LADDR(&l.ltp[i]);
		MPus(m->flags) = HADDR(&l.ltp[i]);
	}
	MPus(lm->tdralow) = LADDR(l.lm->tmr);
	MPus(lm->tdrahigh) = (l.logntrb<<13)|HADDR(l.lm->tmr);

	/*
	 *  point lance to the initialization block
	 */
	*l.rap = 1;
	*l.rdp = LADDR(l.lm);
	wbflush();
	*l.rap = 2;
	*l.rdp = HADDR(l.lm);

	/*
	 *  The lance byte swaps the ethernet packet unless we tell it not to
	 */
	wbflush();
	*l.rap = 3;
	*l.rdp = l.busctl;

	/*
	 *  initialize lance, turn on interrupts, turn on transmit and rcv.
	 */
	wbflush();
	*l.rap = 0;
	*l.rdp = INEA|INIT|STRT; /**/

	for(i = 0; i < 1000; i++)
		if(l.wedged == 0)
			break;

	qunlock(&l.tlock);
}

void
lanceintr(void)
{
	Msg *m;
	Lancepkt *p;
	Netfile *f, **fp;
	ushort csr, t, x;
	Lancemem *lm = LANCEMEM;

	csr = *l.rdp;

	/*
	 *  turn off the interrupt and any error indicators
	 */
	*l.rdp = IDON|INEA|TINT|RINT|BABL|CERR|MISS|MERR;

	/*
	 *  see if an error occurred
	 */
	if(csr & (BABL|MISS|MERR)){
		if(l.misses++ < 4)
			print("lance err #%ux\n", csr);
		else {
			print("lance stopped\n");
			l.wedged = 1;
			l.misses = 0;
			lancereset();
			wakeup(&l.tr);
			return;
		}
	}

	if(csr & IDON)
		l.wedged = 0;

	/*
	 *  the lance turns off if it gets strange output errors
	 */
	if((csr & (TXON|RXON)) != (TXON|RXON))
		l.wedged = 1;

	/*
	 *  process incoming frames
	 */
	if(csr & RINT) {
		m = &(lm->rmr[l.rl]);
		while((MPus(m->flags) & LANCEOWNER)==0){
			l.inpackets++;
			t = MPus(m->flags);
			if(t & ERR){
				if(t & FRAM)
					l.frames++;
				if(t & OFLO)
					l.overflows++;
				if(t & CRC)
					l.crcs++;
				if(t & BUFF)
					l.buffs++;
			} else {
				/* stuff packet up each queue that wants it */
				p = &l.rp[l.rl];
				x = MPus(m->cntflags) - 4;
				t = (p->type[0]<<8) | p->type[1];

				for(fp = l.f; fp < &l.f[Ntypes]; fp++){
					f = *fp;
					if(f == 0)
						continue;
					if(f->type == t || f->type < 0)
						qproduce(f->in, p->d, x);
				}
			}

			/*
			 *  stage the next input buffer
			 */
			MPs(m->size) = -sizeof(Lancepkt);
			MPus(m->cntflags) = 0;
			MPus(m->laddr) = LADDR(&l.lrp[l.rl]);
			MPus(m->flags) = LANCEOWNER|HADDR(&l.lrp[l.rl]);
			wbflush();
			l.rl = RSUCC(l.rl);
			m = &(lm->rmr[l.rl]);
		}
	}

	/*
	 *  wake any process waiting for a transmit buffer
	 */
	if(csr & TINT)
		wakeup(&l.tr);
}

/*
 *  turn promiscuous mode on/off
 */
static void
promiscuous(void*, int on)
{
	if(on)
		lancestart(PROM);
	else
		lancestart(0);;
}

static void
lanceinit(void)
{
	lancestart(0);
	print("lance ether: %.2x%.2x%.2x%.2x%.2x%.2x\n",
		l.ea[0], l.ea[1], l.ea[2], l.ea[3], l.ea[4], l.ea[5]);
}

static Chan*
lanceattach(char *spec)
{
	char *s;

	s = spec;
	if(s && *s && (*s != '0' || *(s+1)))
		error(Enodev);

	return devattach('l', spec);
}

static int
lancewalk(Chan *c, char *name)
{
	return netifwalk(&l, c, name);
}

static Chan*
lanceopen(Chan *c, int omode)
{
	return netifopen(&l, c, omode);
}

static void
lancecreate(Chan*, char*, int, ulong)
{
}

static void
lanceclose(Chan *c)
{
	netifclose(&l, c);
}

static long
lanceread(Chan *c, void *buf, long n, ulong offset)
{
	return netifread(&l, c, buf, n, offset);
}

static int
isoutbuf(void *x)
{
	Msg *m;

	m = x;
	return l.wedged || (MPus(m->flags)&LANCEOWNER) == 0;
}

static int
etherloop(Etherpkt *p, long n)
{
	int s, different;
	ushort t;
	Netfile *f, **fp;

	different = memcmp(p->d, p->s, sizeof(p->d));
	if(different && memcmp(p->d, l.bcast, sizeof(p->d)))
		return 0;

	s = splhi();
	t = (p->type[0]<<8) | p->type[1];
	for(fp = l.f; fp < &l.f[Ntypes]; fp++) {
		f = *fp;
		if(f == 0)
			continue;
		if(f->type == t || f->type < 0)
			qproduce(f->in, p->d, n);
	}
	splx(s);
	return !different;
}

static long
lancewrite(Chan *c, void *buf, long n, ulong)
{
	Msg *m;
	Lancepkt *p;

	if(n > ETHERMAXTU)
		error(Ebadarg);

	/* etherif.c handles structure */
	if(NETTYPE(c->qid.path) != Ndataqid)
		return netifwrite(&l, c, buf, n);

	/* we handle data */
	if(etherloop(buf, n))
		return n;

	qlock(&l.tlock);
	if(waserror()) {
		qunlock(&l.tlock);
		nexterror();
	}

	m = &(LANCEMEM->tmr[l.tc]);
	tsleep(&l.tr, isoutbuf, m, 10000);
	if(!isoutbuf(m) || l.wedged)
		print("lance transmitter jammed\n");
	else {
		p = &l.tp[l.tc];
		memmove(p->d, buf, n);
		if(n < 60) {
			memset(p->d+n, 0, 60-n);
			n = 60;
		}
		memmove(p->s, l.ea, sizeof(l.ea));

		l.outpackets++;
		MPs(m->size) = -n;
		MPus(m->cntflags) = 0;
		MPus(m->laddr) = LADDR(&l.ltp[l.tc]);
		MPus(m->flags) = LANCEOWNER|STP|ENP|HADDR(&l.ltp[l.tc]);
		l.tc = TSUCC(l.tc);
		*l.rdp = INEA|TDMD;
	}
	qunlock(&l.tlock);
	poperror();
	return n;
}

static void
lanceremove(Chan*)
{
}

static void
lancestat(Chan *c, char *dp)
{
	netifstat(&l, c, dp);
}

static void
lancewstat(Chan *c, char *dp)
{
	netifwstat(&l, c, dp);
}

int
parseether(uchar *to, char *from)
{
	char nip[4];
	char *p;
	int i;

	p = from;
	for(i = 0; i < 6; i++){
		if(*p == 0)
			return -1;
		nip[0] = *p++;
		if(*p == 0)
			return -1;
		nip[1] = *p++;
		nip[2] = 0;
		to[i] = strtoul(nip, 0, 16);
		if(*p == ':')
			p++;
	}
	return 0;
}

Dev lancedevtab = {
	'l',
	"lance",

	lancereset,
	lanceinit,
	lanceattach,
	devclone,
	lancewalk,
	lancestat,
	lanceopen,
	lancecreate,
	lanceclose,
	lanceread,
	devbread,
	lancewrite,
	devbwrite,
	lanceremove,
	lancewstat,
};

M port/devmouse.c => port/devmouse.c +9 -9
@@ 5,19 5,20 @@
#include	"fns.h"
#include	"../port/error.h"

#include	<libg.h>
#define	Image	IMAGE
#define	mouse	moose
#include	<draw.h>
#undef	mouse
#include	<memdraw.h>
#include	"screen.h"

typedef struct Mouseinfo	Mouseinfo;

struct Mouseinfo
{
	/*
	 * First three fields are known in some l.s's
	 */
	int	dx;
	int	dy;
	int	track;		/* l.s has updated dx & dy */
	int	track;		/* dx & dy updated */
	Mouse;
	int	redraw;		/* update cursor on screen */
	ulong	counter;	/* increments every update */


@@ 33,7 34,6 @@ struct Mouseinfo
Mouseinfo	mouse;
Cursorinfo	cursor;
int		mouseshifted;
int		mousetype;
int		mouseswap;
Cursor		curs;



@@ 68,7 68,7 @@ Dirtab mousedir[]={
	"mousectl",	{Qmousectl},	0,			0220,
};

extern	Bitmap	gscreen;
extern	Memimage	gscreen;

static void
mousereset(void)


@@ 336,7 336,7 @@ mouseclock(void)
		mouse.redraw = cursoron(0);
		unlock(&cursor);
	}
	graphicsactive(0);
	drawactive(0);
}

static int


@@ 395,7 395,7 @@ mousetrack(int b, int dx, int dy)
	mouse.buttons = b;
	mouse.redraw = 1;
	wakeup(&mouse.r);
	graphicsactive(1);
	drawactive(1);
}

/*

M port/portfns.h => port/portfns.h +3 -2
@@ 72,6 72,8 @@ void		devstat(Chan*, char*, Dirtab*, int, Devgen*);
int		devwalk(Chan*, char*, Dirtab*, int, Devgen*);
void		devwstat(Chan*, char*);
Chan*		domount(Chan*);
void		drawactive(int);
void		drawcmap(int);
void		dumpaproc(Proc*);
void		dumpqueues(void);
void		dumpregs(Ureg*);


@@ 104,8 106,6 @@ void		freesegs(int);
void		freesession(Session*);
void		getcolor(ulong, ulong*, ulong*, ulong*);
void		gotolabel(Label*);
void		graphicsactive(int);
void		graphicscmap(int);
int		haswaitq(void*);
long		hostdomainwrite(char*, int);
long		hostownerwrite(char*, int);


@@ 177,6 177,7 @@ void		pgrpcpy(Pgrp*, Pgrp*);
void		pgrpnote(ulong, char*, long, int);
Pgrp*		pgrptab(int);
void		pio(Segment *, ulong, ulong, Page **);
void		poolsummary(void);
#define		poperror()		up->nerrlab--
int		postnote(Proc*, int, char*, int);
int		pprint(char*, ...);

A port/xalloc.c => port/xalloc.c +232 -0
@@ 0,0 1,232 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"

#define datoff		((ulong)((Xhdr*)0)->data)

enum
{
	Chunk		= 64*1024,
	Nhole		= 128,
	Magichole	= 0xDeadBabe,
};

typedef struct Hole Hole;
typedef struct Xalloc Xalloc;
typedef struct Xhdr Xhdr;

struct Hole
{
	ulong	addr;
	ulong	size;
	ulong	top;
	Hole*	link;
};

struct Xhdr
{
	ulong	size;
	ulong	magix;
	char	data[1];
};

struct Xalloc
{
	Lock;
	Hole	hole[Nhole];
	Hole*	flist;
	Hole*	table;
};

static Xalloc	xlists;

void
xinit(void)
{
	Hole *h, *eh;
	int upages, np0, np1;

	eh = &xlists.hole[Nhole-1];
	for(h = xlists.hole; h < eh; h++)
		h->link = h+1;

	xlists.flist = xlists.hole;

	upages = conf.upages;
	np1 = upages;
	if(np1 > conf.npage1)
		np1 = conf.npage1;

	palloc.p1 = conf.base1 + (conf.npage1 - np1)*BY2PG;
	conf.npage1 -= np1;
	xhole(conf.base1, conf.npage1*BY2PG);
	conf.npage1 = conf.base1+(conf.npage1*BY2PG);
	upages -= np1;

	np0 = upages;
	if(np0 > conf.npage0)
		np0 = conf.npage0;

	palloc.p0 = conf.base0 + (conf.npage0 - np0)*BY2PG;
	conf.npage0 -= np0;
	xhole(conf.base0, conf.npage0*BY2PG);
	conf.npage0 = conf.base0+(conf.npage0*BY2PG);

	palloc.np0 = np0;
	palloc.np1 = np1;
	/* Save the bounds of kernel alloc memory for kernel mmu mapping */
	conf.base0 = (ulong)KADDR(conf.base0);
	conf.base1 = (ulong)KADDR(conf.base1);
	conf.npage0 = (ulong)KADDR(conf.npage0);
	conf.npage1 = (ulong)KADDR(conf.npage1);
}

void*
xspanalloc(ulong size, int align, ulong span)
{
	ulong a, v, t;

	a = (ulong)xalloc(size+align+span);
	if(a == 0)
		panic("xspanalloc: %d %d %lux\n", size, align, span);

	if(span > 2) {
		v = (a + span) & ~(span-1);
		t = v - a;
		if(t > 0)
			xhole(PADDR(a), t);
		t = a + span - v;
		if(t > 0)
			xhole(PADDR(v+size+align), t);
	}
	else
		v = a;

	if(align > 1)
		v = (v + align) & ~(align-1);

	return (void*)v;
}

void*
xallocz(ulong size, int zero)
{
	Xhdr *p;
	Hole *h, **l;

	size += BY2V + sizeof(Xhdr);
	size &= ~(BY2V-1);

	ilock(&xlists);
	l = &xlists.table;
	for(h = *l; h; h = h->link) {
		if(h->size >= size) {
			p = (Xhdr*)h->addr;
			h->addr += size;
			h->size -= size;
			if(h->size == 0) {
				*l = h->link;
				h->link = xlists.flist;
				xlists.flist = h;
			}
			iunlock(&xlists);
			p = KADDR(p);
			p->magix = Magichole;
			p->size = size;
			if(zero)
				memset(p->data, 0, size);
			return p->data;
		}
		l = &h->link;
	}
	iunlock(&xlists);
	return nil;
}

void
xfree(void *p)
{
	Xhdr *x;

	x = (Xhdr*)((ulong)p - datoff);
	if(x->magix != Magichole) {
		xsummary();
		panic("xfree(0x%lux) 0x%lux!=0x%lux", p, Magichole, x->magix);
	}
	xhole(PADDR(x), x->size);
}

void
xhole(ulong addr, ulong size)
{
	ulong top;
	Hole *h, *c, **l;

	if(size == 0)
		return;

	top = addr + size;
	ilock(&xlists);
	l = &xlists.table;
	for(h = *l; h; h = h->link) {
		if(h->top == addr) {
			h->size += size;
			h->top = h->addr+h->size;
			c = h->link;
			if(c && h->top == c->addr) {
				h->top += c->size;
				h->size += c->size;
				h->link = c->link;
				c->link = xlists.flist;
				xlists.flist = c;
			}
			iunlock(&xlists);
			return;
		}
		if(h->addr > addr)
			break;
		l = &h->link;
	}
	if(h && top == h->addr) {
		h->addr -= size;
		h->size += size;
		iunlock(&xlists);
		return;
	}

	if(xlists.flist == nil) {
		iunlock(&xlists);
		print("xfree: no free holes, leaked %d bytes\n", size);
		return;
	}

	h = xlists.flist;
	xlists.flist = h->link;
	h->addr = addr;
	h->top = top;
	h->size = size;
	h->link = *l;
	*l = h;
	iunlock(&xlists);
}

void
xsummary(void)
{
	int i;
	Hole *h;

	i = 0;
	for(h = xlists.flist; h; h = h->link)
		i++;

	print("%d holes free\n", i);
	i = 0;
	for(h = xlists.table; h; h = h->link) {
		print("%.8lux %.8lux %d\n", h->addr, h->top, h->size);
		i += h->size;
	}
	print("%d bytes free\n", i);
}