~kris/9p

9hist

e730a2625ae2ad2616b5736919f6afd6e1b4243f — David du Colombier 27 years ago 87deae0
Plan 9 from Bell Labs 1999-04-15
A alphapc/arch164.c => alphapc/arch164.c +389 -0
@@ 0,0 1,389 @@
/*
 *	EB164 and similar
 *	CPU:	21164
 *	Core Logic: 21172 CIA or 21174 PYXIS
  */
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"ureg.h"

static ulong *core;
static ulong *wind;

static ulong windsave[16];
static ulong coresave[1];

ulong	iobase0;
ulong	iobase1;
#define	iobase(p)	(iobase0+(p))

static int
ident(void)
{
	return 0;	/* bug! */
}

static void *
kmapio(ulong space, ulong offset, int size)
{
	return kmapv(((uvlong)space<<32LL)|offset, size);
}

static void
coreinit(void)
{
	int i;

	core = kmapio(0x87, 0x40000000, 0x10000);
	wind = kmapio(0x87, 0x60000000, 0x1000);

	iobase0 = (ulong)kmapio(0x89, 0, 0x20000);

	/* hae_io = core[0x440/4];
	iobase1 = (ulong)kmapio(0x89, hae_io, 0x10000); */

	/* save critical parts of hardware memory mapping */
	for (i = 4; i < 8; i++) {
		windsave[4*(i-4)+0] = wind[(i*0x100+0x00)/4];
		windsave[4*(i-4)+1] = wind[(i*0x100+0x40)/4];
		windsave[4*(i-4)+2] = wind[(i*0x100+0x80)/4];
	}
	coresave[0] = core[0x140/4];

	/* direct map bottom 2G PCI target space to KZERO in window 1 */
	wind[0x500/4] = KZERO|1;
	wind[0x540/4] = 0x7ff00000;
	wind[0x580/4] = 0;

	/* disable other windows */
	wind[0x400/4] = 0;
	wind[0x600/4] = 0;
	wind[0x700/4] = 0;

	/* clear error state */
	core[0x8200/4] = 0x7ff;

	/* set config: byte/word enable, no monster window, etc. */
	core[0x140/4] = 1;

	/* turn off mcheck on master abort.  now we can probe PCI space. */
	core[0x8280/4] &= ~(1<<7);

	/* set up interrupts. */
	i8259init();
	cserve(52, 4);		/* enable SIO interrupt */
}

static void
corehello(void)
{
	print("cpu%d: CIA revision %d; cnfg %lux cntrl %lux\n",
			0,	/* BUG */
			core[0x80/4] & 0x7f, core[0x140/4], core[0x100/4]);
	print("cpu%d: HAE_IO %lux\n", 0, core[0x440/4]);
	print("\n");
}

static void
coredetach(void)
{
	int i;

	for (i = 4; i < 8; i++) {
		wind[(i*0x100+0x00)/4] = windsave[4*(i-4)+0];
		wind[(i*0x100+0x40)/4] = windsave[4*(i-4)+1];
		wind[(i*0x100+0x80)/4] = windsave[4*(i-4)+2];
	}
	core[0x140/4] = coresave[0];
/*	for (i = 0; i < 4; i++)
		if (i != 4)
			cserve(53, i);		/* disable interrupts */
}

static Lock	pcicfgl;
static ulong	pcimap[256];

static void*
pcicfg2117x(int tbdf, int rno)
{
	int space, bus;
	ulong base;

	bus = BUSBNO(tbdf);
	lock(&pcicfgl);
	base = pcimap[bus];
	if (base == 0) {
		if(bus)
			space = 0x8B;
		else
			space = 0x8A;
		pcimap[bus] = base = (ulong)kmapio(space, MKBUS(0, bus, 0, 0), (1<<16));
	}
	unlock(&pcicfgl);
	return (void*)(base + BUSDF(tbdf) + rno);
}

static void*
pcimem2117x(int addr, int len)
{
	return kmapio(0x88, addr, len);
}

/*
 *	interrupts -- adapted from PC, needs work.
 */

static Lock irqctllock;
static Irqctl *irqctl[256];
static char irqmask[3];

static void
intr164(Ureg *ur)
{
	int i, v;
	Irqctl *ctl;
	Irq *irq;
	Mach *mach;

	v = (ulong)ur->a1>>4;
	if (v < 0x80) {
		iprint("unknown device intr v %d\n", v);
		return;
	}
	v -= 0x80;
	if(v < 256 && (ctl = irqctl[v])){
		if(ctl->isintr){
			m->intr++;
			if(ctl->isr)
				ctl->isr(v);
/*				if(v >= VectorPIC && v <= MaxVectorPIC)
				m->lastintr = v-VectorPIC; */
		}

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

		if(ctl->eoi)
			ctl->eoi(v);
	}
	else if(v >= VectorPIC && v <= MaxVectorPIC){
		/*
		 * An unknown interrupt.
		 * Check for a default IRQ7. This can happen when
		 * the IRQ input goes away before the acknowledge.
		 * In this case, a 'default IRQ7' is generated, but
		 * the corresponding bit in the ISR isn't set.
		 * In fact, just ignore all such interrupts.
		 */
		iprint("cpu%d: spurious interrupt %d, last %d",
			m->machno, v-VectorPIC, 0 /*m->lastintr*/);
		for(i = 0; i < 32; i++){
			if(!(active.machs & (1<<i)))
				continue;
			mach = MACHP(i);
			if(m->machno == mach->machno)
				continue;
			iprint(": cpu%d: last %d", mach->machno, 0 /*mach->lastintr*/);
		}
		iprint("\n");
/*			m->spuriousintr++; */
		return;
	}
	else{
		dumpregs(ur);
		panic("unknown intr: %d\n", v); /* */
	}
}

static int
intrenable164(int v, void (*f)(Ureg*, void*), void*a, int tbdf)
{
	Irq * irq;
	Irqctl *ctl;

	lock(&irqctllock);
	if(irqctl[v] == 0){
		ctl = xalloc(sizeof(Irqctl));
/* this is all wrong; FIXME! */
		if(BUSTYPE(tbdf) == BusPCI)
			cserve(52, v-VectorPCI);
		else if(v >= VectorPIC && i8259enable(v, tbdf, ctl) == -1){
			unlock(&irqctllock);
			iprint("intrenable: didn't find v %d, tbdf 0x%uX\n", v, tbdf);
			xfree(ctl);
			return -1;
		}
		irqctl[v] = ctl;
	}
	ctl = irqctl[v];
	irq = xalloc(sizeof(Irq));
	irq->f = f;
	irq->a = a;
	irq->next = ctl->irq;
	ctl->irq = irq;
	unlock(&irqctllock);
	return 0;
}

/*
 *	I have a function pointer in PCArch for every one of these, because on
 *	some Alphas we have to use sparse mode, but on others we can use
 *	MOVB et al.  Additionally, the PC164 documentation threatened us
 *	with the lie that the SIO is in region B, but everything else in region A.
 *	This turned out not to be the case.  Given the cost of this solution, it
 *	may be better just to use sparse mode for I/O space on all platforms.
 */
int
inb2117x(int port)
{
	mb();
	return *(uchar*)(iobase(port));
}

ushort
ins2117x(int port)
{
	mb();
	return *(ushort*)(iobase(port));
}

ulong
inl2117x(int port)
{
	mb();
	return *(ulong*)(iobase(port));
}

void
outb2117x(int port, int val)
{
	mb();
	*(uchar*)(iobase(port)) = val;
}

void
outs2117x(int port, ushort val)
{
	mb();
	*(ushort*)(iobase(port)) = val;
}

void
outl2117x(int port, ulong val)
{
	mb();
	*(ulong*)(iobase(port)) = val;
}

void
insb2117x(int port, void *buf, int len)
{
	int i;
	uchar *p, *q;

	p = (uchar*)iobase(port);
	q = buf;
	for(i = 0; i < len; i++){
		mb();
		*q++ = *p;
	}
}

void
inss2117x(int port, void *buf, int len)
{
	int i;
	ushort *p, *q;

	p = (ushort*)iobase(port);
	q = buf;
	for(i = 0; i < len; i++){
		mb();
		*q++ = *p;
	}
}

void
insl2117x(int port, void *buf, int len)
{
	int i;
	ulong *p, *q;

	p = (ulong*)iobase(port);
	q = buf;
	for(i = 0; i < len; i++){
		mb();
		*q++ = *p;
	}
}

void
outsb2117x(int port, void *buf, int len)
{
	int i;
	uchar *p, *q;

	p = (uchar*)iobase(port);
	q = buf;
	for(i = 0; i < len; i++){
		mb();
		*p = *q++;
	}
}

void
outss2117x(int port, void *buf, int len)
{
	int i;
	ushort *p, *q;

	p = (ushort*)iobase(port);
	q = buf;
	for(i = 0; i < len; i++){
		mb();
		*p = *q++;
	}
}

void
outsl2117x(int port, void *buf, int len)
{
	int i;
	ulong *p, *q;

	p = (ulong*)iobase(port);
	q = buf;
	for(i = 0; i < len; i++){
		mb();
		*p = *q++;
	}
}

PCArch arch164 = {
	"EB164",
	ident,
	coreinit,
	corehello,
	coredetach,
	pcicfg2117x,
	pcimem2117x,
	intr164,
	intrenable164,

	inb2117x,
	ins2117x,
	inl2117x,
	outb2117x,
	outs2117x,
	outl2117x,
	insb2117x,
	inss2117x,
	insl2117x,
	outsb2117x,
	outss2117x,
	outsl2117x,
};

A alphapc/axp.h => alphapc/axp.h +71 -0
@@ 0,0 1,71 @@
typedef struct Hwrpb	Hwrpb;
typedef struct Hwcpu	Hwcpu;
typedef struct Hwdsr	Hwdsr;

struct Hwrpb
{
	uvlong	phys;
	uvlong	sign;
	uvlong	rev;
	uvlong	size;
	uvlong	cpu0;
	uvlong	by2pg;
	uvlong	pabits;
	uvlong	maxasn;
	char		ssn[16];
	uvlong	systype;
	uvlong	sysvar;
	uvlong	sysrev;
	uvlong	ifreq;
	uvlong	cfreq;
	uvlong	vptb;
	uvlong	resv;
	uvlong	tbhint;
	uvlong	ncpu;
	uvlong	cpulen;
	uvlong	cpuoff;
	uvlong	nctb;
	uvlong	ctblen;
	uvlong	ctboff;
	uvlong	ccrboff;
	uvlong	memoff;
	uvlong	confoff;
	uvlong	fruoff;
	uvlong	termsaveva;
	uvlong	termsavex;
	uvlong	termrestva;
	uvlong	termrestx;
	uvlong	termresetva;
	uvlong	termresetx;
	uvlong	sysresv;
	uvlong	hardresv;
	uvlong	csum;
	uvlong	rxrdymsk;
	uvlong	txrdymsk;
	uvlong	dsroff;		/* rev 6 or higher */
};

extern Hwrpb* hwrpb;

struct Hwcpu
{
	uvlong	hwpcb[16];
	uvlong	state;
	uvlong	palmainlen;
	uvlong	palscratchlen;
	uvlong	palmainpa;
	uvlong	palscratchpa;
	uvlong	palrev;
	uvlong	cputype;
	uvlong	cpuvar;
	uvlong	cpurev;
	uvlong	serial[2];
	/* more crap ... */
};

struct Hwdsr
{
	vlong	smm;
	uvlong	lurtoff;
	uvlong	sysnameoff;
};

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

enum {
	Width		= 160,
	Height		= 25,

	Attr		= 0x4f,	/* white on blue */
};

static ulong	cgabase;
#define CGASCREENBASE	((uchar*)cgabase)

static int cgapos;
static int screeninitdone;
static Lock cgascreenlock;

static uchar
cgaregr(int index)
{
	outb(0x3D4, index);
	return inb(0x3D4+1) & 0xFF;
}

static void
cgaregw(int index, int data)
{
	outb(0x3D4, index);
	outb(0x3D4+1, data);
}

static void
movecursor(void)
{
	cgaregw(0x0E, (cgapos/2>>8) & 0xFF);
	cgaregw(0x0F, cgapos/2 & 0xFF);
	CGASCREENBASE[cgapos+1] = Attr;
}

static void
cgascreenputc(int c)
{
	int i;

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

void
screeninit(void)
{
	cgabase = (ulong)arch->pcimem(0xB8000, 0x8000);

	cgapos = cgaregr(0x0E)<<8;
	cgapos |= cgaregr(0x0F);
	cgapos *= 2;
	screeninitdone = 1;
}

static void
cgascreenputs(char* s, int n)
{
	if(!screeninitdone)
		return;
	if(!islo()){
		/*
		 * Don't deadlock trying to
		 * print in an interrupt.
		 */
		if(!canlock(&cgascreenlock))
			return;
	}
	else
		lock(&cgascreenlock);

	while(n-- > 0)
		cgascreenputc(*s++);

	unlock(&cgascreenlock);
}

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

A alphapc/clock.c => alphapc/clock.c +146 -0
@@ 0,0 1,146 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"

#include	"ureg.h"

void (*kproftimer)(ulong);

typedef struct Clock0link Clock0link;
typedef struct Clock0link {
	void		(*clock)(void);
	Clock0link*	link;
} Clock0link;

static Clock0link *clock0link;
static Lock clock0lock;

void
addclock0link(void (*clock)(void))
{
	Clock0link *lp;

	if((lp = malloc(sizeof(Clock0link))) == 0){
		print("addclock0link: too many links\n");
		return;
	}
	ilock(&clock0lock);
	lp->clock = clock;
	lp->link = clock0link;
	clock0link = lp;
	iunlock(&clock0lock);
}


/*
 *  delay for l milliseconds more or less.  delayloop is set by
 *  clockinit() to match the actual CPU speed.
 */
void
delay(int l)
{
	ulong i, j;

	j = m->delayloop;
	while(l-- > 0)
		for(i=0; i < j; i++)
			;
}

void
microdelay(int l)
{
	ulong i, j;

//	j = m->delayloop/1000;
j = 10000;
	while(l-- > 0)
		for(i=0; i < j; i++)
			;
}

void
clockinit(void)
{
m->delayloop = 250*1000;	/* BUG */
#ifdef	NOTYET
	long x;

	m->delayloop = m->speed*100;
	do {
		x = rdcount();
		delay(10);
		x = rdcount() - x;
	} while(x < 0);

	/*
	 *  fix count
	 */
	m->delayloop = (m->delayloop*m->speed*1000*10)/x;
	if(m->delayloop == 0)
		m->delayloop = 1;

/*	wrcompare(rdcount()+(m->speed*1000000)/HZ); */
#endif
}

void
clock(Ureg *ur)
{
	Clock0link *lp;
	static int count;

	/* HZ == 100, timer == 1024Hz.  error < 1ms */
	count += 100;
	if (count < 1024)
		return;
	count -= 1024;

	m->ticks++;
	if(m->proc)
		m->proc->pc = ur->pc;

	accounttime();

	if(kproftimer != nil)
		kproftimer(ur->pc);

	if((active.machs&(1<<m->machno)) == 0)
		return;

	if(active.exiting && (active.machs & (1<<m->machno))) {
		print("someone's exiting\n");
		exit(0);
	}

	checkalarms();
	if(m->machno == 0){
		lock(&clock0lock);
		for(lp = clock0link; lp; lp = lp->link)
			lp->clock();
		unlock(&clock0lock);
	}

	if(up == 0 || up->state != Running)
		return;

	if(anyready())
		sched();

	/* user profiling clock */
	if(ur->status & UMODE) {
		(*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1);
		segclock(ur->pc);
	}
}

vlong
fastticks(uvlong *hz)
{
	if (hz)
		*hz = 100;
	return m->ticks;
}

A alphapc/dat.h => alphapc/dat.h +228 -0
@@ 0,0 1,228 @@
typedef struct Conf	Conf;
typedef struct FPsave	FPsave;
typedef struct Irq	Irq;
typedef struct Irqctl	Irqctl;
typedef struct ISAConf	ISAConf;
typedef struct Label	Label;
typedef struct Lock	Lock;
typedef struct Mach	Mach;
typedef struct Notsave	Notsave;
typedef struct Page	Page;
typedef struct PCArch	PCArch;
typedef struct PCB	PCB;
typedef struct Pcidev	Pcidev;
typedef struct PMMU	PMMU;
typedef struct Sys	Sys;
typedef struct Ureg	Ureg;
typedef struct Proc	Proc;

/*
 *  parameters for sysproc.c
 */
#define AOUT_MAGIC	L_MAGIC

/*
 *  machine dependent definitions used by ../port/dat.h
 */

struct Lock
{
	ulong	key;			/* semaphore (non-zero = locked) */
	ulong	sr;
	ulong	pc;
	Proc	*p;
	ulong	pid;
	ushort	isilock;
};

struct Label
{
	ulong	sp;
	ulong	pc;
};

/*
 * FPsave.fpstatus
 */
enum
{
	FPinit,
	FPactive,
	FPinactive,
};

struct	FPsave
{
	long	fpreg[2*32];
	long	dummy;		/* lower bits of FPCR, useless */
	long	fpstatus;
};

struct Conf
{
	ulong	nmach;		/* processors */
	ulong	nproc;		/* processes */
	ulong	npage0;		/* total physical pages of memory */
	ulong	npage1;		/* total physical pages of memory */
	ulong	npage;		/* total physical pages of memory */
	ulong	base0;		/* base of bank 0 */
	ulong	base1;		/* base of bank 1 */
	ulong	upages;		/* user page pool */
	ulong	nimage;		/* number of page cache image headers */
	ulong	nswap;		/* number of swap pages */
	int	nswppo;		/* max # of pageouts per segment pass */
	ulong	copymode;	/* 0 is copy on write, 1 is copy on reference */
	ulong	ptebase;
	ulong	mbytes;
	int	monitor;		/* has display? */
	ulong	ialloc;		/* bytes available for interrupt time allocation */
	ulong	pipeqsize;	/* size in bytes of pipe queues */
};

/*
 *  mmu goo in the Proc structure
 */
struct PMMU
{
	Page	*mmutop;	/* 1st level table */
	Page	*mmulvl2;	/* 2nd level table */
	Page	*mmufree;	/* unused page table pages */
	Page	*mmuused;	/* used page table pages, except for mmustk */
};

/*
 *  things saved in the Proc structure during a notify
 */
struct Notsave
{
	ulong	UNUSED;
};

#include "../port/portdat.h"

/*
 *  machine dependent definitions not used by ../port/dat.h
 */
/*
 * Fake kmap
 */
typedef	void		KMap;
#define	VA(k)		((ulong)(k))
#define	kmap(p)		(KMap*)((p)->pa|KZERO)
#define	kunmap(k)

/*
 *	Process Control Block, used by PALcode
 */
struct PCB {
	uvlong	ksp;
	uvlong	usp;
	uvlong	ptbr;
	ulong	asn;
	ulong	pcc;
	uvlong	unique;
	ulong	fen;
	ulong	dummy;
	uvlong	rsrv1;
	uvlong	rsrv2;
};

struct Mach
{
	/* OFFSETS OF THE FOLLOWING KNOWN BY l.s */
	int	machno;			/* physical id of processor */
	ulong	splpc;			/* pc that called splhi() */
	Proc	*proc;			/* current process on this processor */

	/* ordering from here on irrelevant */
	int	tlbfault;			/* only used by devproc; no access to tlb */
	int	tlbpurge;			/* ... */
	ulong	ticks;			/* of the clock since boot time */
	Label	sched;			/* scheduler wakeup */
	Lock	alarmlock;		/* access to alarm list */
	void	*alarm;			/* alarms bound to this clock */
	Page	*ufreeme;		/* address of upage of exited process */
	int	speed;			/* cpu speed */
	ulong	delayloop;		/* for the delay() routine */
	int	nrdy;
	ulong	fairness;		/* for runproc */

	int	pfault;
	int	cs;
	int	syscall;
	int	load;
	int	intr;
	int	nettime;
	int	flushmmu;		/* make current proc flush it's mmu state */

	PCB;

	/* MUST BE LAST */
	int	stack[1];
};

struct
{
	Lock;
	short	machs;
	short	exiting;
	short	ispanic;
}active;

/*
 *	Implementation-dependant functions (outside of Alpha architecture proper).
 *	Called PCArch because that's what mkdevc calls it (for the PC).
 */
struct PCArch
{
	char*	id;
	int	(*ident)(void);

	void	(*coreinit)(void);		/* set up core logic, PCI mappings etc */
	void	(*corehello)(void);		/* identify core logic to user */
	void	(*coredetach)(void);		/* restore core logic before return to console */
	void	*(*pcicfg)(int, int);		/* map and point to PCI cfg space */
	void	*(*pcimem)(int, int);		/* map and point to PCI memory space */
	void	(*intr)(Ureg*);
	int	(*intrenable)(int, void (*)(Ureg*, void*), void*, int);

	int		(*_inb)(int);
	ushort	(*_ins)(int);
	ulong	(*_inl)(int);
	void		(*_outb)(int, int);
	void		(*_outs)(int, ushort);
	void		(*_outl)(int, ulong);
	void		(*_insb)(int, void*, int);
	void		(*_inss)(int, void*, int);
	void		(*_insl)(int, void*, int);
	void		(*_outsb)(int, void*, int);
	void		(*_outss)(int, void*, int);
	void		(*_outsl)(int, void*, int);
};

/*
 *  a parsed plan9.ini line
 */
#define ISAOPTLEN	16
#define NISAOPT		8

struct ISAConf {
	char	type[NAMELEN];
	ulong	port;
	ulong	irq;
	ulong	dma;
	ulong	mem;
	ulong	size;
	ulong	freq;

	int	nopt;
	char	opt[NISAOPT][ISAOPTLEN];
};

extern PCArch	*arch;

#define	MACHP(n)	((Mach *)((int)&mach0+n*BY2PG))
extern Mach		mach0;

extern register Mach	*m;
extern register Proc	*up;

A alphapc/devether.c => alphapc/devether.c +436 -0
@@ 0,0 1,436 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
#include "../port/error.h"
#include "../port/netif.h"

#include "etherif.h"

static Ether *etherxx[MaxEther];

Chan*
etherattach(char* spec)
{
	ulong ctlrno;
	char *p;
	Chan *chan;

	ctlrno = 0;
	if(spec && *spec){
		ctlrno = strtoul(spec, &p, 0);
		if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
			error(Ebadarg);
	}
	if(etherxx[ctlrno] == 0)
		error(Enodev);

	chan = devattach('l', spec);
	chan->dev = ctlrno;
	if(etherxx[ctlrno]->attach)
		etherxx[ctlrno]->attach(etherxx[ctlrno]);
	return chan;
}

static int
etherwalk(Chan* chan, char* name)
{
	return netifwalk(etherxx[chan->dev], chan, name);
}

static void
etherstat(Chan* chan, char* dp)
{
	netifstat(etherxx[chan->dev], chan, dp);
}

static Chan*
etheropen(Chan* chan, int omode)
{
	return netifopen(etherxx[chan->dev], chan, omode);
}

static void
ethercreate(Chan*, char*, int, ulong)
{
}

static void
etherclose(Chan* chan)
{
	netifclose(etherxx[chan->dev], chan);
}

static long
etherread(Chan* chan, void* buf, long n, vlong off)
{
	Ether *ether;
	ulong offset = off;

	ether = etherxx[chan->dev];
	if((chan->qid.path & CHDIR) == 0 && ether->ifstat){
		/*
		 * With some controllers it is necessary to reach
		 * into the chip to extract statistics.
		 */
		if(NETTYPE(chan->qid.path) == Nifstatqid)
			return ether->ifstat(ether, buf, n, offset);
		else if(NETTYPE(chan->qid.path) == Nstatqid)
			ether->ifstat(ether, buf, 0, offset);
	}

	return netifread(ether, chan, buf, n, offset);
}

static Block*
etherbread(Chan* chan, long n, ulong offset)
{
	return netifbread(etherxx[chan->dev], chan, n, offset);
}

static void
etherremove(Chan*)
{
}

static void
etherwstat(Chan* chan, char* dp)
{
	netifwstat(etherxx[chan->dev], chan, dp);
}

static void
etherrtrace(Netfile* f, Etherpkt* pkt, int len)
{
	int i, n;
	Block *bp;

	if(qwindow(f->in) <= 0)
		return;
	if(len > 64)
		n = 64;
	else
		n = len;
	bp = iallocb(n);
	if(bp == 0)
		return;
	memmove(bp->wp, pkt->d, n);
	i = TK2MS(MACHP(0)->ticks);
	bp->wp[58] = len>>8;
	bp->wp[59] = len;
	bp->wp[60] = i>>24;
	bp->wp[61] = i>>16;
	bp->wp[62] = i>>8;
	bp->wp[63] = i;
	bp->wp += 64;
	qpass(f->in, bp);
}

Block*
etheriq(Ether* ether, Block* bp, int freebp)
{
	Etherpkt *pkt;
	ushort type;
	int len;
	Netfile **ep, *f, **fp, *fx;
	Block *xbp;

	ether->inpackets++;

	pkt = (Etherpkt*)bp->rp;
	len = BLEN(bp);
	type = (pkt->type[0]<<8)|pkt->type[1];
	fx = 0;
	ep = &ether->f[Ntypes];

	/* check for valid multcast addresses */
	if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
			if(freebp){
				freeb(bp);
				bp = 0;
			}
			return bp;
		}
	}

	/*
	 * Multiplex the packet to all the connections which want it.
	 * If the packet is not to be used subsequently (freebp != 0),
	 * attempt to simply pass it into one of the connections, thereby
	 * saving a copy of the data (usual case hopefully).
	 */
	for(fp = ether->f; fp < ep; fp++){
		if((f = *fp) && (f->type == type || f->type < 0)){
			if(f->type > -2){
				if(freebp && fx == 0)
					fx = f;
				else if(xbp = iallocb(len)){
					memmove(xbp->wp, pkt, len);
					xbp->wp += len;
					qpass(f->in, xbp);
				}
				else
					ether->soverflows++;
			}
			else
				etherrtrace(f, pkt, len);
		}
	}

	if(fx){
		qpass(fx->in, bp);
		return 0;
	}
	if(freebp){
		freeb(bp);
		return 0;
	}

	return bp;
}

static int
etheroq(Ether* ether, Block* bp)
{
	int len, loopback, s;
	Etherpkt *pkt;

	ether->outpackets++;

	/*
	 * Check if the packet has to be placed back onto the input queue,
	 * i.e. if it's a loopback or broadcast packet or the interface is
	 * in promiscuous mode.
	 * If it's a loopback packet indicate to etheriq that the data isn't
	 * needed and return, etheriq will pass-on or free the block.
	 */
	pkt = (Etherpkt*)bp->rp;
	len = BLEN(bp);
	loopback = (memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0);
	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
		s = splhi();
		etheriq(ether, bp, loopback);
		splx(s);
	}

	if(!loopback){
		qbwrite(ether->oq, bp);
		ether->transmit(ether);
	}

	return len;
}

static long
etherwrite(Chan* chan, void* buf, long n, vlong)
{
	Ether *ether;
	Block *bp;

	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);
		nexterror();
	}
	memmove(bp->rp, buf, n);
	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
	poperror();
	bp->wp += n;

	return etheroq(ether, bp);
}

static long
etherbwrite(Chan* chan, Block* bp, ulong)
{
	Ether *ether;
	long n;

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

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

	return etheroq(ether, bp);
}

static struct {
	char*	type;
	int	(*reset)(Ether*);
} cards[MaxEther+1];

void
addethercard(char* t, int (*r)(Ether*))
{
	static int ncard;

	if(ncard == MaxEther)
		panic("too many ether cards");
	cards[ncard].type = t;
	cards[ncard].reset = r;
	ncard++;
}

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;
}

static void
etherreset(void)
{
	Ether *ether;
	int i, n, ctlrno;
	char name[NAMELEN], buf[128];

	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
		if(ether == 0)
			ether = malloc(sizeof(Ether));
		memset(ether, 0, sizeof(Ether));
		ether->ctlrno = ctlrno;
		ether->tbdf = BUSUNKNOWN;
		ether->mbps = 10;
		if(isaconfig("ether", ctlrno, ether) == 0)
			continue;
		for(n = 0; cards[n].type; n++){
			if(cistrcmp(cards[n].type, ether->type))
				continue;
			for(i = 0; i < ether->nopt; i++){
				if(strncmp(ether->opt[i], "ea=", 3))
					continue;
				if(parseether(ether->ea, &ether->opt[i][3]) == -1)
					memset(ether->ea, 0, Eaddrlen);
			}	
			if(cards[n].reset(ether))
				break;

			/*
			 * IRQ2 doesn't really exist, it's used to gang the interrupt
			 * controllers together. A device set to IRQ2 will appear on
			 * the second interrupt controller as IRQ9.
			 */
			if(ether->irq == 2)
				ether->irq = 9;
			intrenable(VectorPCI+ether->irq, ether->interrupt, ether, ether->tbdf);

			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", 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",
				ether->ea[0], ether->ea[1], ether->ea[2],
				ether->ea[3], ether->ea[4], ether->ea[5]);
			sprint(buf+i, "\n");
			print(buf);

			snprint(name, sizeof(name), "ether%d", ctlrno);
			if(ether->mbps == 100){
				netifinit(ether, name, Ntypes, 256*1024);
				if(ether->oq == 0)
					ether->oq = qopen(256*1024, 1, 0, 0);
			}
			else{
				netifinit(ether, name, Ntypes, 65*1024);
				if(ether->oq == 0)
					ether->oq = qopen(65*1024, 1, 0, 0);
			}
			if(ether->oq == 0)
				panic("etherreset %s", name);
			ether->alen = Eaddrlen;
			memmove(ether->addr, ether->ea, Eaddrlen);
			memset(ether->bcast, 0xFF, Eaddrlen);

			etherxx[ctlrno] = ether;
			ether = 0;
			break;
		}
	}
	if(ether)
		free(ether);
}

#define POLY 0xedb88320

/* really slow 32 bit crc for ethers */
ulong
ethercrc(uchar *p, int len)
{
	int i, j;
	ulong crc, b;

	crc = 0xffffffff;
	for(i = 0; i < len; i++){
		b = *p++;
		for(j = 0; j < 8; j++){
			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
			b >>= 1;
		}
	}
	return crc;
}

Dev etherdevtab = {
	'l',
	"ether",

	etherreset,
	devinit,
	etherattach,
	devclone,
	etherwalk,
	etherstat,
	etheropen,
	ethercreate,
	etherclose,
	etherread,
	etherbread,
	etherwrite,
	etherbwrite,
	etherremove,
	etherwstat,
};

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

#include	"floppy.h"

/* Intel 82077A (8272A compatible) floppy controller */

/* This module expects the following functions to be defined
 * elsewhere: 
 * 
 * inb()
 * outb()
 * floppyexec()
 * floppyeject() 
 * floppysetup0()
 * floppysetup1()
 * dmainit()
 * dmasetup()
 * dmaend()
 * 
 * On DMA systems, floppyexec() should be an empty function; 
 * on non-DMA systems, dmaend() should be an empty function; 
 * dmasetup() may enforce maximum transfer sizes. 
 */

enum {
	/* file types */
	Qdir=		0, 
	Qdata=		(1<<2),
	Qctl=		(2<<2),
	Qmask=		(3<<2),

	DMAchan=	2,	/* floppy dma channel */
};

#define DPRINT if(floppydebug)print
int floppydebug = 0;

/*
 *  types of drive (from PC equipment byte)
 */
enum
{
	Tnone=		0,
	T360kb=		1,
	T1200kb=	2,
	T720kb=		3,
	T1440kb=	4,
};

FType floppytype[] =
{
 { "3½HD",	T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54,	0, },
 { "3½DD",	T1440kb, 512,  9, 2, 1, 80, 0x1B, 0x54, 2, },
 { "3½DD",	T720kb,  512,  9, 2, 1, 80, 0x1B, 0x54, 2, },
 { "5¼HD",	T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
 { "5¼DD",	T1200kb, 512,  9, 2, 2, 40, 0x2A, 0x50, 1, },
 { "ATT3B1",	T1200kb, 512,  8, 2, 2, 48, 0x2A, 0x50, 1, },
 { "5¼DD",	T360kb,  512,  9, 2, 1, 40, 0x2A, 0x50, 2, },
};

/*
 *  bytes per sector encoding for the controller.
 *  - index for b2c is is (bytes per sector/128).
 *  - index for c2b is code from b2c
 */
static int b2c[] =
{
[1]	0,
[2]	1,
[4]	2,
[8]	3,
};
static int c2b[] =
{
	128,
	256,
	512,
	1024,
};

FController	fl;

#define MOTORBIT(i)	(1<<((i)+4))

/*
 *  predeclared
 */
static int	cmddone(void*);
static void	floppyformat(FDrive*, char*);
static void	floppykproc(void*);
static void	floppypos(FDrive*,long);
static int	floppyrecal(FDrive*);
static int	floppyresult(void);
static void	floppyrevive(void);
static long	floppyseek(FDrive*, long);
static int	floppysense(void);
static void	floppywait(void);
static long	floppyxfer(FDrive*, int, void*, long, long);

Dirtab floppydir[]={
	"fd0disk",		{Qdata + 0},	0,	0660,
	"fd0ctl",		{Qctl + 0},	0,	0660,
	"fd1disk",		{Qdata + 1},	0,	0660,
	"fd1ctl",		{Qctl + 1},	0,	0660,
	"fd2disk",		{Qdata + 2},	0,	0660,
	"fd2ctl",		{Qctl + 2},	0,	0660,
	"fd3disk",		{Qdata + 3},	0,	0660,
	"fd3ctl",		{Qctl + 3},	0,	0660,
};
#define NFDIR	2	/* directory entries/drive */

static void
fldump(void)
{
mb();
	DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb),
		inb(Pdor), inb(Pmsr), inb(Pdir));
mb();
}

/*
 *  set floppy drive to its default type
 */
static void
floppysetdef(FDrive *dp)
{
	FType *t;

	for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++)
		if(dp->dt == t->dt){
			dp->t = t;
			floppydir[NFDIR*dp->dev].length = dp->t->cap;
			break;
		}
}

static void
floppyreset(void)
{
	FDrive *dp;
	FType *t;
	ulong maxtsize;

	dmainit(DMAchan);
	
	floppysetup0(&fl);

	/*
	 *  init dependent parameters
	 */
	maxtsize = 0;
	for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
		t->cap = t->bytes * t->heads * t->sectors * t->tracks;
		t->bcode = b2c[t->bytes/128];
		t->tsize = t->bytes * t->sectors;
		if(maxtsize < t->tsize)
			maxtsize = t->tsize;
	}

	/*
	 *  allocate the drive storage
	 */
	fl.d = xalloc(fl.ndrive*sizeof(FDrive));
	fl.selected = fl.d;

	/*
	 *  stop the motors
	 */
	fl.motor = 0;
	delay(10);
mb();
	outb(Pdor, fl.motor | Fintena | Fena);
mb();
	delay(10);

	/*
	 *  init drives
	 */
	for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
		dp->dev = dp - fl.d;
		dp->dt = T1440kb;
		floppysetdef(dp);
		dp->cyl = -1;			/* because we don't know */
		dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024);
		dp->ccyl = -1;
		dp->vers = 0;
	}

	/*
	 *  first operation will recalibrate
	 */
	fl.confused = 1;

	floppysetup1(&fl);
}

static Chan*
floppyattach(char *spec)
{
	static int kstarted;

	if(kstarted == 0){
		/*
		 *  watchdog to turn off the motors
		 */
		kstarted = 1;
		kproc("floppy", floppykproc, 0);
	}
	return devattach('f', spec);
}

static int
floppywalk(Chan *c, char *name)
{
	return devwalk(c, name, floppydir, fl.ndrive*NFDIR, devgen);
}

static void
floppystat(Chan *c, char *dp)
{
	devstat(c, dp, floppydir, fl.ndrive*NFDIR, devgen);
}

static Chan*
floppyopen(Chan *c, int omode)
{
	return devopen(c, omode, floppydir, fl.ndrive*NFDIR, devgen);
}

static void
floppyclose(Chan *)
{
}

static void
islegal(ulong offset, long n, FDrive *dp)
{
	if(offset % dp->t->bytes)
		error(Ebadarg);
	if(n % dp->t->bytes)
		error(Ebadarg);
}

/*
 *  check if the floppy has been replaced under foot.  cause
 *  an error if it has.
 *
 *  a seek and a read clears the condition.  this was determined
 *  experimentally, there has to be a better way.
 *
 *  if the read fails, cycle through the possible floppy
 *  density till one works or we've cycled through all
 *  possibilities for this drive.
 */
static void
changed(Chan *c, FDrive *dp)
{
	ulong old;
	FType *start;

	/*
	 *  if floppy has changed or first time through
	 */
mb();
	if((inb(Pdir)&Fchange) || dp->vers == 0){
mb();
		DPRINT("changed\n");
		fldump();
		dp->vers++;
		floppysetdef(dp);
		start = dp->t;
		dp->confused = 1;	/* make floppyon recal */
DPRINT("b4 floppyon:\n");
fldump();
		floppyon(dp);
DPRINT("after floppyon:\n");
fldump();
		floppyseek(dp, dp->t->heads*dp->t->tsize);
DPRINT("after floppyseek:\n");
fldump();
		while(waserror()){
			while(++dp->t){
				if(dp->t == &floppytype[nelem(floppytype)])
					dp->t = floppytype;
				if(dp->dt == dp->t->dt)
					break;
			}
			floppydir[NFDIR*dp->dev].length = dp->t->cap;
			floppyon(dp);
			DPRINT("changed: trying %s\n", dp->t->name);
			fldump();
			if(dp->t == start)
				nexterror();
		}
		floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize);
		poperror();
	}

	old = c->qid.vers;
	c->qid.vers = dp->vers;
	if(old && old != dp->vers)
		error(Eio);
}

static int
readtrack(FDrive *dp, int cyl, int head)
{
	int i, nn, sofar;
	ulong pos;

	nn = dp->t->tsize;
	if(dp->ccyl==cyl && dp->chead==head)
		return nn;
	pos = (cyl*dp->t->heads+head) * nn;
	for(sofar = 0; sofar < nn; sofar += i){
		dp->ccyl = -1;
		i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar);
		if(i <= 0)
			return -1;
	}
	dp->ccyl = cyl;
	dp->chead = head;
	return nn;
}

static long
floppyread(Chan *c, void *a, long n, vlong off)
{
	FDrive *dp;
	long rv;
	int sec, head, cyl;
	long len;
	uchar *aa;
	ulong offset = off;

	if(c->qid.path == CHDIR)
		return devdirread(c, a, n, floppydir, fl.ndrive*NFDIR, devgen);

	rv = 0;
	dp = &fl.d[c->qid.path & ~Qmask];
	switch ((int)(c->qid.path & Qmask)) {
	case Qdata:
		islegal(offset, n, dp);
		aa = a;

		qlock(&fl);
		if(waserror()){
			qunlock(&fl);
			nexterror();
		}
		floppyon(dp);
		changed(c, dp);
		for(rv = 0; rv < n; rv += len){
			/*
			 *  all xfers come out of the track cache
			 */
			dp->len = n - rv;
			floppypos(dp, offset+rv);
			cyl = dp->tcyl;
			head = dp->thead;
			len = dp->len;
			sec = dp->tsec;
			if(readtrack(dp, cyl, head) < 0)
				break;
			memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len);
		}
		qunlock(&fl);
		poperror();

		break;
	case Qctl:
		return readstr(offset, a, n, dp->t->name);
	default:
		panic("floppyread: bad qid");
	}

	return rv;
}

#define SNCMP(a, b) strncmp(a, b, sizeof(b)-1)
static long
floppywrite(Chan *c, void *a, long n, vlong off)
{
	FDrive *dp;
	long rv, i;
	char *aa = a;
	char ctlmsg[64];
	ulong offset = off;

	rv = 0;
	dp = &fl.d[c->qid.path & ~Qmask];
	switch ((int)(c->qid.path & Qmask)) {
	case Qdata:
		islegal(offset, n, dp);
		qlock(&fl);
		if(waserror()){
			qunlock(&fl);
			nexterror();
		}
		floppyon(dp);
		changed(c, dp);
		for(rv = 0; rv < n; rv += i){
			floppypos(dp, offset+rv);
			if(dp->tcyl == dp->ccyl)
				dp->ccyl = -1;
			i = floppyxfer(dp, Fwrite, aa+rv, offset+rv, n-rv);
			if(i < 0)
				break;
			if(i == 0)
				error(Eio);
		}
		qunlock(&fl);
		poperror();
		break;
	case Qctl:
		rv = n;
		qlock(&fl);
		if(waserror()){
			qunlock(&fl);
			nexterror();
		}
		if(n >= sizeof(ctlmsg))
			n = sizeof(ctlmsg) - 1;
		memmove(ctlmsg, aa, n);
		ctlmsg[n] = 0;
		if(SNCMP(ctlmsg, "eject") == 0){
			floppyeject(dp);
		} else if(SNCMP(ctlmsg, "reset") == 0){
			fl.confused = 1;
			floppyon(dp);
		} else if(SNCMP(ctlmsg, "format") == 0){
			floppyformat(dp, ctlmsg);
		} else if(SNCMP(ctlmsg, "debug") == 0){
			floppydebug = 1;
		} else
			error(Ebadctl);
		poperror();
		qunlock(&fl);
		break;
	default:
		panic("floppywrite: bad qid");
	}

	return rv;
}

static void
floppykproc(void *)
{
	FDrive *dp;

	while(waserror())
		;
	for(;;){
		for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
			if((fl.motor&MOTORBIT(dp->dev))
			&& TK2SEC(m->ticks - dp->lasttouched) > 5
			&& canqlock(&fl)){
				if(TK2SEC(m->ticks - dp->lasttouched) > 5)
					floppyoff(dp);
				qunlock(&fl);
			}
		}
		tsleep(&fl.kr, return0, 0, 1000);
	}
}

/*
 *  start a floppy drive's motor.
 */
static void
floppyon(FDrive *dp)
{
	int alreadyon;
	int tries;

	if(fl.confused)
		floppyrevive();

	/* start motor and select drive */
	alreadyon = fl.motor & MOTORBIT(dp->dev);
	fl.motor |= MOTORBIT(dp->dev);
mb();
	outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
mb();
	if(!alreadyon){
		/* wait for drive to spin up */
		tsleep(&dp->r, return0, 0, 750);

		/* clear any pending interrupts */
		floppysense();
	}

	/* set transfer rate */
	if(fl.rate != dp->t->rate){
		fl.rate = dp->t->rate;
mb();
		outb(Pdsr, fl.rate);
mb();
	}

	/* get drive to a known cylinder */
	if(dp->confused)
		for(tries = 0; tries < 4; tries++)
			if(floppyrecal(dp) >= 0)
				break;
	dp->lasttouched = m->ticks;
	fl.selected = dp;
}

/*
 *  stop the floppy if it hasn't been used in 5 seconds
 */
static void
floppyoff(FDrive *dp)
{
	fl.motor &= ~MOTORBIT(dp->dev);
mb();
	outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
mb();
}

/*
 *  send a command to the floppy
 */
static int
floppycmd(void)
{
	int i;
	int tries;

	fl.nstat = 0;
	for(i = 0; i < fl.ncmd; i++){
		for(tries = 0; ; tries++){
mb();
			if((inb(Pmsr)&(Ffrom|Fready)) == Fready)
				break;
mb();
			if(tries > 1000){
				DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i);
				fldump();

				/* empty fifo, might have been a bad command */
				floppyresult();
				return -1;
			}
			microdelay(8);	/* for machine independence */
		}
mb();
		outb(Pfdata, fl.cmd[i]);
mb();
	}
	return 0;
}

/*
 *  get a command result from the floppy
 *
 *  when the controller goes ready waiting for a command
 *  (instead of sending results), we're done
 * 
 */
static int
floppyresult(void)
{
	int i, s;
	int tries;

	/* get the result of the operation */
	for(i = 0; i < sizeof(fl.stat); i++){
		/* wait for status byte */
		for(tries = 0; ; tries++){
mb();
			s = inb(Pmsr)&(Ffrom|Fready);
mb();
			if(s == Fready){
				fl.nstat = i;
				return fl.nstat;
			}
			if(s == (Ffrom|Fready))
				break;
			if(tries > 1000){
				DPRINT("floppyresult: %d stats\n", i);
				fldump();
				fl.confused = 1;
				return -1;
			}
			microdelay(8);	/* for machine independence */
		}
mb();
		fl.stat[i] = inb(Pfdata);
mb();
// print("stat[%d]: %.2ux\n", i, fl.stat[i]);
	}
	fl.nstat = sizeof(fl.stat);
	return fl.nstat;
}

/*
 *  calculate physical address of a logical byte offset into the disk
 *
 *  truncate dp->length if it crosses a track boundary
 */
static void
floppypos(FDrive *dp, long off)
{
	int lsec;
	int ltrack;
	int end;

	lsec = off/dp->t->bytes;
	ltrack = lsec/dp->t->sectors;
	dp->tcyl = ltrack/dp->t->heads;
	dp->tsec = (lsec % dp->t->sectors) + 1;
	dp->thead = (lsec/dp->t->sectors) % dp->t->heads;

	/*
	 *  can't read across track boundaries.
	 *  if so, decrement the bytes to be read.
	 */
	end = (ltrack+1)*dp->t->sectors*dp->t->bytes;
	if(off+dp->len > end)
		dp->len = end - off;
}

/*
 *  get the interrupt cause from the floppy.
 */
static int
floppysense(void)
{
	fl.ncmd = 0;
	fl.cmd[fl.ncmd++] = Fsense;
	if(floppycmd() < 0)
		return -1;
	if(floppyresult() < 2){
		DPRINT("can't read sense response\n");
		fldump();
		fl.confused = 1;
		return -1;
	}
	return 0;
}

static int
cmddone(void *)
{
	return fl.ncmd == 0;
}

/*
 *  Wait for a floppy interrupt.  If none occurs in 5 seconds, we
 *  may have missed one.  This only happens on some portables which
 *  do power management behind our backs.  Call the interrupt
 *  routine to try to clear any conditions.
 */
static void
floppywait(void)
{
	tsleep(&fl.r, cmddone, 0, 5000);
	if(!cmddone(0)){
		floppyintr(0);
		fl.confused = 1;
	}
}

/*
 *  we've lost the floppy position, go to cylinder 0.
 */
static int
floppyrecal(FDrive *dp)
{
	dp->ccyl = -1;
	dp->cyl = -1;

	fl.ncmd = 0;
	fl.cmd[fl.ncmd++] = Frecal;
	fl.cmd[fl.ncmd++] = dp->dev;
	if(floppycmd() < 0)
		return -1;
	floppywait();
	if(fl.nstat < 2){
mb();
		DPRINT("recalibrate: confused %ux\n", inb(Pmsr));
mb();
		fl.confused = 1;
		return -1;
	}
	if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
		DPRINT("recalibrate: failed\n");
		dp->confused = 1;
		return -1;
	}
	dp->cyl = fl.stat[1];
	if(dp->cyl != 0){
		DPRINT("recalibrate: wrong cylinder %d\n", dp->cyl);
		dp->cyl = -1;
		dp->confused = 1;
		return -1;
	}

	dp->confused = 0;
	return 0;
}

/*
 *  if the controller or a specific drive is in a confused state,
 *  reset it and get back to a kown state
 */
static void
floppyrevive(void)
{
	FDrive *dp;

	/*
	 *  reset the controller if it's confused
	 */
	if(fl.confused){
		DPRINT("floppyrevive in\n");
		fldump();

		/* reset controller and turn all motors off */
		splhi();
		fl.ncmd = 1;
		fl.cmd[0] = 0;
mb();
		outb(Pdor, 0);
mb();
		delay(10);
mb();
		outb(Pdor, Fintena|Fena);
mb();
		delay(10);
		spllo();
		fl.motor = 0;
		fl.confused = 0;
		floppywait();

		/* mark all drives in an unknown state */
		for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++)
			dp->confused = 1;

		/* set rate to a known value */
mb();
		outb(Pdsr, 0);
mb();
		fl.rate = 0;

		DPRINT("floppyrevive out\n");
		fldump();
	}
}

/*
 *  seek to the target cylinder
 *
 *	interrupt, no results
 */
static long
floppyseek(FDrive *dp, long off)
{
	floppypos(dp, off);
	if(dp->cyl == dp->tcyl)
		return dp->tcyl;
	dp->cyl = -1;

	fl.ncmd = 0;
	fl.cmd[fl.ncmd++] = Fseek;
	fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
	fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps;
	if(floppycmd() < 0)
		return -1;
	floppywait();
	if(fl.nstat < 2){
		DPRINT("seek: confused\n");
		fl.confused = 1;
		return -1;
	}
	if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
		DPRINT("seek: failed\n");
		dp->confused = 1;
		return -1;
	}

	dp->cyl = dp->tcyl;
	return dp->tcyl;
}

/*
 *  read or write to floppy.  try up to three times.
 */
static long
floppyxfer(FDrive *dp, int cmd, void *a, long off, long n)
{
	long offset;
	int tries;

	if(off >= dp->t->cap)
		return 0;
	if(off + n > dp->t->cap)
		n = dp->t->cap - off;

	/* retry on error (until it gets ridiculous) */
	tries = 0;
	while(waserror()){
		if(tries++ > 20)
			nexterror();
		DPRINT("floppyxfer: retrying\n");
		/*floppyon(dp);*/
	}

	dp->len = n;
	if(floppyseek(dp, off) < 0){
		DPRINT("xfer: seek failed\n");
		dp->confused = 1;
		error(Eio);
	}

	/*
	 *  set up the dma (dp->len may be trimmed)
	 */
	if(waserror()){
		dmaend(DMAchan);
		nexterror();
	}
	dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread);
	if(dp->len < 0)
		error(Eio);

	/*
	 *  start operation
	 */
	fl.ncmd = 0;
	fl.cmd[fl.ncmd++] = cmd | (dp->t->heads > 1 ? Fmulti : 0);
	fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
	fl.cmd[fl.ncmd++] = dp->tcyl;
	fl.cmd[fl.ncmd++] = dp->thead;
	fl.cmd[fl.ncmd++] = dp->tsec;
	fl.cmd[fl.ncmd++] = dp->t->bcode;
	fl.cmd[fl.ncmd++] = dp->t->sectors;
	fl.cmd[fl.ncmd++] = dp->t->gpl;
	fl.cmd[fl.ncmd++] = 0xFF;
	if(floppycmd() < 0)
		error(Eio);

	/* Poll ready bits and transfer data */
	floppyexec((char*)a, dp->len, cmd==Fread);

	/*
	 *  give bus to DMA, floppyintr() will read result
	 */
	floppywait();
	dmaend(DMAchan);
	poperror();

	/*
	 *  check for errors
	 */
	if(fl.nstat < 7){
		DPRINT("xfer: confused\n");
		fl.confused = 1;
		error(Eio);
	}
	if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){
		DPRINT("xfer: failed %ux %ux %ux\n", fl.stat[0],
			fl.stat[1], fl.stat[2]);
		DPRINT("offset %lud len %ld\n", off, dp->len);
		if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun){
			DPRINT("DMA overrun: retry\n");
		} else
			dp->confused = 1;
		error(Eio);
	}

	/*
	 *  check for correct cylinder
	 */
	offset = fl.stat[3] * dp->t->heads + fl.stat[4];
	offset = offset*dp->t->sectors + fl.stat[5] - 1;
	offset = offset * c2b[fl.stat[6]];
	if(offset != off+dp->len){
		DPRINT("xfer: ends on wrong cyl\n");
		dp->confused = 1;
		error(Eio);
	}
	poperror();

	dp->lasttouched = m->ticks;
	return dp->len;
}

/*
 *  format a track
 */
static void
floppyformat(FDrive *dp, char *params)
{
 	int cyl, h, sec;
	ulong track;
	uchar *buf, *bp;
	FType *t;
	char *f[3];

	/*
	 *  set the type
	 */
	if(parsefields(params, f, 3, " ") > 1){
		for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
			if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){
				dp->t = t;
				floppydir[NFDIR*dp->dev].length = dp->t->cap;
				break;
			}
		}
		if(t >= &floppytype[nelem(floppytype)])
			error(Ebadarg);
	} else {
		floppysetdef(dp);
		t = dp->t;
	}

	/*
	 *  buffer for per track info
	 */
	buf = smalloc(t->sectors*4);
	if(waserror()){
		free(buf);
		nexterror();
	}

	/* force a recalibrate to cylinder 0 */
	dp->confused = 1;
	if(!waserror()){
		floppyon(dp);
		poperror();
	}

	/*
	 *  format a track at time
	 */
	for(track = 0; track < t->tracks*t->heads; track++){
		cyl = track/t->heads;
		h = track % t->heads;

		/*
		 *  seek to track, ignore errors
		 */
		floppyseek(dp, track*t->tsize);
		dp->cyl = cyl;
		dp->confused = 0;

		/*
		 *  set up the dma (dp->len may be trimmed)
		 */
		bp = buf;
		for(sec = 1; sec <= t->sectors; sec++){
			*bp++ = cyl;
			*bp++ = h;
			*bp++ = sec;
			*bp++ = t->bcode;
		}
		if(waserror()){
			dmaend(DMAchan);
			nexterror();
		}
		if(dmasetup(DMAchan, buf, bp-buf, 0) < 0)
			error(Eio);

		/*
		 *  start operation
		 */
		fl.ncmd = 0;
		fl.cmd[fl.ncmd++] = Fformat;
		fl.cmd[fl.ncmd++] = (h<<2) | dp->dev;
		fl.cmd[fl.ncmd++] = t->bcode;
		fl.cmd[fl.ncmd++] = t->sectors;
		fl.cmd[fl.ncmd++] = t->fgpl;
		fl.cmd[fl.ncmd++] = 0x5a;
		if(floppycmd() < 0)
			error(Eio);

		/* Poll ready bits and transfer data */
		floppyexec((char *)buf, bp-buf, 0);

		/*
		 *  give bus to DMA, floppyintr() will read result
		 */
		floppywait();
		dmaend(DMAchan);
		poperror();

		/*
		 *  check for errors
		 */
		if(fl.nstat < 7){
			DPRINT("format: confused\n");
			fl.confused = 1;
			error(Eio);
		}
		if((fl.stat[0]&Codemask)!=0 || fl.stat[1]|| fl.stat[2]){
			DPRINT("format: failed %ux %ux %ux\n",
				fl.stat[0], fl.stat[1], fl.stat[2]);
			dp->confused = 1;
			error(Eio);
		}
	}
	free(buf);
	dp->confused = 1;
	poperror();
}

static void
floppyintr(Ureg *)
{
	switch(fl.cmd[0]&~Fmulti){
	case Fread:
	case Fwrite:
	case Fformat:
	case Fdumpreg: 
		floppyresult();
		break;
	case Fseek:
	case Frecal:
	default:
		floppysense();	/* to clear interrupt */
		break;
	}
	fl.ncmd = 0;
	wakeup(&fl.r);
}

Dev floppydevtab = {
	'f',
	"floppy",

	floppyreset,
	devinit,
	floppyattach,
	devclone,
	floppywalk,
	floppystat,
	floppyopen,
	devcreate,
	floppyclose,
	floppyread,
	devbread,
	floppywrite,
	devbwrite,
	devremove,
	devwstat,
};

A alphapc/devvga.c => alphapc/devvga.c +331 -0
@@ 0,0 1,331 @@
/*
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

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

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

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)
{
	conf.monitor = 1;
}

static Chan*
vgaattach(char* spec)
{
	if(*spec && strcmp(spec, "0"))
		error(Eio);
	return devattach('v', spec);
}

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

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

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

static void
vgaclose(Chan*)
{
}

static long
vgaread(Chan* c, void* a, long n, vlong off)
{
	int len, port;
	char *p, *s;
	ushort *sp;
	ulong *lp;
	VGAscr *scr;
	ulong offset = off;

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

	case Qdir:
		return devdirread(c, a, n, vgadir, nelem(vgadir), devgen);

	case Qvgactl:
		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
			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;
		for(p = a; port < offset+n; port++)
			*p++ = inb(port);
		return n;

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

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

	default:
		error(Egreg);
		break;
	}

	return 0;
}

static void
vgactl(char* a)
{
	int align, i, n, size, x, y, z;
	char *field[4], *p;
	VGAscr *scr;
	extern VGAdev *vgadev[];
	extern VGAcur *vgacur[];

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

	scr = &vgascreen[0];
	if(strcmp(field[0], "hwgc") == 0){
		if(n < 2)
			error(Ebadarg);
		if(strcmp(field[1], "off") == 0){
			lock(&cursor);
			if(scr->cur){
				if(scr->cur->disable)
					scr->cur->disable(scr);
				scr->cur = nil;
			}
			unlock(&cursor);
			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(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], &p, 0);
		if(x == 0 || x > 2048)
			error(Ebadarg);
		if(*p)
			p++;

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

		switch(strtoul(p, &p, 0)){
		case 8:
			z = 3;
			break;

		default:
			z = 0;
			error(Ebadarg);
		}

		cursoroff(1);
		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);
		if(screenaperture(size, align))
			error("not enough free address space");
		return;
	}

	error(Ebadarg);
}

static long
vgawrite(Chan* c, void* a, long n, vlong off)
{
	int port;
	char *p;
	ushort *sp;
	ulong *lp;
	ulong offset = off;

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

	case Qdir:
		error(Eperm);

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

	case Qvgaiob:
		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;
		sp = a;
		for(port = offset; port < offset+n; port += 2)
			outs(port, *sp++);
		return n*2;

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

	default:
		error(Egreg);
		break;
	}

	return 0;
}

Dev vgadevtab = {
	'v',
	"vga",

	vgareset,
	devinit,
	vgaattach,
	devclone,
	vgawalk,
	vgastat,
	vgaopen,
	devcreate,
	vgaclose,
	vgaread,
	devbread,
	vgawrite,
	devbwrite,
	devremove,
	devwstat,
};

A alphapc/dma.c => alphapc/dma.c +232 -0
@@ 0,0 1,232 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"

typedef struct DMAport	DMAport;
typedef struct DMA	DMA;
typedef struct DMAxfer	DMAxfer;

enum
{
	/*
	 *  the byte registers for DMA0 are all one byte apart
	 */
	Dma0=		0x00,
	Dma0status=	Dma0+0x8,	/* status port */
	Dma0reset=	Dma0+0xD,	/* reset port */

	/*
	 *  the byte registers for DMA1 are all two bytes apart (why?)
	 */
	Dma1=		0xC0,
	Dma1status=	Dma1+2*0x8,	/* status port */
	Dma1reset=	Dma1+2*0xD,	/* reset port */
};

/*
 *  state of a dma transfer
 */
struct DMAxfer
{
	ulong	bpa;		/* bounce buffer physical address */
	void*	bva;		/* bounce buffer virtual address */
	void*	va;		/* virtual address destination/src */
	long	len;		/* bytes to be transferred */
	int	isread;
};

/*
 *  the dma controllers.  the first half of this structure specifies
 *  the I/O ports used by the DMA controllers.
 */
struct DMAport
{
	uchar	addr[4];	/* current address (4 channels) */
	uchar	count[4];	/* current count (4 channels) */
	uchar	page[4];	/* page registers (4 channels) */
	uchar	cmd;		/* command status register */
	uchar	req;		/* request registers */
	uchar	sbm;		/* single bit mask register */
	uchar	mode;		/* mode register */
	uchar	cbp;		/* clear byte pointer */
	uchar	mc;		/* master clear */
	uchar	cmask;		/* clear mask register */
	uchar	wam;		/* write all mask register bit */
};

struct DMA
{
	DMAport;
	int	shift;
	Lock;
	DMAxfer	x[4];
};

DMA dma[2] = {
	{ 0x00, 0x02, 0x04, 0x06,
	  0x01, 0x03, 0x05, 0x07,
	  0x87, 0x83, 0x81, 0x82,
	  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
	 0 },

	{ 0xc0, 0xc4, 0xc8, 0xcc,
	  0xc2, 0xc6, 0xca, 0xce,
	  0x8f, 0x8b, 0x89, 0x8a,
	  0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
	 1 },
};

/*
 *  DMA must be in the first 16MB.  This gets called early by the
 *  initialisation routines of any devices which require DMA to ensure
 *  the allocated bounce buffers are below the 16MB limit.
 */
void
dmainit(int chan)
{
	DMA *dp;
	DMAxfer *xp;
	ulong v;

	dp = &dma[(chan>>2)&1];
	chan = chan & 3;
	xp = &dp->x[chan];
	if(xp->bva != nil)
		return;

	v = (ulong)xalloc(BY2PG+BY2PG);
	if(v == 0 || PADDR(v) >= 16*MB){
		print("dmainit: chan %d: 0x%luX out of range\n", chan, v);
		xfree((void*)v);
		v = 0;
	}
	xp->bva = (void*)ROUND(v, BY2PG);
	xp->bpa = PADDR(xp->bva);
	xp->len = 0;
	xp->isread = 0;
}

/*
 *  setup a dma transfer.  if the destination is not in kernel
 *  memory, allocate a page for the transfer.
 *
 *  we assume BIOS has set up the command register before we
 *  are booted.
 *
 *  return the updated transfer length (we can't transfer across 64k
 *  boundaries)
 */
long
dmasetup(int chan, void *va, long len, int isread)
{
	DMA *dp;
	ulong pa;
	uchar mode;
	DMAxfer *xp;

	dp = &dma[(chan>>2)&1];
	chan = chan & 3;
	xp = &dp->x[chan];

	/*
	 *  if this isn't kernel memory or crossing 64k boundary or above 16 meg
	 *  use the allocated low memory page.
	 */
	pa = PADDR(va);
	if((((ulong)va)&0xF0000000) != KZERO
	|| (pa&0xFFFF0000) != ((pa+len)&0xFFFF0000)
	|| pa >= 16*MB) {
		if(xp->bva == nil)
			return -1;
		if(len > BY2PG)
			len = BY2PG;
		if(!isread)
			memmove(xp->bva, va, len);
		xp->va = va;
		xp->len = len;
		xp->isread = isread;
		pa = xp->bpa;
	}
	else
		xp->len = 0;

	/*
	 * this setup must be atomic
	 */
	ilock(dp);
	mode = (isread ? 0x44 : 0x48) | chan;
	outb(dp->mode, mode);	/* single mode dma (give CPU a chance at mem) */
	outb(dp->page[chan], pa>>16);
	outb(dp->cbp, 0);		/* set count & address to their first byte */
	outb(dp->addr[chan], pa>>dp->shift);		/* set address */
	outb(dp->addr[chan], pa>>(8+dp->shift));
	outb(dp->count[chan], (len>>dp->shift)-1);		/* set count */
	outb(dp->count[chan], ((len>>dp->shift)-1)>>8);
	outb(dp->sbm, chan);		/* enable the channel */
	iunlock(dp);

	return len;
}

int
dmadone(int chan)
{
	DMA *dp;

	dp = &dma[(chan>>2)&1];
	chan = chan & 3;

	return inb(dp->cmd) & (1<<chan);
}

/*
 *  this must be called after a dma has been completed.
 *
 *  if a page has been allocated for the dma,
 *  copy the data into the actual destination
 *  and free the page.
 */
void
dmaend(int chan)
{
	DMA *dp;
	DMAxfer *xp;

	dp = &dma[(chan>>2)&1];
	chan = chan & 3;

	/*
	 *  disable the channel
	 */
	ilock(dp);
	outb(dp->sbm, 4|chan);
	iunlock(dp);

	xp = &dp->x[chan];
	if(xp->len == 0 || !xp->isread)
		return;

	/*
	 *  copy out of temporary page
	 */
	memmove(xp->va, xp->bva, xp->len);
	xp->len = 0;
}

/*
int
dmacount(int chan)
{
	int     retval;
	DMA     *dp;
 
	dp = &dma[(chan>>2)&1];
	outb(dp->cbp, 0);
	retval = inb(dp->count[chan]);
	retval |= inb(dp->count[chan]) << 8;
	return((retval<<dp->shift)+1);
}
 */

A alphapc/etherif.h => alphapc/etherif.h +33 -0
@@ 0,0 1,33 @@
enum {
	MaxEther	= 24,
	Ntypes		= 8,
};

typedef struct Ether Ether;
struct Ether {
	ISAConf;			/* hardware info */

	int	ctlrno;
	int	tbdf;			/* type+busno+devno+funcno */
	int	mbps;			/* Mbps */
	uchar	ea[Eaddrlen];

	void	(*attach)(Ether*);	/* filled in by reset routine */
	void	(*transmit)(Ether*);
	void	(*interrupt)(Ureg*, void*);
	long	(*ifstat)(Ether*, void*, long, ulong);
	void	*ctlr;

	Queue*	oq;

	Netif;
};

extern Block* etheriq(Ether*, Block*, int);
extern void addethercard(char*, int(*)(Ether*));
extern ulong ethercrc(uchar*, int);

#define NEXT(x, l)	(((x)+1)%(l))
#define PREV(x, l)	(((x) == 0) ? (l)-1: (x)-1)
#define	HOWMANY(x, y)	(((x)+((y)-1))/(y))
#define ROUNDUP(x, y)	(HOWMANY((x), (y))*(y))

A alphapc/faultalpha.c => alphapc/faultalpha.c +63 -0
@@ 0,0 1,63 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"../port/error.h"

/*
 *  find out fault address and type of access.
 *  Call common fault handler.
 */
void
faultalpha(Ureg *ur)
{
	ulong addr, cause;
	int read, user;
	char buf[ERRLEN];
	uvlong x;

	x = ur->a0&0xffffffff80000000LL;
	if (x != 0LL && x != 0xffffffff80000000LL)
		iprint("faultalpha bad addr %llux pc %llux\n", ur->a0, ur->pc);

	addr = (ulong)ur->a0;
	cause = (ulong)ur->a2;
	addr &= ~(BY2PG-1);
	read = (cause !=1);
	user = (ulong)ur->status&UMODE;

/*	print("fault %s pc=0x%lux addr=0x%lux 0x%lux\n",
		read? (cause != 0) ? "ifetch" : "read" : "write", (ulong)ur->pc, addr, (ulong)ur->a1); /**/

	if(fault(addr, read) == 0)
		return;

	if(user){
		sprint(buf, "sys: trap: fault %s addr=0x%lux",
			read? (cause != 0) ? "ifetch" : "read" : "write", (ulong)ur->a0);
		postnote(up, 1, buf, NDebug);
		return;
	}

	iprint("kernel %s vaddr=0x%lux\n", read? (cause != 0) ? "ifetch" : "read" : "write", (ulong)ur->a0);
iprint("ptbr %lux up %lux\n", (ulong)m->ptbr, up);
if(up) iprint("top %lux lvl2 %lux\n", up->mmutop->va, up->mmulvl2->va);
if(up) iprint("top[N-1] %lux\n", ((uvlong *)up->mmutop->va)[PTE2PG-1]);
	iprint("st=0x%lux pc=0x%lux sp=0x%lux\n", (ulong)ur->status, (ulong)ur->pc, (ulong)ur->sp);
	dumpregs(ur);
	panic("fault");
}

/*
 * called in sysfile.c
 */
void
evenaddr(ulong addr)
{
	if(addr & 3){
		postnote(up, 1, "sys: odd address", NDebug);
		error(Ebadarg);
	}
}

A alphapc/floppy.h => alphapc/floppy.h +173 -0
@@ 0,0 1,173 @@
typedef	struct FController FController;
typedef	struct FDrive FDrive;
typedef struct FType FType;

static void floppyintr(Ureg*);
static void floppyon(FDrive*);
static void floppyoff(FDrive*);
static void floppysetdef(FDrive*);

/*
 *  a floppy drive
 */
struct FDrive
{
	FType	*t;		/* floppy type */
	int	dt;		/* drive type */
	int	dev;

	ulong	lasttouched;	/* time last touched */
	int	cyl;		/* current arm position */
	int	confused;	/* needs to be recalibrated */
	int	vers;

	int	tcyl;		/* target cylinder */
	int	thead;		/* target head */
	int	tsec;		/* target sector */
	long	len;		/* size of xfer */

	uchar	*cache;		/* track cache */
	int	ccyl;
	int	chead;

	Rendez	r;		/* waiting here for motor to spin up */
};

/*
 *  controller for 4 floppys
 */
struct FController
{
	QLock;			/* exclusive access to the contoller */

	int	ndrive;
	FDrive	*d;		/* the floppy drives */
	FDrive	*selected;
	int	rate;		/* current rate selected */
	uchar	cmd[14];	/* command */
	int	ncmd;		/* # command bytes */
	uchar	stat[14];	/* command status */
	int	nstat;		/* # status bytes */
	int	confused;	/* controler needs to be reset */
	Rendez	r;		/* wait here for command termination */
	int	motor;		/* bit mask of spinning disks */
	Rendez	kr;		/* for motor watcher */
};

/*
 *  floppy types (all MFM encoding)
 */
struct FType
{
	char	*name;
	int	dt;		/* compatible drive type */
	int	bytes;		/* bytes/sector */
	int	sectors;	/* sectors/track */
	int	heads;		/* number of heads */
	int	steps;		/* steps per cylinder */
	int	tracks;		/* tracks/disk */
	int	gpl;		/* intersector gap length for read/write */	
	int	fgpl;		/* intersector gap length for format */
	int	rate;		/* rate code */

	/*
	 *  these depend on previous entries and are set filled in
	 *  by floppyinit
	 */
	int	bcode;		/* coded version of bytes for the controller */
	long	cap;		/* drive capacity in bytes */
	long	tsize;		/* track size in bytes */
};
/* bits in the registers */
enum
{
	/* status registers a & b */
	Psra=		0x3f0,
	Psrb=		0x3f1,

	/* digital output register */
	Pdor=		0x3f2,
	Fintena=	0x8,	/* enable floppy interrupt */
	Fena=		0x4,	/* 0 == reset controller */

	/* main status register */
	Pmsr=		0x3f4,
	Fready=		0x80,	/* ready to be touched */
	Ffrom=		0x40,	/* data from controller */
	Ffloppybusy=	0x10,	/* operation not over */

	/* data register */
	Pfdata=		0x3f5,
	Frecal=		0x07,	/* recalibrate cmd */
	Fseek=		0x0f,	/* seek cmd */
	Fsense=		0x08,	/* sense cmd */
	Fread=		0x66,	/* read cmd */
	Freadid=	0x4a,	/* read track id */
	Fspec=		0x03,	/* set hold times */
	Fwrite=		0x45,	/* write cmd */
	Fformat=	0x4d,	/* format cmd */
	Fmulti=		0x80,	/* or'd with Fread or Fwrite for multi-head */
	Fdumpreg=	0x0e,	/* dump internal registers */

	/* digital input register */
	Pdir=		0x3F7,	/* disk changed port (read only) */
	Pdsr=		0x3F7,	/* data rate select port (write only) */
	Fchange=	0x80,	/* disk has changed */

	/* status 0 byte */
	Drivemask=	3<<0,
	Seekend=	1<<5,
	Codemask=	(3<<6)|(3<<3),
	Cmdexec=	1<<6,

	/* status 1 byte */
	Overrun=	0x10,
};


static void
pcfloppyintr(Ureg *ur, void *a)
{
	USED(a);

	floppyintr(ur);
}

void
floppysetup0(FController *fl)
{
	fl->ndrive = 1;
}

void
floppysetup1(FController *fl)
{
	if(fl->ndrive > 0){
		fl->d[0].dt = 4;
		floppysetdef(&fl->d[0]);
	}
	if(fl->ndrive > 1){
		fl->d[1].dt = 4;
		floppysetdef(&fl->d[1]);
	}

	intrenable(VectorPIC+IrqFLOPPY, pcfloppyintr, fl, BUSUNKNOWN);
}

/*
 *  eject disk
 */
void
floppyeject(FDrive *dp)
{
	floppyon(dp);
	dp->vers++;
	floppyoff(dp);
}

int 
floppyexec(char *a, long b, int c)
{
	USED(a, b, c);
	return b;
}

A alphapc/fns.h => alphapc/fns.h +108 -0
@@ 0,0 1,108 @@
#include "../port/portfns.h"

void		addclock0link(void (*)(void));
void		archinit(void);
void		arginit(void);
void		arith(void);
void		clearmmucache(void);
void		clock(Ureg*);
void		clockinit(void);
#define 	coherence 	mb
int		cistrcmp(char*, char*);
int		cistrncmp(char*, char*, int);
void		cpuidprint(void);
void		cserve(ulong, ulong);
int	dmacount(int);
int	dmadone(int);
void	dmaend(int);
void	dmainit(int);
long	dmasetup(int, void*, long, int);
void		evenaddr(ulong);
void		fataltrap(Ureg *, char *);
void		fault0(void);
void		faultalpha(Ureg*);
ulong	fcr31(void);
void		firmware(void);
#define	flushpage(s)	icflush()
void		fpenab(int);
void		fptrap(Ureg*);
ulong	getcallerpc(void*);
char		*getconf(char*);
ulong	getfcr(void);
ulong	getstatus(void);
void		gotopc(ulong);
int		i8042auxcmd(int);
void		i8042auxenable(void (*)(int, int));
void		i8042reset(void);
void		i8259init(void);
int		i8259enable(int, int, Irqctl*);
#define	idlehands()			/* nothing to do in the runproc */
void		icflush(void);
void		illegal0(void);
void		intr(Ureg*);
void		intr0(void);
void		intrenable(int, void (*)(Ureg*, void*), void*, int);
int		iprint(char*, ...);
int		isaconfig(char*, int, ISAConf*);
void		kbdinit(void);
void		*kmapv(uvlong, int);
int		kprint(char*, ...);
void		launchinit(void);
void		launch(int);
void		links(void);
void		mb(void);
ulong 	meminit(void);
void		mmuinit(void);
#define	mmunewpage(x)
void		mntdump(void);
void		ns16552special(int, int, Queue**, Queue**, int (*)(Queue*, int));
void		ns16552setup(ulong, ulong, char*);
void		ns16552install(void);
void		ns16552intr(int);
ulong	pcibarsize(Pcidev*, int);
int	pcicfgr8(Pcidev*, int);
int	pcicfgr16(Pcidev*, int);
int	pcicfgr32(Pcidev*, int);
void	pcicfgw8(Pcidev*, int, int);
void	pcicfgw16(Pcidev*, int, int);
void	pcicfgw32(Pcidev*, int, int);
void	pcihinv(Pcidev*);
Pcidev* pcimatch(Pcidev*, int, int);
void	pcireset(void);
void		prflush(void);
void		printinit(void);
#define	procrestore(p)
#define	procsave(p)
#define	procsetup(p)	((p)->fpstate = FPinit)
void		restfpregs(FPsave*);
void		screeninit(void);
void		(*screenputs)(char*, int);
void 		setpcb(PCB *);
PCB		*swpctx(PCB *);
void		syscall0(void);
int		tas(ulong*);
void		tlbflush(int, ulong);
void		touser(void*);
void		trapinit(void);
void		unaligned(void);
void		wrent(int, void*);
void		wrvptptr(uvlong);

#define	waserror()	(up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
#define	kmapperm(x)	kmap(x)
#define KADDR(a)	((void*)((ulong)(a)|KZERO))
#define PADDR(a)	((ulong)(a)&~KZERO)

#define	inb(p)	(arch->_inb)(p)
#define	ins(p)	(arch->_ins)(p)
#define	inl(p)	(arch->_inl)(p)
#define	outb(p, x)	(arch->_outb)((p), (x))
#define	outs(p, x)	(arch->_outs)((p), (x))
#define	outl(p, x)	(arch->_outl)((p), (x))

#define	insb(p, buf, len)	(arch->_insb)((p), (buf), (len))
#define	inss(p, buf, len)		(arch->_inss)((p), (buf), (len))
#define	insl(p, buf, len)		(arch->_insl)((p), (buf), (len))
#define	outsb(p, buf, len)	(arch->_outsb)((p), (buf), (len))
#define	outss(p, buf, len)	(arch->_outss)((p), (buf), (len))
#define	outsl(p, buf, len)	(arch->_outsl)((p), (buf), (len))

A alphapc/fptrap.c => alphapc/fptrap.c +46 -0
@@ 0,0 1,46 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"io.h"
#include	"../port/error.h"

char *fpcause[] =
{
	"invalid operation",
	"division by zero",
	"overflow",
	"underflow",
	"inexact operation",
	"integer overflow",
};
char	*fpexcname(Ureg*, ulong, char*);

void
fptrap(Ureg *ur)
{
	char buf[ERRLEN];
	int i;
	ulong reason;

	ur->pc &= ~2;
	reason = (ulong)ur->a0;
	for (i = 1; i < 6; i++)
		if (reason & (1<<i)) {
			sprint(buf, "fp: %s", fpcause[i-1]);
			goto found;
		}
	sprint(buf, "fp: code 0x%lux", reason);

found:
	fataltrap(ur, buf);
}

char*
fpexcname(Ureg *ur, ulong fcr31, char *buf)
{
	USED(ur, fcr31, buf);
	return buf;
}

A alphapc/i8259.c => alphapc/i8259.c +151 -0
@@ 0,0 1,151 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

/*
 *  8259 interrupt controllers
 */
enum
{
	Int0ctl=	0x20,		/* control port (ICW1, OCW2, OCW3) */
	Int0aux=	0x21,		/* everything else (ICW2, ICW3, ICW4, OCW1) */
	Int1ctl=	0xA0,		/* control port */
	Int1aux=	0xA1,		/* everything else (ICW2, ICW3, ICW4, OCW1) */

	Icw1=		0x10,		/* select bit in ctl register */
	Ocw2=		0x00,
	Ocw3=		0x08,

	EOI=		0x20,		/* non-specific end of interrupt */

	Elcr1=		0x4D0,		/* Edge/Level Triggered Register */
	Elcr2=		0x4D1,
};

static int int0mask;			/* interrupts enabled for first 8259 */
static int int1mask;			/* interrupts enabled for second 8259 */

int elcr;				/* mask of level-triggered interrupts */

void
i8259init(void)
{
	int /*elcr1, */ x;

	int0mask = 0xFF;
	int1mask = 0xFF;

	/*
	 *  Set up the first 8259 interrupt processor.
	 *  Make 8259 interrupts start at CPU vector Int0vec.
	 *  Set the 8259 as master with edge triggered
	 *  input with fully nested interrupts.
	 */
	outb(Int0ctl, (1<<4)|(0<<3)|(1<<0));	/* ICW1 - master, edge triggered,
					  	   ICW4 will be sent */
	outb(Int0aux, VectorPIC);		/* ICW2 - interrupt vector offset */
	outb(Int0aux, 0x04);			/* ICW3 - have slave on level 2 */
	outb(Int0aux, 0x01);			/* ICW4 - 8086 mode, not buffered */

	/*
	 *  Set up the second 8259 interrupt processor.
	 *  Make 8259 interrupts start at CPU vector VectorPIC+8.
	 *  Set the 8259 as slave with edge triggered
	 *  input with fully nested interrupts.
	 */
	outb(Int1ctl, (1<<4)|(0<<3)|(1<<0));	/* ICW1 - master, edge triggered,
					  	   ICW4 will be sent */
	outb(Int1aux, VectorPIC+8);		/* ICW2 - interrupt vector offset */
	outb(Int1aux, 0x02);			/* ICW3 - I am a slave on level 2 */
	outb(Int1aux, 0x01);			/* ICW4 - 8086 mode, not buffered */
	outb(Int1aux, int1mask);

	/*
	 *  pass #2 8259 interrupts to #1
	 */
	int0mask &= ~0x04;
	outb(Int0aux, int0mask);

	/*
	 * Set Ocw3 to return the ISR when ctl read.
	 * After initialisation status read is set to IRR.
	 * Read IRR first to possibly deassert an outstanding
	 * interrupt.
	 */
	x = inb(Int0ctl); USED(x);
	outb(Int0ctl, Ocw3|0x03);
	x = inb(Int1ctl); USED(x);
	outb(Int1ctl, Ocw3|0x03);

	/*
	 * Check for Edge/Level register.
	 * This check may not work for all chipsets.
	 */
/*	elcr1 = inb(Elcr1);
	outb(Elcr1, 0);
	if(inb(Elcr1) == 0){
		outb(Elcr1, 0x20);
		if(inb(Elcr1) == 0x20)
			elcr = (inb(Elcr2)<<8)|elcr1;
	}
	outb(Elcr1, elcr1);
	if(elcr)
		iprint("ELCR: %4.4uX\n", elcr);
/**/
}

int
i8259isr(int v)
{
	int isr;

	/*
	 *  tell the 8259 that we're done with the
	 *  highest level interrupt (interrupts are still
	 *  off at this point)
	 */
	isr = 0;
	if(v >= VectorPIC && v <= MaxVectorPIC){
		isr = inb(Int0ctl);
		outb(Int0ctl, EOI);
		if(v >= VectorPIC+8){
			isr |= inb(Int1ctl)<<8;
			outb(Int1ctl, EOI);
		}
	}

	return isr & (1<<(v-VectorPIC));
}

int
i8259enable(int v, int, Irqctl* irqctl)
{
	if(v < VectorPIC || v > MaxVectorPIC){
		iprint("i8259enable: vector %d out of range\n", v);
		return -1;
	}
	v -= VectorPIC;

	/*
	 *  enable corresponding interrupt in 8259
	 */
	if(v < 8){
		int0mask &= ~(1<<v);
		outb(Int0aux, int0mask);
	}
	else{
		int1mask &= ~(1<<(v-8));
		outb(Int1aux, int1mask);
	}

	if(elcr & (1<<v))
		irqctl->eoi = i8259isr;
	else
		irqctl->isr = i8259isr;
	irqctl->isintr = 1;

	return v;
}

A alphapc/io.h => alphapc/io.h +204 -0
@@ 0,0 1,204 @@
enum {
	Uart0		= 0x3F8,
	Uart1		= 0x2F8,
	  UartFREQ	= 1843200,
};

enum {
/*	VectorPIC	= 32,		/* external i8259 interrupts */
	IrqCLOCK	= 0,
	IrqKBD		= 1,
	IrqUART1	= 3,
	IrqUART0	= 4,
	IrqPCMCIA	= 5,
	IrqFLOPPY	= 6,
	IrqLPT		= 7,
	IrqIRQ7		= 7,
	IrqAUX		= 12,		/* PS/2 port */
	IrqIRQ13	= 13,		/* coprocessor on 386 */
	IrqATA0		= 14,
	MaxIrqPIC	= 15,

/* deprecated: */
	VectorPIC	= 128,		/* external [A]PIC interrupts */
	VectorCLOCK	= VectorPIC+0,
	VectorKBD	= VectorPIC+1,
	VectorUART1	= VectorPIC+3,
	VectorUART0	= VectorPIC+4,
	VectorPCMCIA	= VectorPIC+5,
	VectorFLOPPY	= VectorPIC+6,
	VectorLPT	= VectorPIC+7,
	VectorIRQ7	= VectorPIC+7,
	VectorAUX	= VectorPIC+12,	/* PS/2 port */
	VectorIRQ13	= VectorPIC+13,	/* corocessor on x386 */
	VectorATA0	= VectorPIC+14,
	MaxVectorPIC	= VectorPIC+15,
	VectorPCI	= 16,		/* PCI bus (PLD) */
};

typedef struct Irq {
	void	(*f)(Ureg*, void*);	/* handler to call */
	void*	a;			/* argument to call it with */

	Irq*	next;			/* link to next handler */
} Irq;

typedef struct Irqctl {
	int	(*isr)(int);		/* get isr bit for this irq */
	int	(*eoi)(int);		/* eoi */
	int	isintr;

	Irq*	irq;			/* handlers on this IRQ */
} Irqctl;

enum {
	BusCBUS		= 0,		/* Corollary CBUS */
	BusCBUSII,			/* Corollary CBUS II */
	BusEISA,			/* Extended ISA */
	BusFUTURE,			/* IEEE Futurebus */
	BusINTERN,			/* Internal bus */
	BusISA,				/* Industry Standard Architecture */
	BusMBI,				/* Multibus I */
	BusMBII,			/* Multibus II */
	BusMCA,				/* Micro Channel Architecture */
	BusMPI,				/* MPI */
	BusMPSA,			/* MPSA */
	BusNUBUS,			/* Apple Macintosh NuBus */
	BusPCI,				/* Peripheral Component Interconnect */
	BusPCMCIA,			/* PC Memory Card International Association */
	BusTC,				/* DEC TurboChannel */
	BusVL,				/* VESA Local bus */
	BusVME,				/* VMEbus */
	BusXPRESS,			/* Express System Bus */
};

#define MKBUS(t,b,d,f)	(((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8))
#define BUSFNO(tbdf)	(((tbdf)>>8)&0x07)
#define BUSDNO(tbdf)	(((tbdf)>>11)&0x1F)
#define BUSBNO(tbdf)	(((tbdf)>>16)&0xFF)
#define BUSTYPE(tbdf)	((tbdf)>>24)
#define BUSDF(tbdf)		((tbdf)&0x000FF00)
#define BUSBDF(tbdf)	((tbdf)&0x0FFFF00)
#define BUSUNKNOWN	(-1)

enum {
	MaxEISA		= 16,
	EISAconfig	= 0xC80,
};

/*
 * PCI support code.
 */
enum {					/* type 0 and type 1 pre-defined header */
	PciVID		= 0x00,		/* vendor ID */
	PciDID		= 0x02,		/* device ID */
	PciPCR		= 0x04,		/* command */
	PciPSR		= 0x06,		/* status */
	PciRID		= 0x08,		/* revision ID */
	PciCCRp		= 0x09,		/* programming interface class code */
	PciCCRu		= 0x0A,		/* sub-class code */
	PciCCRb		= 0x0B,		/* base class code */
	PciCLS		= 0x0C,		/* cache line size */
	PciLTR		= 0x0D,		/* latency timer */
	PciHDT		= 0x0E,		/* header type */
	PciBST		= 0x0F,		/* BIST */

	PciBAR0		= 0x10,		/* base address */
	PciBAR1		= 0x14,

	PciINTL		= 0x3C,		/* interrupt line */
	PciINTP		= 0x3D,		/* interrupt pin */
};

enum {					/* type 0 pre-defined header */
	PciBAR2		= 0x18,
	PciBAR3		= 0x1C,
	PciBAR4		= 0x20,
	PciBAR5		= 0x24,
	PciCIS		= 0x28,		/* cardbus CIS pointer */
	PciSVID		= 0x2C,		/* subsystem vendor ID */
	PciSID		= 0x2E,		/* cardbus CIS pointer */
	PciEBAR0	= 0x30,		/* xpansion ROM base address */
	PciMGNT		= 0x3E,		/* burst period length */
	PciMLT		= 0x3F,		/* maximum latency between bursts */
};

enum {					/* type 1 pre-defined header */
	PciPBN		= 0x18,		/* primary bus number */
	PciSBN		= 0x19,		/* secondary bus number */
	PciUBN		= 0x1A,		/* subordinate bus number */
	PciSLTR		= 0x1B,		/* secondary latency timer */
	PciIBR		= 0x1C,		/* I/O base */
	PciILR		= 0x1D,		/* I/O limit */
	PciSPSR		= 0x1E,		/* secondary status */
	PciMBR		= 0x20,		/* memory base */
	PciMLR		= 0x22,		/* memory limit */
	PciPMBR		= 0x24,		/* prefetchable memory base */
	PciPMLR		= 0x26,		/* prefetchable memory limit */
	PciPUBR		= 0x28,		/* prefetchable base upper 32 bits */
	PciPULR		= 0x2C,		/* prefetchable limit upper 32 bits */
	PciIUBR		= 0x30,		/* I/O base upper 16 bits */
	PciIULR		= 0x32,		/* I/O limit upper 16 bits */
	PciEBAR1	= 0x28,		/* expansion ROM base address */
	PciBCR		= 0x3E,		/* bridge control register */
};

typedef struct Pcidev Pcidev;
typedef struct Pcidev {
	int	tbdf;		/* type+bus+device+function */
	ushort	vid;			/* vendor ID */
	ushort	did;			/* device ID */

	struct {
		ulong	bar;		/* base address */
		int	size;
	} mem[3];

	uchar	intl;			/* interrupt line */
	ushort	ccru;


	Pcidev*	list;
	Pcidev*	bridge;			/* down a bus */
	Pcidev*	link;			/* next device on this bno */
};

/*
 * PCMCIA support code.
 */
/*
 * Map between ISA memory space and PCMCIA card memory space.
 */
struct PCMmap {
	ulong	ca;			/* card address */
	ulong	cea;			/* card end address */
	ulong	isa;			/* ISA address */
	int	len;			/* length of the ISA area */
	int	attr;			/* attribute memory */
	int	ref;
};

/*
 *  SCSI bus
 */
enum {
	MaxScsi		= 8,
	NTarget		= 8,		/* should be 16... */
};
struct Target {
	int	ctlrno;
	int	target;
	uchar*	inq;
	uchar*	scratch;

	Rendez	rendez;

	int	ok;
};

typedef int (*Scsiio)(Target*, int, uchar*, int, void*, int*);

typedef struct SCSIdev {
	char*	type;
	Scsiio	(*reset)(int, ISAConf*);
} SCSIdev;

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

enum {
	Data=		0x60,		/* data port */

	Status=		0x64,		/* status port */
	 Inready=	0x01,		/*  input character ready */
	 Outbusy=	0x02,		/*  output busy */
	 Sysflag=	0x04,		/*  system flag */
	 Cmddata=	0x08,		/*  cmd==0, data==1 */
	 Inhibit=	0x10,		/*  keyboard/mouse inhibited */
	 Minready=	0x20,		/*  mouse character ready */
	 Rtimeout=	0x40,		/*  general timeout */
	 Parity=	0x80,

	Cmd=		0x64,		/* command port (write only) */

	Spec=		0x80,

	PF=		Spec|0x20,	/* num pad function key */
	View=		Spec|0x00,	/* view (shift window up) */
	KF=		Spec|0x40,	/* function key */
	Shift=		Spec|0x60,
	Break=		Spec|0x61,
	Ctrl=		Spec|0x62,
	Latin=		Spec|0x63,
	Caps=		Spec|0x64,
	Num=		Spec|0x65,
	Middle=		Spec|0x66,
	No=		0x00,		/* peter */

	Home=		KF|13,
	Up=		KF|14,
	Pgup=		KF|15,
	Print=		KF|16,
	Left=		View,
	Right=		View,
	End=		'\r',
	Down=		View,
	Pgdown=		View,
	Ins=		KF|20,
	Del=		0x7F,
};

uchar kbtab[] = 
{
[0x00]	No,	0x1b,	'1',	'2',	'3',	'4',	'5',	'6',
[0x08]	'7',	'8',	'9',	'0',	'-',	'=',	'\b',	'\t',
[0x10]	'q',	'w',	'e',	'r',	't',	'y',	'u',	'i',
[0x18]	'o',	'p',	'[',	']',	'\n',	Ctrl,	'a',	's',
[0x20]	'd',	'f',	'g',	'h',	'j',	'k',	'l',	';',
[0x28]	'\'',	'`',	Shift,	'\\',	'z',	'x',	'c',	'v',
[0x30]	'b',	'n',	'm',	',',	'.',	'/',	Shift,	'*',
[0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
[0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	KF|12,	'7',
[0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
[0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
[0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
};

uchar kbtabshift[] =
{
[0x00]	No,	0x1b,	'!',	'@',	'#',	'$',	'%',	'^',
[0x08]	'&',	'*',	'(',	')',	'_',	'+',	'\b',	'\t',
[0x10]	'Q',	'W',	'E',	'R',	'T',	'Y',	'U',	'I',
[0x18]	'O',	'P',	'{',	'}',	'\n',	Ctrl,	'A',	'S',
[0x20]	'D',	'F',	'G',	'H',	'J',	'K',	'L',	':',
[0x28]	'"',	'~',	Shift,	'|',	'Z',	'X',	'C',	'V',
[0x30]	'B',	'N',	'M',	'<',	'>',	'?',	Shift,	'*',
[0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
[0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	KF|12,	'7',
[0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
[0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
[0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
};

uchar kbtabesc1[] =
{
[0x00]	No,	No,	No,	No,	No,	No,	No,	No,
[0x08]	No,	No,	No,	No,	No,	No,	No,	No,
[0x10]	No,	No,	No,	No,	No,	No,	No,	No,
[0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
[0x20]	No,	No,	No,	No,	No,	No,	No,	No,
[0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
[0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
[0x38]	Latin,	No,	No,	No,	No,	No,	No,	No,
[0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
[0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
[0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
[0x58]	No,	No,	No,	No,	No,	No,	No,	No,
};

enum
{
	/* controller command byte */
	Cscs1=		(1<<6),		/* scan code set 1 */
	Cauxdis=	(1<<5),		/* mouse disable */
	Ckbddis=	(1<<4),		/* kbd disable */
	Csf=		(1<<2),		/* system flag */
	Cauxint=	(1<<1),		/* mouse interrupt enable */
	Ckbdint=	(1<<0),		/* kbd interrupt enable */
};

static Lock i8042lock;
static uchar ccc;
static void (*auxputc)(int, int);

/*
 *  wait for output no longer busy
 */
static int
outready(void)
{
	int tries;

	for(tries = 0; (inb(Status) & Outbusy); tries++){
		if(tries > 500)
			return -1;
		delay(2);
	}
	return 0;
}

/*
 *  wait for input
 */
static int
inready(void)
{
	int tries;

	for(tries = 0; !(inb(Status) & Inready); tries++){
		if(tries > 500)
			return -1;
		delay(2);
	}
	return 0;
}

/*
 *  ask 8042 to reset the machine
 */
void
i8042reset(void)
{
	ushort *s = KADDR(0x472);
	int i, x;

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

	/*
	 *  newer reset the machine command
	 */
	outready();
	outb(Cmd, 0xFE);
	outready();

	/*
	 *  Pulse it by hand (old somewhat reliable)
	 */
	x = 0xDF;
	for(i = 0; i < 5; i++){
		x ^= 1;
		outready();
		outb(Cmd, 0xD1);
		outready();
		outb(Data, x);	/* toggle reset */
		delay(100);
	}
}

int
i8042auxcmd(int cmd)
{
	unsigned int c;
	int tries;

	c = 0;
	tries = 0;

	ilock(&i8042lock);
	do{
		if(tries++ > 2)
			break;
		if(outready() < 0)
			break;
		outb(Cmd, 0xD4);
		if(outready() < 0)
			break;
		outb(Data, cmd);
		if(outready() < 0)
			break;
		if(inready() < 0)
			break;
		c = inb(Data);
	} while(c == 0xFE || c == 0);
	iunlock(&i8042lock);

	if(c != 0xFA){
		print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd);
		return -1;
	}
	return 0;
}

/*
 *  keyboard interrupt
 */
static void
i8042intr(Ureg*, void*)
{
	int s, c, i;
	static int esc1, esc2;
	static int alt, caps, ctl, num, shift;
	static int collecting, nk;
	static uchar kc[5];
	int keyup;

	/*
	 *  get status
	 */
	lock(&i8042lock);
	s = inb(Status);
	if(!(s&Inready)){
		unlock(&i8042lock);
		return;
	}

	/*
	 *  get the character
	 */
	c = inb(Data);
	unlock(&i8042lock);

	/*
	 *  if it's the aux port...
	 */
	if(s & Minready){
		if(auxputc != nil)
			auxputc(c, shift);
		return;
	}

	/*
	 *  e0's is the first of a 2 character sequence
	 */
	if(c == 0xe0){
		esc1 = 1;
		return;
	} else if(c == 0xe1){
		esc2 = 2;
		return;
	}

	keyup = c&0x80;
	c &= 0x7f;
	if(c > sizeof kbtab){
		c |= keyup;
		if(c != 0xFF)	/* these come fairly often: CAPSLOCK U Y */
			print("unknown key %ux\n", c);
		return;
	}

	if(esc1){
		c = kbtabesc1[c];
		esc1 = 0;
	} else if(esc2){
		esc2--;
		return;
	} else if(shift)
		c = kbtabshift[c];
	else
		c = kbtab[c];

	if(caps && c<='z' && c>='a')
		c += 'A' - 'a';

	/*
	 *  keyup only important for shifts
	 */
	if(keyup){
		switch(c){
		case Latin:
			alt = 0;
			break;
		case Shift:
			shift = 0;
			break;
		case Ctrl:
			ctl = 0;
			break;
		}
		return;
	}

	/*
 	 *  normal character
	 */
	if(!(c & Spec)){
		if(ctl){
			if(alt && c == Del)
				exit(0);
			c &= 0x1f;
		}
		if(!collecting){
			kbdputc(kbdq, c);
			return;
		}
		kc[nk++] = c;
		c = latin1(kc, nk);
		if(c < -1)	/* need more keystrokes */
			return;
		if(c != -1)	/* valid sequence */
			kbdputc(kbdq, c);
		else	/* dump characters */
			for(i=0; i<nk; i++)
				kbdputc(kbdq, kc[i]);
		nk = 0;
		collecting = 0;
		return;
	} else {
		switch(c){
		case Caps:
			caps ^= 1;
			return;
		case Num:
			num ^= 1;
			return;
		case Shift:
			shift = 1;
			return;
		case Latin:
			alt = 1;
			collecting = 1;
			nk = 0;
			return;
		case Ctrl:
			ctl = 1;
			return;
		}
	}
	kbdputc(kbdq, c);
}

void
i8042auxenable(void (*putc)(int, int))
{
	char *err = "i8042: aux init failed\n";

	/* enable kbd/aux xfers and interrupts */
	ccc &= ~Cauxdis;
	ccc |= Cauxint;

	ilock(&i8042lock);
	if(outready() < 0)
		print(err);
	outb(Cmd, 0x60);			/* write control register */
	if(outready() < 0)
		print(err);
	outb(Data, ccc);
	if(outready() < 0)
		print(err);
	outb(Cmd, 0xA8);			/* auxilliary device enable */
	if(outready() < 0){
		iunlock(&i8042lock);
		return;
	}
	auxputc = putc;
	intrenable(VectorAUX, i8042intr, 0, BUSUNKNOWN);
	iunlock(&i8042lock);
}

void
kbdinit(void)
{
	int c, x;

	kbdq = qopen(4*1024, 0, 0, 0);
	if(kbdq == nil)
		panic("kbdinit");
	qnoblock(kbdq, 1);

	intrenable(VectorKBD, i8042intr, 0, BUSUNKNOWN);

	/* wait for a quiescent controller */
	while((c = inb(Status)) & (Outbusy | Inready))
		if(c & Inready) {
			x = inb(Data);
			USED(x);
		}

	/* get current controller command byte */
	outb(Cmd, 0x20);
	if(inready() < 0){
		print("kbdinit: can't read ccc\n");
		ccc = 0;
	} else
		ccc = inb(Data);

	/* enable kbd xfers and interrupts */
	/* disable mouse */
	ccc &= ~Ckbddis;
	ccc |= Csf | Ckbdint | Cscs1;
	if(outready() < 0)
		print("kbd init failed\n");
	outb(Cmd, 0x60);
	if(outready() < 0)
		print("kbd init failed\n");
	outb(Data, ccc);
	outready();
}

A alphapc/l.s => alphapc/l.s +381 -0
@@ 0,0 1,381 @@
#include "mem.h"

#define SP		R30

#define	HI_IPL	6	/* use 7 to disable mchecks */

TEXT	_main(SB), $-8
	MOVQ	$setSB(SB), R29
	MOVQ	R29, R16
	CALL_PAL	$PALwrkgp
	MOVQ	$mach0(SB), R(MACH)
	MOVQ	$(BY2PG-8)(R(MACH)), R30
	MOVQ	R31, R(USER)

	MOVQ	$edata(SB), R1
	MOVQ	$end(SB), R2
clrbss:
	MOVQ	R31, (R1)
	ADDQ	$8, R1
	CMPUGT	R1, R2, R3
	BEQ		R3, clrbss

	MOVL	R0, bootconf(SB)		/* passed in from boot loader */

	TRAPB
	MOVQ	$1, R1
	SLLQ		$59, R1		/* normal rounding mode */
	MOVQ	R1, (R30)
	MOVT	(R30), F1
	MOVT	F1, FPCR
	TRAPB

	MOVT	$0.5, F28
	ADDT	F28, F28, F29
	ADDT	F29, F29, F30

	JSR	main(SB)
	MOVQ	$_divq(SB), R31		/* touch _divq etc.; doesn't need to execute */
	MOVQ	$_divl(SB), R31			/* touch _divl etc.; doesn't need to execute */
	RET

TEXT	setpcb(SB), $-8
	MOVQ	R30, (R0)
	AND		$0x7FFFFFFF, R0, R16		/* make address physical */
	CALL_PAL	$PALswpctx
	RET

GLOBL	mach0(SB), $(MAXMACH*BY2PG)
GLOBL	init_ptbr(SB), $8

TEXT	firmware(SB), $-8
	CALL_PAL $PALhalt

TEXT	splhi(SB), $0

	MOVL	R26, 4(R(MACH))	/* save PC in m->splpc */
	MOVQ	$HI_IPL, R16
	CALL_PAL $PALswpipl
	RET

TEXT	spllo(SB), $0
	MOVQ	R31, R16
	CALL_PAL $PALswpipl
	RET

TEXT	splx(SB), $0
	MOVL	R26, 4(R(MACH))	/* save PC in m->splpc */

TEXT splxpc(SB), $0				/* for iunlock */
	MOVQ	R0, R16
	CALL_PAL $PALswpipl
	RET

TEXT	spldone(SB), $0
	RET

TEXT	islo(SB), $0
	CALL_PAL $PALrdps
	AND		$IPL, R0
	XOR		$IPL, R0
	RET

TEXT	mb(SB), $-8
	MB
	RET

TEXT	icflush(SB), $-8
	CALL_PAL $PALimb
	RET

TEXT	tlbflush(SB), $-8
	MOVQ	R0, R16
	MOVL	4(FP), R17
	CALL_PAL $PALtbi
	RET

TEXT	swpctx(SB), $-8
	MOVQ	R0, R16
	AND		$0x7FFFFFFF, R16		/* make address physical */
	CALL_PAL $PALswpctx
	RET

TEXT	wrent(SB), $-8
	MOVQ	R0, R17
	MOVL	4(FP), R16
	CALL_PAL $PALwrent
	RET

TEXT	wrvptptr(SB), $-8
	MOVQ	R0, R16
	CALL_PAL	$PALwrvptptr
	RET

TEXT	cserve(SB), $-8
	MOVQ	R0, R16
	MOVL	4(FP), R17
	CALL_PAL	$PALcserve
	RET

TEXT	setlabel(SB), $-8

	MOVL	R30, 0(R0)
	MOVL	R26, 4(R0)
	MOVQ	$0, R0
	RET

TEXT	gotolabel(SB), $-8

	MOVL	0(R0), R30
	MOVL	4(R0), R26
	MOVQ	$1, R0
	RET

TEXT	tas(SB), $-8
	MOVQ	R0, R1			/* l */
tas1:
	MOVLL	(R1), R0		/* l->key */
	BNE	R0, tas2
	MOVQ	$1, R2
	MOVLC	R2, (R1)		/* l->key = 1 */
	BEQ	R2, tas1		/* write failed, try again? */
tas2:
	RET

TEXT	getcallerpc(SB), $-8
	MOVL	0(SP), R0
	RET

TEXT	fpenab(SB), $-8
	MOVQ	R0, R16
	CALL_PAL $PALwrfen
	RET

/*
 *	Exception handlers.  The stack frame looks like this:
 *
 *	R30+0:	(unused) link reg storage (R26) (32 bits)
 *	R30+4:	padding for alignment (32 bits)
 *	R30+8:	trap()'s first arg storage (R0) (32 bits -- type Ureg*)
 *	R30+12:	padding for alignment (32 bits)
 *	R30+16:	first 31 fields of Ureg, saved here (31*64 bits)
 *	R30+264:	other 6 fields of Ureg, saved by PALcode (6*64 bits)
 *	R30+312:	previous value of KSP before trap
 */

TEXT	arith(SB), $-8
	SUBQ	$(4*BY2WD+31*BY2V), R30
	MOVQ	R0, (4*BY2WD+4*BY2V)(R30)
	MOVQ	$1, R0
	JMP		trapcommon

TEXT	illegal0(SB), $-8
	SUBQ	$(4*BY2WD+31*BY2V), R30
	MOVQ	R0, (4*BY2WD+4*BY2V)(R30)
	MOVQ	$2, R0
	JMP		trapcommon

TEXT	fault0(SB), $-8
	SUBQ	$(4*BY2WD+31*BY2V), R30
	MOVQ	R0, (4*BY2WD+4*BY2V)(R30)
	MOVQ	$4, R0
	JMP		trapcommon

TEXT	unaligned(SB), $-8
	SUBQ	$(4*BY2WD+31*BY2V), R30
	MOVQ	R0, (4*BY2WD+4*BY2V)(R30)
	MOVQ	$6, R0
	JMP		trapcommon

TEXT	intr0(SB), $-8
	SUBQ	$(4*BY2WD+31*BY2V), R30
	MOVQ	R0, (4*BY2WD+4*BY2V)(R30)
	MOVQ	$3, R0

trapcommon:
	MOVQ	R0, (4*BY2WD+0*BY2V)(R30)
	MOVQ	R16, (4*BY2WD+1*BY2V)(R30)
	MOVQ	R17, (4*BY2WD+2*BY2V)(R30)
	MOVQ	R18, (4*BY2WD+3*BY2V)(R30)

	/* R0 already saved, (4*BY2WD+4*BY2V)(R30) */
	MOVQ	R1, (4*BY2WD+5*BY2V)(R30)
	MOVQ	R2, (4*BY2WD+6*BY2V)(R30)
	MOVQ	R3, (4*BY2WD+7*BY2V)(R30)
	MOVQ	R4, (4*BY2WD+8*BY2V)(R30)
	MOVQ	R5, (4*BY2WD+9*BY2V)(R30)
	MOVQ	R6, (4*BY2WD+10*BY2V)(R30)
	MOVQ	R7, (4*BY2WD+11*BY2V)(R30)
	MOVQ	R8, (4*BY2WD+12*BY2V)(R30)
	MOVQ	R9, (4*BY2WD+13*BY2V)(R30)
	MOVQ	R10, (4*BY2WD+14*BY2V)(R30)
	MOVQ	R11, (4*BY2WD+15*BY2V)(R30)
	MOVQ	R12, (4*BY2WD+16*BY2V)(R30)
	MOVQ	R13, (4*BY2WD+17*BY2V)(R30)
	MOVQ	R14, (4*BY2WD+18*BY2V)(R30)
	MOVQ	R15, (4*BY2WD+19*BY2V)(R30)
	MOVQ	R19, (4*BY2WD+20*BY2V)(R30)
	MOVQ	R20, (4*BY2WD+21*BY2V)(R30)
	MOVQ	R21, (4*BY2WD+22*BY2V)(R30)
	MOVQ	R22, (4*BY2WD+23*BY2V)(R30)
	MOVQ	R23, (4*BY2WD+24*BY2V)(R30)
	MOVQ	R24, (4*BY2WD+25*BY2V)(R30)
	MOVQ	R25, (4*BY2WD+26*BY2V)(R30)
	MOVQ	R26, (4*BY2WD+27*BY2V)(R30)
	MOVQ	R27, (4*BY2WD+28*BY2V)(R30)
	MOVQ	R28, (4*BY2WD+29*BY2V)(R30)

	MOVQ	$HI_IPL, R16
	CALL_PAL $PALswpipl

	CALL_PAL	$PALrdusp
	MOVQ	R0, (4*BY2WD+30*BY2V)(R30)		/* save USP */

	MOVQ	$mach0(SB), R(MACH)
	MOVQ	$(4*BY2WD)(R30), R0
	JSR		trap(SB)
trapret:
	MOVQ	(4*BY2WD+30*BY2V)(R30), R16	/* USP */
	CALL_PAL	$PALwrusp			/* ... */
	MOVQ	(4*BY2WD+4*BY2V)(R30), R0
	MOVQ	(4*BY2WD+5*BY2V)(R30), R1
	MOVQ	(4*BY2WD+6*BY2V)(R30), R2
	MOVQ	(4*BY2WD+7*BY2V)(R30), R3
	MOVQ	(4*BY2WD+8*BY2V)(R30), R4
	MOVQ	(4*BY2WD+9*BY2V)(R30), R5
	MOVQ	(4*BY2WD+10*BY2V)(R30), R6
	MOVQ	(4*BY2WD+11*BY2V)(R30), R7
	MOVQ	(4*BY2WD+12*BY2V)(R30), R8
	MOVQ	(4*BY2WD+13*BY2V)(R30), R9
	MOVQ	(4*BY2WD+14*BY2V)(R30), R10
	MOVQ	(4*BY2WD+15*BY2V)(R30), R11
	MOVQ	(4*BY2WD+16*BY2V)(R30), R12
	MOVQ	(4*BY2WD+17*BY2V)(R30), R13
	MOVQ	(4*BY2WD+18*BY2V)(R30), R14
	MOVQ	(4*BY2WD+19*BY2V)(R30), R15
	MOVQ	(4*BY2WD+20*BY2V)(R30), R19
	MOVQ	(4*BY2WD+21*BY2V)(R30), R20
	MOVQ	(4*BY2WD+22*BY2V)(R30), R21
	MOVQ	(4*BY2WD+23*BY2V)(R30), R22
	MOVQ	(4*BY2WD+24*BY2V)(R30), R23
	MOVQ	(4*BY2WD+25*BY2V)(R30), R24
	MOVQ	(4*BY2WD+26*BY2V)(R30), R25
	MOVQ	(4*BY2WD+27*BY2V)(R30), R26
	MOVQ	(4*BY2WD+28*BY2V)(R30), R27
	MOVQ	(4*BY2WD+29*BY2V)(R30), R28
	/* USP already restored from (4*BY2WD+30*BY2V)(R30) */
	ADDQ	$(4*BY2WD+31*BY2V), R30
	CALL_PAL	$PALrti

TEXT	forkret(SB), $0
	MOVQ	R31, R0			/* Fake out system call return */
	JMP	systrapret

TEXT	syscall0(SB), $-8
	SUBQ	$(4*BY2WD+31*BY2V), R30
	MOVQ	R0, (4*BY2WD+4*BY2V)(R30)	/* save scallnr in R0 */
	MOVQ	$HI_IPL, R16
	CALL_PAL $PALswpipl
	MOVQ	$mach0(SB), R(MACH)
	CALL_PAL	$PALrdusp
	MOVQ	R0, (4*BY2WD+30*BY2V)(R30)		/* save USP */
	MOVQ	R26, (4*BY2WD+27*BY2V)(R30)	/* save last return address */
	MOVQ	$(4*BY2WD)(R30), R0			/* pass address of Ureg */
	JSR		syscall(SB)
systrapret:
	MOVQ	(4*BY2WD+30*BY2V)(R30), R16	/* USP */
	CALL_PAL	$PALwrusp					/* consider doing this in execregs... */
	MOVQ	(4*BY2WD+27*BY2V)(R30), R26	/* restore last return address */
	ADDQ	$(4*BY2WD+31*BY2V), R30
	CALL_PAL	$PALretsys

/*
 * Take first processor into user mode
 * 	- argument is stack pointer to user
 */

TEXT	touser(SB), $-8
	MOVQ	R0, R16
	CALL_PAL	$PALwrusp					/* set USP to value passed */
	SUBQ	$(6*BY2V), R30					/* create frame for retsys */
	MOVQ	$(UTZERO+32), R26				/* header appears in text */
	MOVQ	R26, (1*BY2V)(R30)				/* PC -- only reg that matters */
	CALL_PAL	$PALretsys

TEXT	rfnote(SB), $0
	SUBL		$(2*BY2WD), R0, SP
	JMP		trapret

TEXT	savefpregs(SB), $-8
	MOVT	F0, 0x00(R0)
	MOVT	F1, 0x08(R0)
	MOVT	F2, 0x10(R0)
	MOVT	F3, 0x18(R0)
	MOVT	F4, 0x20(R0)
	MOVT	F5, 0x28(R0)
	MOVT	F6, 0x30(R0)
	MOVT	F7, 0x38(R0)
	MOVT	F8, 0x40(R0)
	MOVT	F9, 0x48(R0)
	MOVT	F10, 0x50(R0)
	MOVT	F11, 0x58(R0)
	MOVT	F12, 0x60(R0)
	MOVT	F13, 0x68(R0)
	MOVT	F14, 0x70(R0)
	MOVT	F15, 0x78(R0)
	MOVT	F16, 0x80(R0)
	MOVT	F17, 0x88(R0)
	MOVT	F18, 0x90(R0)
	MOVT	F19, 0x98(R0)
	MOVT	F20, 0xA0(R0)
	MOVT	F21, 0xA8(R0)
	MOVT	F22, 0xB0(R0)
	MOVT	F23, 0xB8(R0)
	MOVT	F24, 0xC0(R0)
	MOVT	F25, 0xC8(R0)
	MOVT	F26, 0xD0(R0)
	MOVT	F27, 0xD8(R0)
	MOVT	F28, 0xE0(R0)
	MOVT	F29, 0xE8(R0)
	MOVT	F30, 0xF0(R0)
	MOVT	F31, 0xF8(R0)
	MOVT	FPCR, F0
	MOVT	F0, 0x100(R0)
	RET

TEXT	restfpregs(SB), $-8
	MOVT	0x100(R0), F0
	MOVT	F0, FPCR
	MOVT	0x00(R0), F0
	MOVT	0x08(R0), F1
	MOVT	0x10(R0), F2
	MOVT	0x18(R0), F3
	MOVT	0x20(R0), F4
	MOVT	0x28(R0), F5
	MOVT	0x30(R0), F6
	MOVT	0x38(R0), F7
	MOVT	0x40(R0), F8
	MOVT	0x48(R0), F9
	MOVT	0x50(R0), F10
	MOVT	0x58(R0), F11
	MOVT	0x60(R0), F12
	MOVT	0x68(R0), F13
	MOVT	0x70(R0), F14
	MOVT	0x78(R0), F15
	MOVT	0x80(R0), F16
	MOVT	0x88(R0), F17
	MOVT	0x90(R0), F18
	MOVT	0x98(R0), F19
	MOVT	0xA0(R0), F20
	MOVT	0xA8(R0), F21
	MOVT	0xB0(R0), F22
	MOVT	0xB8(R0), F23
	MOVT	0xC0(R0), F24
	MOVT	0xC8(R0), F25
	MOVT	0xD0(R0), F26
	MOVT	0xD8(R0), F27
	MOVT	0xE0(R0), F28
	MOVT	0xE8(R0), F29
	MOVT	0xF0(R0), F30
	MOVT	0xF8(R0), F31
	RET

A alphapc/main.c => alphapc/main.c +401 -0
@@ 0,0 1,401 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"init.h"
#include	"pool.h"
#include	"/sys/src/boot/alphapc/conf.h"
#include	"axp.h"

char argbuf[128];	/* arguments passed to initcode and /boot */

Hwrpb *hwrpb;
Bootconf *bootconf;
Conf	conf;
FPsave	initfp;

void
main(void)
{
	hwrpb = (Hwrpb*)0x10000000;
	hwrpb = (Hwrpb*)(KZERO|hwrpb->phys);
	arginit();
	machinit();
	clockinit();
	confinit();
	archinit();
	savefpregs(&initfp);
	mmuinit();
	xinit();
	printinit();
	if (arch->coreinit)
		arch->coreinit();
	trapinit();

	/* console */
	screeninit();
	ns16552install();
	ns16552special(0, 9600, 0, &printq, kbdcr2nl);
	kbdinit();

	cpuidprint();
	if (arch->corehello)
		arch->corehello();

#ifdef	NEVER
	percpu = hwrpb + (hwrpb[40]>>2);
//	percpu[32] |= 2;			/* restart capable */
	percpu[32] &= ~1;			/* boot in progress - not */
//	percpu[32] |= (3<<16);		/* warm boot requested */
//	percpu[32] |= (2<<16);		/* cold boot requested */
//	percpu[32] |= (4<<16);		/* stay halted */
	percpu[32] |= (0<<16);		/* default action */
#endif

	pageinit();
	procinit0();
	initseg();
	links();
	chandevreset();
	swapinit();
	userinit();
	schedinit();
}

/*
 *  initialize a processor's mach structure.  each processor does this
 *  for itself.
 */
void
machinit(void)
{
	int n;

	icflush();
	n = m->machno;
	memset(m, 0, sizeof(Mach));
	m->machno = n;

	active.exiting = 0;
	active.machs = 1;
}

void
init0(void)
{
	char buf[2*NAMELEN];

	spllo();

	/*
	 * These are o.k. because rootinit is null.
	 * Then early kproc's will have a root and dot.
	 */
	up->slash = namec("#/", Atodir, 0, 0);
	up->dot = cclone(up->slash, 0);

	chandevinit();

	if(!waserror()){
		ksetenv("cputype", "alpha");
		sprint(buf, "alpha %s axp", conffile);
		ksetenv("terminal", buf);
		ksetenv("sysname", sysname);
		poperror();
	}

	kproc("alarm", alarmkproc, 0);
	touser((uchar*)(USTKTOP - sizeof(argbuf)));
}

void
userinit(void)
{
	Proc *p;
	Segment *s;
	KMap *k;
	char **av;
	Page *pg;

	p = newproc();
	p->pgrp = newpgrp();
	p->egrp = smalloc(sizeof(Egrp));
	p->egrp->ref = 1;
	p->fgrp = dupfgrp(nil);
	p->rgrp = newrgrp();
	p->procmode = 0640;

	strcpy(p->text, "*init*");
	strcpy(p->user, eve);

	p->fpstate = FPinit;
	p->fpsave.fpstatus = initfp.fpstatus;
	fpenab(0);

	/*
	 * Kernel Stack
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = (ulong)p->kstack+KSTACK-(1+MAXSYSARG)*BY2WD;
	/*
	 * User Stack, pass input arguments to boot process
	 */
	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
	p->seg[SSEG] = s;
	pg = newpage(1, 0, USTKTOP-BY2PG);
	segpage(s, pg);
	k = kmap(pg);
	for(av = (char**)argbuf; *av; av++)
		*av += (USTKTOP - sizeof(argbuf)) - (ulong)argbuf;

	memmove((uchar*)VA(k) + BY2PG - sizeof(argbuf), argbuf, sizeof argbuf);
	kunmap(k);

	/*
	 * Text
	 */
	s = newseg(SG_TEXT, UTZERO, 1);
	s->flushme++;
	p->seg[TSEG] = s;
	pg = newpage(1, 0, UTZERO);
	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
	segpage(s, pg);
	k = kmap(s->map[0]->pages[0]);
	memmove((uchar*)VA(k), initcode, sizeof initcode);
	kunmap(k);

	ready(p);
}

void
exit(int)
{
	canlock(&active);
	active.machs &= ~(1<<m->machno);
	active.exiting = 1;
	unlock(&active);

	spllo();
	print("cpu %d exiting\n", m->machno);
	do
		delay(100);
	while(consactive());

	splhi();
	delay(1000);	/* give serial fifo time to finish flushing */
	if (arch->coredetach)
		arch->coredetach();
	firmware();
}

void
confinit(void)
{
	long mbytes;
	int mul;
	ulong ktop;

	mbytes = 50;	/* BUG FIXME */

	/*
	 * This split of memory into 2 banks fools the allocator into
	 * allocating low memory pages from bank 0 for the ethernet since
	 * it has only a 24bit address counter.
	 * Note that the rom monitor has the bottom 2 megs
	 */
	conf.npage0 = (8*1024*1024)/BY2PG;
	conf.base0 = 0;

	conf.npage1 = (mbytes-8)*1024/8;
	conf.base1 = 8*1024*1024;

	conf.npage = conf.npage0+conf.npage1;
	conf.upages = (conf.npage*70)/100;

	ktop = PGROUND((ulong)end);
	conf.ptebase = ktop;
	ktop = PADDR(ktop);
	ktop += ((mbytes+7)/8 + 2)*BY2PG;		/* space for kernel ptes */
	conf.npage0 -= ktop/BY2PG;
	conf.base0 += ktop;
	conf.mbytes = mbytes;
	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;

	mul = (mbytes+11)/12;
	if(mul > 2)
		mul = 2;
	conf.nmach = 1;
	conf.nproc = 20 + 50*mul;
	conf.nswap = conf.nproc*80;
	conf.nimage = 50;
	conf.copymode = 0;			/* copy on write */

	if(cpuserver)
		conf.nproc = 500;
/*	else
		conf.monitor = 1;	/* BUG */
}

void
lights(int l)
{
	USED(l);
}
char *sp;

char *
pusharg(char *p)
{
	int n;

	n = strlen(p)+1;
	sp -= n;
	memmove(sp, p, n);
	return sp;
}

void
arginit(void)
{
	char **av;

	av = (char**)argbuf;
	sp = argbuf + sizeof(argbuf);
	*av++ = pusharg("boot");
	*av = 0;
}

/*
 * Q&D fake-out of plan9.ini until we resolve the booting issues
 */
char *confname[] =
{
	"ether0",
	"scsi0",

};

char *confval[] =
{
	"type=21140",
	"type=aic7xxx",
};

int	nconf = nelem(confname);

char *
getconf(char *name)
{
	int n;

	for(n = 0; n < nconf; n++){
		if(cistrcmp(confname[n], name) == 0)
			return confval[n];
	}
	return 0;
}

int
isaconfig(char *class, int ctlrno, ISAConf *isa)
{
	char cc[NAMELEN], *p, *q, *r;
	int n;

	sprint(cc, "%s%d", class, ctlrno);
	for(n = 0; n < nconf; n++){
		if(cistrncmp(confname[n], cc, NAMELEN))
			continue;
		isa->nopt = 0;
		p = confval[n];
		while(*p){
			while(*p == ' ' || *p == '\t')
				p++;
			if(*p == '\0')
				break;
			if(cistrncmp(p, "type=", 5) == 0){
				p += 5;
				for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){
					if(*p == '\0' || *p == ' ' || *p == '\t')
						break;
					*q = *p++;
				}
				*q = '\0';
			}
			else if(cistrncmp(p, "port=", 5) == 0)
				isa->port = strtoul(p+5, &p, 0);
			else if(cistrncmp(p, "irq=", 4) == 0)
				isa->irq = strtoul(p+4, &p, 0);
			else if(cistrncmp(p, "dma=", 4) == 0)
				isa->dma = strtoul(p+4, &p, 0);
			else if(cistrncmp(p, "mem=", 4) == 0)
				isa->mem = strtoul(p+4, &p, 0);
			else if(cistrncmp(p, "size=", 5) == 0)
				isa->size = strtoul(p+5, &p, 0);
			else if(cistrncmp(p, "freq=", 5) == 0)
				isa->freq = strtoul(p+5, &p, 0);
			else if(isa->nopt < NISAOPT){
				r = isa->opt[isa->nopt];
				while(*p && *p != ' ' && *p != '\t'){
					*r++ = *p++;
					if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1)
						break;
				}
				*r = '\0';
				isa->nopt++;
			}
			while(*p && *p != ' ' && *p != '\t')
				p++;
		}
		return 1;
	}
	return 0;
}

int
cistrcmp(char *a, char *b)
{
	int ac, bc;

	for(;;){
		ac = *a++;
		bc = *b++;
	
		if(ac >= 'A' && ac <= 'Z')
			ac = 'a' + (ac - 'A');
		if(bc >= 'A' && bc <= 'Z')
			bc = 'a' + (bc - 'A');
		ac -= bc;
		if(ac)
			return ac;
		if(bc == 0)
			break;
	}
	return 0;
}

int
cistrncmp(char *a, char *b, int n)
{
	unsigned ac, bc;

	while(n > 0){
		ac = *a++;
		bc = *b++;
		n--;

		if(ac >= 'A' && ac <= 'Z')
			ac = 'a' + (ac - 'A');
		if(bc >= 'A' && bc <= 'Z')
			bc = 'a' + (bc - 'A');

		ac -= bc;
		if(ac)
			return ac;
		if(bc == 0)
			break;
	}

	return 0;
}

A alphapc/mem.h => alphapc/mem.h +134 -0
@@ 0,0 1,134 @@
/*
 * Memory and machine-specific definitions.  Used in C and assembler.
 */

/*
 * Sizes
 */

#define	BI2BY		8			/* bits per byte */
#define	BI2WD		32			/* bits per word */
#define	BY2WD		4			/* bytes per word */
#define 	BY2V		8			/* bytes per vlong */
#define	BY2PG		8192		/* bytes per page */
#define	WD2PG		(BY2PG/BY2WD)	/* words per page */
#define	PGSHIFT		13			/* log(BY2PG) */
#define 	ROUND(s, sz)	(((s)+(sz-1))&~(sz-1))
#define 	PGROUND(s)	ROUND(s, BY2PG)

#define	BY2PTE		8			/* bytes per pte entry */
#define	PTE2PG		(BY2PG/BY2PTE)	/* pte entries per page */

#define	MAXMACH		1			/* max # cpus system can run */
#define	KSTACK		4096			/* Size of kernel stack */

/*
 * Time
 */
#define	HZ		100			/* clock frequency */
#define	MS2HZ	(1000/HZ)
#define	TK2SEC(t)	((t)/HZ)		/* ticks to seconds */
#define	TK2MS(t)	((t)*MS2HZ)		/* ticks to milliseconds */
#define	MS2TK(t)	((t)/MS2HZ)		/* milliseconds to ticks */

/*
 * Magic registers
 */

#define	MACH	15		/* R15 is m-> */
#define	USER		14		/* R14 is up-> */


/*
 * Fundamental addresses
 */
/* XXX MACHADDR, MACHP(n) */

/*
 * MMU
 *
 * A PTE is 64 bits, but a ulong is 32!  Hence we encode
 * the PTEs specially for fault.c, and decode them in putmmu().
 * This means that we can only map the first 2G of physical
 * space via putmmu() - ie only physical memory, not devices.
 */

#define	PTEVALID		0x3301
#define	PTEKVALID	0x1101
#define	PTEASM		0x0010
#define	PTEGH(s)		((s)<<5)
#define	PTEWRITE		0
#define	PTERONLY	0x4
#define	PTEUNCACHED	0
#define	PPN(n)		(((n)>>PGSHIFT)<<14)
#define	FIXPTE(x)		((((uvlong)(x)>>14)<<32)|((x) & 0x3fff))
#define	PTEPFN(pa)	(((uvlong)(pa)>>PGSHIFT)<<32)
#define	NCOLOR		1
#define	getpgcolor(a)	0

#define	PTEMAPMEM	(1024*1024)	
#define	PTEPERTAB	(PTEMAPMEM/BY2PG)
#define	SEGMAPSIZE	512
#define SSEGMAPSIZE	16

/*
 * Address spaces
 */

#define	UZERO	0			/* base of user address space */
#define	UTZERO	(UZERO+BY2PG)		/* first address in user text */
#define	USTKTOP	(TSTKTOP-TSTKSIZ*BY2PG)	/* byte just beyond user stack */
#define	TSTKTOP	KZERO	/* top of temporary stack */
#define	TSTKSIZ 100
#define	KZERO	0x80000000	/* base of kernel address space */
#define	KTZERO	(KZERO+0x400000)		/* first address in kernel text */
#define	USTKSIZE	(4*1024*1024)	/* size of user stack */

/*
 * Palcode instructions a la OSF/1
 */
#define	PALbpt		0x80
#define	PALbugchk	0x81
#define	PALcallsys	0x83
#define	PALimb		0x86
#define	PALgentrap	0xaa
#define	PALrdunique	0x9e
#define	PALwrunique	0x9f

#define	PALhalt		0x00
#define	PALdraina	0x02
#define	PALcserve	0x09
#define	PALrdps		0x36
#define	PALrdusp	0x3a
#define	PALrdval	0x32
#define	PALretsys	0x3d
#define	PALrti		0x3f
#define	PALswpctx	0x30
#define	PALswpipl	0x35
#define	PALtbi		0x33
#define	PALwhami	0x3c
#define	PALwrent	0x34
#define	PALwrfen	0x2b
#define	PALwrkgp	0x37
#define	PALwrusp	0x38
#define	PALwrval	0x31
#define	PALwrvptptr	0x2d

/*
 * Plus some useful VMS ones (needed at early boot time)
 */
#define	PALmfpr_pcbb	0x12
#define	PALmfpr_ptbr	0x15
#define	PALmfpr_vptb	0x29
#define	PALldqp		0x03
#define	PALstqp		0x04
#define	PALswppal	0x0a

/*
 * Processor Status (as returned by rdps)
 */
#define	UMODE	0x8
#define	IPL		0x7


#define isphys(x) (((ulong)x&KZERO)!=0)

A alphapc/mmu.c => alphapc/mmu.c +245 -0
@@ 0,0 1,245 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"/sys/src/boot/alphapc/conf.h"

static uvlong	origlvl1;	/* physical address */
static uvlong	klvl2;	/* physical, as created by boot loader */
static uchar	*nextio;	/* next virtual address to be allocated by kmapv */
extern Bootconf *bootconf;

#define LVL2OFF(v)	((((long)(v))>>(2*PGSHIFT-3))&(PTE2PG-1))
#define LVL3OFF(v)	((((long)(v))>>(PGSHIFT))&(PTE2PG-1))

static void
setptb(ulong pa)
{
	m->ptbr = (uvlong)pa>>PGSHIFT;
	swpctx(m);
}

void
mmuinit(void)
{
	uvlong *plvl2;

	/* set PCB to new one in mach structure before stomping on old one */
	m->usp = 0;
	m->fen = 1;
	m->ptbr = bootconf->pcb->ptbr;
	origlvl1 = (m->ptbr << PGSHIFT);
	setpcb(m);

	plvl2 = (uvlong*) (KZERO|origlvl1|(BY2PG-8));
	klvl2 = (*plvl2 >> 32)<<PGSHIFT;

	nextio = (uchar*) (KZERO|bootconf->maxphys);
}

/*
 * Called splhi, not in Running state
 */
void
mmuswitch(Proc *p)
{
	Page *pg;
	uvlong *lvl2;

	if(p->newtlb){
		/*
		 *  newtlb set means that they are inconsistent
		 *  with the segment.c data structures.
		 *
		 *  bin the current 3rd level page tables and
		 *  the pointers to them in the 2nd level page.
		 *  pg->daddr is used by putmmu to save the offset into
		 *  the 2nd level page.
		 */
		if(p->mmutop && p->mmuused){
			lvl2 = (uvlong*)p->mmulvl2->va;
			for(pg = p->mmuused; pg->next; pg = pg->next)
				lvl2[pg->daddr] = 0;
			lvl2[pg->daddr] = 0;
			pg->next = p->mmufree;
			p->mmufree = p->mmuused;
			p->mmuused = 0;
		}
		p->newtlb = 0;
	}

	/* tell processor about new page table and flush cached entries */
	if(p->mmutop == 0)
		setptb(origlvl1);
	else
		setptb(p->mmutop->pa);
	tlbflush(-1, 0);
	icflush();
}

/*
 *  give all page table pages back to the free pool.  This is called in sched()
 *  with palloc locked.
 */
void
mmurelease(Proc *p)
{
	Page *pg;
	Page *next;

	if(canlock(&palloc))
		panic("mmurelease");

	/* point to protoype page map */
	setptb(origlvl1);
	icflush();

	/* give away page table pages */
	for(pg = p->mmuused; pg; pg = next){
		next = pg->next;
		pg->next = p->mmufree;
		p->mmufree = pg;
	}
	p->mmuused = 0;
	if(p->mmutop) {
		p->mmutop->next = p->mmufree;
		p->mmufree = p->mmutop;
		p->mmutop = 0;
	}
	if(p->mmulvl2) {
		p->mmulvl2->next = p->mmufree;
		p->mmufree = p->mmulvl2;
		p->mmulvl2 = 0;
	}
	for(pg = p->mmufree; pg; pg = next){
		next = pg->next;
		if(--pg->ref)
			panic("mmurelease: pg->ref %d\n", pg->ref);
		pagechainhead(pg);
	}
	if(p->mmufree && palloc.r.p)
		wakeup(&palloc.r);
	p->mmufree = 0;
}

void
mmunewtop(void)
{
	Page *top, *lvl2;
	uvlong *ppte;

	top = newpage(1, 0, 0);
	top->va = VA(kmap(top));
	lvl2 = newpage(1, 0, 0);
	lvl2->va = VA(kmap(lvl2));

	ppte = (uvlong *)top->va;
	ppte[0] = PTEPFN(lvl2->pa) | PTEKVALID;
	ppte[PTE2PG-2] = PTEPFN(top->pa) | PTEKVALID;
	ppte[PTE2PG-1] = PTEPFN(klvl2) | PTEKVALID;

	up->mmutop = top;
	up->mmulvl2 = lvl2;
	setptb(top->pa);
	tlbflush(-1, 0);
	icflush();
}

void
putmmu(ulong va, ulong pa, Page *pg)
{
	int lvl2off;
	uvlong *lvl2, *pt;
	int s;

	if(up->mmutop == 0)
		mmunewtop();

	lvl2 = (uvlong*)up->mmulvl2->va;
	lvl2off = LVL2OFF(va);

	/*
	 *  if bottom level page table missing, allocate one 
	 *  and point the top level page at it.
	 */
	s = splhi();
	if(lvl2[lvl2off] == 0){
		if(up->mmufree == 0){
			spllo();
			pg = newpage(1, 0, 0);
			pg->va = VA(kmap(pg));
			splhi();
		} else {
			pg = up->mmufree;
			up->mmufree = pg->next;
			memset((void*)pg->va, 0, BY2PG);
		}
		lvl2[lvl2off] = PTEPFN(pg->pa) | PTEVALID;
		pg->daddr = lvl2off;
		pg->next = up->mmuused;
		up->mmuused = pg;
	}

	/*
	 *  put in new mmu entry
	 */
	pt = (uvlong*)(((lvl2[lvl2off] >> 32)<<PGSHIFT)|KZERO);
	pt[LVL3OFF(va)] = FIXPTE(pa);

	/* flush cached mmu entries */
	tlbflush(3, va);
	icflush();
	splx(s);
}

void *
kmapv(uvlong pa, int size)
{
	void *va, *new;
	int lvl2off, i, npage, offset;
	uvlong *lvl2, *pt;

	offset = pa&(BY2PG-1);
	npage = ((size+offset+BY2PG-1)>>PGSHIFT);

	va = nextio+offset;
	lvl2 = (uvlong*)(KZERO|klvl2);
	for (i = 0; i < npage; i++) {
		lvl2off = LVL2OFF(nextio);
		if (lvl2[lvl2off] == 0) {
			new = xspanalloc(BY2PG, BY2PG, 0);
			memset(new, 0, BY2PG);
			lvl2[lvl2off] = PTEPFN(PADDR(new)) | PTEKVALID | PTEASM;
		}
		pt = (uvlong*)(((lvl2[lvl2off] >> 32)<<PGSHIFT)|KZERO);
		pt[LVL3OFF(nextio)] = PTEPFN(pa) | PTEKVALID | PTEASM;
		nextio += BY2PG;
		pa += BY2PG;
	}
	return va;
}

void
flushmmu(void)
{
	int s;

	s = splhi();
	up->newtlb = 1;
	mmuswitch(up);
	splx(s);

}

ulong
upamalloc(...)
{
	panic("upamalloc");
}

void
upafree(...)
{
	panic("upafree");
}

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

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

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

/*
 *  setup a serial mouse
 */
static void
serialmouse(int port, char *type, int setspeed)
{
	if(mousetype == Mouseserial)
		error(Emouseset);

	if(port >= 3 || port < 0)
		error(Ebadarg);

	/* set up /dev/eia? as the mouse */
	if(setspeed)
		setspeed = 1200;
	if(type && *type == 'M')
		ns16552special(port, setspeed, 0, 0, m3mouseputc);
	else
		ns16552special(port, setspeed, 0, 0, mouseputc);
	mousetype = Mouseserial;
}

/*
 *  ps/2 mouse message is three bytes
 *
 *	byte 0 -	0 0 SDY SDX 1 M R L
 *	byte 1 -	DX
 *	byte 2 -	DY
 *
 *  shift & left button is the same as middle button
 */
static void
ps2mouseputc(int c, int shift)
{
	static short msg[3];
	static int nb;
	static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 };
	int buttons, dx, dy;

	/* 
	 *  check byte 0 for consistency
	 */
	if(nb==0 && (c&0xc8)!=0x08)
		return;

	msg[nb] = c;
	if(++nb == 3){
		nb = 0;
		if(msg[0] & 0x10)
			msg[1] |= 0xFF00;
		if(msg[0] & 0x20)
			msg[2] |= 0xFF00;

		buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
		dx = msg[1];
		dy = -msg[2];
		mousetrack(buttons, dx, dy);
	}
	return;
}

/*
 *  set up a ps2 mouse
 */
static void
ps2mouse(void)
{
	if(mousetype == MousePS2)
		return;

	i8042auxenable(ps2mouseputc);
	/* make mouse streaming, enabled */
	i8042auxcmd(0xEA);
	i8042auxcmd(0xF4);

	mousetype = MousePS2;
}

static int intellimouse;
static int resolution;
static int accelerated;

static void
setaccelerated(int x)
{
	accelerated = x;
	switch(mousetype){
	case MousePS2:
		i8042auxcmd(0xE7);
		break;
	default:
		mouseaccelerate(x);
		break;
	}
}

static void
setlinear(void)
{
	accelerated = 0;
	switch(mousetype){
	case MousePS2:
		i8042auxcmd(0xE6);
		break;
	default:
		mouseaccelerate(0);
		break;
	}
}

static void
setres(int n)
{
	resolution = n;
	switch(mousetype){
	case MousePS2:
		i8042auxcmd(0xE8);
		i8042auxcmd(n);
		break;
	}
}

static void
setintellimouse(void)
{
	intellimouse = 1;
	switch(mousetype){
	case MousePS2:
		i8042auxcmd(0xF3);	/* set sample */
		i8042auxcmd(0xC8);
		i8042auxcmd(0xF3);	/* set sample */
		i8042auxcmd(0x64);
		i8042auxcmd(0xF3);	/* set sample */
		i8042auxcmd(0x50);
		break;
	}
}

static void
resetmouse(void)
{
	switch(mousetype){
	case MousePS2:
		i8042auxcmd(0xF6);
		i8042auxcmd(0xEA);	/* streaming */
		i8042auxcmd(0xE8);	/* set resolution */
		i8042auxcmd(3);
		i8042auxcmd(0xF4);	/* enabled */
		break;
	}
}

void
mousectl(char* field[], int n)
{
	if(strncmp(field[0], "serial", 6) == 0){
		switch(n){
		case 1:
			serialmouse(atoi(field[0]+6), 0, 1);
			break;
		case 2:
			serialmouse(atoi(field[1]), 0, 0);
			break;
		case 3:
		default:
			serialmouse(atoi(field[1]), field[2], 0);
			break;
		}
	} else if(strcmp(field[0], "ps2") == 0){
		ps2mouse();
	} else if(strcmp(field[0], "ps2intellimouse") == 0){
		ps2mouse();
		setintellimouse();
	} else if(strcmp(field[0], "accelerated") == 0){
		setaccelerated(n == 1 ? 1 : atoi(field[1]));
	} else if(strcmp(field[0], "linear") == 0){
		setlinear();
	} else if(strcmp(field[0], "res") == 0){
		if(n >= 2)
			n = atoi(field[1]);
		setres(n);
	} else if(strcmp(field[0], "reset") == 0){
		resetmouse();
		if(accelerated)
			setaccelerated(accelerated);
		if(resolution)
			setres(resolution);
		if(intellimouse)
			setintellimouse();
	} else if(strcmp(field[0], "intellimouse") == 0){
		setintellimouse();
	}
	else
		error(Ebadctl);
}

A alphapc/ns16552.h => alphapc/ns16552.h +60 -0
@@ 0,0 1,60 @@
#define uartwrreg(u,r,v)	outb((u)->port + (r), (u)->sticky[r] | (v))
#define uartrdreg(u,r)		inb((u)->port + (r))

#define uartpower(x, y)

/*
 *  handle an interrupt to a single uart
 */
static void
ns16552intrx(Ureg*, void* arg)
{
	ns16552intr((ulong)arg);
}

void
ns16552install(void)
{
	static int already;

	if(already)
		return;
	already = 1;

	ns16552setup(Uart0, UartFREQ, "eia0");
	intrenable(VectorUART0, ns16552intrx, (void*)0, BUSUNKNOWN);
	ns16552setup(Uart1, UartFREQ, "eia1");
	intrenable(VectorUART1, ns16552intrx, (void*)0, BUSUNKNOWN);
}

#define RD(r)	inb(Uart0+(r))
static void
ns16552iputc(char c)
{
	mb();
	while((RD(5) & (1<<5)) == 0)
		mb();
	outb(Uart0, c);
	mb();
	while((RD(5) & (1<<5)) == 0)
		mb();
}

int
iprint(char *fmt, ...)
{
	int n, i, s;
	char buf[512];
	va_list arg;

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

	s = splhi();
	for(i = 0; i < n; i++)
		ns16552iputc(buf[i]);
	splx(s);

	return n;
}

A alphapc/pci.c => alphapc/pci.c +351 -0
@@ 0,0 1,351 @@
/*
 * PCI support code.
 * To do:
 *	initialise bridge mappings if the PCI BIOS didn't.
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

enum {
	MaxFNO		= 7,
	MaxUBN		= 255,
};

static Lock pcicfglock;
static Lock pcicfginitlock;
static int pcicfgmode = -1;
static int pcimaxdno;
static Pcidev* pciroot;
static Pcidev* pcilist;
static Pcidev* pcitail;

static int pcicfgrw32(int, int, int, int);

static int
pciscan(int bno, Pcidev** list)
{
	ulong v;
	Pcidev *p, *head, *tail;
	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;

	maxubn = bno;
	head = nil;
	tail = nil;
	for(dno = 0; dno <= pcimaxdno; dno++){
		maxfno = 0;
		for(fno = 0; fno <= maxfno; fno++){
			/*
			 * For this possible device, form the bus+device+function
			 * triplet needed to address it and try to read the vendor
			 * and device ID. If successful, allocate a device struct
			 * and start to fill it in with some useful information from
			 * the device's configuration space.
			 */
			tbdf = MKBUS(BusPCI, bno, dno, fno);
			l = pcicfgrw32(tbdf, PciVID, 0, 1);
			if(l == 0xFFFFFFFF || l == 0)
				continue;
/* optional safety checks:
			if(l == pcicfgrw32(tbdf, PciPCR, 0, 1))
				continue;
			if(l != pcicfgrw32(tbdf, PciVID, 0, 1))
				continue;
			if(l == pcicfgrw32(tbdf, PciPCR, 0, 1))
				continue;
*/
			p = malloc(sizeof(*p));
			p->tbdf = tbdf;
			p->vid = l;
			p->did = l>>16;

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

			p->intl = pcicfgr8(p, PciINTL);
			p->ccru = pcicfgr16(p, PciCCRu);

			/*
			 * If the device is a multi-function device adjust the
			 * loop count so all possible functions are checked.
			 */
			hdt = pcicfgr8(p, PciHDT);
			if(hdt & 0x80)
				maxfno = MaxFNO;

			/*
			 * If appropriate, read the base address registers
			 * and work out the sizes.
			 */
			switch(p->ccru>>8){

			case 0x01:		/* mass storage controller */
			case 0x02:		/* network controller */
			case 0x03:		/* display controller */
			case 0x04:		/* multimedia device */
			case 0x07:		/* simple communication controllers */
			case 0x08:		/* base system peripherals */
			case 0x09:		/* input devices */
			case 0x0A:		/* docking stations */
			case 0x0B:		/* processors */
			case 0x0C:		/* serial bus controllers */
				if((hdt & 0x7F) != 0)
					break;
				rno = PciBAR0 - 4;
				for(i = 0; i < nelem(p->mem); i++){
					rno += 4;
					p->mem[i].bar = pcicfgr32(p, rno);
					pcicfgw32(p, rno, -1);
					v = pcicfgr32(p, rno);
					pcicfgw32(p, rno, p->mem[i].bar);
					p->mem[i].size = -(v & ~0xF);
				}
				break;

			case 0x00:
			case 0x05:		/* memory controller */
			case 0x06:		/* bridge device */
			default:
				break;
			}

			if(head != nil)
				tail->link = p;
			else
				head = p;
			tail = p;
		}
	}

	*list = head;
	for(p = head; p != nil; p = p->link){
		/*
		 * Find PCI-PCI bridges and recursively descend the tree.
		 */
		if(p->ccru != ((0x06<<8)|0x04))
			continue;

		/*
		 * If the secondary or subordinate bus number is not initialised
		 * try to do what the PCI BIOS should have done and fill in the
		 * numbers as the tree is descended. On the way down the subordinate
		 * bus number is set to the maximum as it's not known how many
		 * buses are behind this one; the final value is set on the way
		 * back up.
		 */
		sbn = pcicfgr8(p, PciSBN);
		ubn = pcicfgr8(p, PciUBN);
		if(sbn == 0 || ubn == 0){
			sbn = maxubn+1;
			/*
			 * Make sure memory, I/O and master enables are off,
			 * set the primary, secondary and subordinate bus numbers
			 * and clear the secondary status before attempting to
			 * scan the secondary bus.
			 *
			 * Initialisation of the bridge should be done here.
			 */
			pcicfgw32(p, PciPCR, 0xFFFF0000);
			l = (MaxUBN<<16)|(sbn<<8)|bno;
			pcicfgw32(p, PciPBN, l);
			pcicfgw16(p, PciSPSR, 0xFFFF);
			maxubn = pciscan(sbn, &p->bridge);
			l = (maxubn<<16)|(sbn<<8)|bno;
			pcicfgw32(p, PciPBN, l);
		}
		else{
			maxubn = ubn;
			pciscan(sbn, &p->bridge);
		}
	}

	return maxubn;
}

static void
pcicfginit(void)
{
/*	char *p; */

	lock(&pcicfginitlock);
	if(pcicfgmode == -1){
		pcicfgmode = 0;
/*		if(p = getconf("*pcimaxdno"))
			pcimaxdno = strtoul(p, 0, 0); */
pcimaxdno = 15 /* was 20; what is correct value??? */;

		pciscan(0, &pciroot);
	}
	unlock(&pcicfginitlock);
}

static int
pcicfgrw8(int tbdf, int rno, int data, int read)
{
	int x;
	uchar *p;

	if(pcicfgmode == -1)
		pcicfginit();
	x = -1;
	if(BUSDNO(tbdf) > pcimaxdno)
		return x;

	p = (uchar*)arch->pcicfg(tbdf, rno);
	if(read)
		x = *p;
	else
		*p = data;

	return x;
}

int
pcicfgr8(Pcidev* pcidev, int rno)
{
	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
}

void
pcicfgw8(Pcidev* pcidev, int rno, int data)
{
	pcicfgrw8(pcidev->tbdf, rno, data, 0);
}

static int
pcicfgrw16(int tbdf, int rno, int data, int read)
{
	int x;
	ushort *p;

	if(pcicfgmode == -1)
		pcicfginit();
	x = -1;
	if(BUSDNO(tbdf) > pcimaxdno)
		return x;

	p = (ushort*)arch->pcicfg(tbdf, rno);
	if(read)
		x = *p;
	else
		*p = data;

	return x;
}

int
pcicfgr16(Pcidev* pcidev, int rno)
{
	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
}

void
pcicfgw16(Pcidev* pcidev, int rno, int data)
{
	pcicfgrw16(pcidev->tbdf, rno, data, 0);
}

static int
pcicfgrw32(int tbdf, int rno, int data, int read)
{
	int x;
	ulong *p;

	if(pcicfgmode == -1)
		pcicfginit();
	x = -1;
	if(BUSDNO(tbdf) > pcimaxdno)
		return x;

	p = (ulong*)arch->pcicfg(tbdf, rno);
	if(read)
		x = *p;
	else
		*p = data;

	return x;
}

int
pcicfgr32(Pcidev* pcidev, int rno)
{
	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
}

void
pcicfgw32(Pcidev* pcidev, int rno, int data)
{
	pcicfgrw32(pcidev->tbdf, rno, data, 0);
}

Pcidev*
pcimatch(Pcidev* prev, int vid, int did)
{
	if(pcicfgmode == -1)
		pcicfginit();

	if(prev == nil)
		prev = pcilist;
	else
		prev = prev->list;

	while(prev != nil) {
		if((vid == 0 || prev->vid == vid)
		&& (did == 0 || prev->did == did))
			break;
		prev = prev->list;
	}
	return prev;
}

void
pcihinv(Pcidev* p)
{
	int i;
	Pcidev *t;

	if(p == nil) {
		p = pciroot;
		print("bus dev type vid  did intl memory\n");
	}
	for(t = p; t != nil; t = t->link) {
		print("%d  %2d/%d %.4ux %.4ux %.4ux %2d  ",
			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
			t->ccru, t->vid, t->did, t->intl);

		for(i = 0; i < nelem(p->mem); i++) {
			if(t->mem[i].size == 0)
				continue;
			print("%d:%.8lux %d ", i,
				t->mem[i].bar, t->mem[i].size);
		}
		print("\n");
	}
	while(p != nil) {
		if(p->bridge != nil)
			pcihinv(p->bridge);
		p = p->link;
	}
}

void
pcireset(void)
{
	Pcidev *p;
	int pcr;

	if(pcicfgmode == -1)
		pcicfginit();

	for(p = pcilist; p != nil; p = p->list){
		pcr = pcicfgr16(p, PciPSR);
		pcicfgw16(p, PciPSR, pcr & ~0x04);
	}
}

A alphapc/screen.c => alphapc/screen.c +314 -0
@@ 0,0 1,314 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
#include "../port/error.h"

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

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

Point ZP = {0, 0};

Memdata gscreendata;
Memimage gscreen;

VGAscr vgascreen[1];

Cursor	arrow = {
	{ -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, 
	},
};

int
screensize(int x, int y, int z)
{
	VGAscr *scr;

	scr = &vgascreen[0];

	/*
	 * BUG: need to check if any xalloc'ed memory needs to
	 * be given back if aperture is set.
	 */
	if(scr->aperture == 0){
		int width = (x*(1<<z))/BI2WD;

		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 = (ulong)arch->pcimem(0xA0000, 1<<16);
		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;
}

int
screenaperture(int size, int align)
{
	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;
	}
	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;
}

ulong*
attachscreen(Rectangle* r, int* ld, int* width, int *softscreen)
{
	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;
	*softscreen = scr->useflush;

	return scr->gscreendata->data;
}

void
flushmemscreen(Rectangle r)
{
	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
getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
{
	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);
}

int
setcolor(ulong p, ulong r, ulong g, ulong b)
{
	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;
}

int
cursoron(int dolock)
{
	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
cursoroff(int)
{
}

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

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

	scr->cur->load(scr, curs);
}

A alphapc/screen.h => alphapc/screen.h +122 -0
@@ 0,0 1,122 @@
typedef struct Cursor Cursor;
typedef struct Cursorinfo Cursorinfo;
struct Cursorinfo {
	Cursor;
	Lock;
};

/* devmouse.c */
extern void mousetrack(int, int, int);
extern Point mousexy(void);

extern void mouseaccelerate(int);
extern int m3mouseputc(Queue*, int);
extern int mouseputc(Queue*, int);

extern Cursorinfo cursor;
extern Cursor arrow;

/*
 * 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);

/*
 */
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);
};

/*
 */
struct VGAscr {
	Lock	devlock;
	VGAdev*	dev;

	VGAcur*	cur;
	ulong	storage;
	Cursor;

	int	useflush;

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

	ulong	io;				/* device specific registers */

	ulong	colormap[Pcolours][3];

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

enum {
	Backgnd		= Pwhite,
};

/* mouse.c */
extern void mousectl(char*[], int);

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

/* vga.c */
extern void	vgascreenwin(VGAscr*);

A alphapc/segment.h => alphapc/segment.h +9 -0
@@ 0,0 1,9 @@
/*
 * Attach segment types
 */

Physseg physseg[] = {
	{ SG_SHARED,	"shared",	0,	SEGMAXSIZE,	0, 	0 },
	{ SG_BSS,	"memory",	0,	SEGMAXSIZE,	0,	0 },
	{ 0,		0,		0,	0,		0,	0 },
};

A alphapc/trap.c => alphapc/trap.c +700 -0
@@ 0,0 1,700 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"io.h"
#include	"../port/error.h"

void	noted(Ureg*, Ureg**, ulong);
void	rfnote(Ureg**);
void	kernfault(Ureg*, int);
void	illegal(Ureg *);
void	fen(Ureg *);

char *regname[]={
	"type",	"a0",		"a1",
	"a2",		"R0",		"R1",
	"R2",		"R3",		"R4",
	"R5",		"R6",		"R7",
	"R8",		"R9",		"R10",
	"R11",	"R12",	"R13",
	"R14",	"R15",	"R19",
	"R20",	"R21",	"R22",
	"R23",	"R24",	"R25",
	"R26",	"R27",	"R28",
	"R30",	"status",	"PC",
	"R29",	"R16",	"R17",
	"R18",
};

void
intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf)
{
	arch->intrenable(irq, f, a, tbdf);
}

void
trap(Ureg *ur)
{
	char buf[ERRLEN];
	int user, x;

	user = ur->status&UMODE;

	if(user){
		up = m->proc;
		up->dbgreg = ur;
		if(up && up->fpstate == FPactive) {
			up->fpstate = FPinactive;
			savefpregs(&up->fpsave);
			fpenab(0);
		}
	}
	switch ((int)ur->type) {
	case 1:	/* arith */
		fptrap(ur);
		break;
	case 2:	/* bad instr or FEN */
		illegal(ur);
		break;
	case 3:	/* intr */
		intr(ur);
		break;
	case 4:	/* memory fault */
		if(up == 0)
			kernfault(ur, (ulong)ur->a1);

		x = up->insyscall;
		up->insyscall = 1;
		spllo();
		faultalpha(ur);
		up->insyscall = x;
		break;
	case 6:	/* alignment fault */
		ur->pc -= 4;
		sprint(buf, "trap: unaligned addr 0x%lux", (ulong)ur->a0);
		fataltrap(ur, buf);
		break;
	default:	/* cannot happen */
		panic("bad trap type %d", (int)ur->type);
		break;
	}

	splhi();
	if(!user)
		return;

	notify(ur);
	if(up->fpstate == FPinactive) {
		fpenab(1);
		restfpregs(&up->fpsave);
		up->fpstate = FPactive;
	}
}

typedef struct Mcheck Mcheck;
struct Mcheck
{
	ulong	len;
	ulong	inprogress;
	ulong	procoff;
	ulong	sysoff;
	ulong	code;
};

static char *
smcheck(ulong code)
{
	switch (code) {
	case 0x80: return "tag parity error";
	case 0x82: return "tag control parity error";
	case 0x84: return "generic hard error";
	case 0x86: return "correctable ECC error";
	case 0x88: return "uncorrectable ECC error";
	case 0x8a: return "OS-specific PAL bugcheck";
	case 0x90: return "callsys in kernel mode";
	case 0x96: return "i-cache read retryable error";
	case 0x98: return "processor detected hard error";

	case 0x203: return "system detected uncorrectable ECC error";
	case 0x205: return "parity error detected by CIA";
	case 0x207: return "non-existent memory error";
	case 0x209: return "PCI SERR detected";
	case 0x20b: return "PCI data parity error detected";
	case 0x20d: return "PCI address parity error detected";
	case 0x20f: return "PCI master abort error";
	case 0x211: return "PCI target abort error";
	case 0x213: return "scatter/gather PTE invalid error";
	case 0x215: return "flash ROM write error";
	case 0x217: return "IOA timeout detected";
	case 0x219: return "IOCHK#, EISA add-in board parity or other catastrophic error";
	case 0x21b: return "EISA fail-safe timer timeout";
	case 0x21d: return "EISA bus time-out";
	case 0x21f: return "EISA software generated NMI";
	case 0x221: return "unexpected ev5 IRQ[3] interrupt";
	default: return "unknown mcheck";
	}
}

void
mcheck(void *x)
{
	Mcheck *m;
	uvlong *data;
	int i, col;

	m = x;
	data = x;
	iprint("panic: Machine Check @%lux: %s (%lux) len %d\n",
			m, smcheck(m->code), m->code, m->len);
	iprint("proc offset %lux sys offset %lux\n", m->procoff, m->sysoff);
	for (i = 0, col = 0; i < m->len/8; i++) {
		iprint("%.3lux: %.16llux%s", 8*i, data[i], (col == 2) ? "\n" : "    ");
		if (col++ == 2)
			col = 0;
	}
	firmware();
}

void
intr(Ureg *ur)
{
	m->intr++;
	switch ((int)ur->a0) {
	case 0:	/* interprocessor */
		panic("interprocessor intr");
		break;
	case 1:	/* clock */
		clock(ur);
		break;
	case 2:	/* machine check */
		mcheck((void*)(KZERO|(ulong)ur->a2));
		break;
	case 3:	/* device */
		arch->intr(ur);
		break;
	case 4:	/* perf counter */
		panic("perf count");
		break;
	default:
		panic("bad intr");
		break;
	}

	/* preemptive scheduling */
	if(up && up->state == Running && anyhigher())
		sched();
}

void
trapinit(void)
{
	splhi();
	wrent(0, intr0);
	wrent(1, arith);
	wrent(2, fault0);
	wrent(3, illegal0);
	wrent(4, unaligned);
	wrent(5, syscall0);
}

void
fataltrap(Ureg *ur, char *reason)
{
	char buf[ERRLEN];

	if(ur->status&UMODE) {
		spllo();
		sprint(buf, "sys: %s", reason);
		postnote(up, 1, buf, NDebug);
		return;
	}
	print("kernel %s pc=%lux\n", reason, (ulong)ur->pc);
	dumpregs(ur);
	dumpstack();
	if(m->machno == 0)
		spllo();
	exit(1);
}

void
kernfault(Ureg *ur, int code)
{
	Label l;
	char *s;

	splhi();
	if (code == 0)
		s = "read";
	else if (code == 1)
		s = "write";
	else
		s = "ifetch";
	print("panic: kfault %s VA=0x%lux\n", s, (ulong)ur->a0);
	print("u=0x%lux status=0x%lux pc=0x%lux sp=0x%lux\n",
				up, (ulong)ur->status, (ulong)ur->pc, (ulong)ur->sp);
	dumpregs(ur);
	l.sp = ur->sp;
	l.pc = ur->pc;
	dumpstack();
	exit(1);
}

void
dumpstack(void)
{
	ulong l, sl, el, v, i, instr, op;
	extern ulong etext;

	l=(ulong)&l;
	if(l&4)
		l += 4;
	if(up == 0){
		el = (ulong)m+BY2PG;
		sl = el-KSTACK;
	}
	else{
		sl = (ulong)up->kstack;
		el = sl + KSTACK;
	}
	if(l > el || l < sl){
		el = (ulong)m+BY2PG;
		sl = el-KSTACK;
	}
	iprint("dumpstack: l %lux sl %lux el %lux m %lux\n", l, sl, el, m);
	if(l > el || l < sl){
		return;
	}

	i = 0;
	for(; l<el; l+=8){
		v = *(ulong*)l - 4;
		if(KTZERO < v && v < (ulong)&etext && (v&3) == 0){
			/*
			 * Check for JSR/BSR
			 */
			instr = *(ulong*)v;
			op = (instr>>26);
			if(op == 26 || op == 52){
				iprint("%lux ", v);
				i++;
			}
		}
		if(i == 8){
			i = 0;
			iprint("\n");
		}
	}
}

void
dumpregs(Ureg *ur)
{
	int i, col;
	uvlong *l;

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

	l = &ur->type;
	col = 0;
	for (i = 0; i < sizeof regname/sizeof(char*); i++, l++) {
		iprint("%-7s%.16llux%s", regname[i], *l, col == 2 ? "\n" : "     ");
		if (col++ == 2)
			col = 0;
	}
	iprint("\n");
//	prflush();
}

int
notify(Ureg *ur)
{
	int l;
	ulong sp;
	Note *n;

	if(up->procctl)
		procctl(up);
	if(up->nnote == 0)
		return 0;

	spllo();
	qlock(&up->debug);
	up->notepending = 0;
	n = &up->note[0];
	if(strncmp(n->msg, "sys:", 4) == 0) {
		l = strlen(n->msg);
		if(l > ERRLEN-15)	/* " pc=0x12345678\0" */
			l = ERRLEN-15;

		sprint(n->msg+l, " pc=0x%lux", (ulong)ur->pc);
	}

	if(n->flag != NUser && (up->notified || up->notify==0)) {
		if(n->flag == NDebug)
			pprint("suicide: %s\n", n->msg);
		qunlock(&up->debug);
		pexit(n->msg, n->flag!=NDebug);
	}

	if(up->notified) {
		qunlock(&up->debug);
		splhi();
		return 0;
	}
		
	if(!up->notify) {
		qunlock(&up->debug);
		pexit(n->msg, n->flag!=NDebug);
	}
	sp = ur->usp & ~(BY2V-1);
	sp -= sizeof(Ureg);

	if(!okaddr((ulong)up->notify, BY2WD, 0)
	|| !okaddr(sp-ERRLEN-6*BY2WD, sizeof(Ureg)+ERRLEN-6*BY2WD, 1)) {
		pprint("suicide: bad address or sp in notify\n");
print("suicide: bad address or sp in notify\n");
		qunlock(&up->debug);
		pexit("Suicide", 0);
	}

	memmove((Ureg*)sp, ur, sizeof(Ureg));
	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
	up->ureg = (void*)sp;
	sp -= 2*BY2WD+ERRLEN;
	memmove((char*)sp, up->note[0].msg, ERRLEN);
	sp -= 4*BY2WD;
	*(ulong*)(sp+3*BY2WD) = sp+4*BY2WD;	/* arg 2 is string */
	ur->r0 = (ulong)up->ureg;		/* arg 1 (R0) is ureg* */
	*(ulong*)(sp+2*BY2WD) = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
	*(ulong*)(sp+0*BY2WD) = 0;		/* arg 0 is pc */
	ur->usp = sp;
	ur->pc = (ulong)up->notify;
	up->notified = 1;
	up->nnote--;
	memmove(&up->lastnote, &up->note[0], sizeof(Note));
	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));

	qunlock(&up->debug);
	splhi();
	return 1;
}

/*
 * Check that status is OK to return from note.
 */
int
validstatus(ulong kstatus, ulong ustatus)
{
	if((kstatus & 7) != (ustatus & 7))
		return 0;
	if((ustatus&UMODE) != UMODE)
		return 0;
	return 1;
}

/*
 * Return user to state before notify()
 */
void
noted(Ureg *kur, Ureg **urp, ulong arg0)
{
	Ureg *nur;
	ulong oureg, sp;

	qlock(&up->debug);
	if(arg0!=NRSTR && !up->notified) {
		qunlock(&up->debug);
		pprint("call to noted() when not notified\n");
print("call to noted() when not notified\n");
		pexit("Suicide", 0);
	}
	up->notified = 0;

	nur = up->ureg;

	oureg = (ulong)nur;
	if((oureg & (BY2V-1))
	|| !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
		pprint("bad ureg in noted or call to noted() when not notified\n");
print("bad ureg in noted or call to noted() when not notified\n");
		qunlock(&up->debug);
		pexit("Suicide", 0);
	}

	if(!validstatus(kur->status, nur->status)) {
		qunlock(&up->debug);
		pprint("bad noted ureg status %lux\n", (ulong)nur->status);
print("bad noted ureg status %lux\n", (ulong)nur->status);
		pexit("Suicide", 0);
	}

	memmove(*urp, up->ureg, sizeof(Ureg));
	switch(arg0) {
	case NCONT:
	case NRSTR:
		if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
			pprint("suicide: trap in noted\n");
print("suicide: trap in noted\n");
			qunlock(&up->debug);
			pexit("Suicide", 0);
		}
		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
		qunlock(&up->debug);
		splhi();
		rfnote(urp);
		break;

	case NSAVE:
		if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
			pprint("suicide: trap in noted\n");
print("suicide: trap in noted\n");
			qunlock(&up->debug);
			pexit("Suicide", 0);
		}
		qunlock(&up->debug);
		sp = oureg-4*BY2WD-ERRLEN;
		splhi();
		(*urp)->sp = sp;
		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
		((ulong*)sp)[0] = 0;			/* arg 0 is pc */
		(*urp)->r0 = oureg;		/* arg 1 is ureg* */
		rfnote(urp);
		break;

	default:
		pprint("unknown noted arg 0x%lux\n", arg0);
print("unknown noted arg 0x%lux\n", arg0);
		up->lastnote.flag = NDebug;
		/* fall through */
		
	case NDFLT:
		if(up->lastnote.flag == NDebug)
			pprint("suicide: %s\n", up->lastnote.msg);
		qunlock(&up->debug);
		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
	}
}

#include "../port/systab.h"

long
syscall(Ureg *aur)
{
	long ret;
	ulong sp;
	Ureg *ur;

	m->syscall++;
	up = m->proc;
	up->insyscall = 1;
	ur = aur;
	up->pc = ur->pc;
	up->dbgreg = aur;
	ur->type = 5;		/* for debugging */

	if(up->fpstate == FPactive) {
		up->fpsave.fpstatus = getfcr();
		up->fpstate = FPinit;
		fpenab(0);
	}
	spllo();

	if(up->procctl)
		procctl(up);

	up->scallnr = ur->r0;
	up->nerrlab = 0;
	sp = ur->sp;
	ret = -1;
	if(waserror())
		goto error;

	if(up->scallnr >= nsyscall){
		pprint("bad sys call %d pc %lux\n", up->scallnr, (ulong)ur->pc);
print("bad sys call %d pc %lux\n", up->scallnr, (ulong)ur->pc);
		postnote(up, 1, "sys: bad sys call", NDebug);
		error(Ebadarg);
	}

	if(sp & (BY2WD-1)){	/* XXX too weak? */
		pprint("odd sp in sys call pc %lux sp %lux\n", (ulong)ur->pc, (ulong)ur->sp);
		postnote(up, 1, "sys: odd stack", NDebug);
		error(Ebadarg);
	}

	if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)))
		validaddr(sp, sizeof(Sargs), 0);

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

	ret = (*systab[up->scallnr])(up->s.args);
	poperror();

error:
	up->nerrlab = 0;
	up->psstate = 0;
	up->insyscall = 0;
	if(up->scallnr == NOTED)				/* ugly hack */
		noted(ur, &aur, *(ulong*)(sp+2*BY2WD));	/* doesn't return */

	splhi();
	if(up->scallnr!=RFORK && (up->procctl || up->nnote)){
		ur->r0 = ret;				/* load up for noted() */
		if(notify(ur))
			return ur->r0;
	}

	if(up->fpstate == FPinactive)		/* due to race with intr */
		up->fpstate = FPinit;

	return ret;
}

void
forkchild(Proc *p, Ureg *ur)
{
	Ureg *cur;

	p->sched.sp = (ulong)p->kstack+KSTACK-(4*BY2WD+sizeof(Ureg));
	p->sched.pc = (ulong)forkret;

	cur = (Ureg*)(p->sched.sp+4*BY2WD);
	memmove(cur, ur, sizeof(Ureg));

	/* Things from bottom of syscall we never got to execute */
	p->psstate = 0;
	p->insyscall = 0;
}

static
void
linkproc(void)
{
	spllo();
	up->kpfun(up->kparg);
}

void
kprocchild(Proc *p, void (*func)(void*), void *arg)
{
	p->sched.pc = (ulong)linkproc;
	p->sched.sp = (ulong)p->kstack+KSTACK;

	p->kpfun = func;
	p->kparg = arg;
}

long
execregs(ulong entry, ulong ssize, ulong nargs)
{
	Ureg *ur;
	ulong *sp;

	sp = (ulong*)(USTKTOP - ssize);
	*--sp = nargs;

	ur = (Ureg*)up->dbgreg;
	ur->usp = (ulong)sp;
	ur->pc = entry;
	up->fpsave.fpstatus = initfp.fpstatus;
	return USTKTOP-BY2WD;			/* address of user-level clock */
}

ulong
userpc(void)
{
	Ureg *ur;

	ur = (Ureg*)up->dbgreg;
	return ur->pc;
}

/* This routine must save the values of registers the user is not permitted to write
 * from devproc and then restore the saved values before returning
 */
void
setregisters(Ureg *xp, char *pureg, char *uva, int n)
{
	ulong status;

	status = xp->status;
	memmove(pureg, uva, n);
	xp->status = status;
}

/* Give enough context in the ureg to produce a kernel stack for
 * a sleeping process
 */
void
setkernur(Ureg *xp, Proc *p)
{
	xp->pc = p->sched.pc;
	xp->sp = p->sched.sp;
	xp->r26 = (ulong)sched;
}

ulong
dbgpc(Proc *p)
{
	Ureg *ur;

	ur = p->dbgreg;
	if(ur == 0)
		return 0;

	return ur->pc;
}

void
illegal(Ureg *ur)
{
	switch ((int)ur->a0) {
	case 0:	/* breakpoint */
		ur->pc -= 4;
		fataltrap(ur, "breakpoint");
		break;
	case 1:	/* bugchk */
		fataltrap(ur, "trap: bugchk");
		break;
	case 2:	/* gentrap */
		fataltrap(ur, "trap: gentrap");
		break;
	case 3:	/* FEN */
		fen(ur);
		break;
	case 4:	/* opDEC */
		fataltrap(ur, "trap: illegal instruction");
		break;
	default:
		panic("illegal illegal %d", (int)ur->a0);
		break;
	}
}

void
fen(Ureg *ur)
{
	ulong fpcr;

	if ((ur->status&UMODE) && up) {
		if(up->fpstate == FPinit) {
			up->fpstate = FPactive;
			fpcr = up->fpsave.fpstatus;
			up->fpsave = initfp;
			up->fpsave.fpstatus = fpcr;
			fpenab(1);
			restfpregs(&up->fpsave);
			return;
		}
	}
	fataltrap(ur, "trap: floating enable");		/* should never happen */
}

A alphapc/vga.c => alphapc/vga.c +194 -0
@@ 0,0 1,194 @@
#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 <cursor.h>
#include "screen.h"

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

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 Point curpos;
static Rectangle window;
static int *xp;
static int xbuf[256];
static Lock vgascreenlock;

static void
vgascroll(VGAscr* scr)
{
	int h, o;
	Point p;
	Rectangle r;

	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);

	curpos.y -= o;
}

static void
vgascreenputc(VGAscr* scr, char* buf, Rectangle *flushr)
{
	Point p;
	int h, w, pos;
	Rectangle r;

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

	h = scr->memdefont->height;
	switch(buf[0]){

	case '\n':
		if(curpos.y+h >= window.max.y){
			vgascroll(scr);
			*flushr = window;
		}
		curpos.y += h;
		vgascreenputc(scr, "\r", flushr);
		break;

	case '\r':
		xp = xbuf;
		curpos.x = window.min.x;
		break;

	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 '\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:
		p = memsubfontwidth(scr->memdefont, buf);
		w = p.x;

		if(curpos.x >= window.max.x-w)
			vgascreenputc(scr, "\n", flushr);

		*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
vgascreenputs(char* s, int n)
{
	int i;
	Rune r;
	char buf[4];
	VGAscr *scr;
	Rectangle flushr;

	scr = &vgascreen[0];

	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);
		if(i == 0){
			s++;
			--n;
			continue;
		}
		memmove(buf, s, i);
		buf[i] = 0;
		n -= i;
		s += i;
		vgascreenputc(scr, buf, &flushr);
	}
	flushmemscreen(flushr);

	unlock(&vgascreenlock);
}

void
vgascreenwin(VGAscr* scr)
{
	int h, w;

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

	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;

	screenputs = vgascreenputs;
}

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

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

/*
 * IBM RGB524.
 * 170/220MHz High Performance Palette DAC.
 *
 * Assumes hooked up to an S3 Vision96[48].
 */
enum {
	IndexLo		= 0x00,
	IndexHi		= 0x01,
	Data		= 0x02,
	IndexCtl	= 0x03,
};

enum {						/* index registers */
	CursorCtl	= 0x30,
	CursorXLo	= 0x31,
	CursorXHi	= 0x32,
	CursorYLo	= 0x33,
	CursorYHi	= 0x34,
	CursorHotX	= 0x35,
	CursorHotY	= 0x36,

	CursorR1	= 0x40,
	CursorG1	= 0x41,
	CursorB1	= 0x42,
	CursorR2	= 0x43,
	CursorG2	= 0x44,
	CursorB2	= 0x45,
	CursorR3	= 0x46,
	CursorG3	= 0x47,
	CursorB3	= 0x48,

	CursorArray	= 0x100,
};

/*
 * Lower 2-bits of indirect DAC register
 * addressing.
 */
static ushort dacxreg[4] = {
	PaddrW, Pdata, Pixmask, PaddrR
};

static uchar
rgb524setrs2(void)
{
	uchar rs2;

	rs2 = vgaxi(Crtx, 0x55);
	vgaxo(Crtx, 0x55, (rs2 & 0xFC)|0x01);

	return rs2;
}

static void
rgb524xo(int index, uchar data)
{
	vgao(dacxreg[IndexLo], index & 0xFF);
	vgao(dacxreg[IndexHi], (index>>8) & 0xFF);
	vgao(dacxreg[Data], data);
}

static void
rgb524disable(VGAscr*)
{
	uchar rs2;

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

static void
rgb524enable(VGAscr*)
{
	uchar rs2;

	rs2 = rgb524setrs2();

	/*
	 * 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);

	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
	 * control to defaults.
	 */
	rgb524xo(CursorCtl, 0x00);

	/*
	 * Set auto-increment mode for index-register addressing
	 * and initialise the cursor array index.
	 */
	vgao(dacxreg[IndexCtl], 0x01);
	vgao(dacxreg[IndexLo], CursorArray & 0xFF);
	vgao(dacxreg[IndexHi], (CursorArray>>8) & 0xFF);

	/*
	 * Initialise the 32x32 cursor RAM array. There are 2 planes,
	 * p0 and p1. Data is written 4 pixels per byte, with p1 the
	 * MS bit of each pixel.
	 * The cursor is set in X-Windows mode which gives the following
	 * truth table:
	 *	p1 p0	colour
	 *	 0  0	underlying pixel colour
	 *	 0  1	underlying pixel colour
	 *	 1  0	cursor colour 1
	 *	 1  1	cursor colour 2
	 * Put the cursor into the top-left of the 32x32 array.
	 */
	for(y = 0; y < 32; y++){
		for(x = 0; x < 32/8; x++){
			if(x < 16/8 && y < 16){
				p0 = curs->clr[x+y*2];
				p1 = curs->set[x+y*2];

				p = 0x00;
				if(p1 & 0x80)
					p |= 0xC0;
				else if(p0 & 0x80)
					p |= 0x80;
				if(p1 & 0x40)
					p |= 0x30;
				else if(p0 & 0x40)
					p |= 0x20;
				if(p1 & 0x20)
					p |= 0x0C;
				else if(p0 & 0x20)
					p |= 0x08;
				if(p1 & 0x10)
					p |= 0x03;
				else if(p0 & 0x10)
					p |= 0x02;
				vgao(dacxreg[Data], p);

				p = 0x00;
				if(p1 & 0x08)
					p |= 0xC0;
				else if(p0 & 0x08)
					p |= 0x80;
				if(p1 & 0x04)
					p |= 0x30;
				else if(p0 & 0x04)
					p |= 0x20;
				if(p1 & 0x02)
					p |= 0x0C;
				else if(p0 & 0x02)
					p |= 0x08;
				if(p1 & 0x01)
					p |= 0x03;
				else if(p0 & 0x01)
					p |= 0x02;
				vgao(dacxreg[Data], p);
			}
			else{
				vgao(dacxreg[Data], 0x00);
				vgao(dacxreg[Data], 0x00);
			}
		}
	}

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

	rgb524xo(CursorCtl, 0x23);

	vgaxo(Crtx, 0x55, rs2);
}

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

	rs2 = rgb524setrs2();

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

	vgaxo(Crtx, 0x55, rs2);

	return 0;
}

VGAcur vgargb524cur = {
	"rgb524hwgc",

	rgb524enable,
	rgb524disable,
	rgb524load,
	rgb524move,
};

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

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

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

	crt35 = vgaxi(Crtx, 0x35);
	if(scr->gscreen->ldepth == 3){
		/*
		 * The S3 registers need to be unlocked for this.
		 * Let's hope they are already:
		 *	vgaxo(Crtx, 0x38, 0x48);
		 *	vgaxo(Crtx, 0x39, 0xA0);
		 *
		 * The page is 6 bits, the lower 4 bits in Crt35<3:0>,
		 * the upper 2 in Crt51<3:2>.
		 */
		vgaxo(Crtx, 0x35, page & 0x0F);
		crt51 = vgaxi(Crtx, 0x51);
		vgaxo(Crtx, 0x51, (crt51 & ~0x0C)|((page & 0x30)>>2));
		opage = ((crt51 & 0x0C)<<2)|(crt35 & 0x0F);
	}
	else{
		vgaxo(Crtx, 0x35, (page<<2) & 0x0C);
		opage = (crt35>>2) & 0x03;
	}

	return opage;
}

static void
s3page(VGAscr* scr, int page)
{
	int id;

	id = (vgaxi(Crtx, 0x30)<<8)|vgaxi(Crtx, 0x2E);
	switch(id){

	case 0xE110:				/* ViRGE/GX2 */
		break;

	default:
		lock(&scr->devlock);
		s3pageset(scr, page);
		unlock(&scr->devlock);
		break;
	}
}

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
s3vsyncactive(void)
{
	/*
	 * Hardware cursor information is fetched from display memory
	 * during the horizontal blank active time. The 80x chips may hang
	 * if the cursor is turned on or off during this period.
	 */
	while((vgai(Status1) & 0x08) == 0)
		;
}

static void
s3disable(VGAscr*)
{
	uchar crt45;

	/*
	 * Turn cursor off.
	 */
	crt45 = vgaxi(Crtx, 0x45) & 0xFE;
	s3vsyncactive();
	vgaxo(Crtx, 0x45, crt45);
}

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

	s3disable(scr);

	/*
	 * Cursor colours. Set both the CR0[EF] and the colour
	 * stack in case we are using a 16-bit RAMDAC.
	 * This stuff is just a mystery for the ViRGE/GX2.
	 */
	vgaxo(Crtx, 0x0E, Pwhite);
	vgaxo(Crtx, 0x0F, Pblack);
	vgaxi(Crtx, 0x45);
	id = (vgaxi(Crtx, 0x30)<<8)|vgaxi(Crtx, 0x2E);
	switch(id){

	case 0xE110:				/* ViRGE/GX2 */
		for(i = 0; i < 3; i++)
			vgaxo(Crtx, 0x4A, Pblack);
		vgaxi(Crtx, 0x45);
		for(i = 0; i < 3; i++)
			vgaxo(Crtx, 0x4B, Pwhite);
		break;

	default:
		for(i = 0; i < 3; i++)
			vgaxo(Crtx, 0x4A, Pwhite);
		vgaxi(Crtx, 0x45);
		for(i = 0; i < 3; i++)
			vgaxo(Crtx, 0x4B, Pblack);
		break;
	}

	/*
	 * Find a place for the cursor data in display memory.
	 * Must be on a 1024-byte boundary.
	 */
	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 Microsoft Windows format.
	 */
	vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55) & ~0x10);
	s3vsyncactive();
	vgaxo(Crtx, 0x45, 0x01);
}

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

	/*
	 * Disable the cursor and
	 * set the pointer to the two planes.
	 */
	s3disable(scr);

	opage = 0;
	p = KADDR(scr->aperture);
	id = (vgaxi(Crtx, 0x30)<<8)|vgaxi(Crtx, 0x2E);
	switch(id){

	case 0xE110:				/* ViRGE/GX2 */
		p += scr->storage;
		break;

	default:
		lock(&scr->devlock);
		opage = s3pageset(scr, scr->storage>>16);
		p += (scr->storage & 0xFFFF);
		break;
	}

	/*
	 * The cursor is set in Microsoft Windows format (the ViRGE/GX2 no
	 * longer supports the X11 format) which gives the following truth table:
	 *	and xor	colour
	 *	 0   0	background colour
	 *	 0   1	foreground colour
	 *	 1   0	current screen pixel
	 *	 1   1	NOT current screen pixel
	 * Put the cursor into the top-left of the 64x64 array.
	 *
	 * The cursor pattern in memory is interleaved words of
	 * AND and XOR patterns.
	 */
	for(y = 0; y < 64; y++){
		for(x = 0; x < 64/8; x += 2){
			if(x < 16/8 && y < 16){
				*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++ = 0xFF;
				*p++ = 0xFF;
				*p++ = 0x00;
				*p++ = 0x00;
			}
		}
	}

	switch(id){

	case 0xE110:				/* ViRGE/GX2 */
		break;

	default:
		s3pageset(scr, opage);
		unlock(&scr->devlock);
		break;
	}

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

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

	/*
	 * Mustn't position the cursor offscreen even partially,
	 * or it disappears. Therefore, if x or y is -ve, adjust the
	 * cursor offset instead.
	 * There seems to be a bug in that if the offset is 1, the
	 * cursor doesn't disappear off the left edge properly, so
	 * round it up to be even.
	 */
	if((x = p.x+scr->offset.x) < 0){
		xo = -x;
		xo = ((xo+1)/2)*2;
		x = 0;
	}
	else
		xo = 0;
	if((y = p.y+scr->offset.y) < 0){
		yo = -y;
		y = 0;
	}
	else
		yo = 0;

	vgaxo(Crtx, 0x46, (x>>8) & 0x07);
	vgaxo(Crtx, 0x47, x & 0xFF);
	vgaxo(Crtx, 0x49, y & 0xFF);
	vgaxo(Crtx, 0x4E, xo);
	vgaxo(Crtx, 0x4F, yo);
	vgaxo(Crtx, 0x48, (y>>8) & 0x07);

	return 0;
}

VGAdev vgas3dev = {
	"s3",

	0,
	0,
	s3page,
	s3linear,
};

VGAcur vgas3cur = {
	"s3hwgc",

	s3enable,
	s3disable,
	s3load,
	s3move,
};

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

#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include <cursor.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 mpc/clock.c => mpc/clock.c +6 -6
@@ 59,8 59,10 @@ microdelay(int l)
		;
}

// the following can be 4 or 16 depending on the clock multiplier
// see 15.3.3 in 860 manual
enum {
	Timebase = 4,	/* system clock cycles per time base cycle */
	Timebase = 16,	/* system clock cycles per time base cycle */
};

static	ulong	clkreload;


@@ 70,18 72,18 @@ clockinit(void)
{
	long x, est;

	est = m->clockgen/1000;	/* initial estimate */
	est = m->cpuhz/1000;	/* initial estimate */
	m->delayloop = est;
	do {
		x = gettbl();
		delay(10);
		delay(1);
		x = gettbl() - x;
	} while(x < 0);

	/*
	 *  fix count
	 */
	m->delayloop = (m->delayloop*10*est)/(x*Timebase);
	m->delayloop = (m->delayloop*est/Timebase)/(x);
	if(m->delayloop == 0)
		m->delayloop = 1;



@@ 110,8 112,6 @@ clockintr(Ureg *ur)
	m->iomem->swsr = 0xaa39;
	
	m->ticks++;
	if(m->ticks%MS2TK(1000) == 0)
		*(uchar*)(NIMMEM+0x2200) = (m->ticks/MS2TK(1000))&2;

	if(up)
		up->pc = ur->pc;

M mpc/devuart.c => mpc/devuart.c +5 -5
@@ 462,7 462,7 @@ sccsetup(Uart *up)
	if(0){
		print("gsmrl=%8.8lux gsmrh=%8.8lux dsr=%4.4ux irmode=%4.4ux\n", scc->gsmrl, scc->gsmrh, scc->dsr, scc->irmode);
		for(i=0; i<sizeof(Uartscc); i+=4)
			print("%2.2lux %8.8lux\n", i, *(ulong*)((uchar*)up->param+i));
			print("%2.2ux %8.8lux\n", i, *(ulong*)((uchar*)up->param+i));
	}
}



@@ 763,7 763,7 @@ static void
txstart(Uart *p)
{
	Block *b;
	int n, flags, s;
	int n, flags;


	if(!p->cts || p->blocked || p->txb->status & BDReady)


@@ 1080,8 1080,6 @@ setlength(int i)
void
uartinstall(void)
{
	int port;
	char *p, *q;
	static int already;

	if(already)


@@ 1089,6 1087,8 @@ uartinstall(void)
	already = 1;
	uartsetup(1, SMC1ID, "eia0");
/*
	int port;
	char *p, *q;
	if((p = getconf("console")) || (p = "0")){
		if(USESMC2)
			port = strtol(p, &q, 0);


@@ 1098,7 1098,7 @@ uartinstall(void)
			uartspecial(port, 9600, &kbdq, &printq, kbdcr2nl);
	}
*/
	uartspecial(0, 19200, &kbdq, &printq, kbdcr2nl);
	uartspecial(0, 9600, &kbdq, &printq, kbdcr2nl);

//	if(USESMC2)
//		uartsetup(2, SMC2ID, "eia1");

M mpc/main.c => mpc/main.c +3 -15
@@ 18,18 18,6 @@ int	predawn = 1;
Conf	conf;

void
flash(void)
{
	int i;
	*(uchar*)(NIMMEM+0x2200) = 0;
	for(i=0; i<1000000; i++)
		;
	*(uchar*)(NIMMEM+0x2200) = 0x2;
	for(i=0; i<1000000; i++)
		;
}

void
main(void)
{
	machinit();


@@ 72,7 60,7 @@ machinit(void)
	m->iomem = KADDR(INTMEM);

	io = m->iomem;
	osc = 5;
	osc = 50;
	mf = io->plprcr >> 20;
	m->oscclk = osc;
	m->speed = osc*(mf+1);


@@ 259,8 247,8 @@ confinit(void)
	conf.nproc = 200;	/* processes */

	// hard wire for now
	pa = 0xff200000;		// leave 2 Meg for kernel
	nbytes = 10*1024*1024;	// leave room at the top as well
	pa = 0xffd00000;		// leave 1 Meg for kernel
	nbytes = 2*1024*1024;	// leave room at the top as well
	
	conf.npage0 = nbytes/BY2PG;
	conf.base0 = pa;

M mpc/mem.h => mpc/mem.h +0 -1
@@ 176,7 176,6 @@
 * atlas board registers
 */
#define	INTMEM		0x80000000
#define NIMMEM		0x80100000
#define	FLASH0MEM	0x80200000
#define	FLASH1MEM	0x80400000
#define	SDRAMMEM	0x03000000

M port/devssl.c => port/devssl.c +10 -7
@@ 737,23 737,26 @@ initDESkey(OneWay *w)
static void
initDESkey_40(OneWay *w)
{
	uchar key[8];

	if(w->state){
		free(w->state);
		w->state = 0;
	}

	if(w->slen >= 8) {
		w->secret[0] &= 0x0f;
		w->secret[2] &= 0x0f;
		w->secret[4] &= 0x0f;
		w->secret[6] &= 0x0f;
	if(w->slen >= 8){
		memmove(key, w->secret, 8);
		key[0] &= 0x0f;
		key[2] &= 0x0f;
		key[4] &= 0x0f;
		key[6] &= 0x0f;
	}

	w->state = malloc(sizeof(DESstate));
	if(w->slen >= 16)
		setupDESstate(w->state, w->secret, w->secret+8);
		setupDESstate(w->state, key, w->secret+8);
	else if(w->slen >= 8)
		setupDESstate(w->state, w->secret, 0);
		setupDESstate(w->state, key, 0);
	else
		error("secret too short");
}