瀏覽代碼

sys/src/boot/vt5: import Xilinx Virtex-5 boot loader from Bell Labs (thanks Geoff Collyer)

David du Colombier 3 年之前
父節點
當前提交
1da04ce818

+ 69 - 0
sys/src/boot/vt5/archvt5.c

@@ -0,0 +1,69 @@
+/* virtex 5 dependencies */
+#include "include.h"
+#include "qtm.h"
+
+uvlong myhz = 400000000;	/* fixed 400MHz */
+uchar mymac[Eaddrlen] = { 0x00, 0x0A, 0x35, 0x01, 0xE1, 0x48 };
+
+void
+clrmchk(void)
+{
+	putmcsr(~0);			/* clear machine check causes */
+	sync();
+	isync();
+	putesr(0);			/* clears machine check */
+}
+
+static vlong
+myprobe(uintptr addr)
+{
+	vlong v;
+
+	iprint("myprobe: addr %#lux\n", addr);
+	v = qtmprobeaddr(addr);
+	if (v < 0)
+		iprint("myprobe: failed for %#lux\n", addr);
+	flushwrbufs();
+	qtmerrtestaddr(addr);
+	return v;
+}
+
+/*
+ * size by watching for bus errors (machine checks), but avoid
+ * tlb faults for unmapped memory beyond the maximum we expect.
+ * furthermore, write entire aligned cachelines to avoid macfail
+ * errors if we are using qtm.
+ */
+uintptr
+memsize(void)
+{
+	uintptr sz;
+#ifdef AMBITIOUS		/* this works on vanilla systems */
+	int fault;
+
+	/* try powers of two */
+	fault = 0;
+	if (securemem) {
+		qrp->err = 0;
+		coherence();
+	}
+	for (sz = 64*MB; sz != 0 && sz < MAXMEM; sz <<= 1)
+		if (myprobe(sz) < 0) {
+			fault = 1;
+			break;
+		}
+
+	/* special handling for maximum size */
+	if (sz >= MAXMEM && !fault && myprobe(MEMTOP(sz) - 2*DCACHELINESZ) < 0)
+		sz >>= 1;
+
+	if (securemem) {
+		qrp->err = 0;		/* in case we perturbed qtm */
+		coherence();
+	}
+#else
+	/* the vanilla ddr2 system used to have 512MB, but now only 256MB */
+	sz = 256*MB;
+#endif
+	return securemem? MEMTOP(sz): sz;
+}

+ 231 - 0
sys/src/boot/vt5/data.h

@@ -0,0 +1,231 @@
+enum {
+	PRINTSIZE = 256,
+};
+
+#define		MS2NS(n) (((vlong)(n))*1000000LL)
+#define		TK2MS(x) ((x)*(1000/HZ))
+
+#define MB	(1024*1024)
+
+/*
+ * Where configuration info is left for the loaded programme.
+ * This will turn into a structure as more is done by the boot loader
+ * (e.g. why parse the .ini file twice?).
+ * There are 3584 bytes available at CONFADDR on the PC.
+ *
+ * The low-level boot routines in l.s leave data for us at CONFADDR,
+ * which we pick up before reading the plan9.ini file.
+ */
+#define BOOTLINELEN	64
+#define BOOTARGS	((char*)(CONFADDR+BOOTLINELEN))
+#define	BOOTARGSLEN	1024	/* size reduction */
+#define	MAXCONF		32	/* from 100; size reduction */
+
+/*
+ * intc bits, as of 18 aug 2009.
+ * specific to rae's virtex5 design
+ */
+enum {
+	Bitllfifo,
+	Bittemac,
+	Bitdma,
+	Bitdma2,
+	Bituart,
+	Bitmiiphy,
+	Bitqtmmacfail,			/* qtm only */
+	Bitqtmdraminit,			/* qtm only */
+
+	Intllfifo=1<<Bitllfifo,		/* local-link FIFO */
+	Inttemac= 1<<Bittemac,
+	Intdma	= 1<<Bitdma,
+	Intdma2	= 1<<Bitdma2,
+	Intuart = 1<<Bituart,
+	Intmiiphy = 1<<Bitmiiphy,
+	Intqtmmacfail= 1<<Bitqtmmacfail,
+	Intqtmdraminit= 1<<Bitqtmdraminit,
+};
+
+typedef struct Boot Boot;
+typedef struct File File;
+typedef struct Fs Fs;
+typedef struct Lock Lock;
+typedef union Mach Mach;
+typedef struct Medium Medium;
+typedef u32int Mreg;				/* Msr - bloody UART */
+typedef struct Proc Proc;
+typedef struct Timer Timer;
+typedef struct Type Type;
+typedef struct Ureg Ureg;
+
+struct Lock
+{
+	uint	key;
+	ulong	sr;
+	ulong	pc;
+//	Proc	*p;
+	Mach	*m;
+	ushort	isilock;
+	long	lockcycles;
+};
+
+
+typedef union Mach {
+	struct {
+		int	machno;
+		void*	up;		/* offset known in assember */
+
+		/* ordering from here on irrelevant */
+
+		ulong	ticks;		/* of the clock since boot time */
+		long	oscclk;		/* oscillator frequency (MHz) */
+		long	cpuhz;		/* general system clock (cycles) */
+		long	clockgen;	/* clock generator frequency (cycles) */
+		long	vcohz;
+		long	pllhz;
+		long	plbhz;
+		long	opbhz;
+		long	epbhz;
+		long	pcihz;
+		int	cputype;
+		ulong	delayloop;
+//		uvlong	cyclefreq;	/* frequency of user readable cycle clock */
+		uvlong	fastclock;
+		int	intr;
+	};
+//	uintptr	stack[MACHSIZE/sizeof(uintptr)];	/* now in dram */
+} Mach;
+
+extern Mach* machptr[MAXMACH];
+
+#define	MACHP(n)	machptr[n]
+
+extern register Mach* m;
+extern register void* up;
+
+/*
+ * rest copied from /sys/src/boot/pc/dat.h:
+ */
+
+typedef struct Medium Medium;
+typedef struct Boot Boot;
+
+enum {					/* type */
+	Tether		= 0,
+	Tany		= -1,
+};
+
+enum {					/* name and flag */
+	Fnone		= 0x00,
+
+	Nfs		= 0x00,
+	Ffs		= (1<<Nfs),
+	Nboot		= 0x01,
+	Fboot		= (1<<Nboot),
+	Nbootp		= 0x02,
+	Fbootp		= (1<<Nbootp),
+	NName		= 3,
+
+	Fany		= Fbootp|Fboot|Ffs,
+
+	Fini		= 0x10,
+	Fprobe		= 0x80,
+};
+
+typedef struct Type {
+	ushort	type;
+	ushort	flag;
+	int	(*init)(void);
+	void	(*initdev)(int, char*);
+	void*	(*getfspart)(int, char*, int);	/* actually returns Dos* */
+	void	(*addconf)(int);
+	int	(*boot)(int, char*, Boot*);
+	void	(*printdevs)(int);
+	char**	parts;
+	char**	inis;
+	int	mask;
+	Medium*	media;
+} Type;
+
+extern void (*etherdetach)(void);
+
+#define	_MAGIC(f, b)	((f)|((((4*(b))+0)*(b))+7))
+#define	Q_MAGIC		_MAGIC(0, 21)		/* powerpc */
+
+typedef struct Exec Exec;
+struct	Exec
+{
+	uchar	magic[4];		/* magic number */
+	uchar	text[4];	 	/* size of text segment */
+	uchar	data[4];	 	/* size of initialized data */
+	uchar	bss[4];	  		/* size of uninitialized data */
+	uchar	syms[4];	 	/* size of symbol table */
+	uchar	entry[4];	 	/* entry point */
+	uchar	spsz[4];		/* size of sp/pc offset table */
+	uchar	pcsz[4];		/* size of pc/line number table */
+};
+
+typedef struct Block Block;
+struct Block {
+	Block*	next;
+	uchar*	rp;			/* first unconsumed byte */
+	uchar*	wp;			/* first empty byte */
+	uchar*	lim;			/* 1 past the end of the buffer */
+	uchar*	base;			/* start of the buffer */
+	ulong	flag;
+};
+#define BLEN(s)	((s)->wp - (s)->rp)
+
+enum {
+	Eaddrlen	= 6,
+	/* next two exclude 4-byte ether CRC */
+	ETHERMINTU	= 60,		/* minimum transmit size */
+	ETHERMAXTU	= 1514,		/* maximum transmit size */
+	ETHERHDRSIZE	= 14,		/* size of an ethernet header */
+
+	MaxEther	= 1,	/* from 6; size reduction */
+};
+
+typedef struct {
+	uchar	d[Eaddrlen];
+	uchar	s[Eaddrlen];
+	uchar	type[2];
+	uchar	data[1500];
+	uchar	crc[4];
+} Etherpkt;
+
+enum {	/* returned by bootpass */
+	MORE, ENOUGH, FAIL
+};
+enum {
+	INITKERNEL,
+	READEXEC,
+	READ9TEXT,
+	READ9DATA,
+	READGZIP,
+	READEHDR,
+	READPHDR,
+	READEPAD,
+	READEDATA,
+	TRYBOOT,
+	INIT9LOAD,
+	READ9LOAD,
+	FAILED
+};
+
+struct Boot {
+	int state;
+
+	Exec exec;
+	char *bp;	/* base ptr */
+	char *wp;	/* write ptr */
+	char *ep;	/* end ptr */
+};
+
+extern uvlong	clockintrs;
+extern int	debug;
+extern char	*defaultpartition;
+extern int	iniread;
+extern uvlong	myhz;
+extern int	pxe;
+extern int	securemem;
+extern int	vga;

+ 1 - 0
sys/src/boot/vt5/define.h

@@ -0,0 +1 @@
+#undef PARANOID		/* scan all of dram, we don't trust it */

+ 68 - 0
sys/src/boot/vt5/etherif.h

@@ -0,0 +1,68 @@
+typedef struct RingBuf {
+	uchar	owner;
+	uchar	unused;
+	ushort	len;
+	uchar	pkt[sizeof(Etherpkt)];
+} RingBuf;
+
+enum {
+	Host		= 0,		/* buffer owned by host */
+	Interface	= 1,		/* buffer owned by card */
+
+	Nrb		= 32,		/* default number of receive buffers */
+	Ntb		= 8,		/* default number of transmit buffers */
+};
+
+/*
+ *  a parsed .ini line
+ */
+#define ISAOPTLEN	32
+#define NISAOPT		8
+#define NAMELEN		28
+
+typedef struct  ISAConf {
+	char	type[NAMELEN];
+	ulong	port;
+//	ulong	irq;
+	ulong	mem;
+	ulong	size;
+	uchar	ea[6];
+
+	int	nopt;
+	char	opt[NISAOPT][ISAOPTLEN];
+} ISAConf;
+
+#define	CONFADDR	(0x2200)		/* above ppc vectors */
+#define BOOTLINE	((char*)CONFADDR)
+
+typedef struct Ether Ether;
+struct Ether {
+	ISAConf;			/* hardware info */
+	ushort	ctlrno;
+	ushort	state;			/* 0: unfound, 1: found, 2: attaching */
+
+	void	(*attach)(Ether*);	/* filled in by reset routine */
+	void	(*transmit)(Ether*);
+	int	(*interrupt)(ulong bit);
+	void	(*detach)(Ether*);
+	void	*ctlr;
+
+	ushort	nrb;			/* number of software receive buffers */
+	ushort	ntb;			/* number of software transmit buffers */
+	RingBuf *rb;			/* software receive buffers */
+	RingBuf *tb;			/* software transmit buffers */
+
+	ushort	rh;			/* first receive buffer belonging to host */
+	ushort	ri;			/* first receive buffer belonging to card */	
+
+	ushort	th;			/* first transmit buffer belonging to host */	
+	ushort	ti;			/* first transmit buffer belonging to card */
+	ushort	tbusy;			/* transmitter is busy */
+	ushort	mbps;			/* zero means link down */	
+};
+
+extern void etherrloop(Ether*, Etherpkt*, long);
+extern void addethercard(char*, int(*)(Ether*));
+
+#define NEXT(x, l)	(((x)+1)%(l))
+#define PREV(x, l)	(((x) == 0) ? (l)-1: (x)-1)

+ 22 - 0
sys/src/boot/vt5/fs.h

@@ -0,0 +1,22 @@
+struct File{
+	int	walked;
+	Fs	*fs;
+	char	*path;
+};
+
+struct Fs{
+	int	dev;				/* device id */
+	long	(*diskread)(Fs*, void*, long);	/* disk read routine */
+	vlong	(*diskseek)(Fs*, vlong);	/* disk seek routine */
+	long	(*read)(File*, void*, long);
+	int	(*walk)(File*, char*);
+	File	root;
+};
+
+extern int chatty;
+extern int dotini(Fs*);
+extern int fswalk(Fs*, char*, File*);
+extern int fsread(File*, void*, long);
+extern int fsboot(Fs*, char*, Boot*);
+
+#define BADPTR(x) (0 && (ulong)x < 0x80000000)

+ 9 - 0
sys/src/boot/vt5/include.h

@@ -0,0 +1,9 @@
+#include "u.h"
+#include "libc.h"
+#include "ureg.h"
+#include <thread.h>
+#include "mem.h"
+#include "define.h"
+#include "data.h"
+#include "etherif.h"
+#include "prototype.h"

+ 100 - 0
sys/src/boot/vt5/ip.h

@@ -0,0 +1,100 @@
+typedef struct Udphdr Udphdr;
+struct Udphdr
+{
+	uchar	d[6];		/* Ethernet destination */
+	uchar	s[6];		/* Ethernet source */
+	uchar	type[2];	/* Ethernet packet type */
+
+	uchar	vihl;		/* Version and header length */
+	uchar	tos;		/* Type of service */
+	uchar	length[2];	/* packet length */
+	uchar	id[2];		/* Identification */
+	uchar	frag[2];	/* Fragment information */
+
+	/* Udp pseudo ip really starts here */
+	uchar	ttl;	
+	uchar	udpproto;	/* Protocol */
+	uchar	udpplen[2];	/* Header plus data length */
+	uchar	udpsrc[4];	/* Ip source */
+	uchar	udpdst[4];	/* Ip destination */
+	uchar	udpsport[2];	/* Source port */
+	uchar	udpdport[2];	/* Destination port */
+	uchar	udplen[2];	/* data length */
+	uchar	udpcksum[2];	/* Checksum */
+};
+
+typedef struct Etherhdr Etherhdr;
+struct Etherhdr
+{
+	uchar	d[6];
+	uchar	s[6];
+	uchar	type[2];
+
+	/* Now we have the ip fields */
+	uchar	vihl;		/* Version and header length */
+	uchar	tos;		/* Type of service */
+	uchar	length[2];	/* packet length */
+	uchar	id[2];		/* Identification */
+	uchar	frag[2];	/* Fragment information */
+	uchar	ttl;		/* Time to live */
+	uchar	proto;		/* Protocol */
+	uchar	cksum[2];	/* Header checksum */
+	uchar	src[4];		/* Ip source */
+	uchar	dst[4];		/* Ip destination */
+};
+
+enum
+{
+	IP_VER		= 0x40,
+	IP_HLEN		= 0x05,			
+ 	UDP_EHSIZE	= 22,
+	UDP_PHDRSIZE	= 12,
+	UDP_HDRSIZE	= 20,
+	ETHER_HDR	= 14,
+	IP_UDPPROTO	= 17,
+	ET_IP		= 0x800,
+	Bcastip		= 0xffffffff,
+	BPportsrc	= 68,
+	BPportdst	= 67,
+	TFTPport	= 69,
+	Timeout		= 2000,	/* milliseconds; was 5000 */
+	Bootrequest 	= 1,
+	Bootreply   	= 2,
+	Tftp_READ	= 1,
+	Tftp_WRITE	= 2,
+	Tftp_DATA	= 3,
+	Tftp_ACK	= 4,
+	Tftp_ERROR	= 5,
+	Segsize		= 512,
+	TFTPSZ		= Segsize+10,
+};
+
+typedef struct Bootp Bootp;
+struct Bootp
+{
+	uchar	op;		/* opcode */
+	uchar	htype;		/* hardware type */
+	uchar	hlen;		/* hardware address len */
+	uchar	hops;		/* hops */
+	uchar	xid[4];		/* a random number */
+	uchar	secs[2];	/* elapsed since client started booting */
+	uchar	pad[2];
+	uchar	ciaddr[4];	/* client IP address (client tells server) */
+	uchar	yiaddr[4];	/* client IP address (server tells client) */
+	uchar	siaddr[4];	/* server IP address */
+	uchar	giaddr[4];	/* gateway IP address */
+	uchar	chaddr[16];	/* client hardware address */
+	char	sname[64];	/* server host name (optional) */
+	char	file[128];	/* boot file name */
+	char	vend[128];	/* vendor-specific goo */
+};
+
+typedef struct Netaddr Netaddr;
+struct Netaddr
+{
+	ulong	ip;
+	ushort	port;
+	char	ea[Eaddrlen];
+};
+
+extern int	eipfmt(Fmt*);

+ 904 - 0
sys/src/boot/vt5/l.s

@@ -0,0 +1,904 @@
+/* virtex5 ppc440x5 machine assist */
+#include	"mem.h"
+
+#define MICROBOOT	1	/* if defined, see microboot.s for startup */
+
+/*
+ * Special Purpose Registers of interest here (440 versions)
+ */
+#define SPR_CCR0	0x3b3		/* Core Configuration Register 0 */
+#define SPR_CCR1	0x378	/* core configuration register 1 */
+#define SPR_DAC1	0x13c		/* Data Address Compare 1 */
+#define SPR_DAC2	0x13d		/* Data Address Compare 2 */
+#define SPR_DBCR0	0x134		/* Debug Control Register 0 */
+#define SPR_DBCR1	0x135		/* Debug Control Register 1 */
+#define SPR_DBCR2	0x136		/* Debug Control Register 2 */
+#define SPR_DBSR	0x130		/* Debug Status Register */
+#define SPR_DVC1	0x13e		/* Data Value Compare 1 */
+#define SPR_DVC2	0x13f		/* Data Value Compare 2 */
+#define SPR_DEAR	0x3D		/* Data Error Address Register */
+#define SPR_ESR	0x3E		/* Exception Syndrome Register */
+#define SPR_IAC1	0x138		/* Instruction Address Compare 1 */
+#define SPR_IAC2	0x139		/* Instruction Address Compare 2 */
+#define SPR_IAC3	0x13a		/* Instruction Address Compare 3 */
+#define SPR_IAC4	0x13b		/* Instruction Address Compare 4 */
+#define SPR_PID		0x30		/* Process ID (not the same as 405) */
+#define SPR_PVR		0x11f		/* Processor Version Register */
+
+#define SPR_SPRG0	0x110		/* SPR General 0 */
+#define SPR_SPRG1	0x111		/* SPR General 1 */
+#define SPR_SPRG2	0x112		/* SPR General 2 */
+#define SPR_SPRG3	0x113		/* SPR General 3 */
+
+/* beware that these registers differ in R/W ability on 440 compared to 405 */
+#define SPR_SPRG4R		0x104	/* SPR general 4; user/supervisor R */
+#define SPR_SPRG5R		0x105	/* SPR general 5; user/supervisor R */
+#define SPR_SPRG6R		0x106	/* SPR general 6; user/supervisor R */
+#define SPR_SPRG7R		0x107	/* SPR general 7; user/supervisor R */
+#define SPR_SPRG4W	0x114		/* SPR General 4; supervisor W */
+#define SPR_SPRG5W	0x115		/* SPR General 5; supervisor W  */
+#define SPR_SPRG6W	0x116		/* SPR General 6; supervisor W  */
+#define SPR_SPRG7W	0x117		/* SPR General 7; supervisor W */
+
+#define SPR_SRR0	0x01a		/* Save/Restore Register 0 */
+#define SPR_SRR1	0x01b		/* Save/Restore Register 1 */
+#define SPR_CSRR0	0x03a		/* Critical Save/Restore Register 0 */
+#define SPR_CSRR1	0x03b		/* Critical Save/Restore Register 1 */
+#define SPR_TBL		0x11c		/* Time Base Lower */
+#define SPR_TBU		0x11d		/* Time Base Upper */
+#define	SPR_PIR		0x11e		/* Processor Identity Register */
+
+#define SPR_TCR	0x154	/* timer control */
+#define SPR_TSR	0x150	/* timer status */
+#define SPR_MMUCR	0x3B2	/* mmu control */
+#define SPR_DNV0	0x390	/* data cache normal victim 0-3 */
+#define SPR_DNV1	0x391
+#define SPR_DNV2	0x392
+#define SPR_DNV3	0x393
+#define SPR_DTV0	0x394	/* data cache transient victim 0-3 */
+#define SPR_DTV1	0x395
+#define SPR_DTV2	0x396
+#define SPR_DTV3	0x397
+#define SPR_DVLIM	0x398	/* data cache victim limit */
+#define SPR_INV0	0x370	/* instruction cache normal victim 0-3 */
+#define SPR_INV1	0x371
+#define SPR_INV2	0x372
+#define SPR_INV3	0x374
+#define SPR_ITV0	0x374	/* instruction cache transient victim 0-3 */
+#define SPR_ITV1	0x375
+#define SPR_ITV2	0x376
+#define SPR_ITV3	0x377
+#define SPR_IVOR(n)	(0x190+(n))	/* interrupt vector offset registers 0-15 */
+#define SPR_IVPR	0x03F	/* instruction vector prefix register */
+#define SPR_IVLIM	0x399	/* instruction cache victim limit */
+
+#define SPR_MCSRR0	0x23A	/* 440GX only */
+#define SPR_MCSRR1	0x23B
+#define SPR_MCSR	0x23C
+
+#define SPR_DEC		0x16	/* on 440 they've gone back to using DEC instead of PIT  ... */
+#define SPR_DECAR	0x36	/* ... with the auto-reload register now visible */
+
+/* 440 */
+
+/* use of SPRG registers in save/restore */
+#define	SAVER0	SPR_SPRG0
+#define	SAVER1	SPR_SPRG1
+#define	SAVELR	SPR_SPRG2
+#define	SAVEXX	SPR_SPRG3
+
+/* special instruction definitions */
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+
+#define	TBRL	268	/* read time base lower in MFTB */
+#define	TBRU	269	/* read time base upper in MFTB */
+#define	MFTB(tbr,d)	WORD	$((31<<26)|((d)<<21)|((tbr&0x1f)<<16)|(((tbr>>5)&0x1f)<<11)|(371<<1))
+
+//#define TLBIA		WORD	$((31<<26)|(370<<1))	// not in 440
+#define	TLBSYNC		WORD	$((31<<26)|(566<<1))
+
+/* 400 models; perhaps others */
+#define	ICCCI(a,b)	WORD	$((31<<26)|((a)<<16)|((b)<<11)|(966<<1))
+#define	DCCCI(a,b)	WORD	$((31<<26)|((a)<<16)|((b)<<11)|(454<<1))
+/* these follow the source -> dest ordering */
+#define	DCREAD(s,t)	WORD	$((31<<26)|((t)<<21)|((s)<<11)|(486<<1))
+#define	DCRF(n)	((((n)>>5)&0x1F)|(((n)&0x1F)<<5))
+#define	MTDCR(s,n)	WORD	$((31<<26)|((s)<<21)|(DCRF(n)<<11)|(451<<1))
+#define	MFDCR(n,t)	WORD	$((31<<26)|((t)<<21)|(DCRF(n)<<11)|(323<<1))
+#define	MSYNC		WORD	$((31<<26)|(598<<1))
+#define	TLBRELO(a,t)	WORD	$((31<<26)|((t)<<21)|((a)<<16)|(2<<11)|(946<<1))
+#define	TLBREMD(a,t)	WORD	$((31<<26)|((t)<<21)|((a)<<16)|(1<<11)|(946<<1))
+#define	TLBREHI(a,t)	WORD	$((31<<26)|((t)<<21)|((a)<<16)|(0<<11)|(946<<1))
+#define	TLBWELO(s,a)	WORD	$((31<<26)|((s)<<21)|((a)<<16)|(2<<11)|(978<<1))
+#define	TLBWEMD(s,a)	WORD	$((31<<26)|((s)<<21)|((a)<<16)|(1<<11)|(978<<1))
+#define	TLBWEHI(s,a)	WORD	$((31<<26)|((s)<<21)|((a)<<16)|(0<<11)|(978<<1))
+#define	TLBSXF(a,b,t)	WORD	$((31<<26)|((t)<<21)|((a)<<16)|((b)<<11)|(914<<1))
+#define	TLBSXCC(a,b,t)	WORD	$((31<<26)|((t)<<21)|((a)<<16)|((b)<<11)|(914<<1)|1)
+/* these are useless because there aren't CE/CEI equivalents for critical interrupts */
+//#define	WRTMSR_EE(s)	WORD	$((31<<26)|((s)<<21)|(131<<1))
+//#define	WRTMSR_EEI(e)	WORD	$((31<<26)|((e)<<15)|(163<<1))
+
+/* on some models mtmsr doesn't synchronise enough (eg, 603e) */
+#define	MSRSYNC	MSYNC; ISYNC
+
+/*
+ * on the 4xx series, the prefetcher madly fetches across RFI, sys call,
+ * and others; use BR 0(PC) to stop.
+ */
+#define	RFI		WORD $((19<<26)|(50<<1)); BR 0(PC)
+// #define	RFCI	WORD	$((19<<26)|(51<<1)); BR 0(PC)
+
+/*
+ * print progress character iff on cpu0.
+ * steps on R7 and R8, needs SB set and TLB entry for i/o registers set.
+ */
+#define STEP(c, zero, notzero) \
+	MOVW	SPR(SPR_PIR), R7; \
+	CMP	R7, R0; \
+	BEQ	zero; \
+	CMP	R7, $017; \
+	BNE	notzero; \
+zero:	MOVW	$(Uartlite+4), R7; \
+	MOVW	$(c), R8; \
+	MOVW	R8, 0(R7); \
+notzero: SYNC
+
+//#define STEP(c, z, nz)
+#define PROG(n)	MOVW $(n), R18		/* pre-uart progress indicator */
+
+#define	UREGSPACE	(UREGSIZE+8)
+
+	NOSCHED
+
+TEXT start<>(SB), 1, $-4
+PROG(1)
+	/* except during trap handling, R0 is zero from now on */
+	MOVW	$0, R0
+
+	/*
+	 * setup MSR
+	 * turn off interrupts (clear ME, CE)
+	 * use 0x000 as exception prefix
+	 * enable kernel vm (clear IS, DS)
+	 * clear, then enable machine checks
+	 */
+	MOVW	$~0, R3
+	MOVW	R3, SPR(SPR_MCSR)	/* clear all bits */
+	MSRSYNC
+	MOVW	R0, SPR(SPR_ESR)
+	MSRSYNC
+PROG(2)
+	MOVW	$MSR_ME, R3
+	MOVW	R3, MSR
+	MSRSYNC
+	MOVW	R0, CR
+
+	/* setup SB for pre mmu */
+	MOVW	$setSB(SB), R2
+
+	MOVW	$19, R19
+	MOVW	$20, R20
+	MOVW	$21, R21
+	MOVW	$22, R22
+	MOVW	$23, R23
+	MOVW	$24, R24
+PROG(3)
+#ifndef MICROBOOT
+	/*
+	 * Invalidate the caches.
+	 */
+	ICCCI(0, 2)  /* errata cpu_121 reveals that EA is used; we'll use SB */
+	DCCCI(0, 2)		/* dcache must not be in use */
+	MSYNC
+#endif
+	MOVW	R0, SPR(SPR_DBCR0)
+	MOVW	R0, SPR(SPR_DBCR1)
+	MOVW	R0, SPR(SPR_DBCR2)
+	ISYNC
+	MOVW	$~0, R3
+	MOVW	R3, SPR(SPR_DBSR)
+
+	/*
+	 * CCR0:
+	 *	recover from data parity = 1
+	 *	disable gathering = 0
+	 *	disable trace broadcast = 1
+	 *	force load/store alignment = 0 (was 1)
+	 *	0: fill 1+0 speculative lines on icache miss
+	 * CCR1:
+	 *	normal parity, normal cache operation
+	 *	cpu timer advances with tick of CPU input clock (not timer clock)   TO DO?
+	 */
+#ifndef MICROBOOT
+	MOVW	$((1<<30)|(0<<21)|(1<<15)|(0<<8)|(0<<2)), R3
+	MOVW	R3, SPR(SPR_CCR0)
+	MOVW	$(0<<7), R3	/* TCS=0 */
+	MOVW	R3, SPR(SPR_CCR1)
+#endif
+	/* clear i/d cache regions */
+	MOVW	R0, SPR(SPR_INV0)
+	MOVW	R0, SPR(SPR_INV1)
+	MOVW	R0, SPR(SPR_INV2)
+	MOVW	R0, SPR(SPR_INV3)
+	MOVW	R0, SPR(SPR_DNV0)
+	MOVW	R0, SPR(SPR_DNV1)
+	MOVW	R0, SPR(SPR_DNV2)
+	MOVW	R0, SPR(SPR_DNV3)
+
+	/* set i/d cache limits (all normal) */
+	MOVW	$((0<<22)|(63<<11)|(0<<0)), R3	/* TFLOOR=0, TCEILING=63 ways, NFLOOR = 0 */
+	MOVW	R3, SPR(SPR_DVLIM)
+	MOVW	R3, SPR(SPR_IVLIM)
+
+PROG(4)
+	/*
+	 * set other system configuration values
+	 */
+	MOVW	R0, SPR(SPR_TBL)
+	MOVW	R0, SPR(SPR_TBU)
+	MOVW	R0, SPR(SPR_DEC)
+	MOVW	$~0, R3
+	MOVW	R3, SPR(SPR_TSR)
+	MOVW	R0, SPR(SPR_TCR)
+	ISYNC
+
+	/*
+	 * on the 440, the mmu is always on; kernelmmu just adds tlb entries.
+	 * ppc440x5 cpu core manual §3.1 has the story about shadow
+	 * tlbs and the like at reset.
+	 */
+PROG(5)
+	BL	kernelmmu(SB)
+	/* now running with MMU initialised & in kernel address space */
+
+	TLBWEHI(0,0)
+	TLBWEMD(0,0)
+	TLBWELO(0,0)
+
+	MOVW	$setSB(SB), R2
+	/* it's now safe to print */
+STEP('\r', zerobootcr, notbootcr)
+STEP('\n', zerobootnl, notbootnl)
+STEP('P',  zerobootP,  notbootP)
+
+	/* make the vectors match the old values */
+	MOVW	$PHYSSRAM, R3
+	MOVW	R3, SPR(SPR_IVPR)	/* vector prefix at PHYSSRAM */
+	MOVW	$INT_CI, R3
+	MOVW	R3, SPR(SPR_IVOR(0))
+	MOVW	$INT_MCHECK, R3
+	MOVW	R3, SPR(SPR_IVOR(1))
+	MOVW	$INT_DSI, R3
+	MOVW	R3, SPR(SPR_IVOR(2))
+	MOVW	$INT_ISI, R3
+	MOVW	R3, SPR(SPR_IVOR(3))
+	MOVW	$INT_EI, R3
+	MOVW	R3, SPR(SPR_IVOR(4))
+	MOVW	$INT_ALIGN, R3
+	MOVW	R3, SPR(SPR_IVOR(5))
+	MOVW	$INT_PROG, R3
+	MOVW	R3, SPR(SPR_IVOR(6))
+	MOVW	$INT_FPU, R3
+	MOVW	R3, SPR(SPR_IVOR(7))	/* reserved (FPU?) */
+	MOVW	$INT_SYSCALL, R3
+	MOVW	R3, SPR(SPR_IVOR(8))	/* system call */
+	MOVW	$INT_TRACE, R3
+	MOVW	R3, SPR(SPR_IVOR(9))	/* reserved (trace?) */
+	MOVW	$INT_PIT, R3
+	MOVW	R3, SPR(SPR_IVOR(10))	/* decrementer */
+	MOVW	$INT_FIT, R3
+	MOVW	R3, SPR(SPR_IVOR(11))	/* fixed interval  */
+	MOVW	$INT_WDT, R3
+	MOVW	R3, SPR(SPR_IVOR(12))	/* watchdog */
+	MOVW	$INT_DMISS,	R3
+	MOVW	R3, SPR(SPR_IVOR(13))	/* data TLB */
+	MOVW	$INT_IMISS,	R3
+	MOVW	R3, SPR(SPR_IVOR(14))	/* instruction TLB */
+	MOVW	$INT_DEBUG,  R3
+	MOVW	R3, SPR(SPR_IVOR(15))	/* debug */
+STEP('l', zerobootl, notbootl)
+
+	/*
+	 * Set up SB, vector space (16KiB, 64KiB aligned),
+	 * extern registers (m->, up->) and stack.
+	 * Mach (and stack) will be cleared along with the
+	 * rest of BSS below if this is CPU#0.
+	 * Memstart is the first free memory location
+	 * after the kernel.
+	 */
+	/* set R2 to correct value */
+	MOVW	$setSB(SB), R2
+
+	/* invalidate the caches again to flush any addresses below KZERO */
+	ICCCI(0, 2)  /* errata cpu_121 reveals that EA is used; we'll use SB */
+	ISYNC
+
+	MOVW	SPR(SPR_PIR), R7
+	CMP	R7, $017
+	BNE	notcpu0b
+	MOVW	R0, R7
+notcpu0b:
+	CMP	R0, R7
+	BNE	notcpu0
+
+	/* set up Mach */
+	/* for cpu0 */
+	MOVW	$mach0(SB), R(MACH)
+	/* put stack in sram below microboot temporarily */
+	MOVW	$0xfffffe00, R1
+//	ADD	$(MACHSIZE-8), R(MACH), R1	/* set stack */
+
+//	SUB	$4, R(MACH), R3
+//	ADD	$4, R1, R4
+//clrmach:
+//	MOVWU	R0, 4(R3)
+//	CMP	R3, R4
+//	BNE	clrmach
+
+STEP('a', zeroboota, notboota)
+
+	MOVW	$PHYSSRAM, R6			/* vectors at bottom of sram */
+	MOVW	R0, R(USER)			/* up-> */
+	MOVW	R0, 0(R(MACH))
+
+_CPU0:						/* boot processor */
+	MOVW	$edata-4(SB), R3
+	MOVW	R1, R4				/* stop before microboot */
+_clrbss:					/* clear BSS */
+	MOVWU	R0, 4(R3)
+	CMP	R3, R4
+	BNE	_clrbss
+
+STEP('n', zerobootn, notbootn)
+//	MOVW	R4, memstart(SB)	/* start of unused memory */
+	MOVW	R0, memstart(SB)	/* start of unused memory: dram */
+	MOVW	R6, vectorbase(SB) /* 64KiB aligned vector base, for trapinit */
+
+STEP(' ', zerobootsp, notbootsp)
+	BL	main(SB)
+	BR	0(PC)   		/* paranoia -- not reached */
+
+notcpu0:
+	MOVW	$mach0(SB), R(MACH)
+	ADD	$(MACHSIZE-8), R(MACH)	/* cpu1 */
+	/* put stack in sram below microboot & cpu0's stack temporarily */
+	MOVW	$0xfffffb00, R1
+
+	/* give cpu0 time to set things up */
+	MOVW	$(10*1024*1024), R3
+spin:
+	SUB	$1, R3
+	CMP	R0, R3
+	BNE	spin
+
+	BL	main(SB)
+	BR	0(PC)   		/* paranoia -- not reached */
+
+
+GLOBL	mach0(SB), $(MAXMACH*BY2PG)
+
+TEXT	kernelmmu(SB), 1, $-4
+PROG(6)
+#ifndef MICROBOOT
+	/* make following TLB entries shared, TID=PID=0 */
+	MOVW	R0, SPR(SPR_PID)
+
+	/*
+	 * allocate cache on store miss, disable U1 as transient,
+	 * disable U2 as SWOA, no dcbf or icbi exception, tlbsx search 0.
+	 */
+	MOVW	R0, SPR(SPR_MMUCR)
+	ISYNC
+#endif
+
+	/* map various things 1:1 */
+	MOVW	$tlbtab(SB), R4
+	MOVW	$tlbtabe(SB), R5
+	MOVW	$(3*4), R6	/* sizeof a tlb entry */
+//	ADD	R6, R4		/* skip first 2 TLB entries in tlbtab */
+//	ADD	R6, R4		/* skip first 2 TLB entries in tlbtab */
+	SUB	R4, R5
+	DIVW	R6, R5		/* R5 gets # of tlb entries in table */
+	SUB	$4, R4		/* back up before MOVWU */
+	MOVW	R5, CTR
+	MOVW	$63, R3
+//	SUB	$2, R3		/* skip first 2 TLB entries in TLB (#62-63) */
+	SYNC
+	ISYNC
+PROG(7)
+ltlb:
+	MOVWU	4(R4), R5	/* TLBHI */
+	TLBWEHI(5,3)
+	MOVWU	4(R4), R5	/* TLBMD */
+	TLBWEMD(5,3)
+	MOVWU	4(R4), R5	/* TLBLO */
+	TLBWELO(5,3)
+	SUB	$1, R3
+	BDNZ	ltlb
+PROG(8)
+	/* clear all remaining entries to remove any aliasing from boot */
+#ifndef MICROBOOT
+	CMP	R3, R0
+	BEQ	cltlbe
+	MOVW	R0, R5
+cltlb:
+	/* can't use 0 (R0) as first operand */
+	TLBWEHI(5,3)
+	TLBWEMD(5,3)
+	TLBWELO(5,3)
+	SUB	$1, R3
+	CMP	R3, $0
+	BGE	cltlb
+cltlbe:
+#endif
+	SYNC
+	ISYNC			/* switch to new TLBs */
+PROG(9)
+#ifdef MICROBOOT
+	RETURN
+#else
+	/*
+	 * this is no longer true; the microboot has done this:
+	 * we're currently relying on the shadow I/D TLBs.  to switch to
+	 * the new TLBs, we need a synchronising instruction.
+	 */
+	MOVW	LR, R4
+	MOVW	R4, SPR(SPR_SRR0)
+	MOVW	MSR, R4
+	MOVW	R4, SPR(SPR_SRR1)
+	/*
+	 * resume in kernel mode in caller; R3 has the index of the first
+	 * unneeded TLB entry
+	 */
+	RFI
+#endif
+
+TEXT	tlbinval(SB), 1, $-4
+	TLBWEHI(0, 3)
+	TLBWEMD(0, 3)
+	TLBWELO(0, 3)
+	ISYNC
+	RETURN
+
+TEXT	splhi(SB), 1, $-4
+	MOVW	MSR, R3
+	RLWNM	$0, R3, $~MSR_EE, R4
+	RLWNM	$0, R4, $~MSR_CE, R4
+	MOVW	R4, MSR
+	MSRSYNC
+	MOVW	LR, R31
+	MOVW	R31, 4(R(MACH))	/* save PC in m->splpc */
+	RETURN
+
+TEXT	splx(SB), 1, $-4
+	MOVW	LR, R31
+	MOVW	R31, 4(R(MACH))	/* save PC in m->splpc */
+	/* fall though */
+
+TEXT	splxpc(SB), 1, $-4
+	MOVW	MSR, R4
+	RLWMI	$0, R3, $MSR_EE, R4
+	RLWMI	$0, R3, $MSR_CE, R4
+	MOVW	R4, MSR
+	MSRSYNC
+	RETURN
+
+TEXT	spllo(SB), 1, $-4
+	MOVW	MSR, R3
+	OR	$MSR_EE, R3, R4
+	OR	$MSR_CE, R4
+	MOVW	R4, MSR
+	MSRSYNC
+	RETURN
+
+TEXT	spldone(SB), 1, $-4
+	RETURN
+
+TEXT	islo(SB), 1, $-4
+	MOVW	MSR, R3
+	MOVW	$(MSR_EE|MSR_CE), R4
+	AND	R4, R3
+	RETURN
+
+/* invalidate region of i-cache */
+TEXT	icflush(SB), 1, $-4	/* icflush(virtaddr, count) */
+	MOVW	n+4(FP), R4
+	RLWNM	$0, R3, $~(ICACHELINESZ-1), R5
+	SUB	R5, R3
+	ADD	R3, R4
+	ADD	$(ICACHELINESZ-1), R4
+	SRAW	$ICACHELINELOG, R4
+	MOVW	R4, CTR
+icf0:	ICBI	(R5)
+	ADD	$ICACHELINESZ, R5
+	BDNZ	icf0
+	ISYNC
+	RETURN
+
+TEXT	sync(SB), 1, $0
+	SYNC
+	RETURN
+
+TEXT	isync(SB), 1, $0
+	ISYNC
+	RETURN
+
+/* write-back then invalidate region of d-cache */
+TEXT	dcflush(SB), 1, $-4	/* dcflush(virtaddr, count) */
+	MOVW	n+4(FP), R4
+	RLWNM	$0, R3, $~(DCACHELINESZ-1), R5
+	CMP	R4, $0
+	BLE	dcf1
+	SYNC
+	SUB	R5, R3
+	ADD	R3, R4
+	ADD	$(DCACHELINESZ-1), R4
+	SRAW	$DCACHELINELOG, R4
+	MOVW	R4, CTR
+dcf0:	DCBF	(R5)
+	ADD	$DCACHELINESZ, R5
+	BDNZ	dcf0
+dcf1:
+	SYNC
+	RETURN
+
+TEXT	cacheson(SB), 1, $-4
+	MOVW	$1, R3			/* return value: true iff caches on */
+	RETURN
+
+TEXT	cachesinvalidate(SB), 1, $-4
+	ICCCI(0, 2) /* errata cpu_121 reveals that EA is used; we'll use SB */
+	DCCCI(0, 2) /* dcache must not be in use (or just needs to be clean?) */
+	MSYNC
+	RETURN
+
+TEXT	getpit(SB), 1, $0
+	MOVW	SPR(SPR_DEC), R3	/* they've moved it back to DEC */
+	RETURN
+
+TEXT	putpit(SB), 1, $0
+	MOVW	R3, SPR(SPR_DEC)
+	MOVW	R3, SPR(SPR_DECAR)
+	RETURN
+
+TEXT	putpid(SB), 1, $0
+	MOVW	R3, SPR(SPR_PID)
+	MOVW	SPR(SPR_MMUCR), R4
+	RLWMI	$0, R3, $0xFF, R4
+	MOVW	R4, SPR(SPR_MMUCR)
+	RETURN
+
+TEXT	getpid(SB), 1, $0
+	MOVW	SPR(SPR_PID), R3
+	RETURN
+
+TEXT	getpir(SB), 1, $-4
+	MOVW	SPR(SPR_PIR), R3
+	CMP	R3, $017
+	BNE	normal
+	MOVW	R0, R3
+normal:
+	RETURN
+
+TEXT	putstid(SB), 1, $0
+	MOVW	SPR(SPR_MMUCR), R4
+	RLWMI	$0, R3, $0xFF, R4
+	MOVW	R4, SPR(SPR_MMUCR)
+	RETURN
+
+TEXT	getstid(SB), 1, $0
+	MOVW	SPR(SPR_MMUCR), R3
+	RLWNM	$0, R3, $0xFF, R3
+	RETURN
+
+TEXT	gettbl(SB), 1, $0
+	MFTB(TBRL, 3)
+	RETURN
+
+TEXT	gettbu(SB), 1, $0
+	MFTB(TBRU, 3)
+	RETURN
+
+TEXT	gettsr(SB), 1, $0
+	MOVW	SPR(SPR_TSR), R3
+	RETURN
+
+TEXT	puttsr(SB), 1, $0
+	MOVW	R3, SPR(SPR_TSR)
+	RETURN
+
+TEXT	puttcr(SB), 1, $0
+	MOVW	R3, SPR(SPR_TCR)
+	RETURN
+
+TEXT	getpvr(SB), 1, $0
+	MOVW	SPR(SPR_PVR), R3
+	RETURN
+
+TEXT	getmsr(SB), 1, $0
+	MOVW	MSR, R3
+	RETURN
+
+TEXT	putmsr(SB), 1, $0
+	SYNC
+	MOVW	R3, MSR
+	MSRSYNC
+	RETURN
+
+TEXT	getmcsr(SB), 1, $0
+	MOVW	SPR(SPR_MCSR), R3
+	RETURN
+
+TEXT	putmcsr(SB), 1, $-4
+	MOVW	R3, SPR(SPR_MCSR)
+	RETURN
+
+TEXT	getesr(SB), 1, $0
+	MOVW	SPR(SPR_ESR), R3
+	RETURN
+
+TEXT	putesr(SB), 1, $0
+	MOVW	R3, SPR(SPR_ESR)
+	RETURN
+
+TEXT	putevpr(SB), 1, $0
+	MOVW	R3, SPR(SPR_IVPR)
+	RETURN
+
+TEXT getccr0(SB), 1, $-4
+	MOVW	SPR(SPR_CCR0), R3
+	RETURN
+
+TEXT	setsp(SB), 1, $0
+	MOVW	R3, R1
+	RETURN
+
+TEXT	getsp(SB), 1, $0
+	MOVW	R1, R3
+	RETURN
+
+TEXT	getdear(SB), 1, $0
+	MOVW	SPR(SPR_DEAR), R3
+	RETURN
+
+TEXT	tas32(SB), 1, $0
+	SYNC
+	MOVW	R3, R4
+	MOVW	$0xdead,R5
+tas1:
+	DCBF	(R4)	/* fix for 603x bug */
+	LWAR	(R4), R3
+	CMP	R3, $0
+	BNE	tas0
+	STWCCC	R5, (R4)
+	BNE	tas1
+tas0:
+	SYNC
+	ISYNC
+	RETURN
+
+TEXT	eieio(SB), 1, $0
+	EIEIO
+	RETURN
+
+TEXT	syncall(SB), 1, $0
+	SYNC
+	ISYNC
+	RETURN
+
+TEXT	_xinc(SB), 1, $0	/* void _xinc(long *); */
+	MOVW	R3, R4
+xincloop:
+	DCBF	(R4)		/* fix for 603x bug */
+	LWAR	(R4), R3
+	ADD	$1, R3
+	STWCCC	R3, (R4)
+	BNE	xincloop
+	RETURN
+
+TEXT	_xdec(SB), 1, $0	/* long _xdec(long *); */
+	MOVW	R3, R4
+xdecloop:
+	DCBF	(R4)		/* fix for 603x bug */
+	LWAR	(R4), R3
+	ADD	$-1, R3
+	STWCCC	R3, (R4)
+	BNE	xdecloop
+	RETURN
+
+TEXT cas32(SB), 1, $0			/* int cas32(void*, u32int, u32int) */
+	MOVW	R3, R4			/* addr */
+	MOVW	old+4(FP), R5
+	MOVW	new+8(FP), R6
+	DCBF	(R4)			/* fix for 603x bug? */
+	LWAR	(R4), R3
+	CMP	R3, R5
+	BNE	 fail
+	STWCCC	R6, (R4)
+	BNE	 fail
+	MOVW	 $1, R3
+	RETURN
+fail:
+	MOVW	 $0, R3
+	RETURN
+
+TEXT	tlbwrx(SB), 1, $-4
+	MOVW	hi+4(FP), R5
+	MOVW	mid+8(FP), R6
+	MOVW	lo+12(FP), R7
+	MSYNC
+	TLBWEHI(5, 3)
+	TLBWEMD(6, 3)
+	TLBWELO(7, 3)
+	ISYNC
+	RETURN
+
+TEXT	tlbrehi(SB), 1, $-4
+	TLBREHI(3, 3)
+	RETURN
+
+TEXT	tlbremd(SB), 1, $-4
+	TLBREMD(3, 3)
+	RETURN
+
+TEXT	tlbrelo(SB), 1, $-4
+	TLBRELO(3, 3)
+	RETURN
+
+TEXT	tlbsxcc(SB), 1, $-4
+	TLBSXCC(0, 3, 3)
+	BEQ	tlbsxcc0
+	MOVW	$-1, R3	/* not found */
+tlbsxcc0:
+	RETURN
+
+TEXT	gotopc(SB), 1, $0
+	MOVW	R3, CTR
+	MOVW	LR, R31	/* for trace back */
+	BR	(CTR)
+
+
+/*
+ * following Book E, traps thankfully leave the mmu on.
+ * the following code has been executed at the exception
+ * vector location already:
+ *	MOVW R0, SPR(SAVER0)
+ *	MOVW LR, R0
+ *	MOVW R0, SPR(SAVELR)
+ *	BL	trapvec(SB)
+ */
+TEXT	trapvec(SB), 1, $-4
+	MOVW	LR, R0
+	MOVW	R0, SPR(SAVEXX)	/* save ivoff--interrupt vector offset */
+/* entry point for critical interrupts, machine checks, and faults */
+trapcommon:
+	MOVW	R1, SPR(SAVER1)		/* save stack pointer */
+	/* did we come from user space? */
+	MOVW	SPR(SPR_SRR1), R0
+	MOVW	CR, R1
+	MOVW	R0, CR
+	BC	4,17,ktrap		/* if MSR[PR]=0, we are in kernel space */
+
+	/* switch to kernel stack */
+	MOVW	R1, CR
+
+	MOVW	SPR(SPR_SPRG7R), R1 /* up->kstack+KSTACK-UREGSPACE, set in touser and sysrforkret */
+
+	BL	saveureg(SB)
+	MOVW	$mach0(SB), R(MACH)
+	MOVW	8(R(MACH)), R(USER)
+	BL	trap(SB)
+	BR	restoreureg
+
+ktrap:
+	MOVW	R1, CR
+	MOVW	SPR(SAVER1), R1
+	SUB	$UREGSPACE, R1	/* push onto current kernel stack */
+	BL	saveureg(SB)
+	BL	trap(SB)
+
+restoreureg:
+	MOVMW	48(R1), R2	/* r2:r31 */
+	/* defer R1 */
+	MOVW	40(R1), R0
+	MOVW	R0, SPR(SAVER0)
+	MOVW	36(R1), R0
+	MOVW	R0, CTR
+	MOVW	32(R1), R0
+	MOVW	R0, XER
+	MOVW	28(R1), R0
+	MOVW	R0, CR	/* CR */
+	MOVW	24(R1), R0
+	MOVW	R0, LR
+	MOVW	20(R1), R0
+	MOVW	R0, SPR(SPR_SPRG7W)	/* kstack for traps from user space */
+	MOVW	16(R1), R0
+	MOVW	R0, SPR(SPR_SRR0)	/* old PC */
+	MOVW	12(R1), R0
+	RLWNM	$0, R0, $~MSR_WE, R0	/* remove wait state */
+	MOVW	R0, SPR(SPR_SRR1)	/* old MSR */
+	/* cause, skip */
+	MOVW	44(R1), R1	/* old SP */
+	MOVW	SPR(SAVER0), R0
+	RFI
+
+/*
+ * critical trap/interrupt.
+ * the only one we can take is machine check, synchronously, and
+ * outside any other trap handler.
+ * [MSR_ME not cleared => handler may be interrupted by machine check]
+ */
+TEXT	trapcritvec(SB), 1, $-4
+	MOVW	LR, R0
+	MOVW	R0, SPR(SAVEXX)
+	MOVW	SPR(SPR_CSRR0), R0		/* PC or excepting insn */
+	MOVW	R0, SPR(SPR_SRR0)
+	MOVW	SPR(SPR_CSRR1), R0		/* old MSR */
+	MOVW	R0, SPR(SPR_SRR1)
+	BR	trapcommon
+
+/*
+ * machine check.
+ * make it look like the others.
+ */
+TEXT	trapmvec(SB), 1, $-4
+	MOVW	LR, R0
+	MOVW	R0, SPR(SAVEXX)
+	MOVW	SPR(SPR_MCSRR0), R0		/* PC or excepting insn */
+	MOVW	R0, SPR(SPR_SRR0)
+	MOVW	SPR(SPR_MCSRR1), R0		/* old MSR */
+	MOVW	R0, SPR(SPR_SRR1)
+	BR	trapcommon
+
+/*
+ * enter with stack set and mapped.
+ * on return, SB (R2) has been set, and R3 has the Ureg*,
+ * the MMU has been re-enabled, kernel text and PC are in KSEG,
+ * Stack (R1), R(MACH) and R(USER) are set by caller, if required.
+ */
+TEXT	saveureg(SB), 1, $-4
+/*
+ * save state
+ */
+	MOVMW	R2, 48(R1)		/* save gprs r2 to r31 */
+	MOVW	$setSB(SB), R2
+	MOVW	SPR(SAVER1), R4
+	MOVW	R4, 44(R1)
+	MOVW	SPR(SAVER0), R5
+	MOVW	R5, 40(R1)
+	MOVW	CTR, R6
+	MOVW	R6, 36(R1)
+	MOVW	XER, R4
+	MOVW	R4, 32(R1)
+	MOVW	CR, R5
+	MOVW	R5, 28(R1)
+	MOVW	SPR(SAVELR), R6	/* LR */
+	MOVW	R6, 24(R1)
+	MOVW	SPR(SPR_SPRG7R), R6	/* up->kstack+KSTACK-UREGSPACE */
+	MOVW	R6, 20(R1)
+	MOVW	SPR(SPR_SRR0), R0
+	MOVW	R0, 16(R1)		/* PC of excepting insn (or next insn) */
+	MOVW	SPR(SPR_SRR1), R0
+	MOVW	R0, 12(R1)		/* old MSR */
+	MOVW	SPR(SAVEXX), R0
+	MOVW	R0, 8(R1)		/* cause/vector */
+	ADD	$8, R1, R3		/* Ureg* */
+	STWCCC	R3, (R1)		/* break any pending reservations */
+	MOVW	$0, R0		/* compiler/linker expect R0 to be zero */
+	RETURN
+
+/*
+ * restore state from Ureg and return from trap/interrupt
+ */
+TEXT sysrforkret(SB), 1, $-4
+	MOVW	R1, 20(R1)	/* up->kstack+KSTACK-UREGSPACE set in ureg */
+	BR	restoreureg
+
+/*
+ * 4xx specific
+ */
+TEXT	firmware(SB), 1, $0
+	MOVW	$(3<<28), R3
+	MOVW	R3, SPR(SPR_DBCR0)	/* system reset */
+	BR	0(PC)

+ 102 - 0
sys/src/boot/vt5/libc.h

@@ -0,0 +1,102 @@
+/*
+ * functions (possibly) linked in, complete, from libc.
+ */
+#define nelem(x)	(sizeof(x)/sizeof((x)[0]))
+#define offsetof(s, m)	(ulong)(&(((s*)0)->m))
+#define assert(x)	if(x){}else _assert("x")
+
+/*
+ * mem routines
+ */
+extern void* memset(void*, int, ulong);
+extern int memcmp(void*, void*, ulong);
+extern void* memmove(void*, void*, ulong);
+
+/*
+ * string routines
+ */
+extern int cistrcmp(char *, char *);
+extern int cistrncmp(char *, char *, int);
+extern char *strchr(char *, int);
+extern int strcmp(char *, char *);
+extern char* strecpy(char*, char*, char*);
+extern long strlen(char*);
+extern int strncmp(char *, char *, int);
+extern char* strncpy(char*, char*, long);
+extern char* strstr(char *, char *);
+extern int tokenize(char*, char**, int);
+
+/*
+ * malloc
+ */
+extern void free(void*);
+extern void* malloc(ulong);
+extern void* mallocalign(ulong, ulong, long, ulong);
+extern int mallocinit(void*, ulong);
+
+/*
+ * print routines
+ */
+typedef struct Fmt Fmt;
+struct Fmt {
+	uchar	runes;			/* output buffer is runes or chars? */
+	void*	start;			/* of buffer */
+	void*	to;			/* current place in the buffer */
+	void*	stop;			/* end of the buffer; overwritten if flush fails */
+	int	(*flush)(Fmt*);		/* called when to == stop */
+	void*	farg;			/* to make flush a closure */
+	int	nfmt;			/* num chars formatted so far */
+	va_list	args;			/* args passed to dofmt */
+	int	r;			/* % format Rune */
+	int	width;
+	int	prec;
+	ulong	flags;
+};
+
+extern int print(char*, ...);
+extern char* seprint(char*, char*, char*, ...);
+extern char* vseprint(char*, char*, char*, va_list);
+
+#pragma	varargck	argpos	print		1
+#pragma	varargck	argpos	seprint		3
+
+#pragma	varargck	type	"lld"	vlong
+#pragma	varargck	type	"llx"	vlong
+#pragma	varargck	type	"lld"	uvlong
+#pragma	varargck	type	"llx"	uvlong
+#pragma	varargck	type	"ld"	long
+#pragma	varargck	type	"lx"	long
+#pragma	varargck	type	"ld"	ulong
+#pragma	varargck	type	"lx"	ulong
+#pragma	varargck	type	"d"	int
+#pragma	varargck	type	"x"	int
+#pragma	varargck	type	"c"	int
+#pragma	varargck	type	"C"	int
+#pragma	varargck	type	"d"	uint
+#pragma	varargck	type	"x"	uint
+#pragma	varargck	type	"c"	uint
+#pragma	varargck	type	"C"	uint
+#pragma	varargck	type	"s"	char*
+#pragma	varargck	type	"q"	char*
+#pragma	varargck	type	"S"	Rune*
+#pragma	varargck	type	"%"	void
+#pragma	varargck	type	"p"	uintptr
+#pragma	varargck	type	"p"	void*
+#pragma	varargck	flag	','
+#pragma	varargck	type	"E"	uchar*	/* eipfmt */
+#pragma	varargck	type	"V"	uchar*	/* eipfmt */
+
+extern int fmtinstall(int, int (*)(Fmt*));
+extern int dofmt(Fmt*, char*);
+
+/*
+ * one-of-a-kind
+ */
+extern void _assert(char*);
+extern uintptr getcallerpc(void*);
+extern long strtol(char*, char**, int);
+extern ulong strtoul(char*, char**, int);
+extern	void	longjmp(jmp_buf, int);
+extern	int	setjmp(jmp_buf);
+
+extern char etext[], edata[], end[];

+ 209 - 0
sys/src/boot/vt5/mem.h

@@ -0,0 +1,209 @@
+/*
+ * Memory and machine-specific definitions.  Used in C and assembler.
+ */
+#define KiB		1024u			/* Kibi 0x0000000000000400 */
+#define MiB		1048576u		/* Mebi 0x0000000000100000 */
+#define GiB		1073741824u		/* Gibi 000000000040000000 */
+#define TiB		1099511627776ull	/* Tebi 0x0000010000000000 */
+#define PiB		1125899906842624ull	/* Pebi 0x0004000000000000 */
+#define EiB		1152921504606846976ull	/* Exbi 0x1000000000000000 */
+
+#define HOWMANY(x, y)	(((x)+((y)-1))/(y))
+#define ROUNDUP(x, y)	(HOWMANY((x), (y))*(y))
+#define ROUNDDN(x, y)	(((x)/(y))*(y))
+#define MIN(a, b)	((a) < (b)? (a): (b))
+#define MAX(a, b)	((a) > (b)? (a): (b))
+
+/*
+ * Sizes
+ */
+#define BI2BY		8			/* bits per byte */
+#define BY2V		8			/* bytes per vlong */
+#define BY2SE		4			/* bytes per stack element */
+#define BY2WD		4			/* bytes per int */
+#define BY2PG		4096			/* bytes per page */
+#define PGSHIFT		12			/* log(BY2PG) */
+#define PGROUND(s)	ROUNDUP(s, BY2PG)
+#define UTROUND(t)	ROUNDUP((t), 0x100000)
+#define STACKALIGN(sp)	((sp) & ~7)		/* bug: assure with alloc */
+
+#define ICACHESIZE	32768			/* 0, 4, 8, 16, or 32 KB */
+#define ICACHEWAYSIZE	(ICACHESIZE/64)		/* 64-way set associative */
+#define ICACHELINELOG	5			/* 8 words (4 bytes) per line */
+#define ICACHELINESZ	(1<<ICACHELINELOG)
+
+#define DCACHESIZE	32768			/* 0, 4, 8, 16, or 32 KB */
+#define DCACHEWAYSIZE	(DCACHESIZE/64)		/* 64-way set associative */
+#define DCACHELINELOG	5			/* 8 words (4 bytes) per line */
+#define DCACHELINESZ	(1<<DCACHELINELOG)
+
+#define BLOCKALIGN	DCACHELINESZ		/* for ../port/allocb.c */
+
+#define MAXMACH		2			/* max # cpus system can run */
+#define MACHSIZE	BY2PG
+
+/*
+ * Time
+ */
+#define HZ		100			/* clock frequency */
+#define MHz		1000000
+#define TK2SEC(t)	((t)/HZ)		/* ticks to seconds */
+
+/*
+ * IBM bit field order
+ * used only to derive bit mask for interrupt vector numbers
+ */
+#define IBIT(n)	(1UL<<(31-(n)))
+
+/*
+ * Bit encodings for Machine State Register (MSR)
+ */
+#define MSR_AP	0x02000000	/* auxiliary processor available */
+#define MSR_APE	0x00080000	/* APU exception enable */
+#define MSR_WE	0x00040000	/* wait state enable */
+#define MSR_CE	0x00020000	/* critical interrupt enable */
+#define MSR_EE	0x00008000	/* enable external/decrementer interrupts */
+#define MSR_PR	0x00004000	/* =1, user mode */
+#define MSR_FP	0x00002000	/* floating-point available */
+#define MSR_ME	0x00001000	/* enable machine check exceptions */
+#define MSR_FE0	0x00000800	/* floating-point exception mode 0 */
+#define MSR_DWE	0x00000400	/* debug wait enable */
+#define MSR_DE	0x00000200	/* debug interrupts enable */
+#define MSR_FE1	0x00000100	/* floating-point exception mode 1 */
+#define MSR_IS	0x00000020	/* instruction address space */
+#define MSR_DS	0x00000010	/* data address space */
+
+/* state in user mode */
+#define UMSR	(MSR_PR|MSR_CE|MSR_EE|MSR_DE)
+
+/*
+ * Exception Syndrome Register (ESR)
+ */
+#define ESR_MCI	0x80000000	/* instruction machine check */
+#define ESR_PIL	0x08000000	/* program interrupt: illegal instruction */
+#define ESR_PPR	0x04000000	/* program interrupt: privileged */
+#define ESR_PTR	0x02000000	/* program interrupt: trap with successful compare */
+#define ESR_PEU	0x01000000	/* program interrupt: unimplemented APU/FPU operation */
+#define ESR_DST	0x00800000	/* data storage interrupt: store fault */
+#define ESR_DIZ	0x00400000	/* data/instruction storage interrupt: zone fault */
+#define ESR_PFP	0x00080000	/* program interrupt: FPU interrupt occurred */
+#define ESR_PAP	0x00040000	/* program interrupt: APU interrupt occurred */
+#define ESR_U0F	0x00008000	/* data storage interrupt: u0 fault */
+
+/*
+ * Interrupt vector offsets
+ */
+#define INT_CI		0x0100		/* Critical input interrupt */
+#define INT_MCHECK	0x0200		/* Machine check */
+#define INT_DSI		0x0300		/* Data storage interrupt */
+#define INT_ISI		0x0400		/* Instruction storage interrupt */
+#define INT_EI		0x0500		/* External interrupt */
+#define INT_ALIGN	0x0600		/* Alignment */
+#define INT_PROG	0x0700		/* Program */
+#define INT_FPU		0x0800		/* FPU unavailable */
+#define INT_DEC		0x0900		/* UNUSED on 405? */
+#define INT_SYSCALL	0x0C00		/* System call */
+#define INT_TRACE	0x0D00		/* UNUSED on 405? */
+#define INT_FPA		0x0E00		/* UNUSED on 405? */
+#define INT_APU		0x0F20		/* APU unavailable */
+#define INT_PIT		0x1000		/* PIT interrupt */
+#define INT_FIT		0x1010		/* FIT interrupt */
+#define INT_WDT		0x1020		/* Watchdog timer */
+#define INT_DMISS	0x1100		/* Data TLB miss */
+#define INT_IMISS	0x1200		/* Instruction TLB miss */
+#define INT_DEBUG	0x2000		/* Debug */
+
+/*
+ * Magic registers
+ */
+#define MACH		30		/* R30 is m-> */
+#define USER		29		/* R29 is up-> */
+
+/*
+ * Virtual MMU
+ */
+#define PTEMAPMEM	(1024*1024)
+#define PTEPERTAB	(PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE	1984
+#define SSEGMAPSIZE	16
+#define PPN(x)		((x)&~(BY2PG-1))
+
+#define PTEVALID	(1<<0)
+#define PTEWRITE	(1<<1)
+#define PTERONLY	(0<<1)
+#define PTEUNCACHED	(1<<2)
+
+/*
+ * Physical MMU
+ */
+#define NTLB		64	/* number of entries */
+#define NTLBPID		256	/* number of hardware pids (0 = global) */
+
+/* TLBHI */
+#define TLBEPN(x)	((x) & ~0x3FF)
+#define TLB1K		(0<<4)
+#define TLB4K		(1<<4)
+#define TLB16K		(2<<4)
+#define TLB64K		(3<<4)
+#define TLB256K		(4<<4)
+#define TLB1MB		(5<<4)
+/* 4Mbyte not implemented */
+#define TLB16MB		(7<<4)
+/* 32Mbyte not implemented */
+#define TLB256MB	(9<<4)
+#define TLBVALID		(1<<9)
+#define TLBTS		(1<<8) /* Translation address space */
+
+/* TLBMID */
+#define TLBRPN(x)	((x) & ~0x3FF)
+#define TLBERPN(uv)	(((uv)>>32)&0xF)	/* with full address as uvlong */
+
+/* TLBLO */
+#define TLBU0	(1<<15) /* user definable */
+#define TLBU1	(1<<14) /* user definable */
+#define TLBU2	(1<<13) /* user definable */
+#define TLBU3	(1<<12) /* user definable */
+#define TLBW	(1<<11)	/* write-through? */
+#define TLBI	(1<<10)	/* cache inhibit */
+#define TLBM	(1<<9)	/* memory coherent */
+#define TLBG	(1<<8)	/* guarded */
+#define TLBLE	(1<<7)  /* little endian mode */
+#define TLBUX	(1<<5)	/* user execute enable */
+#define TLBUW	(1<<4)  /* user writable */
+#define TLBUR	(1<<3)  /* user readable */
+#define TLBSX	(1<<2)	/* supervisor execute enable */
+#define TLBSW	(1<<1)  /* supervisor writable */
+#define TLBSR	(1<<0)  /* supervisor readable */
+
+#define TLBWR	(TLBSW|TLBSR)
+
+/*
+ * software TLB (for quick reload by [id]tlbmiss)
+ */
+#define STLBLOG		10
+#define STLBSIZE	(1<<STLBLOG)
+
+/*
+ * Address spaces
+ */
+#define KSEG0		0x80000000
+#define KSEG1		0xA0000000		/* uncached alias for KZERO */
+#define KSEGM		0xE0000000		/* mask to check segment */
+#define KZERO		KSEG0			/* base of kernel address space */
+#define KTZERO		(KZERO+0x4000)		/* first address in kernel text */
+
+#define TSTKTOP		KZERO			/* top of temporary stack */
+#define TSTKSIZ		100
+
+#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 KSTACK		8192			/* Size of kernel stack */
+
+#define USTKSIZE	(4*1024*1024)		/* size of user stack */
+#define UREGSIZE	((8+40)*4)
+
+#include "physmem.h"
+
+#define getpgcolor(a)	0		/* ../port/page.c */

+ 69 - 0
sys/src/boot/vt5/microboot.hex

@@ -0,0 +1,69 @@
+warning: -D0x10000000 is ignored because of -R0x4
+ fffffee8:		(268)	TEXT	_main+0(SB),R1,$-4
+ fffffee8: 7c021800	(270)	CMP	R2,R3
+ fffffeec: 41820154	(271)	BEQ	,lastword+001f8(BRANCH)
+ fffffef0: 3c400000 60427ff8(273)	MOVW	$setSB+0(SB),R2
+ fffffef8: 38000000	(275)	MOVW	$0,R0
+ fffffefc: 7c00138c	(277)	WORD	$2080379788,
+ ffffff00: 3c604000 60638000(279)	MOVW	$1073774592,R3
+ ffffff08: 7c73eba6	(280)	MOVW	R3,SPR(947)
+ ffffff0c: 7c030378	(281)	MOVW	$0,R3
+ ffffff10: 7c78dba6	(282)	MOVW	R3,SPR(888)
+ ffffff14: 7c12eba6	(285)	MOVW	R0,SPR(946)
+ ffffff18: 7c00178c	(287)	WORD	$2080380812,
+ ffffff1c: 7c0903a6	(288)	MOVW	R0,CTR
+ ffffff20: 7c0103a6	(289)	MOVW	R0,XER
+ ffffff24: 7c100ba6	(292)	MOVW	R0,SPR(48)
+ ffffff28: 3860003f	(295)	MOVW	$63,R3
+ ffffff2c: 3ca0fffe 60a50230(296)	MOVW	$-130512,R5
+ ffffff34: 7ca307a4	(298)	WORD	$2091059108,
+ ffffff38: 3ca0fffe	(298)	MOVW	$-131072,R5
+ ffffff3c: 7ca30fa4	(300)	WORD	$2091061156,
+ ffffff40: 38a00407	(300)	MOVW	$1031,R5
+ ffffff44: 7ca317a4	(302)	WORD	$2091063204,
+ ffffff48: 3863ffff	(303)	ADD	$-1,R3
+ ffffff4c: 3ca0ffff 60a50230(304)	MOVW	$-64976,R5
+ ffffff54: 7ca307a4	(306)	WORD	$2091059108,
+ ffffff58: 3ca0ffff	(306)	MOVW	$-65536,R5
+ ffffff5c: 7ca30fa4	(308)	WORD	$2091061156,
+ ffffff60: 38a00407	(308)	MOVW	$1031,R5
+ ffffff64: 7ca317a4	(310)	WORD	$2091063204,
+ ffffff68: 3863ffff	(311)	ADD	$-1,R3
+ ffffff6c: 38a00290	(313)	MOVW	$656,R5
+ ffffff70: 7ca307a4	(315)	WORD	$2091059108,
+ ffffff74: 7c050378	(315)	MOVW	$0,R5
+ ffffff78: 7ca30fa4	(317)	WORD	$2091061156,
+ ffffff7c: 38a00807	(317)	MOVW	$2055,R5
+ ffffff80: 7ca317a4	(319)	WORD	$2091063204,
+ ffffff84: 3863ffff	(320)	ADD	$-1,R3
+ ffffff88: 3ca01000 60a50290(321)	MOVW	$268436112,R5
+ ffffff90: 7ca307a4	(323)	WORD	$2091059108,
+ ffffff94: 3ca01000	(323)	MOVW	$268435456,R5
+ ffffff98: 7ca30fa4	(325)	WORD	$2091061156,
+ ffffff9c: 38a00807	(325)	MOVW	$2055,R5
+ ffffffa0: 7ca317a4	(327)	WORD	$2091063204,
+ ffffffa4: 3863ffff	(328)	ADD	$-1,R3
+ ffffffa8: 3ca0f000 60a50250(330)	MOVW	$-268434864,R5
+ ffffffb0: 7ca307a4	(332)	WORD	$2091059108,
+ ffffffb4: 3ca0f000	(332)	MOVW	$-268435456,R5
+ ffffffb8: 7ca30fa4	(334)	WORD	$2091061156,
+ ffffffbc: 38a00503	(334)	MOVW	$1283,R5
+ ffffffc0: 7ca317a4	(336)	WORD	$2091063204,
+ ffffffc4: 3863ffff	(337)	ADD	$-1,R3
+ ffffffc8: 7c050378	(339)	MOVW	R0,R5
+ ffffffcc: 7ca307a4	(343)	WORD	$2091059108,
+ ffffffd0: 7ca30fa4	(344)	WORD	$2091061156,
+ ffffffd4: 7ca317a4	(345)	WORD	$2091063204,
+ ffffffd8: 3863ffff	(346)	ADD	$-1,R3
+ ffffffdc: 7c030000	(347)	CMP	R3,$0
+ ffffffe0: 4080ffec	(348)	BGE	,ztlb+00184(BRANCH)
+ ffffffe4: 80628000	(353)	MOVW	bootstart+0(SB),R3
+ ffffffe8: 7c7a03a6	(354)	MOVW	R3,SPR(26)
+ ffffffec: 7c1b03a6	(355)	MOVW	R0,SPR(27)
+ fffffff0: 4c000064	(357)	RFI	,
+ fffffff4: 4bfffefc	(273)	BR	,000a8(BRANCH)
+ fffffff8:		(359)	TEXT	bootstart+0(SB),R1,$-4
+ fffffff8: fffe2100	(360)	WORD	$-122624,
+ fffffffc: 4bfffef4	(273)	BR	,000a8(BRANCH)
+bootstart: warning: text segment wrapped past 0
+

+ 124 - 0
sys/src/boot/vt5/microboot.s

@@ -0,0 +1,124 @@
+/*
+ * ppc440x5 `microboot': immediately after reset, initialise the machine,
+ * notably TLB entries, sufficiently that we can get out of the last 4K of
+ * memory.  these nonsense constraints appears to be specific to the 440x5.
+ */
+#include	"mem.h"
+
+#define MB	(1024*1024)
+
+#define SPR_PID		0x30		/* Process ID (not the same as 405) */
+#define SPR_MMUCR	0x3B2		/* mmu control */
+#define SPR_CCR0	0x3b3		/* Core Configuration Register 0 */
+#define SPR_CCR1	0x378		/* core configuration register 1 */
+#define SPR_SRR0	0x01a		/* Save/Restore Register 0 */
+#define SPR_SRR1	0x01b		/* Save/Restore Register 1 */
+
+#define	ICCCI(a,b)	WORD	$((31<<26)|((a)<<16)|((b)<<11)|(966<<1))
+#define	DCCCI(a,b)	WORD	$((31<<26)|((a)<<16)|((b)<<11)|(454<<1))
+#define	MSYNC		WORD	$((31<<26)|(598<<1))
+
+#define	TLBWELO(s,a)	WORD	$((31<<26)|((s)<<21)|((a)<<16)|(2<<11)|(978<<1))
+#define	TLBWEMD(s,a)	WORD	$((31<<26)|((s)<<21)|((a)<<16)|(1<<11)|(978<<1))
+#define	TLBWEHI(s,a)	WORD	$((31<<26)|((s)<<21)|((a)<<16)|(0<<11)|(978<<1))
+
+	NOSCHED
+
+	TEXT	_main(SB), 1, $-4
+fakestart:
+	CMP	R2, R3
+	BEQ	lastword		/* force loading of last word */
+start:
+	/* we can't issue a synchronising instr. until tlbs are all loaded */
+	MOVW	$setSB(SB), R2
+
+	MOVW	$0, R0
+	DCCCI(0, 2) /* this flush invalidates the dcache of a 440 (must not be in use) */
+
+	/* see l.s */
+	MOVW	$((1<<30)|(0<<21)|(1<<15)|(0<<8)|(0<<2)), R3
+	MOVW	R3, SPR(SPR_CCR0)
+	MOVW	$(0<<7), R3	/* TCS=0 */
+	MOVW	R3, SPR(SPR_CCR1)
+
+	/* allocate cache on store miss, disable U1 as transient, disable U2 as SWOA, no dcbf or icbi exception, tlbsx search 0 */
+	MOVW	R0, SPR(SPR_MMUCR)
+	ICCCI(0, 2) /* this flushes the icache of a 440; the errata reveals that EA is used; we'll use SB */
+
+	MOVW	R0, CTR
+	MOVW	R0, XER
+
+	/* make following TLB entries shared, TID=PID=0 */
+	MOVW	R0, SPR(SPR_PID)
+
+	/* last two tlb entries cover 128K sram */
+	MOVW	$63, R3
+	MOVW	$(PHYSSRAM | TLB64K | TLBVALID), R5	/* TLBHI */
+	TLBWEHI(5,3)
+	MOVW	$(PHYSSRAM), R5				/* TLBMD */
+	TLBWEMD(5,3)
+	MOVW	$(TLBSR | TLBSX | TLBSW | TLBI), R5	/* TLBLO */
+	TLBWELO(5,3)
+	SUB	$1, R3
+
+	MOVW	$(PHYSSRAM+(64*1024) | TLB64K | TLBVALID), R5	/* TLBHI */
+	TLBWEHI(5,3)
+	MOVW	$(PHYSSRAM+(64*1024)), R5		/* TLBMD */
+	TLBWEMD(5,3)
+	MOVW	$(TLBSR | TLBSX | TLBSW | TLBI), R5	/* TLBLO */
+	TLBWELO(5,3)
+	SUB	$1, R3
+
+	/* cover DRAM in case we're going straight to kernel */
+	MOVW	$(PHYSDRAM | TLB256MB | TLBVALID), R5	/* TLBHI */
+	TLBWEHI(5,3)
+	MOVW	$(PHYSDRAM), R5				/* TLBMD */
+	TLBWEMD(5,3)
+	MOVW	$(TLBSR | TLBSX | TLBSW | TLBW), R5	/* TLBLO */
+	TLBWELO(5,3)
+	SUB	$1, R3
+
+	MOVW	$(PHYSDRAM+(256*MB) | TLB256MB | TLBVALID), R5	/* TLBHI */
+	TLBWEHI(5,3)
+	MOVW	$(PHYSDRAM+(256*MB)), R5		/* TLBMD */
+	TLBWEMD(5,3)
+	MOVW	$(TLBSR | TLBSX | TLBSW | TLBW), R5	/* TLBLO */
+	TLBWELO(5,3)
+	SUB	$1, R3
+
+	/* and I/O registers too.  sigh. */
+	MOVW	$(PHYSMMIO | TLB1MB | TLBVALID), R5	/* TLBHI */
+	TLBWEHI(5,3)
+	MOVW	$(PHYSMMIO), R5				/* TLBMD */
+	TLBWEMD(5,3)
+	MOVW	$(TLBSR | TLBSW | TLBI | TLBG), R5	/* TLBLO */
+	TLBWELO(5,3)
+	SUB	$1, R3
+
+	/* invalidate the other TLB entries for now */
+	MOVW	R0, R5
+ztlb:
+	/* can't use 0 (R0) as first operand */
+	TLBWEHI(5,3)
+	TLBWEMD(5,3)
+	TLBWELO(5,3)
+	SUB	$1, R3
+	CMP	R3, $0
+	BGE	ztlb
+
+	/*
+	 * we're currently relying on the shadow I/D TLBs.  to switch to
+	 * the new TLBs, we need a synchronising instruction.
+	 */
+	MOVW	bootstart(SB), R3
+	MOVW	R3, SPR(SPR_SRR0)
+	MOVW	R0, SPR(SPR_SRR1)	/* new MSR */
+	RFI
+
+TEXT	bootstart(SB), 1, $-4
+	WORD	$0xfffe2100
+lastword:
+	/* this instruction must land at 0xfffffffc */
+/* this jump works for addresses within 32MB of zero (1st & last 32MB) */
+/*	WORD	$((18 << 26) | (0x03FFFFFC & 0xfffe2100) | 2) */
+	BR	start

+ 55 - 0
sys/src/boot/vt5/mkenum

@@ -0,0 +1,55 @@
+#!/bin/rc
+
+awk '
+BEGIN{
+	oargc = 0;
+	for(argc = 1; argc < ARGC; argc++){
+		if(ARGV[argc] !~ /^-.+/ || ARGV[argc] ~ /--/)
+			break;
+		if(ARGV[argc] != "-D")
+			oargv[ARGV[argc]] = oargc++;
+		else
+			DEBUG = 1;
+		ARGV[argc] = "";
+	}
+}
+
+/^enum([ \t]*{|$)/{
+	inenum = 1;
+	if(DEBUG)
+		printf "inenum = 1\n";
+	next;
+}
+
+inenum && /^};$/{
+	if(DEBUG)
+		printf "inenum = 0\n";
+	inenum = 0;
+}
+
+inenum && $0 ~ /^[ \t]+[_A-Za-z][_0-9A-Za-z]+[ \t]+=[ \t]+[0-9A-Z_a-z()<> ]+,/{
+	tab = "\t";
+	if(length($1) < 8)
+		sep = tab tab;
+	else
+		sep = tab;
+	split($3, a, ",");
+	printf "#define %s%s%s", $1, sep, a[1];
+	if(match($0, /\/\*.*\*\/$/)){
+		len = length(a[1]);
+		sep = "";
+		while(len < 24){
+			sep = sep tab;
+			len += 8;
+		}
+		printf "%s%s", sep, substr($0, RSTART);
+	}
+	printf "\n"
+}
+
+/^$/{
+	printf "\n";
+}
+
+END{
+}' $*

+ 56 - 0
sys/src/boot/vt5/mkfile

@@ -0,0 +1,56 @@
+CONF=vt5load
+CONFLIST=vt5load
+BASE=0xfffe2100		# first location after vectors; see PHYSSRAM
+
+objtype=power
+</$objtype/mkfile
+p=9
+
+CFLAGS=$CFLAGS -. -I.
+AFLAGS=$AFLAGS -. -I.
+HFILES=\
+	data.h\
+	define.h\
+	etherif.h\
+	fs.h\
+	include.h\
+	ip.h\
+	libc.h\
+	mem.h\
+	physmem.h\
+	portdata.h\
+	portprototype.h\
+	prototype.h\
+
+all:VQ:	$p$CONF microboot.elf
+
+<| awk -f parse $CONF
+<portmkfile
+
+OBJ=$MACH $DEVS $PORT
+
+$p$CONF:D:	$OBJ mkfile $CONF
+	$LD -o $target.elf -aH5 -l -T$BASE -R4 $OBJ $LIB >$target.list
+	$LD -o $target		-l -T$BASE -R4 $OBJ $LIB
+	size $target
+	nm -n $target | tail -5
+	nm -n $target >$target.names
+
+$OBJ: $HFILES
+
+${objtype}a.h:D:	$objtype.h
+	rc mkenum $objtype.h > $target
+
+install:V:	$p$CONF $p$CONF.elf microboot.elf
+	cp -x $prereq /power
+	{ 9fs lookout  && cp -x $prereq /n/lookout/power } &
+	{ 9fs piestand && cp -x $prereq /n/piestand/power } &
+	{ 9fs slocum && cp $prereq /n/slocum/home/rae/hbsr/ml510 } &
+	wait
+
+microboot.hex microboot.elf: microboot.q
+	# ignore "_main: odd branch target address"
+	$LD -a -o microboot.elf -s -l -H5 -T0xfffffee8 -R4 $prereq >microboot.hex
+
+nuke clean:V:
+	rm -f *.[$OS] *.out *.acid *.elf $p$CONF^* $O.*

+ 12 - 0
sys/src/boot/vt5/mkfilelist

@@ -0,0 +1,12 @@
+#!/bin/rc
+
+rfork e
+switch($#*){
+case 1
+	RE=`{echo *.c | sed 's/ /|/g; s/.*/^(&)$/'}
+	LIST=`{builtin cd $1; ls *.c | grep -v ''$RE''}
+	echo $LIST | sed 's/\.c//g; s/ +/|/g'
+case *
+	exit 'usage'
+}
+exit ''

+ 536 - 0
sys/src/boot/vt5/parse

@@ -0,0 +1,536 @@
+BEGIN{
+	oargc = 0;
+	for(argc = 1; argc < ARGC; argc++){
+		if(ARGV[argc] !~ /^-.+/ || ARGV[argc] ~ /--/)
+			break;
+		if(ARGV[argc] != "-D")
+			oargv[ARGV[argc]] = oargc++;
+		else
+			DEBUG = 1;
+		ARGV[argc] = "";
+	}
+
+	objtype = ENVIRON["objtype"];
+
+	while(getline > 0){
+		if(/^[ \t]*$/ || /^#/)
+			continue;
+
+		if(/^[^ \t]/){
+			#section[$1] = 0;
+			tag = $1;
+		}
+		if(!tag)
+			continue;
+		sub(/^[ \t]*/, "");
+		line[tag, section[tag]++] = $0;
+	}
+
+	o = "";
+	if(!oargc || ("-mkdevlist" in oargv)){
+		s = mkdevlist();
+		if(!("-mkdevlist" in oargv) || (oargc > 1))
+			s = "DEVS=" s;
+		o = o s "\n";
+	}
+	if((!oargc || ("-mkmach" in oargv)) && (objtype in section)){
+		s = mkmach();
+		if(!("-mkmach" in oargv) || (oargc > 1))
+			s = "MACH=" s;
+		o = o s "\n";
+	}
+	if((!oargc || ("-mklib" in oargv)) && ("lib" in section)){
+		s = mklib();
+		if(!("-mklib" in oargv) || (oargc > 1))
+			s = "LIB=" s;
+		o = o s "\n";
+	}
+	if((!oargc || ("-mkport" in oargv) ) && ("port" in section)){
+		s = mkport();
+		if(!("-mkport" in oargv) || (oargc > 1))
+			s = "PORT=" s;
+		o = o s "\n";
+	}
+	if("dbgflg" in section){
+		for(i = 1; i < section["dbgflg"]; i++){
+			n = split(line["dbgflg", i], a);
+			if(n < 2 || n > 4 || a[2] !~ /'[a-zA-Z]'/)
+				continue;
+			if(n > 2 && a[3] !~ /'[a-zA-Z]'/)
+				continue;
+			if(n == 4 && (a[4] < 1 || a[4] >= 128))
+				continue;
+			dbgc[a[1]] = a[2];
+			if(n == 4)
+				dbgflg[a[3]] = a[4];
+			else if(n == 3)
+				dbgflg[a[3]] = 1;
+		}
+	}
+	if((!oargc || ("-mkrules" in oargv)) && ("dir" in section)){
+		o = o mkrules(".", exists, a, c, "-I.");
+		for(i = 1; i < section["dir"]; i++){
+			n = split(line["dir", i], a);
+			dir = "../" a[1];
+			if(n == 1)
+				a[2] = "-I.";
+			s = a[2];
+			o = o mkrules(dir, exists, a, c, s);
+			l = listolate(a, "|");
+			if(l != ""){
+				o = o "^(" l ")\\.$O:R:	" dir "/\\1.s\n";
+				o = o "\t$AS $AFLAGS " s " " dir "/$stem1.s\n";
+			}
+			l = listolate(c, "|");
+			if(l != ""){
+				o = o "^(" l ")\\.$O:R:	" dir "/\\1.c\n";
+				o = o "\t$CC $CFLAGS " s " " dir "/$stem1.c\n";
+			}
+		}
+	}
+	if((!oargc || ("-mkrootrules" in oargv)) && ("rootdir" in section)){
+		mkrootrules(name, cname, src);
+		s = ARGV[argc] ".root.s:D:";
+		for(i = 1; i < section["rootdir"]; i++)
+			s = s " " src[i];
+		s = s "\n\tmkrootall\\\n";
+		for(i = 1; i < section["rootdir"]; i++)
+			s = s "\t\t" name[i] " " cname[i] " " src[i] "\\\n";
+		s = s "\t>$target\n";
+		if(section["rootdir"] > 1)
+			o = o s;
+	}
+	if((!oargc || ("-mkrrrules" in oargv)) && ("rr" in section)){
+		n = split(line["rr", 0], a);
+		if(n == 1)
+			a[2] = ARGV[argc] ".proto";
+		s = "$CONF.rr:\tmkrr $CONF " a[2] "\n";
+		s = s "\tmkrr $CONF " a[2] "\n";
+		for(i = 1; i < section["rr"]; i++)
+			s = s "$CONF.rr:\t" line["rr", i] "\n";
+		o = o s;
+	}
+	if("-mkdevc" in oargv)
+		o = o mkdevc();
+	if("-mkerrstr" in oargv)
+		o = o mkerrstr();
+	if("-mksystab" in oargv)
+		o = o mksystab();
+	if("-mkbootconf" in oargv)
+		o = o mkbootconf();
+
+	#
+	# to do:
+	#	bootmkfile
+	#	mkrootall (can it be done at all?)
+	#
+	printf o;
+
+	exit 0;
+}
+
+function mkbootconf(				a, n, s, t, u, c, d, p, r){
+	s = "#include <u.h>\n";
+	s = s "#include <libc.h>\n\n";
+	s = s "#include \"../boot/boot.h\"\n\n";
+	s = s "Method method[] = {\n";
+
+	c = "0";
+	d = "#S/sdC0/";
+	p = "boot";
+	r = "/root";
+
+	for(i = 0; i < section["boot"]; i++){		# NOTE: start at 0
+		n = split(line["boot", i], a);
+		if(a[1] == "boot"){
+			if(a[2] == "cpu"){
+				c = "1";
+				if(n == 4 && a[3] == "boot")
+					d = a[4];
+			}
+			else if(a[2] == "rootdir" && n == 3)
+				r = a[3];
+			else if(a[2] ~ /^(bboot|dosboot|romboot)$/){
+				c = "1";
+				p = a[2];
+			}
+			else if(a[2] == "boot" && n == 3)
+				d = a[3];
+			continue;
+		}
+		s = s "\t{ \"" a[1] "\", config" a[1] ", connect" a[1] ", ";
+		t = "nil";
+		if(n > 1){
+			u = line["boot", i];
+			if(sub(/^[_A-Za-z][_A-Za-z0-9]*[ \t]*/, "", u)){
+				if(match(u, /^".*"$/))
+					u = substr(u, RSTART+1, RLENGTH-2);
+				t = "\"" u "\"";
+			}
+		}
+		s = s t ", },\n";
+	}
+	s = s "\t{ nil },\n};\n\n";
+	s = s "int cpuflag = " c ";\n";
+	s = s "char* rootdir = \"" r "\";\n";
+	s = s "char* bootdisk = \"" d "\";\n";
+	s = s "extern void " p "(int, char**);\n\n";
+	s = s "void\nmain(int argc, char **argv)\n";
+	s = s "{\n\t" p "(argc, argv);\n}\n"
+
+	t = "int (*cfs)(int) = 0;\n";
+	for(i = 1; i < section["rootdir"]; i++){
+		if($1 !~ /\/bin\/cfs$/)
+			continue;
+		t = "int (*cfs)(int) = cache;\n";
+		break;
+	}
+	s = s t;
+
+	return s;
+}
+
+function mksystab(					a, i, f, n, s, t){
+	s = "#include \"/sys/src/libc/9syscall/sys.h\"\n\n";
+	s = s "typedef void Syscall(Ar0*, va_list);\n\n";
+
+	t = "";
+	while(getline < "/sys/src/libc/9syscall/sys.h"){
+		if($1 != "#define" || NF != 3)
+			continue;
+
+		f = "sys" tolower($2);
+		if($2 == "SYSR1")
+			f = "sysr1";
+		if($2 == "RENDEZVOUS")
+			n = "Rendez";
+		else if($2 == "BRK_")
+			n = "Brk";
+		else
+			n = substr($2, 1, 1) tolower(substr($2, 2));
+
+		s = s "Syscall " f ";\n";
+		t = t "\t[" $2 "]\t";
+		if(length($2) < 6)
+			t = t "\t";
+		t = t "{ \"" n "\", " f ", ";
+		#
+		# if($1 ~ "(FVERSION|FSTAT|STAT)")
+		#	t = t "{ .u = 0 } },\n";
+		# else
+		#
+		if($1 ~ "(BIND|MOUNT|FWSTAT|WSTAT)")
+			t = t "{ .l = 0 } },\n";
+		else if($1 ~ "(EXEC|RENDEZVOUS|SEGBRK|SEGATTACH)")
+			t = t "{ .v = (void*)-1 } },\n";
+		else
+			t = t "{ .i = -1 } },\n";
+	}
+	if("syscall" in section){
+		for(i = 1; i < section["syscall"]; i++){
+			if(split(line["syscall", i], a) != 8)
+				continue;
+			if(line["syscall", i] !~ /#define.*{ \.[ilpuv] = .* }$/)
+				continue;
+
+			f = "sys" tolower(a[2]);
+			n = substr(a[2], 1, 1) tolower(substr(a[2], 2));
+
+			s = s "\nSyscall " f ";\n";
+			t = t a[1] " " a[2] "\t" a[3] "\n\t[" a[2] "]\t";
+			if(length(a[2]) < 6)
+				t = t "\t";
+			split(line["syscall", i], a, "{");
+			t = t "{ \"" n "\", " f ", {" a[2] " },\n";
+		}
+	}
+	s = s "struct {\n\tchar*\tn;\n\tSyscall*f;\n\tAr0\tr;\n}";
+	s = s " systab[] = {\n" t "};\n\nint nsyscall = nelem(systab);\n";
+
+	return s;
+}
+
+function mkerrstr(					a, s){
+	FS="[ \t;]+";
+	while(getline < "error.h"){
+		split($0, a, /\/\* | \*\//);
+		s = s $2 " " $3 " = \"" a[2] "\";\n";
+	}
+	FS=" ";
+
+	return s;
+}
+
+function mkdevc(		a, d, i, m, n, s, t, u, name, cname){
+	s = "#include \"u.h\"\n";
+	s = s "#include \"lib.h\"\n";
+	s = s "#include \"mem.h\"\n";
+	s = s "#include \"dat.h\"\n";
+	s = s "#include \"fns.h\"\n";
+	s = s "#include \"error.h\"\n\n";
+	s = s "#include \"io.h\"\n\n";
+
+	t = "";
+	for(i = 1; i < section["dev"]; i++){
+		split(line["dev", i], a);
+		s = s "extern Dev " a[1] "devtab;\n";
+		t = t "\t&" a[1] "devtab,\n";
+		d[a[1]]++;
+	}
+	s = s "Dev* devtab[] = {\n" t "\tnil,\n};\n\n";
+
+	mkrootrules(name, cname, m);
+	t = "";
+	for(i = 1; i < section["rootdir"]; i++){
+		s = s "extern uchar " cname[i] "code[];\n";
+		s = s "extern usize " cname[i] "len;\n";
+		t = t "\taddbootfile(\"" name[i] "\", " cname[i] "code, " cname[i] "len);\n";
+	}
+	for(i = 1; i < section["link"]; i++){
+		split(line["link", i], a);
+		s = s "extern void " a[1] "link(void);\n";
+		t = t "\t" a[1] "link();\n";
+	}
+	s = s "void\nlinks(void)\n{\n" t "}\n\n";
+
+	if("ip" in d && "ip" in section){
+		t = "";
+		s = s "#include \"../ip/ip.h\"\n";
+		for(i = 1; i < section["ip"]; i++){
+			split(line["ip", i], a);
+			s = s "extern void " a[1] "init(Fs*);\n";
+			t = t "\t" a[1] "init,\n";
+		}
+		s = s "void (*ipprotoinit[])(Fs*) = {\n" t "\tnil,\n};\n\n";
+	}
+
+	if("sd" in d && "sd" in section){
+		t = "";
+		s = s "#include \"sd.h\"\n";
+		for(i = 1; i < section["sd"]; i++){
+			split(line["sd", i], a);
+			s = s "extern SDifc " a[1] "ifc;\n";
+			t = t  "\t&" a[1] "ifc,\n";
+		}
+		s = s "SDifc* sdifc[] = {\n" t "\tnil,\n};\n\n";
+	}
+
+	if("uart" in d && "uart" in section){
+		t = "";
+		for(i = 1; i < section["uart"]; i++){
+			split(line["uart", i], a);
+			a[1] = substr(a[1], 5, length(a[1])-4) "physuart";
+			s = s "extern PhysUart " a[1] ";\n";
+			t = t  "\t&" a[1] ",\n";
+		}
+		s = s "PhysUart* physuart[] = {\n" t "\tnil,\n};\n\n";
+	}
+
+	t = "";
+	n = 0;
+	if("physseg" in section){
+		for(i = 1; i < section["physseg"]; i++){
+			u = line["physseg", i];
+			if(u ~ /^\.[_A-Za-z][_A-Za-z0-9]*/)
+				t = t "\t";
+			t = t "\t" u "\n";
+			if(sub(/.*\.pgalloc.*=[^_A-Za-z]*/, "", u)){
+				if(match(u, /^[_A-Za-z][_A-Za-z0-9]*/)){
+					u = substr(u, RSTART, RLENGTH);
+					s = s "extern Page *(*" u ")(Segment*, uintptr);\n";
+				}
+			}
+			else if(sub(/.*\.pgfree.*=[^_A-Za-z]*/, "", u)){
+				if(match(u, /^[_A-Za-z][_A-Za-z0-9]*/)){
+					u = substr(u, RSTART, RLENGTH);
+					s = s "extern void (*" u ")(Page*);\n";
+				}
+			}
+			if(match(u, /}/))
+				n++;
+		}
+	}
+	s = s "Physseg physseg[" n+8 "] = {\n";
+	s = s "\t{\t.attr\t= SG_SHARED,\n";
+	s = s "\t\t.name\t= \"shared\",\n";
+	s = s "\t\t.size\t= SEGMAXSIZE,\n\t},\n";
+	s = s "\t{\t.attr\t= SG_BSS,\n";
+	s = s "\t\t.name\t= \"memory\",\n";
+	s = s "\t\t.size\t= SEGMAXSIZE,\n\t},\n";
+	s = s t "};\nint nphysseg = " n+8 ";\n\n";
+
+	s = s "char dbgflg[256]";
+	t = "";
+	for(u in dbgflg)
+		t = t "\t[" u "]\t" dbgflg[u] ",\n";
+	if(t != "")
+		s = s " = {\n" t "}";
+	s = s ";\n\n";
+
+	for(i in m)
+		delete m[i];
+
+	for(i = 1; i < section["misc"]; i++){
+		split(line["misc", i], a);
+		m[a[1]] = line["misc", i];
+	}
+	if("cache" in m){
+		s = s "extern void cinit(void);\n";
+		s = s "extern void copen(Chan*);\n";
+		s = s "extern int cread(Chan*, uchar*, int, vlong);\n";
+		s = s "extern void cupdate(Chan*, uchar*, int, vlong);\n";
+		s = s "extern void cwrite(Chan*, uchar*, int, vlong);\n\n";
+		s = s "void (*mfcinit)(void) = cinit;\n";
+		s = s "void (*mfcopen)(Chan*) = copen;\n";
+		s = s "int (*mfcread)(Chan*, uchar*, int, vlong) = cread;\n";
+		s = s "void (*mfcupdate)(Chan*, uchar*, int, vlong) = cupdate;\n";
+		s = s "void (*mfcwrite)(Chan*, uchar*, int, vlong) = cwrite;\n\n";
+	}
+	else{
+		s = s "void (*mfcinit)(void) = nil;\n";
+		s = s "void (*mfcopen)(Chan*) = nil;\n";
+		s = s "int (*mfcread)(Chan*, uchar*, int, vlong) = nil;\n";
+		s = s "void (*mfcupdate)(Chan*, uchar*, int, vlong) = nil;\n";
+		s = s "void (*mfcwrite)(Chan*, uchar*, int, vlong) = nil;\n\n";
+	}
+	if(!("rdb" in misc)){
+		s = s "void\n";
+		s = s "rdb(void)\n";
+		s = s "{\n";
+		s = s "\tsplhi();\n";
+		s = s "\tiprint(\"rdb...not installed\\n\");\n";
+		s = s "\tfor(;;);\n";
+		s = s "}\n\n";
+	}
+
+	if("conf" in section){
+		for(i = 1; i < section["conf"]; i++)
+			s = s line["conf", i] "\n";
+		s = s "\n";
+	}
+	t = ".";
+	while("pwd" | getline > 0){
+		if($0 ~ /^\//)
+			t = $0;
+	}
+	s = s "char* conffile = \"" t "/" ARGV[argc] "\";\n";
+	s = s "ulong kerndate = KERNDATE;\n";
+
+	return s;
+}
+
+function mkrootrules(name, cname, src,			a, i, n){
+	for(i = 1; i < section["rootdir"]; i++){
+		n = split(line["rootdir", i], a);
+		if(n >= 2)
+			name[i] = a[2];
+		else
+			name[i] = a[1];
+		sub(/.*\//, "", name[i]);
+		cname[i] = a[1];
+		gsub(/[^a-zA-Z0-9_]/, "_", cname[i]);
+		src[i] = a[1];
+	}
+}
+
+function mkrules(dir, exists, ameta, cmeta, flags,		f, i, s, t){
+	for(i in ameta)
+		delete ameta[i];
+	for(i in cmeta)
+		delete cmeta[i];
+
+	s = "";
+	while("cd " dir "; /bin/ls *.[cs]" | getline > 0){
+		if($0 !~ /^[A-Za-z0-9]*\.[cs]$/)
+			continue;
+		f = $0;
+		if(!sub(/\.[cs]$/, ""))
+			continue;
+		if($0 in exists)
+			continue;
+		exists[$0] = dir;
+		if(f ~ /\.c$/){
+			if(!($0 in dbgc)){
+				cmeta[$0]++;
+				continue;
+			}
+			t = "$CC $CFLAGS " flags;
+		}
+		else{
+			if(!($0 in dbgc)){
+				ameta[$0]++;
+				continue;
+			}
+			t = "$AS $AFLAGS " flags;
+		}
+		s = s $0 ".$O:\t" dir "/" f "\n";
+		s = s "\t" t " -D'_DBGC_='" dbgc[$0] "'' " dir "/" f "\n";
+	}
+	return s;
+}
+
+function mkport(					array){
+	arrayify(array, "port", "", ".$O", 1);
+
+	return listolate(array, " ");
+}
+
+function mklib(						array){
+	arrayify(array, "lib", "/$objtype/lib/", ".a", 1);
+
+	return listolate(array," ");
+}
+
+function mkmach(					a, i, s){
+	s = "";
+	for(i = 1; i < section[objtype]; i++){
+		if(!split(line[objtype, i], a))
+			continue;
+		if(s == "")
+			s = a[1] ".$O";
+		else
+			s = s " " a[1] ".$O";
+	}
+
+	return s;
+}
+
+function mkdevlist(					a, array, i, j, n, s){
+	for(s in section){
+		if(line[s, 0] !~ /[ \t]\+dev[^_A-Za-z0-9]*/)
+			continue;
+		if(s == "dev")
+			arrayify(array, s, "dev", ".$O", 1);
+		else if(s == objtype)
+			arrayify(array, s, "", ".$O", 0);
+		else
+			arrayify(array, s, "", ".$O", 1);
+	}
+
+	return listolate(array, " ");
+}
+
+function listolate(array, sep,				a, s){
+	s = "";
+	for(a in array){
+		if(s == "")
+			s = a;
+		else
+			s = a sep s;
+	}
+
+	return s;
+}
+
+function arrayify(array, tag, prefix, suffix, one,	a, i, j, n){
+	for(i = 1; i < section[tag]; i++){
+		n = split(line[tag, i], a);
+		if(one)
+			array[prefix a[1] suffix]++;
+		for(j = 2; j <= n; j++){
+			if(a[$j] ~ /[+=-].*/)
+				continue;
+			array[a[j] suffix]++;
+		}
+	}
+}

+ 31 - 0
sys/src/boot/vt5/physmem.h

@@ -0,0 +1,31 @@
+/*
+ * Memory-mapped IO
+ */
+
+/*
+ * virtex5 system loses top 1/5th of 512MB to ECC in the secure memory system.
+ */
+#define MEMTOP(phys)	((((((phys)/DCACHELINESZ)*4)/5) * DCACHELINESZ) & -128)
+#define MAXMEM		(512*MB)
+
+/* memory map for rae's virtex4 design */
+#define	PHYSDRAM	0
+#define PHYSSRAM	0xfffe0000	/* 128K long, in top 128M */
+#define PHYSMMIO	Io
+
+#define	Io		0xf0000000	/* ~512K of IO registers */
+#define Uartlite	0xf0000000
+#define Gpio		0xf0010000
+#define Intctlr		0xf0020000
+#define Temac		0xf0030000
+#define Llfifo		0xf0040000
+#define Dmactlr		0xf0050000
+#define Dmactlr2	0xf0060000
+/*
+ * if these devices exist in a given hardware configuration,
+ * they will be at these addresses.
+ */
+#define Qtm		0xf0070000	/* encrypted memory control */
+#define Mpmc		0xf0080000	/* multi-port memory controller */
+/* setting low bit interrupts cpu0; don't set Hie */
+#define Intctlr2	0xf0090000	/* sw interrupt controller */

+ 16 - 0
sys/src/boot/vt5/portmkfile

@@ -0,0 +1,16 @@
+%.$O:		%.s
+	$AS $AFLAGS $stem.s
+
+%.$O:		%.c
+	$CC $CFLAGS $stem.c
+
+%.$O:		include.h
+%.$O:		/$objtype/include/u.h
+%.$O:		libc.h
+%.$O:		define.h
+%.$O:		data.h portdata.h
+%.$O:		prototype.h portprototype.h
+%.$O:		glue.h
+
+clean:V:
+	rm -f *.[$OS] *.out *.m *.acid $p$CONF *.elf

+ 2 - 0
sys/src/boot/vt5/portprototype.h

@@ -0,0 +1,2 @@
+extern void	ilock(Lock*);
+extern void	iunlock(Lock*);

+ 199 - 0
sys/src/boot/vt5/prototype.h

@@ -0,0 +1,199 @@
+#define PTR2UINT(p)	((uintptr)(p))
+#define UINT2PTR(i)	((void*)(i))
+
+/* physical == virtual in our world! */
+#define PADDR(a)	((ulong)(a) & ~0xF0000000)
+
+#define	GSHORT(p)	(((p)[1]<<8)|(p)[0])
+#define	GLONG(p)	((GSHORT(p+2)<<16)|GSHORT(p))
+#define	GLSHORT(p)	(((p)[0]<<8)|(p)[1])
+#define	GLLONG(p)	(((ulong)GLSHORT(p)<<16)|GLSHORT(p+2))
+#define	PLLONG(p,v)	(p)[3]=(v);(p)[2]=(v)>>8;(p)[1]=(v)>>16;(p)[0]=(v)>>24
+
+#define mallocalign(n, a, o, s)	ialloc((n), (a))
+
+/* emergency debugging printing, from uart.c */
+#define Uarttxfifo	((ulong *)(Uartlite + 4))
+#define PROG(c)		{ coherence(); *Uarttxfifo = (uchar)(c); coherence(); }
+
+/*
+ * l32p.s
+ */
+void	cachesinvalidate(void);
+void	dcbi(void*);
+void	dcflush(uintptr, usize);
+void	eieio(void);
+u32int	esrget(void);
+void	esrput(u32int);
+// char*	getconf(char*);
+#define getconf(s) nil
+u32int	getccr0(void);
+u32int	getdar(void);
+u32int	getdear(void);
+u32int	getdec(void);
+u32int	getesr(void);
+u32int	getmsr(void);
+u32int	getpid(void);
+u32int	getpir(void);
+u32int	getpit(void);
+u32int	getpvr(void);
+uintptr	getsp(void);
+u32int	gettbl(void);
+u32int	gettsr(void);
+void	icflush(uintptr, usize);
+int	islo(void);
+void	isync(void);
+void	microdelay(int);
+u32int	mmucrget(void);
+void	mmucrput(u32int);
+void	putdec(ulong);
+void	putesr(ulong);
+void	putevpr(ulong);
+void	putmcsr(u32int);
+void	putmsr(u32int);
+void	putpid(u32int);
+void	putpit(u32int);
+void	putsdr1(u32int);
+void	puttcr(u32int);
+void	puttsr(u32int);
+void	setsp(uintptr);
+void	spldone(void);
+int	splhi(void);
+int	spllo(void);
+void	splx(int);
+void	splxpc(int);
+void	sync(void);
+void	syncall(void);
+int	tas32(uint*);
+void	trapvec(void);
+int	_xdec(long *);
+int	_xinc(long *);
+
+/*
+ * trap.c
+ */
+void	trapdisable(void);
+void	trapinit(void);
+
+/*
+ * intr.c
+ */
+void	intr(Ureg *ur);
+void	intrack(ulong);
+void	intrenable(ulong bit, int (*func)(ulong));
+void	intrinit(void);
+ulong	lddbg(void);
+
+/*
+ * uart.c
+ */
+int	vuartgetc(void);
+void	vuartputc(int c);
+int	vuartputs(char *s, int len);
+
+/*
+ * clock.c
+ */
+void	clockinit(void);
+void	clockintr(Ureg *ureg);
+void	delay(int);
+void	prcpuid(void);
+void	timerintr(Ureg*);
+
+/*
+ * dma.c
+ */
+void	dmacpy(void *dest, void *src, ulong len, ulong flags);
+void	dmainit(void);
+void	dmastart(void *dest, void *src, ulong len, ulong flags);
+void	dmawait(void);
+
+/*
+ * ether.c
+ */
+uchar	*etheraddr(int ctlrno);
+int	etherinit(void);
+void	etherinitdev(int, char*);
+void	etherprintdevs(int);
+int	etherrxflush(int ctlrno);
+int	etherrxpkt(int ctlrno, Etherpkt* pkt, int timo);
+int	ethertxpkt(int ctlrno, Etherpkt* pkt, int len, int);
+
+/*
+ * llfifo.c
+ */
+void	llfifoinit(Ether *);
+int	llfifointr(ulong bit);
+void	llfiforeset(void);
+void	llfifotransmit(uchar *ubuf, unsigned len);
+
+/*
+ * load.c
+ */
+int	getfields(char*, char**, int, char);
+void*	ialloc(ulong, int);
+
+/*
+ * boot.c
+ */
+int	bootpass(Boot *b, void *vbuf, int nbuf);
+
+/*
+ * bootp.c
+ */
+int	bootpboot(int, char*, Boot*);
+void*	pxegetfspart(int, char*, int);
+
+/*
+ * conf.c
+ */
+int	dotini(Fs *fs);
+
+/*
+ * console.c
+ */
+void	consinit(char*, char*);
+int	getstr(char*, char*, int, char*, int);
+void	kbdinit(void);
+void	warp86(char*, ulong);
+void	warp9(ulong);
+
+/*
+ * inflate.c
+ */
+int	gunzip(uchar*, int, uchar*, int);
+
+/*
+ * misc.
+ */
+
+void	ilock(Lock*);
+void	iunlock(Lock*);
+int	lock(Lock*);
+void	unlock(Lock*);
+
+void	panic(char *fmt, ...);
+
+#define TAS(l)		tas32(l)
+
+#define iprint		print
+
+#define coherence()	eieio()
+#define exit(n)		for(;;) ;
+
+void	cacheline0(uintptr addr);
+ulong	cacheson(void);
+void	clrmchk(void);
+void	dump(void *, int);
+void	dumpregs(Ureg *);
+void	flushwrbufs(void);
+uintptr	memsize(void);
+vlong	probeaddr(uintptr addr);
+/*
+ * qtm.c
+ */
+int	qtmerrfmt(char *, int);
+void	qtmerrtest(char *);
+void	qtmerrtestaddr(ulong);
+int	qtmmemreset(void);
+vlong	qtmprobeaddr(uintptr addr);

+ 42 - 0
sys/src/boot/vt5/tlb.s

@@ -0,0 +1,42 @@
+/* virtex5 ppc440x5 bootstrap tlb entries */
+#include	"mem.h"
+
+#define MB (1024*1024)
+
+/*
+ * TLB prototype entries, loaded once-for-all at startup,
+ * remaining unchanged thereafter.
+ * Limit the table size to ensure it fits in small TLBs.
+ * First entry will be tlb entry #63 and we count down from there.
+ *
+ * Add TLBW for write-through caching.
+ * TLBM doesn't help on the Xilinx virtex 5, alas.
+ * The low 4 bits of the middle word are high bits (33-36) of the RPN;
+ * we set them to zero.
+ */
+#define TLBE(hi, md, lo)    WORD    $(hi);  WORD $(md);   WORD    $(lo)
+
+TEXT    tlbtab(SB), 1, $-4
+
+	/*
+	 * SRAM, 128K.  put vectors here.
+	 * the `microboot' at the end of SRAM has already installed these
+	 * TLB entries for SRAM.
+	 */
+	TLBE(PHYSSRAM | TLB64K | TLBVALID, PHYSSRAM,
+		TLBSR | TLBSX | TLBSW)
+	TLBE(PHYSSRAM+(64*1024) | TLB64K | TLBVALID, PHYSSRAM+(64*1024),
+		TLBSR | TLBSX | TLBSW)
+
+	/* DRAM, 512MB */
+	TLBE(PHYSDRAM | TLB256MB | TLBVALID, PHYSDRAM,
+		TLBSR | TLBSX | TLBSW)
+	TLBE(PHYSDRAM+(256*MB) | TLB256MB | TLBVALID, PHYSDRAM+(256*MB),
+		TLBSR | TLBSX | TLBSW)
+
+	/* memory-mapped IO, 1MB */
+	TLBE(PHYSMMIO | TLB1MB | TLBVALID, PHYSMMIO,
+		TLBSR | TLBSW | TLBI | TLBG)
+
+TEXT    tlbtabe(SB), 1, $-4
+	RETURN

+ 327 - 0
sys/src/boot/vt5/trap.c

@@ -0,0 +1,327 @@
+/*
+ * power pc 440 traps
+ */
+#include "include.h"
+
+static struct {
+	ulong off;
+	char *name;
+} intcause[] = {
+	{ INT_CI,	"critical input" },
+	{ INT_MCHECK,	"machine check" },
+	{ INT_DSI,	"data access" },
+	{ INT_ISI,	"instruction access" },
+	{ INT_EI,	"external interrupt" },
+	{ INT_ALIGN,	"alignment" },
+	{ INT_PROG,	"program exception" },
+	{ INT_FPU,	"floating-point unavailable" },
+	{ INT_DEC,	"decrementer" },
+	{ INT_SYSCALL,	"system call" },
+	{ INT_TRACE,	"trace trap" },
+	{ INT_FPA,	"floating point unavailable" },
+	{ INT_APU,	"auxiliary processor unavailable" },
+	{ INT_PIT,	"programmable interval timer interrrupt" },
+	{ INT_FIT,	"fixed interval timer interrupt" },
+	{ INT_WDT,	"watch dog timer interrupt" },
+	{ INT_DMISS,	"data TLB miss" },
+	{ INT_IMISS,	"instruction TLB miss" },
+	{ INT_DEBUG,	"debug interrupt" },
+	{ 0,		"unknown interrupt" }
+};
+
+static char *excname(ulong, u32int);
+
+char *regname[]={
+	"CAUSE",	"SRR1",
+	"PC",		"GOK",
+	"LR",		"CR",
+	"XER",	"CTR",
+	"R0",		"R1",
+	"R2",		"R3",
+	"R4",		"R5",
+	"R6",		"R7",
+	"R8",		"R9",
+	"R10",	"R11",
+	"R12",	"R13",
+	"R14",	"R15",
+	"R16",	"R17",
+	"R18",	"R19",
+	"R20",	"R21",
+	"R22",	"R23",
+	"R24",	"R25",
+	"R26",	"R27",
+	"R28",	"R29",
+	"R30",	"R31",
+};
+
+void	intr(Ureg *ur);
+
+static int probing, trapped;
+static jmp_buf probenv;
+
+static void
+sethvec(uintptr v, void (*r)(void))
+{
+	u32int *vp;
+	ulong o, ra;
+	long d;
+
+	vp = UINT2PTR(v);
+	vp[0] = 0x7c1043a6;			/* MOVW R0, SPR(SPRG0) */
+	vp[1] = 0x7c0802a6;			/* MOVW LR, R0 */
+	vp[2] = 0x7c1243a6;			/* MOVW R0, SPR(SPRG2) */
+	d = (uchar*)r - (uchar*)&vp[3];
+	o = (ulong)d >> 25;
+	if(o != 0 && o != 0x7F){
+		/* a branch too far: running from ROM */
+		ra = (ulong)r;
+		vp[3] = (15<<26)|(ra>>16);	/* MOVW $r&~0xFFFF, R0 */
+		vp[4] = (24<<26)|(ra&0xFFFF);	/* OR $r&0xFFFF, R0 */
+		vp[5] = 0x7c0803a6;		/* MOVW	R0, LR */
+		vp[6] = 0x4e800021;		/* BL (LR) */
+	}
+	else
+		vp[3] = (18<<26)|(d&0x3FFFFFC)|1;	/* BL (relative) */
+	dcflush(PTR2UINT(vp), 8*sizeof(u32int));
+}
+
+static void
+sethvec2(uintptr v, void (*r)(void))
+{
+	u32int *vp;
+	long d;
+
+	vp = UINT2PTR(v);
+	d = (uchar*)r - (uchar*)&vp[0];
+	vp[0] = (18<<26)|(d & 0x3FFFFFC);	/* B (relative) */
+	dcflush(PTR2UINT(vp), sizeof(*vp));
+}
+
+extern uintptr vectorbase;
+
+void
+trapinit(void)
+{
+	uintptr e, s;
+
+	putesr(0);				/* clears machine check */
+	coherence();
+
+	/*
+	 * set all exceptions to trap
+	 */
+	s = vectorbase + 0x100;		/* Mach is at vectorbase */
+	/* 0x2000 is last documented 405 vector */
+	for(e = s+0x2100; s < e; s += 0x100)
+		sethvec(s, trapvec);
+	coherence();
+
+	/*
+	 * set exception handlers
+	 */
+//	sethvec(vectorbase + INT_RESET, trapcritvec);
+//	sethvec(vectorbase + INT_MCHECK, trapcritvec);
+	sethvec(vectorbase + INT_DSI, trapvec);
+	sethvec(vectorbase + INT_ISI, trapvec);
+	sethvec(vectorbase + INT_EI, trapvec); /* external non-critical intrs */
+	sethvec(vectorbase + INT_ALIGN, trapvec);
+	sethvec(vectorbase + INT_PROG, trapvec);
+	sethvec(vectorbase + INT_FPU, trapvec);
+	sethvec(vectorbase + INT_SYSCALL, trapvec);
+	sethvec(vectorbase + INT_APU, trapvec);
+	sethvec(vectorbase + INT_PIT, trapvec);
+	sethvec(vectorbase + INT_FIT, trapvec);
+//	sethvec(vectorbase + INT_WDT, trapcritvec);
+//	sethvec2(vectorbase + INT_DMISS, dtlbmiss);
+//	sethvec2(vectorbase + INT_IMISS, itlbmiss);
+//	sethvec(vectorbase + INT_DEBUG, trapcritvec);
+	syncall();
+
+	/* l.s already set EVPR */
+	putmsr(getmsr() | MSR_CE | MSR_ME);	/* no MSR_EE here */
+	coherence();
+}
+
+void
+trapdisable(void)
+{
+	putmsr(getmsr() & ~( MSR_EE | MSR_CE | MSR_ME)); /* MSR_DE as well? */
+}
+
+static char*
+excname(ulong ivoff, u32int esr)
+{
+	int i;
+
+	if(ivoff == INT_PROG){
+		if(esr & ESR_PIL)
+			return "illegal instruction";
+		if(esr & ESR_PPR)
+			return "privileged";
+		if(esr & ESR_PTR)
+			return "trap with successful compare";
+		if(esr & ESR_PEU)
+			return "unimplemented APU/FPU";
+		if(esr & ESR_PAP)
+			return "APU exception";
+		if(esr & ESR_U0F)
+			return "data storage: u0 fault";
+	}
+	for(i=0; intcause[i].off != 0; i++)
+		if(intcause[i].off == ivoff)
+			break;
+	return intcause[i].name;
+}
+
+void
+dumpstack(void)
+{
+	/* sorry.  stack is in dram, not Mach now */
+}
+
+void
+dumpregs(Ureg *ureg)
+{
+	int i;
+	uintptr *l;
+
+	iprint("cpu%d: registers for boot\n", m->machno);
+
+	l = &ureg->cause;
+	for(i = 0; i < nelem(regname); i += 2, l += 2)
+		iprint("%s\t%.8p\t%s\t%.8p\n", regname[i], l[0], regname[i+1], l[1]);
+}
+
+static void
+faultpower(Ureg *ureg, ulong addr, int read)
+{
+	USED(read);
+	dumpregs(ureg);
+	panic("boot fault: 0x%lux", addr);
+}
+
+void
+trap(Ureg *ur)
+{
+	int ecode;
+	u32int esr;
+
+	ur->cause &= 0xFFE0;
+	ecode = ur->cause;
+	if(ecode < 0 || ecode >= 0x2000)
+		ecode = 0x3000;
+	esr = getesr();
+	putesr(0);
+
+	switch(ecode){
+	case INT_SYSCALL:
+		panic("syscall in boot: srr1 %#4.4luX pc %#p\n",
+			ur->srr1, ur->pc);
+
+	case INT_PIT:
+		clockintr(ur);
+		break;
+
+	case INT_MCHECK:
+		if (probing) {
+			trapped++;
+			longjmp(probenv, 1);
+		}
+		if(esr & ESR_MCI){
+			//iprint("mcheck-mci %lux\n", ur->pc);
+			faultpower(ur, ur->pc, 1);
+			break;
+		}
+		//iprint("mcheck %#lux esr=%#ux dear=%#ux\n", ur->pc, esr, getdear());
+		ur->pc -= 4;	/* back up to faulting instruction */
+		/* fall through */
+	case INT_DSI:
+	case INT_DMISS:
+		faultpower(ur, getdear(), !(esr&ESR_DST));
+		break;
+
+	case INT_ISI:
+	case INT_IMISS:
+		faultpower(ur, ur->pc, 1);
+		break;
+
+	case INT_EI:
+		intr(ur);
+		break;
+
+	case INT_PROG:
+	default:
+		print("boot %s pc=%#lux\n", excname(ecode, esr), ur->pc);
+		dumpregs(ur);
+		dumpstack();
+		if(m->machno == 0)
+			spllo();
+		exit(1);
+	}
+	splhi();
+}
+
+static Lock fltlck;
+
+vlong
+probeaddr(uintptr addr)
+{
+	vlong v;
+
+	ilock(&fltlck);
+	probing = 1;
+	/*
+	 * using setjmp & longjmp is a sleazy hack; see ../../9k/vt4/trap.c
+	 * for a less sleazy hack.
+	 */
+	if (setjmp(probenv) == 0)
+		v = *(ulong *)addr;	/* this may cause a fault */
+	else
+		v = -1;
+	probing = 0;
+	iunlock(&fltlck);
+	return v;
+}
+
+vlong
+qtmprobeaddr(uintptr addr)
+{
+	int i;
+	vlong v, junk;
+	vlong *ptr;
+
+	ilock(&fltlck);
+	probing = 1;
+	trapped = 0;
+	v = 0;
+	/*
+	 * using setjmp & longjmp is a sleazy hack; see ../../9k/vt4/trap.c
+	 * for a less sleazy hack.
+	 */
+	if (setjmp(probenv) == 0) {
+		syncall();
+		clrmchk();
+		syncall();
+
+		/* write entire cache lines, unless we get a bus error */
+		ptr = (vlong *)(addr & ~(DCACHELINESZ - 1));
+		for (i = 0; !trapped && !(getesr() & ESR_MCI) &&
+		    i < DCACHELINESZ/sizeof *ptr; i++) {
+			ptr[i] = 0;
+			coherence();
+		}
+		junk = ptr[0];
+		USED(junk);
+	} else
+		v = -1;
+
+	syncall();
+	if(getesr() & ESR_MCI)
+		v = -1;
+	syncall();
+	clrmchk();
+	syncall();
+	probing = 0;
+	iunlock(&fltlck);
+	return v;
+}

+ 28 - 0
sys/src/boot/vt5/vt5load

@@ -0,0 +1,28 @@
+# rae's virtex5 ml510 boot
+power
+	l
+	tlb
+	load
+	trap
+	archvt5
+	clock
+	intr
+	uart
+	ethertemac
+	llfifo
+	fakeqtm
+# port stuff
+	portclock
+	malloc
+	print
+	console
+	taslock
+	ether
+	boot
+	fs
+	bootp
+dir
+	vt4
+lib
+	libip
+	libc

+ 21 - 0
sys/src/boot/vt5/words

@@ -0,0 +1,21 @@
+This bootstrap is intended to load a Plan 9 kernel via bootp and tftp
+into a Xilinx Virtex 5 ML510 board.  Most of its source is in ../vt4.
+The mkfile generates an elf file which is then fed into the Xilinx CAD
+tool to generate a bitstream for loading into the FPGA on the ML510.
+
+This bootstrap will almost certainly not work for you without some
+changes.  In particular, the addresses of the I/O registers in
+physmem.h will have to be changed to match yours and you'll need to
+make sure that they are mapped if you have more than 512K of them.
+
+Because of pecularities of the PowerPC 440, there's a `micro
+bootstrap' in microboot.s that kicks everything off.  The bootstrap
+runs with the MMU on, because it's always on on a 440.
+
+This bootstrap does not use dma but in principle it could, by
+replacing calls to fifocpy with calls to dmacpy.  dma is one more
+thing that could go wrong, so we ended up using the cpu to copy words
+to and from ethernet fifos.
+
+This code runs in high memory (above 0xfffe0000) and its global data
+is thus in sram.