Browse Source

Plan 9 from Bell Labs 2013-07-24

David du Colombier 6 years ago
parent
commit
7137e45891

+ 10 - 15
sys/lib/lp/bin/lpsend.rc

@@ -1,18 +1,13 @@
 #!/bin/rc
-if (! ~ $DEBUG '') { flag x + }
-if (test -e /net/tcp/clone) {
-	dialstring=`{ndb/query sys $1 dom}
-	network=tcp
-	if (~ $#dialstring 0 || ! ~ $dialstring '') {
-		dialstring=$1
-	}
-	if(lpsend $network^!^$dialstring^!printer) exit ''
-	rv='tcp failed'
-}
-if not rv='no tcp'
+# lpsend.rc dialstring - run lpsend network!dialstring!printer
+if (! ~ $DEBUG '')
+	flag x +
+if (! test -e /net/tcp/clone)
+	exit 'no tcp'
 
+dialstring=`{ndb/query sys $1 dom}
+if (~ $#dialstring 0 || ~ $dialstring '')	# no dom for sys in ndb?
+	dialstring=$1				# use arg unchanged
 
-if (! ~ $dialstring '')
-	exit 'lpsend: no dialstring'
-if not
-	exit 'lpsend: '^$rv
+lpsend tcp!^$dialstring^!printer
+exit $status

+ 1 - 0
sys/src/9/mkfile

@@ -5,6 +5,7 @@ ARCH=\
 	omap\
 	pc\
 	ppc\
+	rb\
 	teg2\
 	
 all:V:

+ 3 - 0
sys/src/9/rb/c_fcr0.s

@@ -0,0 +1,3 @@
+TEXT	C_fcr0(SB), $-4
+	MOVW	$0x500, R1	/* claim to be an r4k, thus have ll/sc */
+	RET

+ 299 - 0
sys/src/9/rb/clock.c

@@ -0,0 +1,299 @@
+/*
+ * ar7161 clocks and timers
+ */
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"io.h"
+
+#include	"ureg.h"
+
+enum {
+	Cyccntres	= 2, /* counter advances at ½ clock rate (mips 24k) */
+	Basetickfreq	= 680*Mhz / Cyccntres,	/* rb450g */
+};
+
+void (*kproftimer)(ulong);
+
+void
+silencewdog(void)
+{
+	*Rstwdogtimer = Basetickfreq * 2 * 5;	/* pet the dog */
+}
+
+void
+sicwdog(void)
+{
+	*Rstwdogtimer = Basetickfreq * 2;
+	*Rstwdogctl = Wdogreset;		/* wake the dog */
+}
+
+void
+wdogreset(void)
+{
+	*Rstwdogtimer = Basetickfreq / 100;
+	*Rstwdogctl = Wdogreset;		/* wake the dog */
+	coherence();
+	*Rstwdogtimer = Basetickfreq / 10000;
+	coherence();
+}
+
+void
+stopwdog(void)
+{
+	*Rstwdogtimer = ~0;
+	*Rstwdogctl = Wdognoaction;		/* put the dog to sleep */
+}
+
+void
+clockshutdown(void)
+{
+	stopwdog();
+}
+
+/*
+ *  delay for l milliseconds more or less.
+ */
+void
+delay(int l)
+{
+	while(l-- > 0)
+		microdelay(1000);
+}
+
+/*
+ *  microseconds delay
+ */
+void
+microdelay(int l)
+{
+	int s;
+	ulong x, cyc, cnt, speed;
+
+	speed = m->speed;
+	if (speed == 0)
+		speed = Basetickfreq / Mhz * Cyccntres;
+	cyc = (ulong)l * (speed / Cyccntres);
+	s = splhi();
+	cnt = rdcount();
+	x = cnt + cyc;
+	if (x < cnt || x >= ~0ul - Basetickfreq) {
+		/* counter will wrap between now and x, or x is too near ~0 */
+		wrcount(0);			/* somewhat drastic */
+		wrcompare(rdcompare() - cnt);	/* match new count */
+		x = cyc;
+	}
+	while(rdcount() < x)
+		;
+	splx(s);
+	silencewdog();
+}
+
+void
+clock(Ureg *ureg)
+{
+	wrcompare(rdcount()+m->maxperiod);	/* side-effect: dismiss intr */
+	silencewdog();
+	timerintr(ureg, 0);
+}
+
+enum {
+	Instrs		= 10*Mhz,
+};
+
+static long
+issue1loop(void)
+{
+	register int i;
+	long st;
+
+	i = Instrs;
+	st = perfticks();
+	do {
+		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
+		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
+		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
+		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
+		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
+		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
+		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
+		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
+		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
+		--i; --i; --i; --i; --i;
+		/* omit 3 (--i) to account for conditional branch, nop & jump */
+		i -= 1+3;	 /* --i plus 3 omitted (--i) instructions */
+	} while(--i >= 0);
+	return perfticks() - st;
+}
+
+/* estimate instructions/s. */
+static int
+guessmips(long (*loop)(void), char *)
+{
+	int s;
+	long cyc;
+
+	do {
+		s = splhi();
+		cyc = loop();
+		splx(s);
+		if (cyc < 0)
+			iprint("again...");
+	} while (cyc < 0);
+	/*
+	 * Instrs instructions took cyc cycles @ Basetickfreq Hz.
+	 * round the result.
+	 */
+	return (((vlong)Basetickfreq * Instrs) / cyc + Mhz/2) / Mhz;
+}
+
+void
+clockinit(void)
+{
+	int mips;
+
+	silencewdog();
+
+	/*
+	 * calibrate fastclock
+	 */
+	mips = guessmips(issue1loop, "single");
+
+	/*
+	 * m->delayloop should be the number of delay loop iterations
+	 * needed to consume 1 ms, assuming 2 instr'ns in the delay loop.
+	 */
+	m->delayloop = mips*Mhz / (1000 * 2);
+	if(m->delayloop == 0)
+		m->delayloop = 1;
+
+	m->speed = mips;
+	m->hz = m->speed*Mhz;
+
+	m->maxperiod = Basetickfreq / HZ;
+	m->minperiod = Basetickfreq / (100*HZ);
+	wrcompare(rdcount()+m->maxperiod);
+
+	/*
+	 *  desynchronize the processor clocks so that they all don't
+	 *  try to resched at the same time.
+	 */
+	delay(m->machno*2);
+
+	syncclock();
+	intron(INTR7);
+}
+
+/*
+ * Tval is supposed to be in fastticks units.
+ * One fasttick unit is 1/Basetickfreq seconds.
+ */
+void
+timerset(Tval next)
+{
+	int x;
+	long period;
+
+	if(next == 0)
+		return;
+	x = splhi();			/* don't let us get scheduled */
+	period = next - fastticks(nil);
+	if(period > m->maxperiod - m->minperiod)
+		period = m->maxperiod;
+	else if(period < m->minperiod)
+		period = m->minperiod;
+	wrcompare(rdcount()+period);
+	silencewdog();
+	splx(x);
+}
+
+/*
+ *  The rewriting of compare in this routine shouldn't be necessary.
+ *  However, we lose clock interrupts if I don't, either a chip bug
+ *  or one of ours -- presotto
+ */
+uvlong
+fastticks(uvlong *hz)
+{
+	int x;
+	ulong delta, count;
+
+	if(hz)
+		*hz = Basetickfreq;
+
+	/* avoid reentry on interrupt or trap, to prevent recursion */
+	x = splhi();
+	count = rdcount();
+	if(rdcompare() - count > m->maxperiod)
+		wrcompare(count+m->maxperiod);
+	silencewdog();
+
+	if (count < m->lastcount)		/* wrapped around? */
+		delta = count + ((1ull<<32) - m->lastcount);
+	else
+		delta = count - m->lastcount;
+	m->lastcount = count;
+	m->fastticks += delta;
+	splx(x);
+	return m->fastticks;
+}
+
+ulong
+µs(void)
+{
+	return fastticks2us(fastticks(nil));
+}
+
+/*
+ *  performance measurement ticks.  must be low overhead.
+ *  doesn't have to count over a second.
+ */
+ulong
+perfticks(void)
+{
+	return rdcount();
+}
+
+long
+lcycles(void)
+{
+	return perfticks();
+}
+
+/* should use vlong hw counters ideally; lcycles is inadequate */
+void
+cycles(uvlong *cycp)
+{
+	*cycp = fastticks(nil);
+}
+
+Lock mpsynclock;
+
+/*
+ *  synchronize all clocks with processor 0
+ */
+void
+syncclock(void)
+{
+	uvlong x;
+
+	if(m->machno == 0){
+		m->lastcount = rdcount();
+		m->fastticks = 0;
+		m->ticks = 0;
+		wrcompare(rdcount()+m->maxperiod);
+	} else {
+		/* wait for processor 0's soft clock to change and then sync ours */
+		lock(&mpsynclock);
+		x = MACHP(0)->fastticks;
+		while(MACHP(0)->fastticks == x)
+			;
+		m->lastcount = rdcount();
+		m->fastticks = MACHP(0)->fastticks;
+		m->ticks = MACHP(0)->ticks;
+		wrcompare(rdcount()+m->maxperiod);
+		unlock(&mpsynclock);
+	}
+}

+ 225 - 0
sys/src/9/rb/dat.h

@@ -0,0 +1,225 @@
+typedef struct Conf	Conf;
+typedef struct Confmem	Confmem;
+typedef struct FPsave	FPsave;
+typedef struct KMap	KMap;
+typedef struct Lance	Lance;
+typedef struct Lancemem	Lancemem;
+typedef struct Label	Label;
+typedef struct Lock	Lock;
+typedef struct Mach	Mach;
+typedef struct MMU	MMU;
+typedef struct Notsave	Notsave;
+typedef struct Pcidev	Pcidev;
+typedef struct PMMU	PMMU;
+typedef struct Softtlb	Softtlb;
+typedef struct Ureg	Ureg;
+typedef struct Proc	Proc;
+typedef uvlong		Tval;
+
+#pragma incomplete Pcidev
+
+#define MAXSYSARG	5	/* for mount(fd, afd, mpt, flag, arg) */
+
+/*
+ *  parameters for sysproc.c and rebootcmd.c
+ */
+#define AOUT_MAGIC	V_MAGIC || magic==M_MAGIC
+/* r3k or r4k boot images */
+#define BOOT_MAGIC	(0x160<<16) || magic == ((0x160<<16)|3)
+
+/*
+ *  machine dependent definitions used by ../port/dat.h
+ */
+
+struct Lock
+{
+	ulong	key;			/* semaphore (non-zero = locked) */
+	ulong	sr;
+	ulong	pc;
+	Proc	*p;
+	Mach	*m;
+	ushort	isilock;
+};
+
+struct Label
+{
+	ulong	sp;
+	ulong	pc;
+};
+
+struct Confmem
+{
+	ulong	base;
+	ulong	npage;
+	ulong	kbase;
+	ulong	klimit;
+};
+
+struct Conf
+{
+	ulong	nmach;		/* processors */
+	ulong	nproc;		/* processes */
+	Confmem	mem[1];
+	ulong	npage;		/* total physical pages of memory */
+	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	ialloc;		/* bytes available for interrupt-time allocation */
+	ulong	pipeqsize;	/* size in bytes of pipe queues */
+	int	nuart;		/* number of uart devices */
+};
+
+/*
+ * floating point registers
+ */
+enum
+{
+	/* floating point state */
+	FPinit,
+	FPactive,
+	FPinactive,
+	FPemu,
+
+	/* bit meaning floating point illegal */
+	FPillegal= 0x100,
+};
+
+enum {
+	Nfpregs		= 32,		/* floats; half as many doubles */
+};
+
+/*
+ * emulated floating point (mips32r2 with ieee fp regs)
+ * fpstate is separate, kept in Proc
+ */
+struct FPsave
+{
+	/* /dev/proc expects the registers to be first in FPsave */
+	ulong	reg[Nfpregs];		/* the canonical bits */
+	union {
+		ulong	fpstatus;	/* both are fcr31 */
+		ulong	fpcontrol;
+	};
+
+	int	fpdelayexec;		/* executing delay slot of branch */
+	uintptr	fpdelaypc;		/* pc to resume at after */
+	ulong	fpdelaysts;	/* save across user-mode delay-slot execution */
+
+	/* stuck-fault detection */
+	uintptr	fppc;			/* addr of last fault */
+	int	fpcnt;			/* how many consecutive at that addr */
+};
+
+int fpemudebug;
+
+/*
+ *  mmu goo in the Proc structure
+ */
+struct PMMU
+{
+	int	pidonmach[MAXMACH];
+};
+
+/*
+ *  things saved in the Proc structure during a notify
+ */
+struct Notsave
+{
+	ulong	nonempty;
+};
+
+#include "../port/portdat.h"
+
+/* First FIVE members' offsets known by l.s */
+struct Mach
+{
+	/* the following are all known by l.s and cannot be moved */
+	int	machno;			/* physical id of processor FIRST */
+	Softtlb*stb;			/* Software tlb simulation SECOND */
+	Proc*	proc;			/* process on this processor THIRD */
+	ulong	splpc;			/* pc that called splhi() FOURTH */
+	ulong	tlbfault;		/* # of tlb faults FIFTH */
+	ulong	ktlbfault;
+	ulong	utlbfault;
+
+	/* the following is safe to move */
+	ulong	tlbpurge;
+	ulong	ticks;			/* of the clock since boot time */
+	Label	sched;			/* scheduler wakeup */
+	void*	alarm;			/* alarms bound to this clock */
+	int	lastpid;		/* last pid allocated on this machine */
+	Proc*	pidproc[NTLBPID];	/* proc that owns tlbpid on this mach */
+	KMap*	kactive;		/* active on this machine */
+	int	knext;
+	uchar	ktlbx[NTLB];		/* tlb index used for kmap */
+	uchar	ktlbnext;
+	int	speed;			/* cpu speed */
+	ulong	delayloop;		/* for the delay() routine */
+	ulong	fairness;		/* for runproc */
+	int	flushmmu;
+	int	inclockintr;
+	int	ilockdepth;
+	Perf	perf;			/* performance counters */
+	uvlong	cyclefreq;		/* Frequency of user readable cycle counter */
+
+	/* for per-processor timers */
+	ulong	lastcount;
+	uvlong	fastticks;
+	ulong	hz;
+	ulong	maxperiod;
+	ulong	minperiod;
+
+	Proc*	readied;		/* for runproc */
+	ulong	schedticks;		/* next forced context switch */
+
+	int	pfault;
+	int	cs;
+	int	syscall;
+	int	load;
+	int	intr;
+	int	hashcoll;		/* soft-tlb hash collisions */
+	int	paststartup;		/* for putktlb */
+
+	int	stack[1];
+};
+
+struct KMap
+{
+	Ref;
+	ulong	virt;
+	ulong	phys0;
+	ulong	phys1;
+	KMap*	next;
+	KMap*	konmach[MAXMACH];
+	Page*	pg;
+	ulong	pc;			/* of caller to kmap() */
+};
+
+#define	VA(k)		((k)->virt)
+#define PPN(x)		((ulong)(x)>>6)
+
+/* offsets known by l.s */
+struct Softtlb
+{
+	ulong	virt;
+	ulong	phys0;
+	ulong	phys1;
+};
+
+struct
+{
+	Lock;
+	long	machs;		/* bitmap of processors */
+	short	exiting;
+	int	ispanic;
+}active;
+
+extern KMap kpte[];
+extern register Mach	*m;
+extern register Proc	*up;
+
+extern FPsave initfp;
+
+extern	int normalprint;

+ 258 - 0
sys/src/9/rb/devarch.c

@@ -0,0 +1,258 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "io.h"
+
+#include "../ip/ip.h"
+
+enum {
+	Qdir = 0,
+	Qbase,
+
+	Qmax = 16,
+};
+
+typedef long Rdwrfn(Chan*, void*, long, vlong);
+
+static Rdwrfn *readfn[Qmax];
+static Rdwrfn *writefn[Qmax];
+
+static Dirtab archdir[Qmax] = {
+	".",		{ Qdir, 0, QTDIR },	0,	0555,
+};
+
+Lock archwlock;	/* the lock is only for changing archdir */
+int narchdir = Qbase;
+
+/*
+ * Add a file to the #P listing.  Once added, you can't delete it.
+ * You can't add a file with the same name as one already there,
+ * and you get a pointer to the Dirtab entry so you can do things
+ * like change the Qid version.  Changing the Qid path is disallowed.
+ */
+Dirtab*
+addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
+{
+	int i;
+	Dirtab d;
+	Dirtab *dp;
+
+	memset(&d, 0, sizeof d);
+	strcpy(d.name, name);
+	d.perm = perm;
+
+	lock(&archwlock);
+	if(narchdir >= Qmax){
+		unlock(&archwlock);
+		return nil;
+	}
+
+	for(i=0; i<narchdir; i++)
+		if(strcmp(archdir[i].name, name) == 0){
+			unlock(&archwlock);
+			return nil;
+		}
+
+	d.qid.path = narchdir;
+	archdir[narchdir] = d;
+	readfn[narchdir] = rdfn;
+	writefn[narchdir] = wrfn;
+	dp = &archdir[narchdir++];
+	unlock(&archwlock);
+
+	return dp;
+}
+
+static Chan*
+archattach(char* spec)
+{
+	return devattach('P', spec);
+}
+
+Walkqid*
+archwalk(Chan* c, Chan *nc, char** name, int nname)
+{
+	return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
+}
+
+static int
+archstat(Chan* c, uchar* dp, int n)
+{
+	return devstat(c, dp, n, archdir, narchdir, devgen);
+}
+
+static Chan*
+archopen(Chan* c, int omode)
+{
+	return devopen(c, omode, archdir, narchdir, devgen);
+}
+
+static void
+archclose(Chan*)
+{
+}
+
+static long
+archread(Chan *c, void *a, long n, vlong offset)
+{
+	Rdwrfn *fn;
+
+	switch((ulong)c->qid.path){
+	case Qdir:
+		return devdirread(c, a, n, archdir, narchdir, devgen);
+
+	default:
+		if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
+			return fn(c, a, n, offset);
+		error(Eperm);
+		break;
+	}
+
+	return 0;
+}
+
+static long
+archwrite(Chan *c, void *a, long n, vlong offset)
+{
+	Rdwrfn *fn;
+
+	if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
+		return fn(c, a, n, offset);
+	error(Eperm);
+
+	return 0;
+}
+
+void archinit(void);
+
+Dev archdevtab = {
+	'P',
+	"arch",
+
+	devreset,
+	archinit,
+	devshutdown,
+	archattach,
+	archwalk,
+	archstat,
+	archopen,
+	devcreate,
+	archclose,
+	archread,
+	devbread,
+	archwrite,
+	devbwrite,
+	devremove,
+	devwstat,
+};
+
+static long
+cputyperead(Chan*, void *a, long n, vlong offset)
+{
+	char str[128];
+
+	snprint(str, sizeof str, "MIPS 24k %lud\n", m->hz / Mhz);
+	return readstr(offset, a, n, str);
+}
+
+static long
+tbread(Chan*, void *a, long n, vlong offset)
+{
+	char str[16];
+	uvlong tb;
+
+	cycles(&tb);
+
+	snprint(str, sizeof(str), "%16.16llux", tb);
+	return readstr(offset, a, n, str);
+}
+
+static long
+nsread(Chan*, void *a, long n, vlong offset)
+{
+	char str[16];
+	uvlong tb;
+
+	cycles(&tb);
+
+	snprint(str, sizeof(str), "%16.16llux", (tb/700)* 1000);
+	return readstr(offset, a, n, str);
+}
+
+char *cputype = "mips";
+
+char	*faultsprint(char *, char *);
+char	*fpemuprint(char *, char *);
+
+static long
+archctlread(Chan*, void *a, long nn, vlong offset)
+{
+	int n;
+	char *buf, *p, *ep;
+
+	p = buf = malloc(READSTR);
+	if(p == nil)
+		error(Enomem);
+	ep = p + READSTR;
+	p = seprint(p, ep, "cpu %s %lud\n", cputype,
+		(ulong)(m->hz+999999)/1000000);
+	p = seprint(p, ep, "stlb hash collisions");
+	for (n = 0; n < conf.nmach; n++)
+		p = seprint(p, ep, " %d", MACHP(n)->hashcoll);
+	p = seprint(p, ep, "\n");
+	p = seprint(p, ep, "NKTLB %d ktlb misses %ld utlb misses %ld\n",
+		NKTLB, m->ktlbfault, m->utlbfault);
+	p = fpemuprint(p, ep);
+	faultsprint(p, ep);
+	n = readstr(offset, a, nn, buf);
+	free(buf);
+	return n;
+}
+
+enum
+{
+	CMfpemudebug,
+};
+
+static Cmdtab archctlmsg[] =
+{
+#ifdef FPEMUDEBUG
+	CMfpemudebug,	"fpemudebug",	2,
+#else
+	CMfpemudebug,	"dummy",	1,
+#endif
+};
+
+static long
+archctlwrite(Chan*, void *a, long n, vlong)
+{
+	Cmdbuf *cb;
+	Cmdtab *ct;
+
+	cb = parsecmd(a, n);
+	if(waserror()){
+		free(cb);
+		nexterror();
+	}
+	ct = lookupcmd(cb, archctlmsg, nelem(archctlmsg));
+	switch(ct->index){
+	case CMfpemudebug:
+		fpemudebug = atoi(cb->f[1]);
+		break;
+	}
+	free(cb);
+	poperror();
+	return n;
+}
+
+void
+archinit(void)
+{
+	addarchfile("cputype", 0444, cputyperead, nil);
+	addarchfile("timebase",0444, tbread, nil);
+	addarchfile("archctl", 0664, archctlread, archctlwrite);
+//	addarchfile("nsec", 0444, nsread, nil);
+}

File diff suppressed because it is too large
+ 1475 - 0
sys/src/9/rb/devether.c


+ 36 - 0
sys/src/9/rb/etherif.h

@@ -0,0 +1,36 @@
+enum {
+	MaxEther	= 2,
+	Ntypes		= 8,
+};
+
+typedef struct Ether Ether;
+struct Ether {
+	int	ctlrno;
+	int	port;
+	int	irq;
+	int	tbdf;			/* type+busno+devno+funcno */
+
+	void	*ctlr;
+	Queue*	oq;
+	uchar	ea[Eaddrlen];
+
+	long	(*ifstat)(Ether*, void*, long, ulong);
+#ifdef MULTIETHERTYPES
+	void	(*attach)(Ether*);	/* filled in by reset routine */
+	void	(*detach)(Ether*);
+	void	(*transmit)(Ether*);
+	void	(*interrupt)(Ureg*, void*);
+	long 	(*ctl)(Ether*, void*, long); /* custom ctl messages */
+	void	(*power)(Ether*, int);	/* power on/off */
+	void	(*shutdown)(Ether*);	/* shutdown hardware before reboot */
+#endif
+	Netif;
+};
+
+extern Block* etheriq(Ether*, Block*, int);
+extern void addethercard(char*, int(*)(Ether*));
+extern ulong ethercrc(uchar*, int);
+extern int parseether(uchar*, char*);
+
+#define NEXT(x, l)	(((x)+1)%(l))
+#define PREV(x, l)	(((x) == 0) ? (l)-1: (x)-1)

+ 235 - 0
sys/src/9/rb/ethermii.c

@@ -0,0 +1,235 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+
+#include "etherif.h"
+#include "ethermii.h"
+
+int
+mii(Mii* mii, int mask)
+{
+	MiiPhy *miiphy;
+	int bit, oui, phyno, r, rmask;
+
+	/*
+	 * Probe through mii for PHYs in mask;
+	 * return the mask of those found in the current probe.
+	 * If the PHY has not already been probed, update
+	 * the Mii information.
+	 */
+	rmask = 0;
+	for(phyno = 0; phyno < NMiiPhy; phyno++){
+		bit = 1<<phyno;
+		if(!(mask & bit))
+			continue;
+		if(mii->mask & bit){
+			rmask |= bit;
+			continue;
+		}
+		if(mii->mir(mii, phyno, Bmsr) == -1)
+			continue;
+		r = mii->mir(mii, phyno, Phyidr1);
+		oui = (r & 0x3FFF)<<6;
+		r = mii->mir(mii, phyno, Phyidr2);
+		oui |= r>>10;
+		if(oui == 0xFFFFF || oui == 0)
+			continue;
+
+		if((miiphy = malloc(sizeof(MiiPhy))) == nil)
+			continue;
+
+		miiphy->mii = mii;
+		miiphy->oui = oui;
+		miiphy->phyno = phyno;
+
+		miiphy->anar = ~0;
+		miiphy->fc = ~0;
+		miiphy->mscr = ~0;
+
+		mii->phy[phyno] = miiphy;
+		if(mii->curphy == nil)
+			mii->curphy = miiphy;
+		mii->mask |= bit;
+		mii->nphy++;
+
+		rmask |= bit;
+	}
+	return rmask;
+}
+
+int
+miimir(Mii* mii, int r)
+{
+	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
+		return -1;
+	return mii->mir(mii, mii->curphy->phyno, r);
+}
+
+int
+miimiw(Mii* mii, int r, int data)
+{
+	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
+		return -1;
+	return mii->miw(mii, mii->curphy->phyno, r, data);
+}
+
+int
+miireset(Mii* mii)
+{
+	int bmcr;
+
+	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
+		return -1;
+	bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr);
+	bmcr |= BmcrR;
+	mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr);
+	microdelay(1);
+
+	return 0;
+}
+
+int
+miiane(Mii* mii, int a, int p, int e)
+{
+	int anar, bmsr, mscr, r, phyno;
+
+	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
+		return -1;
+	phyno = mii->curphy->phyno;
+
+	bmsr = mii->mir(mii, phyno, Bmsr);
+	if(!(bmsr & BmsrAna))
+		return -1;
+
+	if(a != ~0)
+		anar = (AnaTXFD|AnaTXHD|Ana10FD|Ana10HD) & a;
+	else if(mii->curphy->anar != ~0)
+		anar = mii->curphy->anar;
+	else{
+		anar = mii->mir(mii, phyno, Anar);
+		anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
+		if(bmsr & Bmsr10THD)
+			anar |= Ana10HD;
+		if(bmsr & Bmsr10TFD)
+			anar |= Ana10FD;
+		if(bmsr & Bmsr100TXHD)
+			anar |= AnaTXHD;
+		if(bmsr & Bmsr100TXFD)
+			anar |= AnaTXFD;
+	}
+	mii->curphy->anar = anar;
+
+	if(p != ~0)
+		anar |= (AnaAP|AnaP) & p;
+	else if(mii->curphy->fc != ~0)
+		anar |= mii->curphy->fc;
+	mii->curphy->fc = (AnaAP|AnaP) & anar;
+
+	if(bmsr & BmsrEs){
+		mscr = mii->mir(mii, phyno, Mscr);
+		mscr &= ~(Mscr1000TFD|Mscr1000THD);
+		if(e != ~0)
+			mscr |= (Mscr1000TFD|Mscr1000THD) & e;
+		else if(mii->curphy->mscr != ~0)
+			mscr = mii->curphy->mscr;
+		else{
+			r = mii->mir(mii, phyno, Esr);
+			if(r & Esr1000THD)
+				mscr |= Mscr1000THD;
+			if(r & Esr1000TFD)
+				mscr |= Mscr1000TFD;
+		}
+		mii->curphy->mscr = mscr;
+		mii->miw(mii, phyno, Mscr, mscr);
+	}
+	mii->miw(mii, phyno, Anar, anar);
+
+	r = mii->mir(mii, phyno, Bmcr);
+	if(!(r & BmcrR)){
+		r |= BmcrAne|BmcrRan;
+		mii->miw(mii, phyno, Bmcr, r);
+	}
+
+	return 0;
+}
+
+int
+miistatus(Mii* mii)
+{
+	MiiPhy *phy;
+	int anlpar, bmsr, p, r, phyno;
+
+	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
+		return -1;
+	phy = mii->curphy;
+	phyno = phy->phyno;
+
+	/*
+	 * Check Auto-Negotiation is complete and link is up.
+	 * (Read status twice as the Ls bit is sticky).
+	 */
+	bmsr = mii->mir(mii, phyno, Bmsr);
+	if(!(bmsr & (BmsrAnc|BmsrAna))) {
+		// print("miistatus: auto-neg incomplete\n");
+		return -1;
+	}
+
+	bmsr = mii->mir(mii, phyno, Bmsr);
+	if(!(bmsr & BmsrLs)){
+		// print("miistatus: link down\n");
+		phy->link = 0;
+		return -1;
+	}
+
+	phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
+	if(phy->mscr){
+		r = mii->mir(mii, phyno, Mssr);
+		if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
+			phy->speed = 1000;
+			phy->fd = 1;
+		}
+		else if((phy->mscr & Mscr1000THD) && (r & Mssr1000THD))
+			phy->speed = 1000;
+	}
+
+	anlpar = mii->mir(mii, phyno, Anlpar);
+	if(phy->speed == 0){
+		r = phy->anar & anlpar;
+		if(r & AnaTXFD){
+			phy->speed = 100;
+			phy->fd = 1;
+		}
+		else if(r & AnaTXHD)
+			phy->speed = 100;
+		else if(r & Ana10FD){
+			phy->speed = 10;
+			phy->fd = 1;
+		}
+		else if(r & Ana10HD)
+			phy->speed = 10;
+	}
+	if(phy->speed == 0) {
+		// print("miistatus: phy speed 0\n");
+		return -1;
+	}
+
+	if(phy->fd){
+		p = phy->fc;
+		r = anlpar & (AnaAP|AnaP);
+		if(p == AnaAP && r == (AnaAP|AnaP))
+			phy->tfc = 1;
+		else if(p == (AnaAP|AnaP) && r == AnaAP)
+			phy->rfc = 1;
+		else if((p & AnaP) && (r & AnaP))
+			phy->rfc = phy->tfc = 1;
+	}
+
+	phy->link = 1;
+
+	return 0;
+}

+ 116 - 0
sys/src/9/rb/ethermii.h

@@ -0,0 +1,116 @@
+typedef struct Mii Mii;
+typedef struct MiiPhy MiiPhy;
+
+enum {					/* registers */
+	Bmcr		= 0x00,		/* Basic Mode Control */
+	Bmsr		= 0x01,		/* Basic Mode Status */
+	Phyidr1		= 0x02,		/* PHY Identifier #1 */
+	Phyidr2		= 0x03,		/* PHY Identifier #2 */
+	Anar		= 0x04,		/* Auto-Negotiation Advertisement */
+	Anlpar		= 0x05,		/* AN Link Partner Ability */
+	Aner		= 0x06,		/* AN Expansion */
+	Annptr		= 0x07,		/* AN Next Page TX */
+	Annprr		= 0x08,		/* AN Next Page RX */
+	Mscr		= 0x09,		/* MASTER-SLAVE Control */
+	Mssr		= 0x0A,		/* MASTER-SLAVE Status */
+	Esr		= 0x0F,		/* Extended Status */
+
+	NMiiPhyr	= 32,
+	NMiiPhy		= 32,
+};
+
+enum {					/* Bmcr */
+	BmcrSs1		= 0x0040,	/* Speed Select[1] */
+	BmcrCte		= 0x0080,	/* Collision Test Enable */
+	BmcrDm		= 0x0100,	/* Duplex Mode */
+	BmcrRan		= 0x0200,	/* Restart Auto-Negotiation */
+	BmcrI		= 0x0400,	/* Isolate */
+	BmcrPd		= 0x0800,	/* Power Down */
+	BmcrAne		= 0x1000,	/* Auto-Negotiation Enable */
+	BmcrSs0		= 0x2000,	/* Speed Select[0] */
+	BmcrLe		= 0x4000,	/* Loopback Enable */
+	BmcrR		= 0x8000,	/* Reset */
+};
+
+enum {					/* Bmsr */
+	BmsrEc		= 0x0001,	/* Extended Capability */
+	BmsrJd		= 0x0002,	/* Jabber Detect */
+	BmsrLs		= 0x0004,	/* Link Status */
+	BmsrAna		= 0x0008,	/* Auto-Negotiation Ability */
+	BmsrRf		= 0x0010,	/* Remote Fault */
+	BmsrAnc		= 0x0020,	/* Auto-Negotiation Complete */
+	BmsrPs		= 0x0040,	/* Preamble Suppression Capable */
+	BmsrEs		= 0x0100,	/* Extended Status */
+	Bmsr100T2HD	= 0x0200,	/* 100BASE-T2 HD Capable */
+	Bmsr100T2FD	= 0x0400,	/* 100BASE-T2 FD Capable */
+	Bmsr10THD	= 0x0800,	/* 10BASE-T HD Capable */
+	Bmsr10TFD	= 0x1000,	/* 10BASE-T FD Capable */
+	Bmsr100TXHD	= 0x2000,	/* 100BASE-TX HD Capable */
+	Bmsr100TXFD	= 0x4000,	/* 100BASE-TX FD Capable */
+	Bmsr100T4	= 0x8000,	/* 100BASE-T4 Capable */
+};
+
+enum {					/* Anar/Anlpar */
+	Ana10HD		= 0x0020,	/* Advertise 10BASE-T */
+	Ana10FD		= 0x0040,	/* Advertise 10BASE-T FD */
+	AnaTXHD		= 0x0080,	/* Advertise 100BASE-TX */
+	AnaTXFD		= 0x0100,	/* Advertise 100BASE-TX FD */
+	AnaT4		= 0x0200,	/* Advertise 100BASE-T4 */
+	AnaP		= 0x0400,	/* Pause */
+	AnaAP		= 0x0800,	/* Asymmetrical Pause */
+	AnaRf		= 0x2000,	/* Remote Fault */
+	AnaAck		= 0x4000,	/* Acknowledge */
+	AnaNp		= 0x8000,	/* Next Page Indication */
+};
+
+enum {					/* Mscr */
+	Mscr1000THD	= 0x0100,	/* Advertise 1000BASE-T HD */
+	Mscr1000TFD	= 0x0200,	/* Advertise 1000BASE-T FD */
+};
+
+enum {					/* Mssr */
+	Mssr1000THD	= 0x0400,	/* Link Partner 1000BASE-T HD able */
+	Mssr1000TFD	= 0x0800,	/* Link Partner 1000BASE-T FD able */
+};
+
+enum {					/* Esr */
+	Esr1000THD	= 0x1000,	/* 1000BASE-T HD Capable */
+	Esr1000TFD	= 0x2000,	/* 1000BASE-T FD Capable */
+	Esr1000XHD	= 0x4000,	/* 1000BASE-X HD Capable */
+	Esr1000XFD	= 0x8000,	/* 1000BASE-X FD Capable */
+};
+
+typedef struct Mii {
+	Lock;
+	int	nphy;
+	int	mask;
+	MiiPhy*	phy[NMiiPhy];
+	MiiPhy*	curphy;
+
+	void*	ctlr;
+	int	(*mir)(Mii*, int, int);
+	int	(*miw)(Mii*, int, int, int);
+} Mii;
+
+typedef struct MiiPhy {
+	Mii*	mii;
+	int	oui;
+	int	phyno;
+
+	int	anar;
+	int	fc;
+	int	mscr;
+
+	int	link;
+	int	speed;
+	int	fd;
+	int	rfc;
+	int	tfc;
+};
+
+extern int mii(Mii*, int);
+extern int miiane(Mii*, int, int, int);
+extern int miimir(Mii*, int);
+extern int miimiw(Mii*, int, int);
+extern int miireset(Mii*);
+extern int miistatus(Mii*);

+ 238 - 0
sys/src/9/rb/faultmips.c

@@ -0,0 +1,238 @@
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"ureg.h"
+#include	"../port/error.h"
+#include	"io.h"
+
+enum {
+	Debug = 0,
+};
+
+typedef struct Fault Fault;
+struct Fault {
+	uintptr	va;
+	ulong	pid;
+	uintptr	pc;
+	int	cnt;
+	char	*prog;
+	int	code;
+};
+
+extern char *excname[];
+
+static Fault lflt, maxflt;
+
+/*
+ * Ask if the instruction at EPC could have cause this badvaddr
+ */
+int
+tstbadvaddr(Ureg *ur)
+{
+	int rn;
+	ulong iw, off, ea;
+
+	iw = ur->pc;
+	if(ur->cause & BD)
+		iw += 4;
+
+	if(seg(up, iw, 0) == 0)
+		return 0;
+
+	iw = *(ulong*)iw;
+
+/*	print("iw: %#lux\n", iw);	/**/
+
+	switch((iw>>26) & 0x3f) {
+	default:
+		return 1;
+	case 0x20:	/* LB */
+	case 0x24:	/* LBU */
+			/* LD */
+	case 0x35:
+	case 0x36:
+	case 0x37:	/* LDCz */
+	case 0x1A:	/* LDL */
+	case 0x1B:	/* LDR */
+	case 0x21:	/* LH */
+	case 0x25:	/* LHU */
+	case 0x30:	/* LL */
+	case 0x34:	/* LLD */
+	case 0x23:	/* LW */
+	case 0x31:
+	case 0x32:	/* LWCz possible 0x33 */
+	case 0x27:	/* LWU */
+	case 0x22:	/* LWL */
+	case 0x26:	/* LWR */
+		break;
+
+	case 0x28:	/* SB */
+	case 0x38:	/* SC */
+	case 0x3C:	/* SCD */
+	case 0x3D:
+	case 0x3E:
+	case 0x3F:	/* SDCz */
+	case 0x2C:	/* SDL */
+	case 0x2D:	/* SDR */
+	case 0x29:	/* SH */
+	case 0x2B:	/* SW */
+	case 0x39:
+	case 0x3A:	/* SWCz */
+	case 0x2A:	/* SWL */
+	case 0x2E:	/* SWR */
+		break;
+	}
+
+	off = iw & 0xffff;
+	if(off & 0x8000)
+		off |= ~0xffff;
+
+	rn = (iw>>21) & 0x1f;
+	ea = *reg(ur, rn);
+	if(rn == 0)
+		ea = 0;
+	ea += off;
+
+	/* print("ea %#lux %#lux(R%d) bv %#lux pc %#lux\n", ea, off, rn, ur->badvaddr, ur->pc); /**/
+
+	if(ur->badvaddr == ea)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * we think we get consecutive page faults from unlucky combinations of
+ * scheduling and stlb hashes, and they only happen with 16K pages.
+ * however, we also get page faults while servicing the exact same fault.
+ * more than 5 consecutive faults is unusual, now that we have a better
+ * hash function.
+ *
+ * this can be helpful during mmu and cache debugging.
+ */
+static int
+ckfaultstuck(Ureg *ur, int read, int code)
+{
+	uintptr pc, va;
+
+	va = ur->badvaddr;
+	pc = ur->pc;
+	if (va != lflt.va || up->pid != lflt.pid || pc != lflt.pc ||
+	    code != lflt.code) {
+		/* at least one address or cause is different from last time */
+		lflt.cnt = 1;
+		lflt.va = va;
+		lflt.pid = up->pid;
+		lflt.pc = pc;
+		lflt.code = code;
+		return 0;
+	}
+	++lflt.cnt;
+	if (lflt.cnt >= 1000)	/* fixfault() isn't fixing underlying cause? */
+		panic("fault: %d consecutive faults for va %#p", lflt.cnt, va);
+	if (lflt.cnt > maxflt.cnt) {
+		maxflt.cnt = lflt.cnt;
+		maxflt.va = va;
+		maxflt.pid = up->pid;
+		maxflt.pc = pc;
+		kstrdup(&maxflt.prog, up->text);
+	}
+
+	/* we're servicing that fault now! */
+	/* adjust the threshold and program name to suit */
+	if (lflt.cnt < 5 || strncmp(up->text, "8l", 2) != 0)
+		return 0;
+	iprint("%d consecutive faults for va %#p at pc %#p in %s "
+		"pid %ld\n", lflt.cnt, lflt.va, pc, up->text, lflt.pid);
+	iprint("\t%s: %s%s r31 %#lux tlbvirt %#lux\n",
+		excname[code], va == pc? "[instruction] ": "",
+		(read? "read": "write"), ur->r31, tlbvirt());
+	return 0;
+}
+
+char *
+faultsprint(char *p, char *ep)
+{
+	if (Debug)
+		p = seprint(p, ep,
+			"max consecutive faults %d for va %#p in %s\n",
+			maxflt.cnt, maxflt.va, maxflt.prog);
+	return p;
+}
+
+/*
+ *  find out fault address and type of access.
+ *  Call common fault handler.
+ */
+void
+faultmips(Ureg *ur, int user, int code)
+{
+	int read;
+	ulong addr;
+	char *p, buf[ERRMAX];
+	static int infault, printed;
+
+	if (0 && infault && !printed) {
+		printed = 1;
+		print("fault: recursive fault (%d deep) pc %#p va %#p\n",
+			infault+1, ur->pc, ur->badvaddr);
+	}
+	infault++;
+	if(waserror()){
+		infault--;
+		nexterror();
+	}
+
+	addr = ur->badvaddr;
+	addr &= ~(BY2PG-1);
+
+	read = !(code==CTLBM || code==CTLBS);
+
+/*	print("fault: %s code %d va %#p pc %#p r31 %#lux tlbvirt %#lux\n",
+		up->text, code, ur->badvaddr, ur->pc, ur->r31, tlbvirt());/**/
+
+	if (Debug && ckfaultstuck(ur, read, code) || fault(addr, read) == 0){
+		infault--;
+		poperror();
+		return;
+	}
+
+	infault--;
+	poperror();
+
+	if(tstbadvaddr(ur)) {
+		print("fault: spurious badvaddr %#lux in %s at pc %#lux\n",
+			ur->badvaddr, up->text, ur->pc);/**/
+		return;
+	}
+
+	if(user) {
+		p = "store";
+		if(read)
+			p = "load";
+		snprint(buf, sizeof buf, "sys: trap: fault %s addr=%#lux r31=%#lux",
+			p, ur->badvaddr, ur->r31);
+		postnote(up, 1, buf, NDebug);
+		return;
+	}
+
+	print("kernel %s vaddr=%#lux\n", excname[code], ur->badvaddr);
+	print("st=%#lux pc=%#lux r31=%#lux sp=%#lux\n",
+		ur->status, ur->pc, ur->r31, 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);
+	}
+}

+ 146 - 0
sys/src/9/rb/fns.h

@@ -0,0 +1,146 @@
+#include "../port/portfns.h"
+
+void	arginit(void);
+int	busprobe(ulong);
+ulong	cankaddr(ulong);
+void	cleancache(void);
+void	clearmmucache(void);
+void	clock(Ureg*);
+void	clockinit(void);
+void	clockshutdown(void);
+int	cmpswap(long*, long, long);
+void	coherence(void);
+void	cycles(uvlong *);
+void	dcflush(void*, ulong);
+void	evenaddr(ulong);
+void	faultmips(Ureg*, int, int);
+ulong	fcr31(void);
+void	firmware(int);
+void	fpclear(void);
+void	fpsave(FPsave *);
+void	fptrap(Ureg*);
+int	fpuemu(Ureg *);
+void	fpwatch(Ureg *);
+ulong	getcause(void);
+char*	getconf(char*);
+ulong	getconfig(void);
+ulong	getconfig1(void);
+ulong	getconfig2(void);
+ulong	getconfig3(void);
+ulong	getconfig7(void);
+ulong	gethwreg3(void);
+ulong	getpagemask(void);
+ulong	getstatus(void);
+int	gettlbp(ulong, ulong*);
+ulong	gettlbvirt(int);
+void	gotopc(ulong);
+void	hinv(void);
+int	i8250console(void);
+void	icflush(void *, ulong);
+void	idle(void);
+void	idlehands(void);
+int	inb(int);
+void	insb(int, void*, int);
+ushort	ins(int);
+void	inss(int, void*, int);
+ulong	inl(int);
+void	insl(int, void*, int);
+void	ioinit(void);
+void	introff(int);
+void	intron(int);
+void	intrshutdown(void);
+void	kfault(Ureg*);
+KMap*	kmap(Page*);
+void	kmapinit(void);
+void	kmapinval(void);
+void	kunmap(KMap*);
+void	launchinit(void);
+void	launch(int);
+void	links(void);
+ulong	machstatus(void);
+void	newstart(void);
+int	newtlbpid(Proc*);
+void	online(void);
+void	outb(int, int);
+void	outsb(int, void*, int);
+void	outs(int, ushort);
+void	outss(int, void*, int);
+void	outl(int, ulong);
+void	outsl(int, void*, int);
+ulong	pcibarsize(Pcidev*, int);
+void	pcibussize(Pcidev*, ulong*, ulong*);
+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	pciclrbme(Pcidev*);
+void	pciclrioe(Pcidev*);
+void	pciclrmwi(Pcidev*);
+int	pcigetpms(Pcidev*);
+void	pcihinv(Pcidev*);
+uchar	pciipin(Pcidev*, uchar);
+Pcidev* pcimatch(Pcidev*, int, int);
+Pcidev* pcimatchtbdf(int);
+void	pcireset(void);
+int	pciscan(int, Pcidev**);
+void	pcisetbme(Pcidev*);
+void	pcisetioe(Pcidev*);
+void	pcisetmwi(Pcidev*);
+int	pcisetpms(Pcidev*, int);
+ulong	prid(void);
+void	procrestore(Proc *);
+void	procsave(Proc *);
+#define	procsetup(p)	((p)->fpstate = FPinit)
+void	purgetlb(int);
+Softtlb*	putstlb(ulong, ulong);
+int	puttlb(ulong, ulong, ulong);
+void	puttlbx(int, ulong, ulong, ulong, int);
+ulong	rdcompare(void);
+ulong	rdcount(void);
+ulong*	reg(Ureg*, int);
+void	restfpregs(FPsave*, ulong);
+void	intrenable(int, void(*)(void *), void *);
+void	setleveldest(int, int, uvlong*);
+void	setpagemask(ulong);
+void	setsp(ulong);
+void	setstatus(ulong);
+void	setwatchhi0(ulong);
+void	setwatchlo0(ulong);
+void	setwired(ulong);
+void	sicwdog(void);
+void	silencewdog(void);
+ulong	stlbhash(ulong);
+void	stopwdog(void);
+void	syncclock(void);
+long	syscall(Ureg*);
+void	syscallfmt(int syscallno, ulong pc, va_list list);
+void	sysretfmt(int syscallno, va_list list, long ret, uvlong start, uvlong stop);
+int	tas(ulong*);
+void	tlbinit(void);
+ulong	tlbvirt(void);
+void	touser(uintptr);
+void	unleash(void);
+#define	userureg(ur) ((ur)->status & KUSER)
+void	vecinit(void);
+void	vector0(void);
+void	vector100(void);
+void	vector180(void);
+void	wdogreset(void);
+void	wrcompare(ulong);
+void	wrcount(ulong);
+ulong	wiredpte(vlong);
+void	machwire(void);
+void	_uartputs(char*, int);
+int	_uartprint(char*, ...);
+
+#define PTR2UINT(p)	((uintptr)(p))
+#define UINT2PTR(i)	((void*)(i))
+
+#define	waserror()	(up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
+
+#define KADDR(a)	((void*)((ulong)(a)|KSEG0))
+#define PADDR(a)	((ulong)(a)&~KSEGM)
+
+#define KSEG1ADDR(a)	((void*)((ulong)(a)|KSEG1))

File diff suppressed because it is too large
+ 1485 - 0
sys/src/9/rb/fpimips.c


+ 8 - 0
sys/src/9/rb/init9.s

@@ -0,0 +1,8 @@
+TEXT	_main(SB), $8
+	MOVW	$setR30(SB), R30
+	MOVW	$boot(SB), R1
+	ADDU	$12, R29, R2	/* get a pointer to 0(FP) */
+	MOVW	R1, 4(R29)
+	MOVW	R2, 8(R29)
+	JAL	startboot(SB)
+

+ 44 - 0
sys/src/9/rb/initcode

@@ -0,0 +1,44 @@
+#include "/sys/src/libc/9syscall/sys.h"
+
+/*
+ *  we pass in the argument of the exec parameters as 0(FP)
+ */
+
+TEXT	main(SB),$8
+
+	MOVW	$setR30(SB), R30
+
+	MOVW	$boot(SB), R1
+	ADD	$12, R29, R2	/* get a pointer to 0(FP) */
+	MOVW	R1, 4(R29)
+	MOVW	R2, 8(R29)
+	JAL	exec(SB)
+
+	MOVW	$(1<<4), R1
+	MOVW	R1, 4(R29)
+	MOVW	$RFORK, R1
+	SYSCALL
+	MOVW	$RFORK, R1
+	SYSCALL
+	MOVW	$RFORK, R1
+	SYSCALL
+again:
+	ADDU	$1, R2
+	MOVW	$0, R1	/* print r1 */
+	SYSCALL
+	MOVW	$5000000, R3
+foo:
+	SUBU	$1, R3
+	BNE	R3, foo
+	JMP	again
+
+TEXT	exec(SB), $0
+	MOVW	$EXEC, R1
+	SYSCALL
+	RET
+
+DATA	boot+0(SB)/5,$"/boot"
+DATA	boot+5(SB)/5,$"/boot"
+DATA	bootv+0(SB)/4,$boot+6(SB)
+GLOBL	boot+0(SB),$11
+GLOBL	bootv+0(SB),$8

+ 60 - 0
sys/src/9/rb/initreboot.s

@@ -0,0 +1,60 @@
+/*
+ * mips 24k machine assist for routerboard rb450g (minimal for reboot)
+ */
+#include "mem.h"
+#include "mips.s"
+
+	NOSCHED
+
+TEXT	_main(SB), $0
+	MOVW	$setR30(SB), R30
+	JMP	main(SB)
+
+/* target for JALRHB in BARRIERS */
+TEXT ret(SB), $-4
+	JMP	(R22)
+	NOP
+
+TEXT	setsp(SB), $-4
+	MOVW	R1, SP
+	RETURN
+
+TEXT	coherence(SB), $-4
+	BARRIERS(7, R7, cohhb)
+	SYNC
+	EHB
+	RETURN
+
+/*
+ *  cache manipulation
+ */
+
+/* the i and d caches may be different sizes, so clean them separately */
+TEXT	cleancache(SB), $-4
+	DI(10)				/* intrs off, old status -> R10 */
+	SYNC
+	EHB
+
+	MOVW	R0, R1			/* index, not address */
+	MOVW	$ICACHESIZE, R9
+iccache:
+	CACHE	PI+IWBI, (R1)		/* flush & invalidate I by index */
+	SUBU	$CACHELINESZ, R9
+	ADDU	$CACHELINESZ, R1
+	BGTZ	R9, iccache
+	NOP
+
+	MOVW	R0, R1			/* index, not address */
+	MOVW	$DCACHESIZE, R9
+dccache:
+	CACHE	PD+IWBI, (R1)		/* flush & invalidate D by index */
+	SUBU	$CACHELINESZ, R9
+	ADDU	$CACHELINESZ, R1
+	BGTZ	R9, dccache
+	NOP
+
+	SYNC
+	MOVW	R10, M(STATUS)
+	JRHB(31)			/* return and clear all hazards */
+
+	SCHED

+ 333 - 0
sys/src/9/rb/io.h

@@ -0,0 +1,333 @@
+enum {
+	Mhz		= 1000*1000,
+};
+
+/*
+ *  duarts, frequency and registers
+ */
+#define DUARTFREQ	3672000
+
+/*
+ *  interrupt levels on CPU boards.
+ */
+enum
+{
+	ILmin		= 2,
+	ILpci		= 2,
+	ILehci		= 3,
+	ILenet1		= 4,		/* arge1 @ 0x19:: w switch */
+	ILenet0		= 5,		/* arge0 @ 0x1a:: */
+	ILduart0	= 6,		/* actually APB, uart is subintr 3 */
+	ILclock		= 7,
+	ILmax		= 7,
+
+	ILshift		= 8,
+};
+
+#define	Rstblockbase	(ulong *)KSEG1ADDR(0x18060000)
+
+#define Rstwdogctl	(ulong *)KSEG1ADDR(0x18060008)
+#define		Wdoglast	(1 << 31)
+#define		Wdogmask	3
+#define		Wdognoaction	0
+#define		Wdoggpintr	1
+#define		Wdognmi		2
+#define		Wdogreset	3
+#define Rstwdogtimer	(ulong *)KSEG1ADDR(0x1806000c)
+
+/*
+ * APB interrupt status and mask register and interrupt bits
+ */
+#define Apbintrsts	(ulong *)KSEG1ADDR(0x18060010)
+#define Apbintrmask	(ulong *)KSEG1ADDR(0x18060014)
+#define		Apbintrtimer		0
+#define		Apbintrerror		1
+#define		Apbintrgpio		2
+#define		Apbintruart		3
+#define		Apbintrwatchdog		4
+#define		Apbintrperf		5
+#define		Apbintrohci		6
+#define		Apbintrdma		7
+
+#define Pciintrsts	(ulong *)KSEG1ADDR(0x18060018)
+#define Pciintrmask	(ulong *)KSEG1ADDR(0x1806001C)
+#define		PCI_INTR_CORE		(1 << 4)
+
+#define Reset	(ulong *)KSEG1ADDR(0x18060024)
+#define		Rstfullchip	(1 << 24) /* same as pulling the reset pin */
+#define		Rstcpucold	(1 << 20) /* cold reset */
+#define		Rstge1mac	(1 << 13)
+#define		Rstge1phy	(1 << 12)
+#define		Rstge0mac	(1 <<  9)
+#define		Rstge0phy	(1 <<  8)
+#define		Rstusbohcidll	(1 <<  6)
+#define		Rstusbhost	(1 <<  5)
+#define		Rstusbphy	(1 <<  4)
+#define		Rstpcibus	(1 <<  1)
+#define		Rstpcicore	(1 <<  0)
+
+/*
+ * mostly PCI from here on
+ */
+
+typedef struct Pcisiz Pcisiz;
+typedef struct Pcidev Pcidev;
+typedef struct Vctl Vctl;
+
+struct Vctl {
+	Vctl*	next;			/* handlers on this vector */
+
+	char	name[KNAMELEN];		/* of driver */
+	int	isintr;			/* interrupt or fault/trap */
+	int	irq;
+	int	tbdf;
+	int	(*isr)(int);		/* get isr bit for this irq */
+	int	(*eoi)(int);		/* eoi */
+
+	void	(*f)(Ureg*, void*);	/* handler to call */
+	void*	a;			/* argument to call it with */
+};
+
+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 BUSBDF(tbdf)	((tbdf)&0x00FFFF00)
+#define BUSUNKNOWN	(-1)
+
+enum {
+	MaxEISA		= 16,
+	CfgEISA		= 0xC80,
+};
+
+/*
+ * PCI support code.
+ */
+enum {					/* type 0 & 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 */
+};
+
+/* ccrb (base class code) values; controller types */
+enum {
+	Pcibcpci1	= 0,		/* pci 1.0; no class codes defined */
+	Pcibcstore	= 1,		/* mass storage */
+	Pcibcnet	= 2,		/* network */
+	Pcibcdisp	= 3,		/* display */
+	Pcibcmmedia	= 4,		/* multimedia */
+	Pcibcmem	= 5,		/* memory */
+	Pcibcbridge	= 6,		/* bridge */
+	Pcibccomm	= 7,		/* simple comms (e.g., serial) */
+	Pcibcbasesys	= 8,		/* base system */
+	Pcibcinput	= 9,		/* input */
+	Pcibcdock	= 0xa,		/* docking stations */
+	Pcibcproc	= 0xb,		/* processors */
+	Pcibcserial	= 0xc,		/* serial bus (e.g., USB) */
+	Pcibcwireless	= 0xd,		/* wireless */
+	Pcibcintell	= 0xe,		/* intelligent i/o */
+	Pcibcsatcom	= 0xf,		/* satellite comms */
+	Pcibccrypto	= 0x10,		/* encryption/decryption */
+	Pcibcdacq	= 0x11,		/* data acquisition & signal proc. */
+};
+
+/* ccru (sub-class code) values; common cases only */
+enum {
+	/* mass storage */
+	Pciscscsi	= 0,		/* SCSI */
+	Pciscide	= 1,		/* IDE (ATA) */
+	Pciscsata	= 6,		/* SATA */
+
+	/* network */
+	Pciscether	= 0,		/* Ethernet */
+
+	/* display */
+	Pciscvga	= 0,		/* VGA */
+	Pciscxga	= 1,		/* XGA */
+	Pcisc3d		= 2,		/* 3D */
+
+	/* bridges */
+	Pcischostpci	= 0,		/* host/pci */
+	Pciscpcicpci	= 1,		/* pci/pci */
+
+	/* simple comms */
+	Pciscserial	= 0,		/* 16450, etc. */
+	Pciscmultiser	= 1,		/* multiport serial */
+
+	/* serial bus */
+	Pciscusb	= 3,		/* USB */
+};
+
+enum {					/* type 0 pre-defined header */
+	PciCIS		= 0x28,		/* cardbus CIS pointer */
+	PciSVID		= 0x2C,		/* subsystem vendor ID */
+	PciSID		= 0x2E,		/* cardbus CIS pointer */
+	PciEBAR0	= 0x30,		/* expansion 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 */
+};
+
+enum {					/* type 2 pre-defined header */
+	PciCBExCA	= 0x10,
+	PciCBSPSR	= 0x16,
+	PciCBPBN	= 0x18,		/* primary bus number */
+	PciCBSBN	= 0x19,		/* secondary bus number */
+	PciCBUBN	= 0x1A,		/* subordinate bus number */
+	PciCBSLTR	= 0x1B,		/* secondary latency timer */
+	PciCBMBR0	= 0x1C,
+	PciCBMLR0	= 0x20,
+	PciCBMBR1	= 0x24,
+	PciCBMLR1	= 0x28,
+	PciCBIBR0	= 0x2C,		/* I/O base */
+	PciCBILR0	= 0x30,		/* I/O limit */
+	PciCBIBR1	= 0x34,		/* I/O base */
+	PciCBILR1	= 0x38,		/* I/O limit */
+	PciCBSVID	= 0x40,		/* subsystem vendor ID */
+	PciCBSID	= 0x42,		/* subsystem ID */
+	PciCBLMBAR	= 0x44,		/* legacy mode base address */
+};
+
+struct Pcisiz
+{
+	Pcidev*	dev;
+	int	siz;
+	int	bar;
+};
+
+struct Pcidev
+{
+	int	tbdf;			/* type+bus+device+function */
+	ushort	vid;			/* vendor ID */
+	ushort	did;			/* device ID */
+
+	ushort	pcr;
+
+	uchar	rid;
+	uchar	ccrp;
+	uchar	ccru;
+	uchar	ccrb;
+	uchar	cls;
+	uchar	ltr;
+
+	struct {
+		ulong	bar;		/* base address */
+		int	size;
+	} mem[6];
+
+	struct {
+		ulong	bar;	
+		int	size;
+	} rom;
+	uchar	intl;			/* interrupt line */
+
+	Pcidev*	list;
+	Pcidev*	link;			/* next device on this bno */
+
+	Pcidev*	bridge;			/* down a bus */
+	struct {
+		ulong	bar;
+		int	size;
+	} ioa, mema;
+
+	int	pmrb;			/* power management register block */
+};
+
+enum {
+	/* vendor ids */
+	Vatiamd	= 0x1002,
+	Vintel	= 0x8086,
+	Vjmicron= 0x197b,
+	Vmarvell= 0x1b4b,
+	Vmyricom= 0x14c1,
+};
+
+#define PCIWINDOW	0
+#define PCIWADDR(va)	(PADDR(va)+PCIWINDOW)
+#define ISAWINDOW	0
+#define ISAWADDR(va)	(PADDR(va)+ISAWINDOW)
+
+/* SMBus transactions */
+enum
+{
+	SMBquick,		/* sends address only */
+
+	/* write */
+	SMBsend,		/* sends address and cmd */
+	SMBbytewrite,		/* sends address and cmd and 1 byte */
+	SMBwordwrite,		/* sends address and cmd and 2 bytes */
+
+	/* read */
+	SMBrecv,		/* sends address, recvs 1 byte */
+	SMBbyteread,		/* sends address and cmd, recv's byte */
+	SMBwordread,		/* sends address and cmd, recv's 2 bytes */
+};
+
+typedef struct SMBus SMBus;
+struct SMBus {
+	QLock;		/* mutex */
+	Rendez	r;	/* rendezvous point for completion interrupts */
+	void	*arg;	/* implementation dependent */
+	ulong	base;	/* port or memory base of smbus */
+	int	busy;
+	void	(*transact)(SMBus*, int, int, int, uchar*);
+};
+
+#pragma varargck	type	"T"	int
+#pragma varargck	type	"T"	uint

File diff suppressed because it is too large
+ 1073 - 0
sys/src/9/rb/l.s


+ 622 - 0
sys/src/9/rb/main.c

@@ -0,0 +1,622 @@
+#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	"../ip/ip.h"
+#include	<tos.h>
+#include	<bootexec.h>
+#include	"reboot.h"
+
+typedef struct mipsexec Mipsexec;
+
+/*
+ * Option arguments from the command line.
+ * oargv[0] is the boot file.
+ */
+static int oargc;
+static char* oargv[20];
+static char oargb[128];
+static int oargblen;
+
+static uintptr sp;		/* XXX - must go - user stack of init proc */
+
+/*
+ * software tlb simulation
+ */
+static Softtlb stlb[MAXMACH][STLBSIZE];
+
+Conf	conf;
+FPsave	initfp;
+
+int normalprint;
+
+char *
+getconf(char *)
+{
+	return nil;	/* stub */
+}
+
+static void
+optionsinit(char* s)
+{
+	strecpy(oargb, oargb+sizeof(oargb), s);
+
+	oargblen = strlen(oargb);
+	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
+	oargv[oargc] = nil;
+}
+
+static void
+prcpuid(void)
+{
+	ulong cpuid, cfg1;
+	char *cpu;
+
+	cpuid = prid();
+	if (((cpuid>>16) & MASK(8)) == 0)		/* vendor */
+		cpu = "old mips";
+	else if (((cpuid>>16) & MASK(8)) == 1)
+		switch ((cpuid>>8) & MASK(8)) {		/* processor */
+		case 0x93:
+			cpu = "mips 24k";
+			break;
+		case 0x96:
+			cpu = "mips 24ke";
+			break;
+		default:
+			cpu = "mips";
+			break;
+		}
+	else
+		cpu = "other mips";
+	delay(20);
+	print("cpu%d: %ldMHz %s %se v%ld.%ld rev %ld, ",
+		m->machno, m->hz / Mhz, cpu, getconfig() & (1<<15)? "b": "l",
+		(cpuid>>5) & MASK(3), (cpuid>>2) & MASK(3), cpuid & MASK(2));
+	delay(200);
+	cfg1 = getconfig1();
+	print("%s fpu\n", (cfg1 & 1? "has": "no"));
+	print("cpu%d: %ld tlb entries, using %dK pages\n", m->machno,
+		((cfg1>>25) & MASK(6)) + 1, BY2PG/1024);
+	delay(50);
+	print("cpu%d: l1 i cache: %d sets 4 ways 32 bytes/line\n", m->machno,
+		64 << ((cfg1>>22) & MASK(3)));
+	delay(50);
+	print("cpu%d: l1 d cache: %d sets 4 ways 32 bytes/line\n", m->machno,
+		64 << ((cfg1>>13) & MASK(3)));
+	delay(500);
+	if (0)
+		print("cpu%d: cycle counter res = %ld\n",
+			m->machno, gethwreg3());
+}
+
+static void
+fmtinit(void)
+{
+	printinit();
+	quotefmtinstall();
+	/* ipreset installs these when chandevreset runs */
+	fmtinstall('i', eipfmt);
+	fmtinstall('I', eipfmt);
+	fmtinstall('E', eipfmt);
+	fmtinstall('V', eipfmt);
+	fmtinstall('M', eipfmt);
+}
+
+static int
+ckpagemask(ulong mask, ulong size)
+{
+	int s;
+	ulong pm;
+
+	s = splhi();
+	setpagemask(mask);
+	pm = getpagemask();
+	splx(s);
+	if(pm != mask){
+		iprint("page size %ldK not supported on this cpu; "
+			"mask %#lux read back as %#lux\n", size/1024, mask, pm);
+		return -1;
+	}
+	return 0;
+}
+
+/* called from rebootcmd() */
+int
+parsemipsboothdr(Chan *c, ulong magic, Execvals *evp)
+{
+	long extra;
+	Mipsexec me;
+
+	/*
+	 * BOOT_MAGIC is sometimes defined like this:
+	 * #define BOOT_MAGIC	(0x160<<16) || magic == ((0x160<<16)|3)
+	 * so we can only use it in a fairly stylized manner.
+	 */
+	if(magic == BOOT_MAGIC) {
+		c->offset = 0;			/* back up */
+		readn(c, &me, sizeof me);
+		/* if binary is -H1, read an extra long */
+		if (l2be(me.amagic) == 0407 && me.nscns == 0)
+			readn(c, &extra, sizeof extra);
+		evp->entry = l2be(me.mentry);
+		evp->textsize = l2be(me.tsize);
+		evp->datasize = l2be(me.dsize);
+		return 0;
+	} else
+		return -1;
+}
+
+void
+main(void)
+{
+	stopwdog();			/* tranquilise the dog */
+	optionsinit("/boot/boot boot");
+	confinit();
+	savefpregs(&initfp);
+
+	machinit();			/* calls clockinit */
+	active.exiting = 0;
+	active.machs = 1;
+
+	kmapinit();
+	xinit();
+
+	timersinit();
+	fmtinit();
+	vecinit();
+
+	normalprint = 1;
+	print("\nPlan 9\n");
+	prcpuid();
+	if (PTECACHABILITY == PTENONCOHERWT)
+		print("caches configured as write-through\n");
+	if (0)
+		xsummary();
+
+	ckpagemask(PGSZ, BY2PG);
+	tlbinit();
+	machwire();
+	pageinit();
+	procinit0();
+	initseg();
+	links();
+	chandevreset();
+
+	swapinit();
+	userinit();
+	sicwdog();
+	parseboothdr = parsemipsboothdr;
+	schedinit();
+	panic("schedinit returned");
+}
+
+/*
+ *  initialize a processor's mach structure.  each processor does this
+ *  for itself.
+ */
+void
+machinit(void)
+{
+	/* Ensure CU1 is off */
+	clrfpintr();
+
+	m->stb = &stlb[m->machno][0];
+
+	clockinit();
+}
+
+/*
+ *  setup MIPS trap vectors
+ */
+void
+vecinit(void)
+{
+	memmove((ulong*)UTLBMISS, (ulong*)vector0, 0x80);
+	memmove((ulong*)XEXCEPTION, (ulong*)vector0, 0x80);
+	memmove((ulong*)CACHETRAP, (ulong*)vector100, 0x80);
+	memmove((ulong*)EXCEPTION, (ulong*)vector180, 0x80);
+	memmove((ulong*)(KSEG0+0x200), (ulong*)vector180, 0x80);
+	icflush((ulong*)UTLBMISS, 4*1024);
+
+	setstatus(getstatus() & ~BEV);
+}
+
+void
+init0(void)
+{
+	char buf[128];
+
+	up->nerrlab = 0;
+
+	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);
+	pathclose(up->slash->path);
+	up->slash->path = newpath("/");
+	up->dot = cclone(up->slash);
+
+	chandevinit();
+
+	if(!waserror()){
+		ksetenv("cputype", "mips", 0);
+		snprint(buf, sizeof buf, "mips %s rb450g", conffile);
+		ksetenv("terminal", buf, 0);
+		if(cpuserver)
+			ksetenv("service", "cpu", 0);
+		else
+			ksetenv("service", "terminal", 0);
+		/*
+		 * we don't have a good way to read our cfg file in
+		 * RouterBOOT, so set the configuration here.
+		 */
+		ksetenv("nobootprompt", "tcp", 0);
+		ksetenv("nvram", "/boot/nvram", 0);
+		poperror();
+	}
+	kproc("alarm", alarmkproc, 0);
+	i8250console();
+	touser(sp);
+}
+
+FPsave	initfp;
+
+static void
+bootargs(uintptr base)
+{
+	int i;
+	ulong ssize;
+	char **av, *p;
+
+	/*
+	 * Push the boot args onto the stack.
+	 * The initial value of the user stack must be such
+	 * that the total used is larger than the maximum size
+	 * of the argument list checked in syscall.
+	 */
+	i = oargblen+1;
+	p = UINT2PTR(STACKALIGN(base + BY2PG - sizeof(Tos) - i));
+	memmove(p, oargb, i);
+
+	/*
+	 * Now push the argv pointers.
+	 * The code jumped to by touser in lproc.s expects arguments
+	 *	main(char* argv0, ...)
+	 * and calls
+	 * 	startboot("/boot/boot", &argv0)
+	 * not the usual (int argc, char* argv[])
+	 */
+	av = (char**)(p - (oargc+1)*sizeof(char*));
+	ssize = base + BY2PG - PTR2UINT(av);
+	for(i = 0; i < oargc; i++)
+		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
+	*av = nil;
+	sp = USTKTOP - ssize;
+}
+
+void
+userinit(void)
+{
+	Proc *p;
+	KMap *k;
+	Page *pg;
+	Segment *s;
+
+	p = newproc();
+	p->pgrp = newpgrp();
+	p->egrp = smalloc(sizeof(Egrp));
+	p->egrp->ref = 1;
+	p->fgrp = dupfgrp(nil);
+	p->rgrp = newrgrp();
+	p->procmode = 0640;
+
+	kstrdup(&eve, "");
+	kstrdup(&p->text, "*init*");
+	kstrdup(&p->user, eve);
+
+	p->fpstate = FPinit;
+	p->fpsave.fpstatus = initfp.fpstatus;
+
+	/*
+	 * Kernel Stack
+	 */
+	p->sched.pc = (ulong)init0;
+	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
+	p->sched.sp = STACKALIGN(p->sched.sp);
+
+	/*
+	 * User Stack
+	 *
+	 * Technically, newpage can't be called here because it
+	 * should only be called when in a user context as it may
+	 * try to sleep if there are no pages available, but that
+	 * shouldn't be the case here.
+	 */
+	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
+	p->seg[SSEG] = s;
+	pg = newpage(1, 0, USTKTOP-BY2PG);
+	segpage(s, pg);
+	k = kmap(pg);
+	bootargs(VA(k));
+	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]);
+	memset((void *)VA(k), 0, BY2PG);
+	memmove((ulong*)VA(k), initcode, sizeof initcode);
+	kunmap(k);
+
+	ready(p);
+}
+
+void
+procrestore(Proc *p)
+{
+	uvlong t;
+
+	if(p->kp)
+		return;
+	cycles(&t);
+	p->pcycles -= t;
+}
+
+/*
+ *  Save the mach dependent part of the process state.
+ */
+void
+procsave(Proc *p)
+{
+	uvlong t;
+
+	cycles(&t);
+	p->pcycles += t;
+	/* no fpu, so no fp state to save */
+}
+
+static void
+writeconf(void)
+{
+	char *p, *q;
+	int n;
+
+	p = getconfenv();
+
+	if(waserror()) {
+		free(p);
+		nexterror();
+	}
+
+	/* convert to name=value\n format */
+	for(q=p; *q; q++) {
+		q += strlen(q);
+		*q = '=';
+		q += strlen(q);
+		*q = '\n';
+	}
+	n = q - p + 1;
+#ifdef BOOTARGS_EXIST
+	if(n >= BOOTARGSLEN)
+		error("kernel configuration too large");
+	memmove(BOOTARGS, p, n);
+	memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
+#endif
+	USED(n);
+	poperror();
+	free(p);
+}
+
+static void
+shutdown(int ispanic)
+{
+	int ms, once;
+
+	ilock(&active);
+	if(ispanic)
+		active.ispanic = ispanic;
+	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
+		active.ispanic = 0;
+	once = active.machs & (1<<m->machno);
+	/*
+	 * setting exiting will make hzclock() on each processor call exit(0),
+	 * which calls shutdown(0) and idles non-bootstrap cpus and returns
+	 * on bootstrap processors (to permit a reboot).  clearing our bit
+	 * in machs avoids calling exit(0) from hzclock() on this processor.
+	 */
+	active.machs &= ~(1<<m->machno);
+	active.exiting = 1;
+	iunlock(&active);
+
+	if(once) {
+		delay(m->machno*1000);		/* stagger them */
+		iprint("cpu%d: exiting\n", m->machno);
+	}
+	spllo();
+	ms = MAXMACH * 1000;
+	for(; ms > 0; ms -= TK2MS(2)){
+		delay(TK2MS(2));
+		if(active.machs == 0 && consactive() == 0)
+			break;
+	}
+	delay(100);
+}
+
+/*
+ * the new kernel is already loaded at address `code'
+ * of size `size' and entry point `entry'.
+ */
+void
+reboot(void *entry, void *code, ulong size)
+{
+	void (*f)(ulong, ulong, ulong);
+
+	writeconf();
+
+	/*
+	 * the boot processor is cpu0.  execute this function on it
+	 * so that the new kernel has the same cpu0.
+	 */
+	if (m->machno != 0) {
+		procwired(up, 0);
+		sched();
+	}
+	if (m->machno != 0)
+		print("on cpu%d (not 0)!\n", m->machno);
+
+	shutdown(0);
+
+	/*
+	 * should be the only processor running now
+	 */
+//	iprint("reboot: entry %#p code %#p size %ld\n", entry, code, size);
+//	iprint("code[0] = %#lux\n", *(ulong *)code);
+
+	/* turn off buffered serial console */
+	serialoq = nil;
+	kprintoq = nil;
+	screenputs = nil;
+
+	/* shutdown devices */
+	chandevshutdown();
+
+	/* call off the dog */
+	clockshutdown();
+
+	splhi();
+	intrshutdown();
+
+	/* is the watchdog tied into the usb machinery? */
+//	*Reset |= Rstusbohcidll | Rstusbhost | Rstusbphy;
+//		Rstge0mac | Rstge0phy |
+//		Rstge1mac | Rstge1phy;
+
+	/* setup reboot trampoline function */
+	f = (void*)REBOOTADDR;
+	memmove(f, rebootcode, sizeof(rebootcode));
+	icflush(f, sizeof(rebootcode));
+
+	setstatus(BEV);		/* also, kernel mode, no interrupts */
+	coherence();
+
+	/* off we go - never to return */
+	(*f)((ulong)entry, (ulong)code, size);
+
+	panic("loaded kernel returned!");
+}
+
+void
+exit(int type)
+{
+	int timer;
+	void (*fnp)(void);
+
+	stopwdog();
+
+	delay(1000);
+	lock(&active);
+	active.machs &= ~(1<<m->machno);
+	active.exiting = 1;
+	unlock(&active);
+	spllo();
+
+	print("cpu %d exiting\n", m->machno);
+	timer = 0;
+	while(active.machs || consactive()) {
+		if(timer++ > 400)
+			break;
+		delay(10);
+	}
+	delay(1000);
+	splhi();
+	USED(type);
+
+	setstatus(BEV);
+	coherence();
+
+	iprint("exit: awaiting reset\n");
+	wdogreset();			/* wake the dog with v. short timeout */
+
+//	*Reset |= Rstfullchip;
+//	*Reset |= Rstcpucold;
+
+	delay(1000);			/* await a reset */
+
+	iprint("exit: jumping to rom\n");
+	fnp = (void (*)(void))ROM;
+	(*fnp)();
+
+	iprint("exit: looping\n");
+	for (;;)
+		;
+}
+
+void
+idlehands(void)
+{
+	stopwdog();
+	idle();
+	sicwdog();			/* wake the dog */
+}
+
+void
+confinit(void)
+{
+	ulong kpages, ktop;
+
+	/*
+	 *  divide memory twixt user pages and kernel.
+	 */
+	conf.mem[0].base = ktop = PADDR(PGROUND((ulong)end));
+	/* fixed memory on routerboard */
+	conf.mem[0].npage = MEMSIZE/BY2PG - ktop/BY2PG;
+	conf.npage = conf.mem[0].npage;
+	conf.nuart = 1;
+
+	kpages = conf.npage - (conf.npage*80)/100;
+	if(kpages > (64*MB + conf.npage*sizeof(Page))/BY2PG){
+		kpages = (64*MB + conf.npage*sizeof(Page))/BY2PG;
+		kpages += (conf.nproc*KSTACK)/BY2PG;
+	}
+	conf.upages = conf.npage - kpages;
+	conf.ialloc = (kpages/2)*BY2PG;
+
+	kpages *= BY2PG;
+	kpages -= conf.upages*sizeof(Page)
+		+ conf.nproc*sizeof(Proc)
+		+ conf.nimage*sizeof(Image)
+		+ conf.nswap
+		+ conf.nswppo*sizeof(Page);
+	mainmem->maxsize = kpages;
+
+	/*
+	 *  set up CPU's mach structure
+	 *  cpu0's was zeroed in l.s and our stack is in Mach, so don't zero it.
+	 */
+	m->machno = 0;
+	m->speed = 680;			/* initial guess at MHz, for rb450g */
+	m->hz = m->speed * Mhz;
+	conf.nmach = 1;
+
+	/* set up other configuration parameters */
+	conf.nproc = 2000;
+	conf.nswap = 262144;
+	conf.nswppo = 4096;
+	conf.nimage = 200;
+
+	conf.copymode = 0;		/* copy on write */
+}

+ 328 - 0
sys/src/9/rb/mem.h

@@ -0,0 +1,328 @@
+/*
+ * 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 MAXBY2PG (16*1024) /* rounding for UTZERO in executables; see mkfile */
+#define UTROUND(t)	ROUNDUP((t), MAXBY2PG)
+
+#ifndef BIGPAGES
+#define	BY2PG		4096			/* bytes per page */
+#define	PGSHIFT		12			/* log2(BY2PG) */
+#define	PGSZ		PGSZ4K
+#define MACHSIZE	(2*BY2PG)
+#else
+/* 16K pages work very poorly */
+#define	BY2PG		(16*1024)		/* bytes per page */
+#define	PGSHIFT		14			/* log2(BY2PG) */
+#define PGSZ		PGSZ16K
+#define MACHSIZE	BY2PG
+#endif
+
+#define	KSTACK		8192			/* Size of kernel stack */
+#define	WD2PG		(BY2PG/BY2WD)		/* words per page */
+
+#define	MAXMACH		1   /* max # cpus system can run; see active.machs */
+#define STACKALIGN(sp)	((sp) & ~7)		/* bug: assure with alloc */
+#define	BLOCKALIGN	16
+#define CACHELINESZ	32			/* mips24k */
+#define ICACHESIZE	(64*1024)		/* rb450g */
+#define DCACHESIZE	(32*1024)		/* rb450g */
+
+#define MASK(w)		FMASK(0, w)
+
+/*
+ * Time
+ */
+#define	HZ		100			/* clock frequency */
+#define	MS2HZ		(1000/HZ)		/* millisec per clock tick */
+#define	TK2SEC(t)	((t)/HZ)		/* ticks to seconds */
+
+/*
+ * CP0 registers
+ */
+
+#define INDEX		0
+#define RANDOM		1
+#define TLBPHYS0	2	/* aka ENTRYLO0 */
+#define TLBPHYS1	3	/* aka ENTRYLO1 */
+#define CONTEXT		4
+#define PAGEMASK	5
+#define WIRED		6
+#define BADVADDR	8
+#define COUNT		9
+#define TLBVIRT		10	/* aka ENTRYHI */
+#define COMPARE		11
+#define STATUS		12
+#define CAUSE		13
+#define EPC		14
+#define	PRID		15
+#define	CONFIG		16
+#define	LLADDR		17
+#define	WATCHLO		18
+#define	WATCHHI		19
+#define DEBUG		23
+#define DEPC		24
+#define PERFCOUNT	25
+#define	CACHEECC	26
+#define	CACHEERR	27
+#define	TAGLO		28
+#define	TAGHI		29
+#define	ERROREPC	30
+#define DESAVE		31
+
+/*
+ * M(STATUS) bits
+ */
+#define KMODEMASK	0x0000001f
+#define IE		0x00000001	/* master interrupt enable */
+#define EXL		0x00000002	/* exception level */
+#define ERL		0x00000004	/* error level */
+#define KSUPER		0x00000008
+#define KUSER		0x00000010
+#define KSU		0x00000018
+//#define UX		0x00000020 /* no [USK]X 64-bit extension bits on 24k */
+//#define SX		0x00000040
+//#define KX		0x00000080
+#define INTMASK		0x0000ff00
+#define INTR0		0x00000100	/* interrupt enable bits */
+#define INTR1		0x00000200
+#define INTR2		0x00000400
+#define INTR3		0x00000800
+#define INTR4		0x00001000
+#define INTR5		0x00002000
+#define INTR6		0x00004000
+#define INTR7		0x00008000
+//#define DE		0x00010000	/* not on 24k */
+#define TS		0x00200000	/* tlb shutdown; on 24k at least */
+#define BEV		0x00400000	/* bootstrap exception vectors */
+#define RE		0x02000000	/* reverse-endian in user mode */
+#define FR		0x04000000	/* enable 32 FP regs */
+#define CU0		0x10000000
+#define CU1		0x20000000	/* FPU enable */
+
+/*
+ * M(CONFIG) bits
+ */
+
+#define CFG_K0		7	/* kseg0 cachability */
+#define CFG_MM		(1<<18)	/* write-through merging enabled */
+
+/*
+ * M(CAUSE) bits
+ */
+
+#define BD		(1<<31)	/* last excep'n occurred in branch delay slot */
+
+/*
+ * Exception codes
+ */
+#define	EXCMASK	0x1f		/* mask of all causes */
+#define	CINT	 0		/* external interrupt */
+#define	CTLBM	 1		/* TLB modification: store to unwritable page */
+#define	CTLBL	 2		/* TLB miss (load or fetch) */
+#define	CTLBS	 3		/* TLB miss (store) */
+#define	CADREL	 4		/* address error (load or fetch) */
+#define	CADRES	 5		/* address error (store) */
+#define	CBUSI	 6		/* bus error (fetch) */
+#define	CBUSD	 7		/* bus error (data load or store) */
+#define	CSYS	 8		/* system call */
+#define	CBRK	 9		/* breakpoint */
+#define	CRES	10		/* reserved instruction */
+#define	CCPU	11		/* coprocessor unusable */
+#define	COVF	12		/* arithmetic overflow */
+#define	CTRAP	13		/* trap */
+#define	CVCEI	14		/* virtual coherence exception (instruction) */
+#define	CFPE	15		/* floating point exception */
+#define CTLBRI	19		/* tlb read-inhibit */
+#define CTLBXI	20		/* tlb execute-inhibit */
+#define	CWATCH	23		/* watch exception */
+#define CMCHK	24		/* machine checkcore */
+#define CCACHERR 30		/* cache error */
+#define	CVCED	31		/* virtual coherence exception (data) */
+
+/*
+ * M(CACHEECC) a.k.a. ErrCtl bits
+ */
+#define PE	(1<<31)
+#define LBE	(1<<25)
+#define WABE	(1<<24)
+
+/*
+ * Trap vectors
+ */
+
+#define	UTLBMISS	(KSEG0+0x000)
+#define	XEXCEPTION	(KSEG0+0x080)
+#define	CACHETRAP	(KSEG0+0x100)
+#define	EXCEPTION	(KSEG0+0x180)
+
+/*
+ * Magic registers
+ */
+
+#define	USER		24		/* R24 is up-> */
+#define	MACH		25		/* R25 is m-> */
+
+/*
+ * offsets in ureg.h for l.s
+ */
+#define	Ureg_status	(Uoffset+0)
+#define	Ureg_pc		(Uoffset+4)
+#define	Ureg_sp		(Uoffset+8)
+#define	Ureg_cause	(Uoffset+12)
+#define	Ureg_badvaddr	(Uoffset+16)
+#define	Ureg_tlbvirt	(Uoffset+20)
+
+#define	Ureg_hi		(Uoffset+24)
+#define	Ureg_lo		(Uoffset+28)
+#define	Ureg_r31	(Uoffset+32)
+#define	Ureg_r30	(Uoffset+36)
+#define	Ureg_r28	(Uoffset+40)
+#define	Ureg_r27	(Uoffset+44)
+#define	Ureg_r26	(Uoffset+48)
+#define	Ureg_r25	(Uoffset+52)
+#define	Ureg_r24	(Uoffset+56)
+#define	Ureg_r23	(Uoffset+60)
+#define	Ureg_r22	(Uoffset+64)
+#define	Ureg_r21	(Uoffset+68)
+#define	Ureg_r20	(Uoffset+72)
+#define	Ureg_r19	(Uoffset+76)
+#define	Ureg_r18	(Uoffset+80)
+#define	Ureg_r17	(Uoffset+84)
+#define	Ureg_r16	(Uoffset+88)
+#define	Ureg_r15	(Uoffset+92)
+#define	Ureg_r14	(Uoffset+96)
+#define	Ureg_r13	(Uoffset+100)
+#define	Ureg_r12	(Uoffset+104)
+#define	Ureg_r11	(Uoffset+108)
+#define	Ureg_r10	(Uoffset+112)
+#define	Ureg_r9		(Uoffset+116)
+#define	Ureg_r8		(Uoffset+120)
+#define	Ureg_r7		(Uoffset+124)
+#define	Ureg_r6		(Uoffset+128)
+#define	Ureg_r5		(Uoffset+132)
+#define	Ureg_r4		(Uoffset+136)
+#define	Ureg_r3		(Uoffset+140)
+#define	Ureg_r2		(Uoffset+144)
+#define	Ureg_r1		(Uoffset+148)
+
+/* ch and carrera used these defs */
+	/* Sizeof(Ureg) + (R5,R6) + 16 bytes slop + retpc + ur */
+// #define UREGSIZE ((Ureg_r1+4-Uoffset) + 2*BY2V + 16 + BY2WD + BY2WD)
+// #define Uoffset	8
+
+// #define UREGSIZE	(Ureg_r1 + 4 - Uoffset)	/* this ought to work */
+#define UREGSIZE ((Ureg_r1+4-Uoffset) + 2*BY2V + 16 + BY2WD + BY2WD)
+#define Uoffset		0
+#define Notuoffset	8
+
+/*
+ * MMU
+ */
+#define	PGSZ4K		(0x00<<13)
+#define PGSZ16K		(0x03<<13)	/* on 24k */
+#define	PGSZ64K		(0x0F<<13)
+#define	PGSZ256K	(0x3F<<13)
+#define	PGSZ1M		(0xFF<<13)
+#define	PGSZ4M		(0x3FF<<13)
+// #define PGSZ8M	(0x7FF<<13)	/* not on 24k */
+#define	PGSZ16M		(0xFFF<<13)
+#define PGSZ64M		(0x3FFF<<13)	/* on 24k */
+#define PGSZ256M	(0xFFFF<<13)	/* on 24k */
+
+/* mips address spaces, tlb-mapped unless marked otherwise */
+#define	KUSEG	0x00000000	/* user process */
+#define KSEG0	0x80000000	/* kernel (direct mapped, cached) */
+#define KSEG1	0xA0000000	/* kernel (direct mapped, uncached: i/o) */
+#define	KSEG2	0xC0000000	/* kernel, used for TSTKTOP */
+#define	KSEG3	0xE0000000	/* kernel, used by kmap */
+#define	KSEGM	0xE0000000	/* mask to check which seg */
+
+/*
+ * Fundamental addresses
+ */
+
+#define	REBOOTADDR	KADDR(0x1000)	/* just above vectors */
+#define	MACHADDR	0x80005000	/* Mach structures */
+#define	MACHP(n)	((Mach *)(MACHADDR+(n)*MACHSIZE))
+#define ROM		0xbfc00000
+#define	KMAPADDR	0xE0000000	/* kmap'd addresses */
+#define	WIREDADDR	0xE2000000	/* address wired kernel space */
+
+#define PHYSCONS	(KSEG1|0x18020000)		/* i8250 uart */
+
+#define PIDXSHFT	12
+#ifndef BIGPAGES
+#define NCOLOR		8
+#define PIDX		((NCOLOR-1)<<PIDXSHFT)
+#define getpgcolor(a)	(((ulong)(a)>>PIDXSHFT) % NCOLOR)
+#else
+/* no cache aliases are possible with pages of 16K or larger */
+#define NCOLOR		1
+#define PIDX		0
+#define getpgcolor(a)	0
+#endif
+#define KMAPSHIFT	15
+
+#define	PTEGLOBL	(1<<0)
+#define	PTEVALID	(1<<1)
+#define	PTEWRITE	(1<<2)
+#define PTERONLY	0
+#define PTEALGMASK	(7<<3)
+#define PTENONCOHERWT	(0<<3)		/* cached, write-through (slower) */
+#define PTEUNCACHED	(2<<3)
+#define PTENONCOHERWB	(3<<3)		/* cached, write-back */
+#define PTEUNCACHEDACC	(7<<3)
+/* rest are reserved on 24k */
+#define PTECOHERXCL	(4<<3)
+#define PTECOHERXCLW	(5<<3)
+#define PTECOHERUPDW	(6<<3)
+
+/* how much faster is it? mflops goes from about .206 (WT) to .37 (WB) */
+#define PTECACHABILITY PTENONCOHERWT	/* 24k erratum 48 disallows WB */
+// #define PTECACHABILITY PTENONCOHERWB
+
+#define	PTEPID(n)	(n)
+#define PTEMAPMEM	(1024*1024)
+#define	PTEPERTAB	(PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE	512
+#define SSEGMAPSIZE	16
+
+#define STLBLOG		15
+#define STLBSIZE	(1<<STLBLOG)	/* entries in the soft TLB */
+/* page # bits that don't fit in STLBLOG bits */
+#define HIPFNBITS	(BI2WD - (PGSHIFT+1) - STLBLOG)
+#define KPTELOG		8
+#define KPTESIZE	(1<<KPTELOG)	/* entries in the kfault soft TLB */
+
+#define TLBPID(n) ((n)&0xFF)
+#define	NTLBPID	256		/* # of pids (affects size of Mach) */
+#define	NTLB	16		/* # of entries (mips 24k) */
+#define TLBOFF	1		/* first tlb entry (0 used within mmuswitch) */
+#define NKTLB	2		/* # of initial kfault tlb entries */
+#define WTLBOFF	(TLBOFF+NKTLB)	/* first large IO window tlb entry */
+#define NWTLB	0		/* # of large IO window tlb entries */
+#define	TLBROFF	(WTLBOFF+NWTLB)	/* offset of first randomly-indexed entry */
+
+/*
+ * Address spaces
+ */
+#define	UZERO	KUSEG			/* base of user address space */
+#define	UTZERO	(UZERO+MAXBY2PG)	/* 1st user text address; see mkfile */
+#define	USTKTOP	(KZERO-BY2PG)		/* byte just beyond user stack */
+#define	USTKSIZE (8*1024*1024)		/* size of user stack */
+#define TSTKTOP (KSEG2+USTKSIZE-BY2PG)	/* top of temporary stack */
+#define TSTKSIZ (1024*1024/BY2PG)	/* can be at most UTSKSIZE/BY2PG */
+#define	KZERO	KSEG0			/* base of kernel address space */
+#define	KTZERO	(KZERO+0x20000)		/* first address in kernel text */
+#define MEMSIZE	(256*MB)		/* fixed memory on routerboard */
+#define PCIMEM	0x10000000		/* on rb450g */

+ 84 - 0
sys/src/9/rb/mips.s

@@ -0,0 +1,84 @@
+/*
+ * mips 24k machine assist
+ */
+#undef	MASK
+#define	MASK(w) ((1<<(w))-1)
+
+#define	SP	R29
+
+#define NOP	NOR R0, R0, R0
+
+#define	CONST(x,r) MOVW $((x)&0xffff0000), r; OR  $((x)&0xffff), r
+
+/* a mips 24k erratum requires a NOP after; experience dictates EHB before */
+#define	ERET	EHB; WORD $0x42000018; NOP
+
+#define RETURN	RET; NO