shithub: n900

Download patch

ref: d93edcf773cf571173e24867e186cecef3b98af8
parent: e8dc10b3b573fb5b696d8667826cd16629983494
author: mia soweli <inbox@tachibana-labs.org>
date: Wed Aug 30 11:16:41 EDT 2023

*: let's get directories

--- a/dat.h
+++ /dev/null
@@ -1,147 +1,0 @@
-typedef struct Conf Conf;
-typedef struct Confmem Confmem;
-typedef struct FPsave FPsave;
-typedef struct Label Label;
-typedef struct Lock Lock;
-typedef struct Mach Mach;
-typedef struct MMMU MMMU;
-typedef struct Page Page;
-typedef struct Proc Proc;
-typedef struct PFPU PFPU;
-typedef struct PMMU PMMU;
-typedef struct Ureg Ureg;
-
-typedef u32int PTE;
-typedef uvlong Tval;
-
-#pragma incomplete Ureg
-
-#define MAXSYSARG 5
-#define AOUT_MAGIC (E_MAGIC)
-
-struct Lock {
-	ulong key;
-	u32int sr;
-	uintptr pc;
-	Proc *p;
-	Mach *m;
-	int isilock;
-};
-
-struct Label {
-	uintptr sp;
-	uintptr pc;
-};
-
-struct Confmem {
-	uintptr base;
-	uintptr limit;
-	uintptr kbase;
-	uintptr klimit;
-	ulong npage;
-};
-
-struct Conf {
-	ulong nmach;
-	ulong nproc;
-	Confmem mem[1];
-	ulong npage;
-	ulong upages;
-	ulong copymode;
-	ulong ialloc;
-	ulong pipeqsize;
-	ulong nimage;
-	ulong nswap;
-	int nswppo;
-	int monitor;
-};
-
-struct FPsave {
-	ulong exc;
-	ulong scr;
-	uchar regs[256];
-};
-
-struct PFPU {
-	enum {
-		FPinit,
-		FPactive,
-		FPinactive,
-
-		FPillegal = 0x100,
-	} fpstate;
-	FPsave fpsave[1];
-};
-
-#define NCOLOR 1
-struct PMMU {
-	Page *mmul2;
-	Page *mmul2cache;
-};
-
-struct MMMU {
-	PTE *mmul1;
-	uint mmupid;
-};
-
-#include "../port/portdat.h"
-
-struct Mach {
-	int machno;
-	uintptr splpc;
-	Proc *proc;
-	MMMU;
-
-	PMach;
-
-	u32int save[5];
-	uintptr stack[1];
-};
-
-typedef struct ISAConf ISAConf;
-typedef struct Devport Devport;
-typedef struct DevConf DevConf;
-
-#define BUSUNKNOWN 0
-#define BUSMODEM 1
-
-#define NISAOPT 8
-struct ISAConf {
-	char *type;
-	uintptr port;
-	int irq;
-	ulong dma;
-	ulong mem;
-	ulong size;
-	ulong freq;
-
-	int nopt;
-	char *opt[NISAOPT];
-};
-
-struct Devport {
-	ulong port;
-	int size;
-};
-
-struct DevConf {
-	ulong intnum;
-	char *type;
-	int nports;
-	Devport *ports;
-};
-
-typedef void KMap;
-#define VA(p) ((uintptr)(p))
-#define kmap(p) (KMap*)((p)->pa|KZERO)
-#define kunmap(p)
-#define kmapinval()
-#define getpgcolor(p) 0
-
-struct {
-	char machs[MAXMACH];
-	int exiting;
-} active;
-
-extern register Mach *m;
-extern register Proc *up;
--- a/devkbd.c
+++ /dev/null
@@ -1,243 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "../port/error.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/i2c.h"
-
-enum {
-	Rctrl		= 0xd2,
-		Csoftreset	= 1<<0,
-		Csoftmode	= 1<<1,
-		Cenable		= 1<<6,
-	Rcode	= 0xdb,
-	Risr		= 0xe3,
-	Rimr		= 0xe4,
-		Ikp			= 1<<0,
-		Ilk			= 1<<1,
-		Ito			= 1<<2,
-	Rsir		= 0xe7,
-	Redr		= 0xe8,
-		Ekpfalling		= 1<<0,
-		Ekprising		= 1<<1,
-		Elkfalling		= 1<<2,
-		Elkrising		= 1<<3,
-		Etofalling		= 1<<4,
-		Etorising		= 1<<5,
-		Emisfalling	= 1<<6,
-		Emisrising	= 1<<7,
-	Rsih		= 0xe9,
-		Scor			= 1<<2,
-};
-
-enum {
-	Qdir,
-	Qscan,
-};
-
-typedef struct Ctlr Ctlr;
-struct Ctlr {
-	Ref;
-	Lock;
-
-	I2Cdev *dev;
-	Queue *q;
-
-	uchar cur[8];
-	uchar prev[8];
-};
-
-static Ctlr ctlr;
-static Dirtab kbdtab[] = {
-	".",			{Qdir, 0, QTDIR},		0, 0555,
-	"scancode",	{Qscan, 0, QTFILE},	0, 0440,
-};
-
-static u8int
-csr8r(Ctlr *ctlr, u8int r)
-{
-	uchar buf;
-
-	i2crecv(ctlr->dev, &buf, sizeof(buf), r);
-	return buf;
-}
-
-static u8int
-csr8w(Ctlr *ctlr, u8int r, u8int w)
-{
-	i2csend(ctlr->dev, &w, sizeof(w), r);
-	return w;
-}
-
-static void
-kbdinterrupt(Ureg *, void*)
-{
-	int i, j, c, k;
-
-	ilock(&ctlr);
-	if(!(csr8r(&ctlr, Risr) & Ikp)) {
-		iunlock(&ctlr);
-		return;
-	}
-
-	/* scan key columns */
-	for(i = 0; i < 8; i++) {
-		ctlr.prev[i] = ctlr.cur[i];
-		ctlr.cur[i] = csr8r(&ctlr, Rcode + i);
-
-		/* changed? */
-		c = ctlr.cur[i] ^ ctlr.prev[i];
-		if(!c)
-			continue;
-
-		/* scan key rows */
-		for(j = 0; j < 8; j++) {
-			if(!(c & (1 << j)))
-				continue;
-
-			/* pressed or released? */
-			k = i << 3 | j;
-			if(ctlr.prev[i] & (1 << j))
-				k |= 0x80;
-
-			qproduce(ctlr.q, &k, 1);
-		}
-	}
-
-	iunlock(&ctlr);
-}
-
-static void
-kbdreset(void)
-{
-	ilock(&ctlr);
-	ctlr.q = qopen(1024, Qcoalesce, 0, 0);
-	if(!ctlr.q) {
-		iunlock(&ctlr);
-		return;
-	}
-
-	ctlr.dev = i2cdev(i2cbus("i2c1"), 0x4a);
-	if(!ctlr.dev) {
-		iunlock(&ctlr);
-		return;
-	}
-
-	ctlr.dev->subaddr = 1;
-	ctlr.dev->size = 0x100;
-
-	csr8w(&ctlr, Rctrl, Csoftreset | Csoftmode | Cenable);
-	csr8w(&ctlr, Rsih, Scor);
-	csr8w(&ctlr, Rimr, ~Ikp);
-
-	intrenable(IRQTWL, kbdinterrupt, nil, BUSUNKNOWN, "kbd");
-	iunlock(&ctlr);
-}
-
-static void
-kbdshutdown(void)
-{
-}
-
-static Chan *
-kbdattach(char *spec)
-{
-	if(!ctlr.dev)
-		error(Enonexist);
-
-	return devattach(L'b', spec);
-}
-
-static Walkqid *
-kbdwalk(Chan *c, Chan *nc, char **name, int nname)
-{
-	return devwalk(c, nc, name, nname, kbdtab, nelem(kbdtab), devgen);
-}
-
-static int
-kbdstat(Chan *c, uchar *dp, int n)
-{
-	return devstat(c, dp, n, kbdtab, nelem(kbdtab), devgen);
-}
-
-static Chan *
-kbdopen(Chan *c, int mode)
-{
-	if(!iseve)
-		error(Eperm);
-
-	if(c->qid.path == Qscan) {
-		if(waserror()) {
-			decref(&ctlr);
-			nexterror();
-		}
-
-		if(incref(&ctlr) != 1)
-			error(Einuse);
-
-		c = devopen(c, mode, kbdtab, nelem(kbdtab), devgen);
-		poperror();
-		return c;
-	}
-
-	return devopen(c, mode, kbdtab, nelem(kbdtab), devgen);
-}
-
-static void
-kbdclose(Chan *c)
-{
-	if((c->flag & COPEN) && c->qid.path == Qscan)
-		decref(&ctlr);
-}
-
-static Block*
-kbdbread(Chan *c, long n, ulong off)
-{
-	if(c->qid.path == Qscan)
-		return qbread(ctlr.q, n);
-
-	return devbread(c, n, off);
-}
-
-static long
-kbdread(Chan *c, void *a, long n, vlong)
-{
-	if(c->qid.path == Qscan)
-		return qread(ctlr.q, a, n);
-
-	if(c->qid.path == Qdir)
-		return devdirread(c, a, n, kbdtab, nelem(kbdtab), devgen);
-
-	error(Egreg);
-	return 0;
-}
-
-static long
-kbdwrite(Chan *, void *, long, vlong)
-{
-	error(Egreg);
-	return 0;
-}
-
-Dev kbddevtab = {
-	L'b',
-	"kbd",
-
-	kbdreset,
-	devinit,
-	kbdshutdown,
-	kbdattach,
-	kbdwalk,
-	kbdstat,
-	kbdopen,
-	devcreate,
-	kbdclose,
-	kbdread,
-	kbdbread,
-	kbdwrite,
-	devbwrite,
-	devremove,
-	devwstat,
-};
--- a/devrtc.c
+++ /dev/null
@@ -1,202 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "../port/error.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/i2c.h"
-
-enum {
-	Rsec		= 0x1c,
-	Rmin	= 0x1d,
-	Rhour	= 0x1e,
-	Rday	= 0x1f,
-	Rmonth	= 0x20,
-	Ryear	= 0x21,
-	Rweeks	= 0x22,
-	Rctrl		= 0x29,
-		Cget		= 1<<6,
-
-	Qdir = 0,
-	Qrtc,
-
-	SecMin	= 60,
-	SecHour	= 60*SecMin,
-	SecDay	= 24*SecHour,
-};
-
-typedef struct Ctlr Ctlr;
-struct Ctlr {
-	I2Cdev *dev;
-
-	int sec;
-	int min;
-	int hour;
-	int day;
-	int month;
-	int year;
-};
-
-static Ctlr ctlr;
-static int dmsize[] = { 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-static int ldmsize[] = { 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-static Dirtab rtctab[] = {
-	".",		{Qdir, 0, QTDIR},	0, 0555,
-	"rtc",	{Qrtc, 0, QTFILE},	0, 0440,
-};
-
-#define bcddec(x) (((x) & 0xf) + ((x) >> 4) * 10)
-#define bcdenc(x) (((x / 10) << 4) + (x) % 10)
-#define leap(x) (((x) % 4) == 0 && ((x % 100) != 0 || (x % 400) == 0))
-
-static u8int
-csr8r(Ctlr *ctlr, u8int r)
-{
-	uchar buf;
-
-	i2crecv(ctlr->dev, &buf, sizeof(buf), r);
-	return buf;
-}
-
-static u8int
-csr8w(Ctlr *ctlr, u8int r, u8int w)
-{
-	i2csend(ctlr->dev, &w, sizeof(w), r);
-	return w;
-}
-
-static vlong
-rtcsnarf(void)
-{
-	vlong s;
-	int i;
-
-	/* latch and snarf */
-	csr8w(&ctlr, Rctrl, csr8r(&ctlr, Rctrl) | Cget);
-	ctlr.sec = bcddec(csr8r(&ctlr, Rsec)) % 60;
-	ctlr.min = bcddec(csr8r(&ctlr, Rmin)) % 60;
-	ctlr.hour = bcddec(csr8r(&ctlr, Rhour)) % 24;
-	ctlr.day = bcddec(csr8r(&ctlr, Rday));
-	ctlr.month = bcddec(csr8r(&ctlr, Rmonth));
-	ctlr.year = bcddec(csr8r(&ctlr, Ryear)) % 100;
-	ctlr.year += 2000;
-
-	/* seconds per year */
-	s = 0;
-	for(i = 1970; i < ctlr.year; i++) {
-		if(leap(i))
-			s += ldmsize[0] * SecDay;
-		else
-			s += dmsize[0] * SecDay;
-	}
-
-	/* seconds per month */
-	for(i = 1; i < ctlr.month; i++) {
-		if(leap(ctlr.year))
-			s += ldmsize[i] * SecDay;
-		else
-			s += dmsize[i] * SecDay;
-	}
-
-	/* days, hours, minutes, seconds */
-	s += (ctlr.day - 1) * SecDay;
-	s += ctlr.hour * SecHour;
-	s += ctlr.min * SecMin;
-	s += ctlr.sec;
-	return s;
-}
-
-static void
-rtcreset(void)
-{
-	ctlr.dev = i2cdev(i2cbus("i2c1"), 0x4b);
-	if(!ctlr.dev)
-		return;
-
-	ctlr.dev->subaddr = 1;
-	ctlr.dev->size = 0x100;
-}
-
-static void
-rtcshutdown(void)
-{
-}
-
-static Chan *
-rtcattach(char *spec)
-{
-	if(!ctlr.dev)
-		error(Enonexist);
-
-	return devattach('r', spec);
-}
-
-static Walkqid *
-rtcwalk(Chan *c, Chan *nc, char **name, int nname)
-{
-	return devwalk(c, nc, name, nname, rtctab, nelem(rtctab), devgen);
-}
-
-static int
-rtcstat(Chan *c, uchar *dp, int n)
-{
-	return devstat(c, dp, n, rtctab, nelem(rtctab), devgen);
-}
-
-static Chan *
-rtcopen(Chan *c, int mode)
-{
-	mode = openmode(mode);
-	if(c->qid.path == Qrtc) {
-		if(!iseve() && mode != OREAD)
-			error(Eperm);
-	}
-
-	return devopen(c, mode, rtctab, nelem(rtctab), devgen);
-}
-
-static void
-rtcclose(Chan *)
-{
-}
-
-static long
-rtcread(Chan *c, void *a, long n, vlong off)
-{
-	if(c->qid.path == Qdir)
-		return devdirread(c, a, n, rtctab, nelem(rtctab), devgen);
-	if(c->qid.path == Qrtc)
-		return readnum(off, a, n, rtcsnarf(), 12);
-
-	error(Egreg);
-	return 0;
-}
-
-static long
-rtcwrite(Chan *, void *, long, vlong)
-{
-	error(Egreg);
-	return 0;
-}
-
-Dev rtcdevtab = {
-	'r',
-	"rtc",
-
-	rtcreset,
-	devinit,
-	rtcshutdown,
-	rtcattach,
-	rtcwalk,
-	rtcstat,
-	rtcopen,
-	devcreate,
-	rtcclose,
-	rtcread,
-	devbread,
-	rtcwrite,
-	devbwrite,
-	devremove,
-	devwstat,
-};
--- a/fns.h
+++ /dev/null
@@ -1,77 +1,0 @@
-#include "../port/portfns.h"
-
-#define KADDR(a) ((void*)(a))
-#define PADDR(a) ((uintptr)(a))
-
-#define userureg(ur) (((ur)->psr & PsrMask) == PsrMusr)
-
-void*	ucallocalign(usize, int, usize);
-void*	ucalloc(usize);
-
-int cmpswap(long *, long, long);
-int cas(long *, long, long);
-int tas(void *);
-
-void evenaddr(uintptr va);
-void procrestore(Proc *);
-void procsave(Proc *);
-void procsetup(Proc *);
-void procfork(Proc *);
-
-void coherence(void);
-void idlehands(void);
-void touser(void*);
-void setR13(uint, u32int*);
-ulong getdfsr(void);
-ulong getifsr(void);
-uintptr getdfar(void);
-uintptr getifar(void);
-void setvectors(uintptr);
-void breakpt(void);
-
-char* getconf(char*);
-int isaconfig(char *, int, ISAConf *);
-
-void mmuinvalidate(void);
-void* mmuuncache(void*, usize);
-uintptr cankaddr(uintptr);
-
-ulong µs(void);
-void delay(int);
-void microdelay(int);
-void cycles(uvlong*);
-
-void dumpureg(Ureg*);
-void dumpstackureg(Ureg*);
-
-void intrenable(int, void (*f)(Ureg *, void*), void *, int, char*);
-void intrdisable(int, void (*f)(Ureg *, void*), void *, int, char*);
-void intr(Ureg *);
-
-void uartinit(void);
-void mmuinit(void);
-void trapinit(void);
-void intrinit(void);
-void timerinit(void);
-void screeninit(void);
-
-void links(void);
-
-void l1icacheinv(void);
-void l1dcachewb(void);
-void l1dcacheinv(void);
-void l1dcachewbinv(void);
-void l1ucachewbinv(void);
-
-void l2idcacheinv(void);
-void l2idcachewb(void);
-void l2idcachewbinv(void);
-void l2ucachewbinv(void);
-
-
-void fpinit(void);
-void fpoff(void);
-void fpclear(void);
-
-void fpsave(FPsave *);
-void fprestore(FPsave *);
--- a/i2cn900.c
+++ /dev/null
@@ -1,224 +1,0 @@
-#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/i2c.h"
-
-enum {
-	Rrev	= 0x00,
-	Rie		= 0x04,
-	Ris		= 0x08,
-		Ial		= 1 << 0, /* arbitration lost */
-		Inack	= 1 << 1, /* no acknowledgement */
-		Iardy	= 1 << 2, /* address ready */
-		Irrdy		= 1 << 3, /* receive ready */
-		Ixrdy	= 1 << 4, /* transmit ready */
-		Ibb		= 1 << 12, /* bus busy */
-		Iall		= 0xffff,
-
-	Rwe		= 0x0c,
-	Rsyss	= 0x10,
-		SSreset	= 1 << 0, /* reset status */
-
-	Rbuf	= 0x14,
-	Rcnt	= 0x18,
-	Rdata	= 0x1c,
-	Rsysc	= 0x20,
-		SCreset	= 1 << 1, /* software reset */
-
-	Rcon	= 0x24,
-		Cstt		= 1 << 0, /* start condition */
-		Cstp		= 1 << 1, /* stop condiction */
-		Cxoa3	= 1 << 4, /* expand address */
-		Cxoa2	= 1 << 5,
-		Cxoa1	= 1 << 6,
-		Cxoa0	= 1 << 7,
-		Cxa		= 1 << 8,
-		Ctrx		= 1 << 9, /* transmit mode */
-		Cmst	= 1 << 10, /* master mode */
-		Cstb		= 1 << 11, /* start byte */
-		Cen		= 1 << 15, /* enable */
-
-	Raddr	= 0x2c,
-};
-
-#define csr32r(c, r) ((c)->io[(r)/4])
-#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
-
-typedef struct Ctlr Ctlr;
-struct Ctlr {
-	u32int *io;
-	ulong irq;
-
-	Rendez;
-};
-
-static Ctlr ctlr[] = {
-	{ .io = (u32int*) PHYSI2C1, .irq = IRQI2C1 },
-	{ .io = (u32int*) PHYSI2C2, .irq = IRQI2C2 },
-	{ .io = (u32int*) PHYSI2C3, .irq = IRQI2C3 },
-};
-
-static void
-n900i2cwaitbus(Ctlr *ctlr)
-{
-	/* FIXME: timeout here? */
-	while(csr32r(ctlr, Ris) & Ibb)
-		;
-}
-
-static int
-n900i2cwaitirq(void *arg)
-{
-	Ctlr *ctlr = arg; return csr32r(ctlr, Ris);
-}
-
-static uint
-n900i2cwait(Ctlr *ctlr)
-{
-	uint s;
-
-	/* FIXME: timeout here? */
-	while(!(s = csr32r(ctlr, Ris))) {
-		if(!up || !islo())
-			continue;
-
-		tsleep(ctlr, n900i2cwaitirq, ctlr, 5);
-	}
-
-	return s;
-}
-
-static void
-n900i2cflush(Ctlr *ctlr)
-{
-	while(csr32r(ctlr, Ris) & Irrdy) {
-		USED(csr32r(ctlr, Rdata));
-		csr32w(ctlr, Ris, Irrdy);
-	}
-}
-
-static void
-n900i2cintr(Ureg *, void *arg)
-{
-	Ctlr *ctlr;
-
-	ctlr = arg;
-	wakeup(ctlr);
-}
-
-static int
-n900i2cinit(I2Cbus *bus)
-{
-	Ctlr *ctlr;
-
-	/* reset the ctlr */
-	ctlr = bus->ctlr;
-	csr32w(ctlr, Rsysc, SCreset);
-	csr32w(ctlr, Rcon, Cen);
-
-	/* FIXME: timeout here? */
-	while(!(csr32r(ctlr, Rsyss) & SSreset))
-		;
-
-	intrenable(ctlr->irq, n900i2cintr, ctlr, 0, bus->name);
-	return 0;
-}
-
-static int
-n900i2cio(I2Cbus *bus, uchar *pkt, int olen, int ilen)
-{
-	Ctlr *ctlr;
-	uint con, addr, stat;
-	uint o;
-
-	ctlr = bus->ctlr;
-	if(olen <= 0 || pkt == nil)
-		return -1;
-
-	o = 0;
-	con = Cen | Cmst | Ctrx | Cstp | Cstt;
-	if((pkt[o] & 0xf8) == 0xf0) {
-		/* 10-bit address: qemu has bugs, nothing on the n900 needs them.
-		 * con |= Cxa;
-		 * addr = ((pkt[o++] & 6) << 7) | pkt[o++];
-		 */
-		return -1;
-	} else {
-		/* 7-bit address */
-		addr = pkt[o++] >> 1;
-	}
-
-	/* wait for bus */
-	n900i2cwaitbus(ctlr);
-
-	/* first attempt to probe, will get nack here if no dev */
-	csr32w(ctlr, Rcnt, olen);
-	csr32w(ctlr, Raddr, addr);
-	csr32w(ctlr, Rcon, con);
-	stat = n900i2cwait(ctlr);
-	if(stat & Inack || stat & Ial) {
-		o = -1; goto err;
-	}
-
-	/* transmit */
-	while(o < olen) {
-		stat = n900i2cwait(ctlr);
-		if(stat == 0 || stat & Inack || stat & Ial) {
-			o = -1; goto err;
-		}
-
-		if(stat & Iardy) {
-			csr32w(ctlr, Ris, Iardy);
-			break;
-		}
-
-		if(stat & Ixrdy) {
-			csr32w(ctlr, Rdata, pkt[o++]);
-			csr32w(ctlr, Ris, Ixrdy);
-		}
-	}
-
-	/* receive */
-	csr32w(ctlr, Rcnt, ilen);
-	csr32w(ctlr, Raddr, addr);
-	csr32w(ctlr, Rcon, Cen | Cmst | Cstp | Cstt);
-	while(o < olen + ilen) {
-		stat = n900i2cwait(ctlr);
-		if(stat == 0 || stat & Inack || stat & Ial) {
-			o = -1; goto err;
-		}
-
-		if(stat & Iardy) {
-			csr32w(ctlr, Ris, Iardy);
-			break;
-		}
-
-		if(stat & Irrdy) {
-			pkt[o++] = csr32r(ctlr, Rdata);
-			csr32w(ctlr, Ris, Irrdy);
-		}
-	}
-
-err:
-	n900i2cflush(ctlr);
-	csr32w(ctlr, Ris, Iall);
-	return o;
-}
-
-void
-i2cn900link(void)
-{
-	int i;
-	static I2Cbus bus[] = {
-		{ "i2c1", 4000000, &ctlr[0], n900i2cinit, n900i2cio },
-		{ "i2c2", 4000000, &ctlr[1], n900i2cinit, n900i2cio },
-		{ "i2c3", 4000000, &ctlr[2], n900i2cinit, n900i2cio },
-	};
-
-	for(i = 0; i < nelem(bus); i++)
-		addi2cbus(&bus[i]);
-}
--- a/init9.s
+++ /dev/null
@@ -1,12 +1,0 @@
-TEXT main(SB), 1, $8
-	MOVW $setR12(SB), R12
-	MOVW $boot(SB), R0
-
-	ADD $12, R13, R1
-
-	MOVW R0, 4(R13)
-	MOVW R1, 8(R13)
-
-	BL startboot(SB)
-_limbo:
-	B _limbo
--- a/intr.c
+++ /dev/null
@@ -1,199 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-
-enum {
-	Rrev			= 0x00,
-	Rsysconf		= 0x10,
-	Rsysstat		= 0x14,
-	Rirq			= 0x40,
-	Rfiq			= 0x44,
-	Rcontrol		= 0x48,
-		Cnewirqgen		= 1<<0,
-	Rprot			= 0x4c,
-	Ridle			= 0x50,
-	Rirqprio		= 0x60,
-	Rfiqprio		= 0x64,
-	Rthreshold		= 0x68,
-
-	Ritr		= 0x80,
-	Rmir		= 0x84,
-	Rmirclear	= 0x88,
-	Rmirset		= 0x8c,
-	Risrset		= 0x90,
-	Risrclear	= 0x94,
-	Rirqpend	= 0x98,
-	Rfiqpend	= 0x9c,
-
-	Rilr		= 0x100,
-};
-
-enum {
-	Nmir = 3,
-	Nitr = 3,
-	Nintrs = 96,
-};
-
-#define Ritrn(n)		(Ritrn + 32*(n))
-#define Rmirn(n)		(Rmirn + 32*(n))
-#define Rmirclearn(n)	(Rmirclear + 32*(n))
-#define Rmirsetn(n)		(Rmirset + 32*(n))
-#define Rirqpendn(n)	(Rirqpend + 32*(n))
-#define Rfiqpendn(n)	(Rfiqpend + 32*(n))
-
-#define Rilrn(n)	(Rilr + 4*(n))
-
-#define csr32r(c, r) ((c)->io[(r)/4])
-#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
-
-typedef struct Intr Intr;
-typedef struct Ctlr Ctlr;
-
-struct Intr {
-	void (*f)(Ureg *, void *);
-	void *arg;
-	char *name;
-
-	Intr *next;
-};
-
-struct Ctlr {
-	Lock;
-
-	u32int *io;
-
-	Intr *intrs[Nintrs];
-};
-
-static Ctlr ctlrmpu = { .io = (u32int*) PHYSINTRMPU };
-
-void
-intrinit(void)
-{
-	Ctlr *ctlr = &ctlrmpu;
-	int i;
-
-	/* mask all interrupts */
-	for (i = 0; i < Nmir; i++)
-		csr32w(ctlr, Rmirsetn(i), ~0);
-
-	/* protection off, threshold off, set all intrs priority 0, mapped to irq */
-	csr32w(ctlr, Rcontrol, 0);
-	csr32w(ctlr, Rthreshold, 0xff);
-	for (i = 0; i < Nintrs; i++)
-		csr32w(ctlr, Rilrn(i), 0);
-
-	coherence();
-}
-
-void
-intrenable(int n, void (*f)(Ureg *, void *), void *arg, int, char *name)
-{
-	Ctlr *ctlr = &ctlrmpu;
-	Intr *intr;
-
-	if (n >= nelem(ctlr->intrs) || n < 0)
-		panic("intrenable %d", n);
-
-	intr = malloc(sizeof(*intr));
-	if(!intr)
-		panic("intrenable: no memory for interrupt");
-
-	intr->f = f;
-	intr->arg = arg;
-	intr->name = name;
-
-	lock(ctlr);
-
-	/* chain this interrupt */
-	intr->next = ctlr->intrs[n];
-	ctlr->intrs[n] = intr;
-
-	/* new handler assigned, unmask this interrupt */
-	csr32w(ctlr, Rmirclearn(n >> 5), 1 << (n & 31));
-
-	unlock(ctlr);
-	coherence();
-}
-
-void
-intrdisable(int n, void (*f)(Ureg *, void *), void *arg, int, char *name)
-{
-	Ctlr *ctlr = &ctlrmpu;
-	Intr *intr, **ip;
-
-	if (n >= nelem(ctlr->intrs) || n < 0)
-		panic("intrdisable %d", n);
-
-	lock(ctlr);
-	for(ip = &ctlr->intrs[n]; intr = *ip; ip = &intr->next) {
-		if(intr->f == f && intr->arg == arg && strcmp(intr->name, name) == 0) {
-			*ip = intr->next;
-			free(intr);
-			break;
-		}
-	}
-
-	/* no more handlers assigned, mask this interrupt */
-	if(ctlr->intrs[n] == nil)
-		csr32w(ctlr, Rmirsetn(n >> 5), 1 << (n & 31));
-
-	unlock(ctlr);
-	coherence();
-}
-
-void
-intr(Ureg *ureg)
-{
-	Ctlr *ctlr = &ctlrmpu;
-	Intr *intr;
-	int n, h, s;
-
-	h = 0;
-	n = csr32r(ctlr, Rirq) & 0x7f;
-	s = csr32r(ctlr, Rirq) & ~0x7f;
-	if(s) {
-		/* interrupt controller reports spurious interrupt flag. */
-		iprint("cpu%d: spurious interrupt\n", m->machno);
-		csr32w(ctlr, Rcontrol, Cnewirqgen);
-		return;
-	}
-
-	if(n >= nelem(ctlr->intrs)) {
-		iprint("cpu%d: invalid interrupt %d\n", m->machno, n);
-		csr32w(ctlr, Rcontrol, Cnewirqgen);
-		return;
-	}
-
-	/* call all handlers for this interrupt number */
-	for (intr = ctlr->intrs[n]; intr; intr = intr->next) {
-		if(intr->f) {
-			if(islo())
-				panic("trap: islo() in interrupt handler\n");
-
-			intr->f(ureg, intr->arg);
-			if(islo())
-				panic("trap: islo() after interrupt handler\n");
-		}
-
-		h++;
-	}
-
-	csr32w(ctlr, Rcontrol, Cnewirqgen);
-	coherence();
-
-	if(!h) iprint("cpu%d: spurious interrupt %d\n", m->machno, n);
-	if(up) {
-		if(n >= IRQTIMER1 && n <= IRQTIMER11) {
-			if(up->delaysched) {
-				splhi();
-				sched();
-			}
-		} else {
-			preempted();
-		}
-	}
-}
--- a/io.h
+++ /dev/null
@@ -1,63 +1,0 @@
-#define PHYSL4 0x40000000
-#define PHYSL4END 0x50000000
-
-#define PHYSTIMER1 0x48318000
-#define PHYSTIMER2 0x49032000
-#define PHYSTIMER3 0x49034000
-#define PHYSTIMER4 0x49036000
-#define PHYSTIMER5 0x49038000
-#define PHYSTIMER6 0x4903a000
-#define PHYSTIMER7 0x4903c000
-#define PHYSTIMER8 0x4903e000
-#define PHYSTIMER9 0x49040000
-#define PHYSTIMER10 0x48086000
-#define PHYSTIMER11 0x48088000
-
-#define PHYSUART1 0x4806a000
-#define PHYSUART2 0x4806c000
-#define PHYSUART3 0x49020000
-
-#define PHYSI2C1 0x48070000
-#define PHYSI2C2 0x48072000
-#define PHYSI2C3 0x48060000
-
-#define PHYSMMC1 0x4809c000
-#define PHYSMMC2 0x480b4000
-#define PHYSMMC3 0x480ad000
-
-#define PHYSDSS 0x48050000
-
-#define PHYSINTRMODEM 0x480c7000
-#define PHYSINTRMPU 0x48200000
-
-#define PHYSL3 0x68000000
-#define PHYSL3END 0x70000000
-
-#define PHYSMEM 0x80000000
-#define PHYSMEMEND 0x90000000
-
-#define IRQTIMER1 37
-#define IRQTIMER2 38
-#define IRQTIMER3 39
-#define IRQTIMER4 40
-#define IRQTIMER5 41
-#define IRQTIMER6 42
-#define IRQTIMER7 43
-#define IRQTIMER8 44
-#define IRQTIMER9 45
-#define IRQTIMER10 46
-#define IRQTIMER11 47
-
-#define IRQUART1 72
-#define IRQUART2 73
-#define IRQUART3 74
-
-#define IRQI2C1 56
-#define IRQI2C2 57
-#define IRQI2C3 61
-
-#define IRQMMC1 83
-#define IRQMMC2 86
-#define IRQMMC3 94
-
-#define IRQTWL 7
--- a/l.s
+++ /dev/null
@@ -1,354 +1,0 @@
-#include "mem.h"
-#include "io.h"
-
-TEXT _start(SB), $-4
-	/* load static base */
-	MOVW $setR12(SB), R12
-
-	/* fiqs and irqs off, svc mode (cortex a8 trm figure 2.12) */
-	MOVW $(PsrDfiq|PsrDirq|PsrMsvc), R0
-	MOVW R0, CPSR
-
-	/* mmu and l1 caches off (cortex a8 trm table 3.46) */
-	MRC 15, 0, R0, C1, C0, 0
-	BIC $(1<<12), R0 /* level 1 instruction cache */
-	BIC $(1<<1), R0 /* level 1 data cache */
-	BIC $(1<<0), R0 /* mmu */
-	MCR 15, 0, R0, C1, C0, 0
-	ISB
-
-	/* l2 caches off (cortex a8 trm table 3.49) */
-	MCR 15, 0, R0, C1, C0, 1
-	BIC $(1<<1), R0 /* level 2 cache */
-	MCR 15, 0, R0, C1, C0, 1
-	ISB
-
-	/* fill mach with 0 */
-	MOVW $0, R0
-	MOVW $MACH(0), R1
-	MOVW $MACH(MAXMACH), R2
-zeromach:
-	MOVW R0, (R1)
-	ADD $4, R1
-	CMP R1, R2
-	BNE zeromach
-
-	/* fill page tables with 0 */
-	MOVW R0, R0
-	MOVW $MACHL1(0), R1 /* bottom of l1 tables */
-	MOVW $MACHL1(MAXMACH), R2 /* top of l1 tables */
-zeropte:
-	MOVW R0, (R1)
-	ADD $4, R1
-	CMP R1, R2
-	BNE zeropte
-
-	/* fill bss with 0 */
-	MOVW $0, R0
-	MOVW $edata(SB), R1
-	MOVW $end(SB), R2
-zerobss:
-	MOVW R0, (R1)
-	ADD $4, R1
-	CMP R1, R2
-	BNE zerobss
-
-	/* fill page tables for memory:
-	 * 1mb section, cached, buffered, kernel read-write */
-	MOVW $((1<<1)|(1<<2)|(1<<3)|(1<<10)), R1
-	MOVW $PHYSMEM, R2
-	MOVW $(MACHL1(0)+L1X(PHYSMEM)), R3
-	MOVW $(MACHL1(0)+L1X(PHYSMEMEND)), R4
-ptemem:
-	ORR R2, R1, R0
-	MOVW R0, (R3)
-	ADD $(MiB), R2
-	ADD $4, R3
-	CMP R3, R4
-	BNE ptemem
-
-	/* fill page tables for l4 interconnect:
-	 * 1mb section, kernel read-write */
-	MOVW $((1<<1)|(1<<4)|(1<<10)), R1
-	MOVW $PHYSL4, R2
-	MOVW $(MACHL1(0)+L1X(PHYSL4)), R3
-	MOVW $(MACHL1(0)+L1X(PHYSL4END)), R4
-ptel4:
-	ORR R2, R1, R0
-	MOVW R0, (R3)
-	ADD $(MiB), R2
-	ADD $4, R3
-	CMP R3, R4
-	BNE ptel4
-
-	/* fill page tables for l3 interconnect:
-	 * 1mb section, kernel read-write */
-	MOVW $((1<<1)|(1<<4)|(1<<10)), R1
-	MOVW $PHYSL3, R2
-	MOVW $(MACHL1(0)+L1X(PHYSL3)), R3
-	MOVW $(MACHL1(0)+L1X(PHYSL3END)), R4
-ptel3:
-	ORR R2, R1, R0
-	MOVW R0, (R3)
-	ADD $(MiB), R2
-	ADD $4, R3
-	CMP R3, R4
-	BNE ptel3
-
-	/* fpu on (set bits 20-23 in CPACR) but disabled */
-	MRC 15, 0, R0, C1, C0, 2
-	ORR $(0xf<<20), R0
-	MCR 15, 0, R0, C1, C0, 2
-
-	VMRS(FPEXC, 0)
-	BIC $(FPEXCEX|FPEXCEN), R0
-	VMSR(0, FPEXC)
-
-	/* invalidate caches */
-	BL l1dcacheinv(SB)
-	BL l1icacheinv(SB)
-
-	/* l2 caches back on */
-	MRC 15, 0, R0, C1, C0, 1
-	ORR $(1<<1), R0
-	MCR 15, 0, R0, C1, C0, 1
-
-	/* l1 caches back on */
-	MRC 15, 0, R0, C1, C0, 0
-	ORR $(1<<12), R0
-	ORR $(1<<1), R0
-	MCR 15, 0, R0, C1, C0, 0
-
-	/* set domain access control to client. */
-	MOVW $1, R0
-	BL putdac(SB)
-
-	/* set translation table base */
-	MOVW $MACHL1(0), R0
-	BL putttb(SB)
-
-	/* mmu on, time to get virtual */
-	MOVW $virt(SB), R2
-	BL mmuinvalidate(SB)
-	BL mmuenable(SB)
-	MOVW R2, R15
-
-TEXT virt(SB), $-4
-	/* setup register variables */
-	MOVW $setR12(SB), R12
-	MOVW $(MACH(0)), R(Rmach)
-	MOVW $0, R(Rup)
-
-	/* setup stack in mach */
-	MOVW $(MACH(0)), R13
-	ADD $(MACHSZ), R13
-	SUB $4, R13
-
-	BL main(SB)
-
-_limbo:
-	BL idlehands(SB)
-	B _limbo
-
-	/* hack to load div */
-	BL _div(SB)
-
-
-TEXT mmuenable(SB), 1, $-4
-	MRC 15, 0, R0, C1, C0, 0
-	ORR $(1<<0), R0
-	MCR 15, 0, R0, C1, C0, 0
-	MCR 15, 0, R0, C7, C5, 6
-	DMB; DSB; ISB
-	RET
-
-TEXT mmudisable(SB), 1, $-4
-	MRC 15, 0, R0, C1, C0, 0
-	BIC $(1<<0), R0
-	MCR 15, 0, R0, C1, C0, 0
-	MCR 15, 0, R0, C7, C5, 6
-	DMB; DSB; ISB
-	RET
-
-TEXT mmuinvalidate(SB), 1, $-4
-	MOVW CPSR, R1
-	CPSID
-
-	MOVW R15, R0
-	MCR 15, 0, R0, C8, C7, 0
-	MCR 15, 0, R0, C7, C5, 6
-	DMB; DSB; ISB
-
-	MOVW R1, CPSR
-	RET
-
-/* get and put domain access control */
-TEXT getdac(SB), 1, $-4; MCR 15, 0, R0, C3, C0; RET
-TEXT putdac(SB), 1, $-4
-	MRC 15, 0, R0, C3, C0
-	ISB
-	RET
-
-
-/* get and put translation table base */
-TEXT getttb(SB), 1, $-4; MRC 15, 0, R0, C2, C0, 0; RET
-TEXT putttb(SB), 1, $-4
-	MCR 15, 0, R0, C2, C0, 0
-	MCR 15, 0, R0, C2, C0, 1
-	ISB
-	RET
-
-TEXT getdfsr(SB), $-4; MRC 15, 0, R0, C5, C0, 0; RET
-TEXT getifsr(SB), $-4; MRC 15, 0, R0, C5, C0, 1; RET
-TEXT getdfar(SB), $-4; MRC 15, 0, R0, C6, C0, 0; RET
-TEXT getifar(SB), $-4; MRC 15, 0, R0, C6, C0, 2; RET
-
-TEXT setvectors(SB), $-4;
-	MCR 15, 0, R0, C12, C0, 0
-	RET
-
-TEXT setlabel(SB), $-4
-	MOVW R13, 0(R0)
-	MOVW R14, 4(R0)
-	MOVW $0, R0
-	RET
-
-TEXT gotolabel(SB), $-4
-	MOVW 0(R0), R13
-	MOVW 4(R0), R14
-	MOVW $1, R0
-	RET
-
-TEXT cas(SB), $0
-TEXT cmpswap(SB), $0
-	MOVW ov+4(FP), R1
-	MOVW nv+8(FP), R2
-casspin:
-	LDREX (R0), R3
-	CMP R3, R1
-	BNE casfail
-	STREX R2, (R0), R4
-	CMP $0, R4
-	BNE casspin
-	MOVW $1, R0
-	DMB
-	RET
-casfail:
-	CLREX
-	MOVW $0, R0
-	RET
-
-TEXT tas(SB), $0
-TEXT _tas(SB), $0
-	MOVW $0xdeaddead, R2
-tasspin:
-	LDREX (R0), R1
-	STREX R2, (R0), R3
-	CMP $0, R3
-	BNE tasspin
-	MOVW R1, R0
-	DMB
-	RET
-
-TEXT idlehands(SB), $-4
-	DMB; DSB; ISB
-	WFI
-	RET
-
-TEXT coherence(SB), $-4
-	DMB; DSB; ISB
-	RET
-
-TEXT splhi(SB), $-4
-	MOVW R14, 4(R(Rmach))
-	MOVW CPSR, R0
-	CPSID
-	RET
-
-TEXT spllo(SB), $-4
-	MOVW CPSR, R0
-	CPSIE
-	RET
-
-TEXT splx(SB), $-4
-	MOVW R14, 4(R(Rmach))
-	MOVW R0, R1
-	MOVW CPSR, R0
-	MOVW R1, CPSR
-	RET
-
-TEXT spldone(SB), $-4
-	RET
-
-TEXT islo(SB), $0
-	MOVW CPSR, R0
-	AND $(PsrDirq), R0
-	EOR $(PsrDirq), R0
-	RET
-
-TEXT perfticks(SB), $0
-	MCR 15, 0, R0, C9, C13, 0
-	RET
-
-TEXT touser(SB), $-4
-	MOVM.DB.W [R0], (R13)
-	MOVM.S (R13), [R13]
-	ADD $4, R13
-
-	MOVW CPSR, R0
-	BIC $(PsrMask|PsrDirq|PsrDfiq), R0
-	ORR $PsrMusr, R0
-	MOVW R0, SPSR
-
-	MOVW $(UTZERO+0x20), R0
-	MOVM.DB.W [R0], (R13)
-
-	MOVM.IA.S.W (R13), [R15]
-
-TEXT forkret(SB), $-4
-	ADD $(15*4), R13
-	MOVW 8(R13), R14
-	MOVW 4(R13), R0
-	MOVW R0, SPSR
-	MOVM.DB.S (R13), [R0-R14]
-	ADD $8, R13
-	MOVM.IA.S.W (R13), [R15]
-
-TEXT peek(SB), $0
-	MOVW src+0(FP), R0
-	MOVW dst+4(FP), R1
-	MOVW cnt+8(FP), R2
-TEXT _peekinst(SB), $0
-_peekloop:
-	MOVB (R0), R3
-	MOVB R3, (R1)
-	SUB.S $1, R0
-	BNE _peekloop
-	RET
-
-TEXT fpinit(SB), $0
-	MOVW $FPEXCEN, R0
-	VMSR(0, FPEXC)
-	MOVW $0, R0
-	VMSR(0, FPSCR)
-	RET
-
-TEXT fpoff(SB), $0
-TEXT fpclear(SB), $0
-	MOVW $0, R1
-	VMSR(1, FPEXC)
-	RET
-
-TEXT fpsave(SB), $0
-	VMRS(FPEXC, 1)
-	VMRS(FPSCR, 2)
-	MOVM.IA.W [R1-R2], (R0)
-	VSTMIA
-	RET
-
-TEXT fprestore(SB), $0
-	MOVM.IA.W (R0), [R1-R2]
-	VMSR(1, FPEXC)
-	VMSR(2, FPSCR)
-	VLDMIA
-	RET
--- a/lcache.s
+++ /dev/null
@@ -1,121 +1,0 @@
-#include "mem.h"
-#include "io.h"
-
-/* l1 instruction cache invalidate */
-TEXT l1icacheinv(SB), $-4
-	MOVW $0, R0
-	MCR 15, 0, R0, C7, C5, 0
-	ISB
-	RET
-
-/* l1 data cache writeback */
-TEXT l1dcachewb(SB), $-4
-	MOVW $cacheopwb(SB), R0
-	MOVW $0, R1
-	B cacheop(SB)
-
-/* l1 data cache invalidate */
-TEXT l1dcacheinv(SB), $-4
-	MOVW $cacheopinv(SB), R0
-	MOVW $0, R1
-	B cacheop(SB)
-
-/* l1 data cache writeback + invalidate */
-TEXT l1dcachewbinv(SB), $-4
-	MOVW $cacheopwbinv(SB), R0
-	MOVW $0, R1
-	B cacheop(SB)
-
-/* l1 unified instruction + data cache writeback + invalidate */
-TEXT l1ucachewbinv(SB), $-4
-	MOVM.DB.W [R14], (SP)
-	BL l1dcachewbinv(SB)
-	BL l1icacheinv(SB)
-	MOVM.IA.W (SP), [R14]
-	RET
-
-/* l2 instruction + data cache writeback */
-TEXT l2idcachewb(SB), $-4
-	MOVW $cacheopwb(SB), R0
-	MOVW $1, R1
-	B cacheop(SB)
-
-/* l2 instruction + data cache invalidate */
-TEXT l2idcacheinv(SB), $-4
-	MOVW $cacheopinv(SB), R0
-	MOVW $1, R1
-	B cacheop(SB)
-
-/* l2 instruction + data cache writeback + invalidate */
-TEXT l2idcachewbinv(SB), $-4
-	MOVW $cacheopwbinv(SB), R0
-	MOVW $1, R1
-	B cacheop(SB)
-
-/* l1 unified instruction + data cache writeback + invalidate */
-TEXT l2ucachewbinv(SB), $-4
-	MOVM.DB.W [R14], (SP)
-	BL l2idcachewbinv(SB)
-	BL l2idcacheinv(SB)
-	MOVM.IA.W (SP), [R14]
-	RET
-
-/* set/way operations for cacheop */
-TEXT cacheopwb(SB), $-4;	MCR 15, 0, R0, C7, C10, 2; RET
-TEXT cacheopinv(SB), $-4;	MCR 15, 0, R0, C7, C6, 2; RET
-TEXT cacheopwbinv(SB), $-4;	MCR 15, 0, R0, C7, C14, 2; RET
-
-#define Rop R2
-#define Rcache R3
-#define Rways R4
-#define Rwayshift R5
-#define Rsets R6
-#define Rsetshift R7
-#define Rset R8
-
-/* apply a cache operation to the whole cache */
-TEXT cacheop(SB), $-4
-	/* stash */
-	MOVM.DB.W [R2,R14], (SP)
-	MOVW R0, Rop
-	MOVW R1, Rcache
-
-	/* get cache geometry */
-	MCR 15, 2, Rcache, C0, C0, 0; ISB
-	MRC 15, 1, R0, C0, C0, 0
-
-	/* compute ways = ((R0 >> 3) & 0x3ff) + 1) */
-	SRA $3, R0, Rways
-	AND $0x3ff, Rways
-	ADD $1, Rways
-
-	/* compute wayshift = log₂(ways) */
-	CLZ(4, 5) /* Rways, Rwayshift */
-	ADD $1, Rwayshift
-
-	/* compute sets = ((R0 >> 13) & 0x7fff) + 1) */
-	SRA $13, R0, Rsets
-	AND $0x7fff, Rsets
-	ADD $1, Rsets
-
-	/* compute setshift = log₂(cache line size) */
-	AND $0x7, R0, Rsetshift
-	ADD $4, Rsetshift
-
-cacheopways:
-	MOVW Rsets, Rset
-cacheopsets:
-	/* compute set / way register contents */
-	SLL Rwayshift, Rways, R0
-	SLL Rsetshift, Rset, R1
-	ORR R1, R0
-	SLL $1, Rcache, R1
-	ORR R1, R0
-
-	BL (Rop)
-	SUB $1, Rset; CMP $0, Rset; BEQ cacheopsets /* loop sets */
-	SUB $1, Rways; CMP $0, Rways; BEQ cacheopways /* loop ways */
-
-	/* restore */
-	MOVM.IA.W (SP), [R2,R14]
-	RET
--- a/ltrap.s
+++ /dev/null
@@ -1,201 +1,0 @@
-#include "mem.h"
-#include "io.h"
-
-TEXT vectors(SB), $-4
-	MOVW 24(R15), R15
-	MOVW 24(R15), R15
-	MOVW 24(R15), R15
-	MOVW 24(R15), R15
-	MOVW 24(R15), R15
-	MOVW 24(R15), R15
-	MOVW 24(R15), R15
-	MOVW 24(R15), R15
-
-TEXT vtable(SB), $-4
-	WORD $_vund(SB)
-	WORD $_vund(SB)
-	WORD $_vsvc(SB)
-	WORD $_viabt(SB)
-	WORD $_vdabt(SB)
-	WORD $_vund(SB)
-	WORD $_virq(SB)
-	WORD $_vfiq(SB)
-
-TEXT _vsvc(SB), $-4
-	CLREX
-	DSB
-
-	/* stash in ureg */
-	MOVM.DB.W [R14], (R13) /* ureg->pc */
-	MOVW SPSR, R14
-	MOVM.DB.W [R14], (R13) /* ureg->psr */
-	MOVW $PsrMsvc, R14
-	MOVM.DB.W [R14], (R13) /* ureg->type */
-
-	/* save user regs.
-	 * not MOVM.DB.W.S because the saved value of R13 is undefined.
-	 * (arm v7 manual §A8.8.199) */
-	MOVM.DB.S [R0-R14], (R13)
-	SUB $(15*4), R13
-
-	/* get our sb, mach, up */
-	MOVW $setR12(SB), R12
-	MOVW $(MACH(0)), R(Rmach)
-	MOVW 8(R(Rmach)), R(Rup)
-
-	/* make space for debugger and go to syscall passing ureg */
-	MOVW R13, R0
-	SUB $8, R13
-	BL syscall(SB)
-	ADD $8, R13
-
-	/* restore link, spsr */
-	ADD $(15*4), R13
-	MOVW 8(R13), R14
-	MOVW 4(R13), R0
-	MOVW R0, SPSR
-
-	/* restore user regs */
-	MOVM.DB.S (R13), [R0-R14]
-
-	/* pop past ureg->type, ureg->psr and restore ureg->pc.
-	 * omap and others have RFE here but 5a has no idea about newer instructions
-	 * and simulates it with the MOVM below */
-	ADD $8, R13
-	MOVM.IA.S.W (R13), [R15]
-
-TEXT _viabt(SB), $-4
-	CLREX
-	DSB
-	MOVM.IA [R0-R4], (R13)
-	MOVW $PsrMiabt, R0
-	B _vswitch
-
-TEXT _vdabt(SB), $-4
-	CLREX
-	DSB
-	MOVM.IA [R0-R4], (R13)
-	MOVW $PsrMdabt, R0
-	B _vswitch
-
-TEXT _virq(SB), $-4
-	CLREX
-	DSB
-	MOVM.IA [R0-R4], (R13)
-	MOVW $PsrMirq, R0
-	B _vswitch
-
-TEXT _vfiq(SB), $-4
-	CLREX
-	DSB
-	MOVM.IA [R0-R4], (R13)
-	MOVW $PsrMfiq, R0
-	B _vswitch
-
-TEXT _vund(SB), $-4
-	CLREX
-	DSB
-	MOVM.IA [R0-R4], (R13)
-	MOVW $PsrMund, R0
-	B _vswitch
-
-_vswitch:
-	/* stash pointer to previous R0-R4, stash SPSR and R14 for ureg */
-	MOVW SPSR, R1
-	MOVW R14, R2
-	MOVW R13, R3
-
-	/* back to svc mode */
-	MOVW CPSR, R14
-	BIC $PsrMask, R14
-	ORR $(PsrDirq|PsrDfiq|PsrMsvc), R14
-	MOVW R14, CPSR
-
-	/* from user or kernel mode? */
-	AND.S $0xf, R1, R4
-	BEQ _vuser
-
-	/* from kernel mode */
-	/* set ureg->type, ureg->psr, ureg->pc */
-	MOVM.DB.W [R0-R2], (R13)
-	MOVM.IA (R3), [R0-R4]
-
-	/* save kernel regs
-	 * not MOVM.DB.W.S because the saved value of R13 is undefined.
-	 * (arm v7 manual §A8.8.199) */
-	MOVM.DB [R0-R14], (R13)
-	SUB $(15*4), R13
-
-	/* get our sb, mach, up */
-	MOVW $setR12(SB), R12
-
-	/* make space for debugger and go to trap passing ureg */
-	MOVW R13, R0
-	SUB $8, R13
-	BL trap(SB)
-	ADD $8, R13
-
-	/* restore link, spsr */
-	ADD $(15*4), R13
-	MOVW 8(R13), R14
-	MOVW 4(R13), R0
-	MOVW R0, SPSR
-
-	/* restore kernel regs */
-	MOVM.DB (R13), [R0-R14]
-
-	/* pop past ureg->type, ureg->psr, and restore ureg->pc. */
-	ADD $8, R13
-	MOVM.IA.S.W (R13), [R15]
-
-_vuser:
-	/* from user mode */
-	/* set ureg->type, ureg->psr, ureg->pc */
-	MOVM.DB.W [R0-R2], (R13)
-	MOVM.IA (R3), [R0-R4]
-
-	/* save kernel regs
-	 * not MOVM.DB.W.S because the saved value of R13 is undefined.
-	 * (arm v7 manual §A8.8.199) */
-	MOVM.DB.S [R0-R14], (R13)
-	SUB $(15*4), R13
-
-	/* get our sb, mach, up */
-	MOVW $setR12(SB), R12
-	MOVW $(MACH(0)), R(Rmach)
-	MOVW 8(R(Rmach)), R(Rup)
-
-	/* make space for debugger and go to trap passing ureg */
-	MOVW R13, R0
-	SUB $8, R13
-	BL trap(SB)
-	ADD $8, R13
-
-	/* restore link, spsr */
-	ADD $(15*4), R13
-	MOVW 8(R13), R14
-	MOVW 4(R13), R0
-	MOVW R0, SPSR
-
-	/* restore kernel regs */
-	MOVM.DB.S (R13), [R0-R14]
-
-	/* pop past ureg->type, ureg->psr, and restore ureg->pc */
-	ADD $8, R13
-	MOVM.IA.S.W (R13), [R15]
-
-TEXT setR13(SB), $-4
-	MOVW 4(FP), R1
-
-	/* switch to new mode */
-	MOVW CPSR, R2
-	BIC $PsrMask, R2, R3
-	ORR R0, R3
-	MOVW R3, CPSR
-
-	/* set r13 */
-	MOVW R1, R13
-
-	/* back to old mode */
-	MOVW R2, CPSR
-	RET
--- a/main.c
+++ /dev/null
@@ -1,222 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-
-#include "tos.h"
-#include "ureg.h"
-#include "pool.h"
-
-#define MAXCONF 64
-
-static char *confname[MAXCONF];
-static char *confval[MAXCONF];
-static int nconf;
-
-Conf conf;
-
-char*
-getconf(char *name)
-{
-	int i;
-
-	for(i = 0; i < nconf; i++)
-		if(cistrcmp(confname[i], name) == 0)
-			return confval[i];
-
-	return nil;
-}
-
-int
-isaconfig(char *, int, ISAConf *)
-{
-	return 0;
-}
-
-void
-cpuidprint(void)
-{
-	/* FIXME: how fast are we really? */
-	print("cpu%d: %dMHz ARM Cortex-A8\n", m->machno, 600);
-}
-
-void
-plan9iniinit(void)
-{
-	char *c, *p, *q;
-	char *v[MAXCONF];
-	int i, n;
-
-	c = (char*) CONFADDR;
-	for(p = q = c; *q; q++) {
-		if(*q == '\r')
-			continue;
-		if(*q == '\t')
-			*q = ' ';
-		*p++ = *q;
-	}
-
-	*p = 0;
-	n = getfields(c, v, MAXCONF, 1, "\n");
-	for(i = 0; i < n; i++) {
-		if(v[i][0] == '#')
-			continue;
-
-		c = strchr(v[i], '=');
-		if(!c)
-			continue;
-
-		confname[nconf] = v[i];
-		confval[nconf] = c;
-		nconf++;
-	}
-}
-
-void
-confinit(void)
-{
-	int i;
-	uintptr pa;
-	ulong kp;
-
-	conf.nmach = 1;
-	conf.npage = 0;
-	conf.mem[0].base = PHYSMEM;
-	conf.mem[0].limit = PHYSMEMEND;
-
-	pa = PADDR(PGROUND((uintptr)end));
-	for(i = 0; i < nelem(conf.mem); i++) {
-		if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
-			conf.mem[i].base = pa;
-
-		conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
-		conf.npage += conf.mem[i].npage;
-	}
-
-	conf.upages = (conf.npage*80)/100;
-	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
-
-	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
-	if(cpuserver)
-		conf.nproc *= 3;
-	if(conf.nproc > 4000)
-		conf.nproc = 4000;
-
-	conf.nswap = conf.npage*3;
-	conf.nswppo = 4096;
-	conf.nimage = 200;
-	conf.copymode = 0;
-
-	kp = conf.npage - conf.upages;
-	kp *= BY2PG;
-	kp -= conf.upages * sizeof(Page)
-		+ conf.nproc * sizeof(Proc*)
-		+ conf.nimage * sizeof(Image)
-		+ conf.nswap
-		+ conf.nswppo * sizeof(Page*);
-
-	mainmem->maxsize = kp;
-	if(!cpuserver)
-		imagmem->maxsize = kp;
-}
-
-void
-machinit(void)
-{
-	m->machno = 0;
-
-	active.machs[0] = 1;
-	active.exiting = 0;
-
-	up = nil;
-}
-
-void
-init0(void)
-{
-	char **sp, buf[KNAMELEN];
-	int i;
-
-	chandevinit();
-	if(!waserror()) {
-		ksetenv("cputype", "arm", 0);
-		if(cpuserver)
-			ksetenv("service", "cpu", 0);
-		else
-			ksetenv("service", "terminal", 0);
-
-		snprint(buf, sizeof(buf), "nokia %s", conffile);
-		ksetenv("terminal", buf, 0);
-		ksetenv("console", "2", 0);
-		ksetenv("kbmap", "n900", 0);
-		for(i = 0; i < nconf; i++) {
-			if(*confname[i] != '*')
-				ksetenv(confname[i], confval[i], 0);
-			ksetenv(confname[i], confval[i], 1);
-		}
-
-		poperror();
-	}
-
-	kproc("alarm", alarmkproc, 0);
-
-	/* prepare stack for boot */
-	sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
-	sp[3] = sp[2] = sp[1] = nil;
-	strcpy(sp[0] = (char*)&sp[4], "boot");
-	touser(sp);
-}
-
-void
-main(void)
-{
-	uartinit();
-	machinit();
-	mmuinit();
-	plan9iniinit();
-	confinit();
-	printinit();
-	quotefmtinstall();
-	fmtinstall(L'H', encodefmt);
-	print("\nPlan 9\n");
-
-	xinit();
-	trapinit();
-	intrinit();
-	timerinit();
-	cpuidprint();
-	procinit0();
-	initseg();
-	links();
-
-	screeninit();
-	chandevreset();
-
-	pageinit();
-	userinit();
-	schedinit();
-
-	panic("schedinit returned");
-}
-
-void
-exit(int)
-{
-	for(;;)
-		idlehands();
-}
-
-void
-reboot(void *, void *, ulong)
-{
-}
-
-void
-setupwatchpts(Proc *, Watchpt *, int n)
-{
-	if(n > 0)
-		error("no watchpoints");
-}
--- a/mem.h
+++ /dev/null
@@ -1,105 +1,0 @@
-#define KiB (1024u)
-#define MiB (1024*1024u)
-#define GiB (1024*1024*1024u)
-
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-
-#define Rmach 10
-#define Rup 9
-
-#define HZ (100)
-#define MS2HZ (1000/HZ)
-#define TK2SEC(t) ((t)/HZ)
-
-#define CONFADDR 0x80010000
-
-#define KZERO 0x80000000
-#define KTZERO 0x80020000
-#define KSTACK (8*KiB)
-
-#define UZERO 0
-#define UTZERO BY2PG
-#define USTKTOP 0x20000000
-#define USTKSIZE (16*MiB)
-
-#define MAXMACH 1
-#define MACHSZ (16*KiB)
-#define L1SZ (4*4096)
-#define L2SZ (4*256)
-
-#define L1X(va) ((((va)>>20) & 0xfff) << 2)
-
-#define MACH(n) (KZERO+(n)*MACHSZ)
-#define MACHP(n) ((Mach*)MACH(n))
-#define MACHL1(n) (MACH(MAXMACH)+(n)*L1SZ)
-#define MACHVEC(n) (MACHL1(MAXMACH)+(n)*64*4)
-
-#define BY2PG (4*KiB)
-#define BY2SE 4
-#define BY2WD 4
-#define BY2V 8
-
-#define CACHELINEZ 64
-#define BLOCKALIGN 32
-
-#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1))
-#define PGROUND(s) ROUND(s, BY2PG)
-#define PGSHIFT 12
-
-#define PTEMAPMEM MiB
-#define PTEPERTAB (PTEMAPMEM/BY2PG)
-#define SEGMAPSIZE 1984
-#define SSEGMAPSIZE 16
-
-#define PPN(p) ((p)&~(BY2PG-1))
-
-#define PTEVALID (1<<0)
-#define PTERONLY (0<<1)
-#define PTEWRITE (1<<1)
-#define PTECACHED (0<<2)
-#define PTEUNCACHED (1<<2)
-#define PTENOEXEC (1<<3)
-
-#define PsrDfiq 0x40
-#define PsrDirq 0x80
-
-#define PsrMusr 0x10
-#define PsrMfiq 0x11
-#define PsrMirq 0x12
-#define PsrMsvc 0x13
-#define PsrMmon 0x16
-#define PsrMiabt 0x17
-#define PsrMdabt 0x18
-#define PsrMund 0x1b
-#define PsrMsys 0x1f
-
-#define PsrMask 0x1f
-
-#define WFI WORD $0xe320f003
-#define DSB WORD $0xf57ff04f
-#define DMB WORD $0xf57ff05f
-#define ISB WORD $0xf57ff06f
-
-#define CPSIE WORD $0xf1080080
-#define CPSID WORD $0xf10c0080
-
-#define CLZ(s, d) WORD $(0xe16f0f10 | (d) << 12 | (s))
-#define VMSR(cpu, fp) WORD $(0xeee00a10|(fp)<<16|(cpu)<<12)
-#define VMRS(fp, cpu) WORD $(0xeef00a10|(fp)<<16|(cpu)<<12)
-
-#define FPSID 0x0
-#define FPSCR 0x1
-#define MVFR1 0x6
-#define MVFR0 0x7
-#define FPEXC 0x8
-#define FPEXCEX (1<<31)
-#define FPEXCEN (1<<30)
-
-/* vlmdia r0!, {d0-d15}
- * vldmia r0!, {d16-d31} */
-#define VLDMIA WORD $0xecb00b20; WORD $0xecf00b20;
-
-/* vstmia r0!, {d0-d15}
- * vstmia r0!, {d16-d31} */
-#define VSTMIA WORD $0xeca00b20; WORD $0xece00b20;
--- a/mkfile
+++ /dev/null
@@ -1,82 +1,0 @@
-CONF=n900
-CONFLIST=n900
-
-p=9
-objtype=arm
-ktzero=0x80020000
-
-</$objtype/mkfile
-
-DEVS=`{rc ../port/mkdevlist $CONF}
-PORT=\
-	alarm.$O\
-	alloc.$O\
-	allocb.$O\
-	auth.$O\
-	cache.$O\
-	chan.$O\
-	dev.$O\
-	edf.$O\
-	fault.$O\
-	mul64fract.$O\
-	rebootcmd.$O\
-	page.$O\
-	parse.$O\
-	pgrp.$O\
-	portclock.$O\
-	print.$O\
-	proc.$O\
-	qio.$O\
-	qlock.$O\
-	segment.$O\
-	sysfile.$O\
-	sysproc.$O\
-	taslock.$O\
-	tod.$O\
-	xalloc.$O\
-	random.$O\
-	rdb.$O\
-	syscallfmt.$O\
-	userinit.$O\
-	ucalloc.$O\
-
-OBJ=\
-	l.$O\
-	lcache.$O\
-	ltrap.$O\
-	main.$O\
-	mmu.$O\
-	timer.$O\
-	trap.$O\
-	intr.$O\
-	$CONF.root.$O\
-	$CONF.rootc.$O\
-	$DEVS\
-	$PORT\
-
-LIB=\
-	/$objtype/lib/libmemlayer.a\
-	/$objtype/lib/libmemdraw.a\
-	/$objtype/lib/libdraw.a\
-	/$objtype/lib/libip.a\
-	/$objtype/lib/libsec.a\
-	/$objtype/lib/libmp.a\
-	/$objtype/lib/libc.a\
-	/$objtype/lib/libdtracy.a\
-
-$p$CONF.u:D: $p$CONF
-	aux/aout2uimage -o $target -Z0 $prereq
-
-$p$CONF:D: $OBJ $CONF.$O $LIB
-	$LD -o $target -T$ktzero -l $prereq
-
-<../boot/bootmkfile
-<../port/portmkfile
-<|../port/mkbootrules $CONF
-
-initcode.out: init9.$O initcode.$O /$objtype/lib/libc.a
-	$LD -l -R1 -s -o $target $prereq
-
-install:V: $p$CONF.u
-	cp $p$CONF /$objtype/
-	cp $p$CONF.u /$objtype/
--- a/mmcn900.c
+++ /dev/null
@@ -1,308 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "../port/error.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/pci.h"
-#include "../port/sd.h"
-
-enum {
-	Rsysc		= 0x10,
-		SCreset		= 1 << 1,
-	Rsyss		= 0x14,
-		SSreset		= 1 << 0,
-	Rcsre		= 0x24,
-	Rcon		= 0x28,
-	Rpwcnt		= 0x2c,
-	Rblk		= 0x104,
-	Rarg		= 0x108,
-	Rcmd		= 0x10c,
-		CRnone		= 0 << 16,
-		CR136		= 1 << 16,
-		CR48		= 2 << 16,
-		CR48busy	= 3 << 16,
-		CRmask		= 3 << 16,
-
-		CFcheckidx	= 1 << 19,
-		CFcheckcrc	= 1 << 20,
-		CFdata		= 1 << 21,
-		CFdataread	= 1 << 4,
-		CFdatamulti	= 1 << 5,
-
-		CTnone		= 0 << 22,
-		CTbus		= 1 << 22,
-		CTfunc		= 2 << 22,
-		CTio		= 3 << 22,
-	Rrsp10		= 0x110,
-	Rrsp32		= 0x114,
-	Rrsp54		= 0x118,
-	Rrsp76		= 0x11c,
-	Rdata		= 0x120,
-	Rpstate		= 0x124,
-	Rhctl		= 0x128,
-	Rsysctl		= 0x12c,
-	Rstatus		= 0x130,
-		STcmd		= 1 << 0,
-		STtransfer	= 1 << 1,
-		STbufwrite	= 1 << 4,
-		STbufread	= 1 << 5,
-
-		STmaskok	= 0xffff << 0,
-		STmaskerr	= 0xffff << 16,
-	Rie			= 0x134,
-	Rise		= 0x138,
-	Rac12		= 0x13c,
-	Rcapa		= 0x140,
-	Rcapacur	= 0x148,
-	Rrev		= 0x1fc,
-};
-
-#define csr32r(c, r) ((c)->io[(r)/4])
-#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
-
-typedef struct Ctlr Ctlr;
-struct Ctlr {
-	char *name;
-	u32int *io;
-	ulong irq;
-
-	struct {
-		uint bcount;
-		uint bsize;
-	} cmd;
-
-	Lock;
-	Rendez;
-};
-
-static int
-n900mmcinit(SDio *io)
-{
-	Ctlr *ctlr;
-
-	ctlr = io->aux;
-	csr32w(ctlr, Rsysc, SCreset);
-	while(!(csr32r(ctlr, Rsyss) & SSreset))
-		;
-
-	return 0;
-}
-
-static void
-n900mmcenable(SDio *)
-{
-}
-
-static int
-n900mmcinquiry(SDio *, char *inquiry, int len)
-{
-	return snprint(inquiry, len, "MMC Host Controller");
-}
-
-static void
-n900mmcintr(Ureg *, void *aux)
-{
-	Ctlr *ctlr;
-
-	ctlr = aux;
-	ilock(ctlr);
-	if(csr32r(ctlr, Rstatus) & STcmd)
-		wakeup(ctlr);
-
-	iunlock(ctlr);
-}
-
-static int
-n900mmcdone(void *aux)
-{
-	Ctlr *ctlr = aux;
-
-	if(csr32r(ctlr, Rstatus) & STcmd)
-		return 1;
-
-	return 0;
-}
-
-static int
-n900mmccmd(SDio *io, SDiocmd *iocmd, u32int arg, u32int *resp)
-{
-	Ctlr *ctlr;
-	u32int cmd;
-
-	/* prepare flags for this command */
-	ctlr = io->aux;
-	cmd = iocmd->index << 24;
-	switch(iocmd->resp) {
-	case 0: cmd |= CRnone; break;
-	case 2: cmd |= CR136 | CFcheckcrc; break;
-	case 3: cmd |= CR48; break;
-	case 1:
-		if(iocmd->busy) {
-			cmd |= CR48busy | CFcheckidx | CFcheckcrc;
-			break;
-		}
-
-	default:
-		cmd |= CR48 | CFcheckidx | CFcheckcrc;
-		break;
-	}
-
-	/* if there is data, set the data, read, and multi flags */
-	if(iocmd->data) {
-		cmd |= CFdata;
-		if(iocmd->data & 1)
-			cmd |= CFdataread;
-		if(iocmd->data > 2)
-			cmd |= CFdatamulti;
-	}
-
-	/* off it goes, wait for a response */
-	csr32w(ctlr, Rstatus, ~0);
-	csr32w(ctlr, Rarg, arg);
-	csr32w(ctlr, Rcmd, cmd);
-
-	/* wait for command to be done */
-	tsleep(ctlr, n900mmcdone, ctlr, 100);
-	if(csr32r(ctlr, Rstatus) & STmaskerr)
-		error(Eio);
-
-	/* unpack the response */
-	switch(cmd & CRmask) {
-	case CRnone:
-		resp[0] = 0;
-		break;
-
-	case CR136:
-		resp[0] = csr32r(ctlr, Rrsp10);
-		resp[1] = csr32r(ctlr, Rrsp32);
-		resp[2] = csr32r(ctlr, Rrsp54);
-		resp[3] = csr32r(ctlr, Rrsp76);
-		break;
-
-	case CR48:
-	case CR48busy:
-		resp[0] = csr32r(ctlr, Rrsp10);
-		break;
-	}
-
-	return 0;
-}
-
-static void
-n900mmciosetup(SDio *io, int, void *, int bsize, int bcount)
-{
-	Ctlr *ctlr;
-
-	ctlr = io->aux;
-	if(bsize == 0 || (bsize & 3) != 0)
-		error(Egreg);
-
-	ctlr->cmd.bsize = bsize;
-	ctlr->cmd.bcount = bcount;
-	csr32w(ctlr, Rblk, (bsize & 0x3ff) | (bcount << 16));
-}
-
-static void
-n900mmcbufread(Ctlr *ctlr, uchar *buf, int len)
-{
-	for(len >>= 2; len > 0; len--) {
-		*((u32int*)buf) = csr32r(ctlr, Rdata);
-		buf += 4;
-	}
-}
-
-static void
-n900mmcbufwrite(Ctlr *ctlr, uchar *buf, int len)
-{
-	for(len >>= 2; len > 0; len--) {
-		csr32w(ctlr, Rdata, *((u32int*)buf));
-		buf += 4;
-	}
-}
-
-static void
-n900mmcio(SDio *io, int write, uchar *buf, int len)
-{
-	Ctlr *ctlr;
-	u32int stat, n;
-
-	ctlr = io->aux;
-	if(len != ctlr->cmd.bsize * ctlr->cmd.bcount)
-		error(Egreg);
-
-	while(len > 0) {
-		stat = csr32r(ctlr, Rstatus);
-		if(stat & STmaskerr) {
-			csr32w(ctlr, Rstatus, STmaskerr);
-			error(Eio);
-		}
-
-		if(stat & STbufwrite) {
-			csr32w(ctlr, Rstatus, STbufwrite);
-			if(!write)
-				error(Eio);
-
-			n = len;
-			if(n > ctlr->cmd.bsize)
-				n = ctlr->cmd.bsize;
-
-			n900mmcbufwrite(ctlr, buf, n);
-			len -= n;
-			buf += n;
-		}
-
-		if(stat & STbufread) {
-			csr32w(ctlr, Rstatus, STbufread);
-			if(write)
-				error(Eio);
-
-			n = len;
-			if(n > ctlr->cmd.bsize)
-				n = ctlr->cmd.bsize;
-
-			n900mmcbufread(ctlr, buf, n);
-			len -= n;
-			buf += n;
-		}
-
-		if(stat & STtransfer) {
-			csr32w(ctlr, Rstatus, STtransfer);
-			if(len != 0)
-				error(Eio);
-		}
-	}
-}
-
-static void
-n900mmcbus(SDio *, int, int)
-{
-	/* FIXME: change bus width */
-}
-
-void
-mmcn900link(void)
-{
-	int i;
-	static Ctlr ctlr[2] = {
-		{ .name = "mmc1", .io = (u32int*) PHYSMMC1, .irq = IRQMMC1, },
-		{ .name = "mmc2", .io = (u32int*) PHYSMMC2, .irq = IRQMMC2, },
-	};
-
-	static SDio io[nelem(ctlr)];
-	for(i = 0; i < nelem(io); i++) {
-		io[i].name = "mmc",
-		io[i].init = n900mmcinit,
-		io[i].enable = n900mmcenable,
-		io[i].inquiry = n900mmcinquiry,
-		io[i].cmd = n900mmccmd,
-		io[i].iosetup = n900mmciosetup,
-		io[i].io = n900mmcio,
-		io[i].bus = n900mmcbus,
-		io[i].aux = &ctlr[i];
-
-		addmmcio(&io[i]);
-		intrenable(ctlr[i].irq, n900mmcintr, &ctlr[i], BUSUNKNOWN, ctlr[i].name);
-	}
-}
--- a/mmu.c
+++ /dev/null
@@ -1,311 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-
-static int debug = 0;
-
-#define L1(va) (((va)>>20) & 0xfff)
-#define L2(va) (((va)>>12) & 0xff)
-#define L1AP(ap) (((ap) << 10) & 0xff) /* dont care about ap[2] */
-#define L2AP(ap) (((ap) << 4) & 0xff)
-
-enum {
-	/* l1 descriptor type (arm v7 manual fig. 12.4) */
-	L1coarse = 1,
-	L1section = 2,
-	L1fine = 3,
-
-	/* l2 descriptor type (arm v7 manual fig. 12.5) */
-	L2large = 1,
-	L2small = 2,
-	L2tiny = 3,
-
-	Fnoexec = 1<<0,
-	Fbuffered = 1<<2,
-	Fcached = 1<<3,
-
-	APkrw = 1, /* kernel read write */
-	APuro = 2, /* user read only */
-	APurw = 3, /* user read write */
-};
-
-void
-mmudebugl2(PTE *l2, uintptr va)
-{
-	uintptr startpa, pa;
-	uintptr startva, endva;
-	int i, t;
-
-	t = 0;
-	startpa = 0;
-	startva = endva = 0;
-	for(i = 0; i < 256; i++) {
-		pa = l2[i] & ~((4*KiB)-1);
-		if(l2[i] == 0) {
-			if(endva) {
-				iprint("mmudebug: l2 type %#ux %#lux %#lux -> %#lux\n", t, startva, endva, startpa);
-				endva = 0;
-			}
-		} else {
-			if(!endva) {
-				startva = va;
-				startpa = pa;
-				t = l2[i] & (L2large | L2small | L2tiny);
-			}
-
-			endva = va + (4*KiB);
-		}
-
-		va += (4*KiB);
-	}
-
-	if(endva)
-		iprint("mmudebug: l2 type %#ux %#lux %#lux -> %#lux\n", t, startva, endva, startpa);
-}
-
-void
-mmudebug(char *where)
-{
-	PTE *l1;
-	uintptr pa, startpa;
-	uintptr va, startva, endva;
-	int i, t;
-
-	if(!debug)
-		return;
-
-	iprint("mmudebug: %s pid %d\n", where, m->mmupid);
-
-	t = 0;
-	l1 = m->mmul1;
-	startpa = 0;
-	startva = endva = 0;
-	for(va = i = 0; i < 4096; i++) {
-		pa = l1[i] & ~(MiB-1);
-		if(l1[i] == 0) {
-			if(endva) {
-				iprint("mmudebug: l1 type %#ux %#lux %#lux -> %#lux\n", t, startva, endva, startpa);
-				endva = 0;
-			}
-		} else {
-			if(!endva) {
-				startva = va;
-				startpa = pa;
-				t = l1[i] & (L1coarse|L1section|L1fine);
-			}
-
-			if(t == L1coarse) {
-				mmudebugl2((PTE*) (l1[i] & ~(KiB-1)), startva);
-				endva = 0;
-			} else {
-				endva = va + MB;
-			}
-		}
-
-		va += MB;
-	}
-
-	if(endva)
-		iprint("mmudebug: l1 type %#ux %#lux %#lux -> %#lux\n", t, startva, endva, startpa);
-}
-
-void
-mmuinit(void)
-{
-	m->mmul1 = (PTE*)MACHL1(m->machno);
-}
-
-static void
-mmul1empty(void)
-{
-	memset(m->mmul1, 0, (ROUND(USTKTOP, MiB)/MiB)*sizeof(PTE));
-}
-
-static void
-mmul2empty(Proc *proc, int clear)
-{
-	PTE *l1;
-	Page **l2, *page;
-
-	l1 = m->mmul1;
-	l2 = &proc->mmul2;
-	for(page = *l2; page != nil; page = page->next) {
-		if(clear)
-			memset((void*)page->va, 0, BY2PG);
-
-		l1[page->daddr] = 0;
-		l2 = &page->next;
-	}
-
-	*l2 = proc->mmul2cache;
-	proc->mmul2cache = proc->mmul2;
-	proc->mmul2 = nil;
-}
-
-void
-mmuswitch(Proc *proc)
-{
-	PTE *l1;
-	Page *page;
-	int l1x;
-
-	if(m->mmupid == proc->pid && !proc->newtlb)
-		return;
-	m->mmupid = proc->pid;
-
-	/* write back and invalidate caches */
-	l1ucachewbinv();
-	l2ucachewbinv();
-
-	if(proc->newtlb) {
-		mmul2empty(proc, 1);
-		proc->newtlb = 0;
-	}
-
-	mmul1empty();
-
-	/* switch to new map */
-	l1 = m->mmul1;
-	for(page = proc->mmul2; page != nil; page = page->next) {
-		l1x = page->daddr;
-		l1[l1x] = PPN(page->pa)|L1coarse;
-	}
-
-	/* FIXME: excessive invalidation */
-	l1ucachewbinv();
-	l2ucachewbinv();
-	mmuinvalidate();
-	mmudebug("mmuswitch");
-}
-
-void
-mmurelease(Proc *proc)
-{
-	l1ucachewbinv();
-	l2ucachewbinv();
-
-	mmul2empty(proc, 0);
-
-	freepages(proc->mmul2cache, nil, 0);
-	proc->mmul2cache = nil;
-
-	mmul1empty();
-
-	/* FIXME: excessive invalidation */
-	l1ucachewbinv();
-	l2ucachewbinv();
-	mmuinvalidate();
-	mmudebug("mmurelease");
-}
-
-void*
-mmuuncache(void *v, usize s)
-{
-	PTE *l1;
-	uintptr va;
-
-	assert(!((uintptr)v & (MiB-1)) && s == MiB);
-
-	va = (uintptr)v;
-	l1 = &m->mmul1[L1(va)];
-	if((*l1 & (L1fine|L1section|L1coarse)) != L1section)
-		return nil;
-
-	*l1 &= ~(Fbuffered|Fcached);
-
-	/* FIXME: excessive invalidation */
-	l1ucachewbinv();
-	l2ucachewbinv();
-	mmuinvalidate();
-	mmudebug("mmuuncache");
-
-	return v;
-}
-
-void
-putmmu(uintptr va, uintptr pa, Page *page)
-{
-	int l1x, s, x;
-	PTE *l1, *l2;
-	Page *pg;
-
-	l1x = L1(va);
-	l1 = &m->mmul1[l1x];
-
-	/* put l1 for l2 table if needed */
-	if(*l1 == 0) {
-		if(up->mmul2cache == nil) {
-			pg = newpage(1, 0, 0);
-			pg->va = VA(kmap(pg));
-		} else {
-			pg = up->mmul2cache;
-			up->mmul2cache = pg->next;
-			memset((void*)pg->va, 0, BY2PG);
-		}
-
-		pg->daddr = l1x;
-		pg->next = up->mmul2;
-		up->mmul2 = pg;
-
-		/* FIXME: excessive invalidation */
-		s = splhi();
-		*l1 = PPN(pg->pa)|L1coarse;
-		l1ucachewbinv();
-		l2ucachewbinv();
-		splx(s);
-	}
-
-	/* put l2 entry */
-	x = L2small;
-	if(!(pa & PTEUNCACHED))
-		x |= Fbuffered|Fcached;
-	if(pa & PTENOEXEC)
-		x |= Fnoexec;
-	if(pa & PTEWRITE)
-		x |= L2AP(APurw);
-	else
-		x |= L2AP(APuro);
-
-	l2 = KADDR(PPN(*l1)); l2[L2(va)] = PPN(pa)|x;
-
-	/* FIXME: excessive invalidation */
-	s = splhi();
-	l1ucachewbinv();
-	l2ucachewbinv();
-	if(needtxtflush(page)) {
-		l1icacheinv();
-		donetxtflush(page);
-	}
-
-	splx(s);
-	mmuinvalidate();
-	mmudebug("putmmu");
-}
-
-void
-checkmmu(uintptr, uintptr)
-{
-	/* this page is intentionally left blank */
-}
-
-void
-flushmmu(void)
-{
-	uint s;
-
-	s = splhi();
-	up->newtlb = 1; mmuswitch(up);
-	splx(s);
-}
-
-uintptr
-cankaddr(uintptr pa)
-{
-	if(pa >= PHYSMEM && pa < PHYSMEMEND)
-		return PHYSMEMEND-pa;
-
-	return 0;
-}
--- a/n900
+++ /dev/null
@@ -1,49 +1,0 @@
-dev
-	root
-	cons
-	swap
-	env
-	pipe
-	proc
-	mnt
-	srv
-	shr
-	dup
-	tls
-	cap
-	sd
-	fs
-	dtracy
-
-	draw	screen
-
-	kbd		devi2c
-	rtc		devi2c
-
-	uart
-	usb
-	i2c
-
-misc
-	uartn900
-
-	sdmmc	mmcn900
-	sdloop
-	sdram
-
-	dtracysys
-	dtracytimer
-	dtracydev
-
-link
-	i2cn900		devi2c
-	mmcn900
-
-port
-	int cpuserver = 0;
-
-bootdir
-	/$objtype/bin/paqfs
-	/$objtype/bin/auth/factotum
-	boot
-	bootfs.paq
--- a/screen.c
+++ /dev/null
@@ -1,373 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-
-#define Image IMAGE
-#include <draw.h>
-#include <memdraw.h>
-#include "screen.h"
-
-enum {
-	/* display controller registers */
-	RDrev			= 0x400,
-	RDsysconf		= 0x410,
-		DSCidle			= 1<<0,
-		DSCreset		= 1<<1,
-		DSCidlesmart	= 2<<3,
-	RDsysstat		= 0x414,
-		DSSreset		= 1<<0,
-	RDirqstat		= 0x418,
-	RDirqen			= 0x41c,
-	RDcontrol		= 0x440,
-		DClcdon			= 1<<0,
-		DClcdactive		= 1<<3,
-		DClcdclockrun	= 1<<27,
-		DClcdenable		= 1<<28,
-		DClcdenablehi	= 1<<29,
-		DClcdbits24		= 3<<8,
-	RDconfig		= 0x444,
-		DCNgamma		= 1<<3,
-	RDdefcolor		= 0x44c,
-	RDtranscolor	= 0x454,
-	RDlinestat		= 0x45c,
-	RDlineintr		= 0x460,
-	RDtimeh			= 0x464,
-	RDtimev			= 0x468,
-	RDsize			= 0x47c,
-
-	/* display controller graphics layer registers */
-	RDgfxba				= 0x480,
-	RDgfxpos			= 0x488,
-	RDgfxsize			= 0x48c,
-	RDgfxattr			= 0x4a0,
-		DGAenable			= 1<<0,
-		DGAfmt				= 0x6<<1,
-		DGAburst			= 0x2<<6,
-	RDgfxrowinc			= 0x4ac,
-	RDgfxpixelinc		= 0x4b0,
-};
-
-enum {
-	Tab	= 4,
-	Scroll = 8,
-};
-
-#define RDdefcolorn(n)		(RDdefcolor + (n)*4)
-#define RDtranscolorn(n)	(RDtranscolor + (n)*4)
-
-#define RDgfxban(n)			(RDgfxba + (n)*4)
-
-#define TIME(s, f, b)		((s & 0xff) | (f & 0xfff) << 8 | (b & 0xfff) << 20)
-#define POS(x, y)			((x)<<16 | (y))
-#define SIZE(w, h)			((h-1)<<16 | (w-1))
-
-typedef struct Ctlr Ctlr;
-struct Ctlr {
-	Lock;
-
-	u32int *io;
-
-	Memdata scrdata;
-	Memimage *scrimg;
-	Memsubfont *scrfont;
-
-	Rectangle win;
-	Point font;
-	Point pos;
-};
-
-static Ctlr ctlr = {
-	.io = (u32int*) PHYSDSS,
-};
-
-#define csr32r(c, r) ((c)->io[(r)/4])
-#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
-
-static void myscreenputs(char *s, int n);
-
-static int
-screendatainit(Ctlr *ctlr)
-{
-	Rectangle r;
-
-	if(memimageinit() < 0)
-		return -1;
-
-	r = Rect(0, 0, 800, 480);
-	ctlr->scrdata.ref = 1;
-	ctlr->scrdata.bdata = ucalloc(r.max.x * r.max.y * 2);
-	if(!ctlr->scrdata.bdata)
-		return -1;
-
-	ctlr->scrimg = allocmemimaged(r, RGB16, &ctlr->scrdata);
-	if(!ctlr->scrimg)
-		return -1;
-
-	ctlr->scrfont = getmemdefont();
-	return 0;
-}
-
-static Memimage*
-screenmkcolor(Memimage *scr, ulong color)
-{
-	Memimage *i;
-
-	i = allocmemimage(Rect(0, 0, 1, 1), scr->chan);
-	if(i) {
-		i->flags |= Frepl;
-		i->clipr = scr->r;
-		memfillcolor(i, color);
-	}
-
-	return i;
-}
-
-static void
-screenwin(Ctlr *ctlr)
-{
-	Rectangle r;
-	Memimage *i;
-	Point p;
-	int h;
-
-	ctlr->font.y = h = ctlr->scrfont->height;
-	ctlr->font.x = ctlr->scrfont->info[' '].width;
-	
-	r = ctlr->scrimg->r;
-	if(i = screenmkcolor(ctlr->scrimg, 0x0D686BFF)) {
-		memimagedraw(ctlr->scrimg, r, i, ZP, memopaque, ZP, S);
-		freememimage(i);
-	}
-
-	r = insetrect(r, 16); memimagedraw(ctlr->scrimg, r, memblack, ZP, memopaque, ZP, S);
-	r = insetrect(r, 4); memimagedraw(ctlr->scrimg, r, memwhite, ZP, memopaque, ZP, S);
-	if(i = screenmkcolor(ctlr->scrimg, 0xaaaaaaff)) {
-		memimagedraw(ctlr->scrimg, Rpt(r.min, Pt(r.max.x, r.min.y+h+12)), i, ZP, memopaque, ZP, S);
-		freememimage(i);
-
-		r = insetrect(r, 6);
-		p = r.min;
-		memimagestring(ctlr->scrimg, p, memblack, ZP, getmemdefont(), " Plan 9 Console ");
-	}
-
-	ctlr->win = Rpt(addpt(r.min, Pt(0, h + 6)), subpt(r.max, Pt(6, 6)));
-	ctlr->pos = ctlr->win.min;
-	screenputs = myscreenputs;
-}
-
-void
-screeninit(void)
-{
-	Ctlr *c;
-
-	c = &ctlr;
-	if(screendatainit(c) < 0)
-		return;
-
-	screenwin(c);
-	screenputs(kmesg.buf, kmesg.n);
-
-	/* reset the display controller */
-	csr32w(c, RDsysconf, DSCreset);
-	while(!(csr32r(c, RDsysstat) & DSSreset))
-		;
-
-	/* configure the display controller */
-	csr32w(c, RDsysconf, DSCidle | DSCidlesmart);
-	csr32w(c, RDcontrol, DClcdbits24);
-	csr32w(c, RDconfig, DCNgamma);
-
-	/* configure display size and timings */
-	csr32w(c, RDtimeh, TIME(3, 15, 11));
-	csr32w(c, RDtimev, TIME(2, 3, 3));
-	csr32w(c, RDsize, SIZE(800, 480));
-
-	/* enable the lcd interface */
-	csr32w(c, RDcontrol, csr32r(c, RDcontrol) | DClcdactive | DClcdclockrun | DClcdenablehi);
-	csr32w(c, RDcontrol, csr32r(c, RDcontrol) | DClcdenable);
-
-	/* configure the graphics layer */
-	csr32w(c, RDgfxban(0), (uintptr) c->scrdata.bdata);
-	csr32w(c, RDgfxpos, POS(c->scrimg->r.min.x, c->scrimg->r.min.y));
-	csr32w(c, RDgfxsize, SIZE(c->scrimg->r.max.x, c->scrimg->r.max.y));
-	csr32w(c, RDgfxattr, DGAfmt | DGAburst);
-	csr32w(c, RDgfxrowinc, 1);
-	csr32w(c, RDgfxpixelinc, 1);
-
-	/* enable gfx pipeline and turn lcd on */
-	csr32w(c, RDgfxattr, csr32r(c, RDgfxattr) | DGAenable);
-	csr32w(c, RDcontrol, csr32r(c, RDcontrol) | DClcdon);
-
-	conf.monitor = 1;
-}
-
-static void
-screenscroll(Ctlr *ctlr)
-{
-	int o, h;
-	Point p;
-	Rectangle r;
-
-	h = ctlr->font.y;
-	o = Scroll * h;
-	r = Rpt(ctlr->win.min, Pt(ctlr->win.max.x, ctlr->win.max.y - o));
-	p = Pt(ctlr->win.min.x, ctlr->win.min.y + o);
-	memimagedraw(ctlr->scrimg, r, ctlr->scrimg, p, nil, p, S);
-	flushmemscreen(r);
-
-	r = Rpt(Pt(ctlr->win.min.x, ctlr->win.max.y - o), ctlr->win.max);
-	memimagedraw(ctlr->scrimg, r, memwhite, ZP, nil, ZP, S);
-	flushmemscreen(r);
-
-	ctlr->pos.y -= o;
-	
-}
-
-static void
-screenputc(Ctlr *ctlr, char *buf)
-{
-	Point p;
-	Rectangle r;
-	uint chr;
-	int w, h;
-	static int *xp;
-	static int xbuf[256];
-
-	w = ctlr->font.x;
-	h = ctlr->font.y;
-	if(xp < xbuf || xp >= &xbuf[nelem(xbuf)])
-		xp = xbuf;
-
-	switch(buf[0]) {
-	case '\n':
-		if(ctlr->pos.y + h >= ctlr->win.max.y)
-			screenscroll(ctlr);
-
-		ctlr->pos.y += h;
-		screenputc(ctlr, "\r");
-		break;
-
-	case '\r':
-		xp = xbuf;
-		ctlr->pos.x = ctlr->win.min.x;
-		break;
-
-	case '\t':
-		if(ctlr->pos.x >= ctlr->win.max.x - 4 * w)
-			screenputc(ctlr, "\n");
-
-		chr = (ctlr->pos.x - ctlr->win.min.x) / w;
-		chr = Tab - chr % Tab;
-		*xp++ = ctlr->pos.x;
-
-		r = Rect(ctlr->pos.x, ctlr->pos.y, ctlr->pos.x + chr * w, ctlr->pos.y + h);
-		memimagedraw(ctlr->scrimg, r, memwhite, ZP, memopaque, ZP, S);
-		flushmemscreen(r);
-		ctlr->pos.x += chr * w;
-		break;
-
-	case '\b':
-		if(xp <= xbuf)
-			break;
-
-		xp--;
-		r = Rect(*xp, ctlr->pos.y, ctlr->pos.x, ctlr->pos.y + h);
-		memimagedraw(ctlr->scrimg, r, memwhite, ZP, memopaque, ZP, S);
-		ctlr->pos.x = *xp;
-		break;
-
-	case '\0':
-		break;
-
-	default:
-		p = memsubfontwidth(getmemdefont(), buf); w = p.x;
-		if(ctlr->pos.x >= ctlr->win.max.x - w)
-			screenputc(ctlr, "\n");
-
-		*xp++ = ctlr->pos.x;
-		r = Rect(ctlr->pos.x, ctlr->pos.y, ctlr->pos.x + w, ctlr->pos.y + h);
-		memimagedraw(ctlr->scrimg, r, memwhite, ZP, memopaque, ZP, S);
-		memimagestring(ctlr->scrimg, ctlr->pos, memblack, ZP, getmemdefont(), buf);
-		ctlr->pos.x += w;
-		break;
-	}
-}
-
-static void
-myscreenputs(char *s, int n)
-{
-	Ctlr *c;
-	Rune r;
-	int i;
-	char buf[UTFmax];
-
-	c = &ctlr;
-	if(!c->scrimg)
-		return;
-
-	if(!islo()) {
-		/* don't deadlock trying to print in an interrupt */
-		if(!canlock(c))
-			return;
-	} else {
-		lock(c);
-	}
-
-	while(n > 0) {
-		i = chartorune(&r, s);
-		if(i == 0) {
-			s++; n--;
-			continue;
-		}
-
-		memmove(buf, s, i);
-		buf[i] = 0;
-		s += i; n -= i;
-		screenputc(c, buf);
-	}
-
-	unlock(c);
-}
-
-Memdata*
-attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen)
-{
-	Ctlr *c;
-
-	c = &ctlr;
-	if(!c->scrimg)
-		return nil;
-
-	*r = c->scrimg->r;
-	*d = c->scrimg->depth;
-	*chan = c->scrimg->chan;
-	*width = c->scrimg->width;
-	*softscreen = 1;
-
-	c->scrdata.ref++;
-	return &c->scrdata;
-}
-
-void
-getcolor(ulong, ulong *, ulong *, ulong *)
-{
-}
-
-int
-setcolor(ulong, ulong, ulong, ulong)
-{
-	return 0;
-}
-
-void
-flushmemscreen(Rectangle)
-{
-}
-
-void
-mouseresize(void)
-{
-}
--- a/screen.h
+++ /dev/null
@@ -1,9 +1,0 @@
-void screeninit(void);
-void flushmemscreen(Rectangle);
-Memdata *attachscreen(Rectangle *, ulong *, int *, int *, int *);
-
-#define ishwimage(i) 1
-
-void mousectl(Cmdbuf*);
-void mouseresize(void);
-void mouseredraw(void);
--- /dev/null
+++ b/sys/src/9/n900/dat.h
@@ -1,0 +1,147 @@
+typedef struct Conf Conf;
+typedef struct Confmem Confmem;
+typedef struct FPsave FPsave;
+typedef struct Label Label;
+typedef struct Lock Lock;
+typedef struct Mach Mach;
+typedef struct MMMU MMMU;
+typedef struct Page Page;
+typedef struct Proc Proc;
+typedef struct PFPU PFPU;
+typedef struct PMMU PMMU;
+typedef struct Ureg Ureg;
+
+typedef u32int PTE;
+typedef uvlong Tval;
+
+#pragma incomplete Ureg
+
+#define MAXSYSARG 5
+#define AOUT_MAGIC (E_MAGIC)
+
+struct Lock {
+	ulong key;
+	u32int sr;
+	uintptr pc;
+	Proc *p;
+	Mach *m;
+	int isilock;
+};
+
+struct Label {
+	uintptr sp;
+	uintptr pc;
+};
+
+struct Confmem {
+	uintptr base;
+	uintptr limit;
+	uintptr kbase;
+	uintptr klimit;
+	ulong npage;
+};
+
+struct Conf {
+	ulong nmach;
+	ulong nproc;
+	Confmem mem[1];
+	ulong npage;
+	ulong upages;
+	ulong copymode;
+	ulong ialloc;
+	ulong pipeqsize;
+	ulong nimage;
+	ulong nswap;
+	int nswppo;
+	int monitor;
+};
+
+struct FPsave {
+	ulong exc;
+	ulong scr;
+	uchar regs[256];
+};
+
+struct PFPU {
+	enum {
+		FPinit,
+		FPactive,
+		FPinactive,
+
+		FPillegal = 0x100,
+	} fpstate;
+	FPsave fpsave[1];
+};
+
+#define NCOLOR 1
+struct PMMU {
+	Page *mmul2;
+	Page *mmul2cache;
+};
+
+struct MMMU {
+	PTE *mmul1;
+	uint mmupid;
+};
+
+#include "../port/portdat.h"
+
+struct Mach {
+	int machno;
+	uintptr splpc;
+	Proc *proc;
+	MMMU;
+
+	PMach;
+
+	u32int save[5];
+	uintptr stack[1];
+};
+
+typedef struct ISAConf ISAConf;
+typedef struct Devport Devport;
+typedef struct DevConf DevConf;
+
+#define BUSUNKNOWN 0
+#define BUSMODEM 1
+
+#define NISAOPT 8
+struct ISAConf {
+	char *type;
+	uintptr port;
+	int irq;
+	ulong dma;
+	ulong mem;
+	ulong size;
+	ulong freq;
+
+	int nopt;
+	char *opt[NISAOPT];
+};
+
+struct Devport {
+	ulong port;
+	int size;
+};
+
+struct DevConf {
+	ulong intnum;
+	char *type;
+	int nports;
+	Devport *ports;
+};
+
+typedef void KMap;
+#define VA(p) ((uintptr)(p))
+#define kmap(p) (KMap*)((p)->pa|KZERO)
+#define kunmap(p)
+#define kmapinval()
+#define getpgcolor(p) 0
+
+struct {
+	char machs[MAXMACH];
+	int exiting;
+} active;
+
+extern register Mach *m;
+extern register Proc *up;
--- /dev/null
+++ b/sys/src/9/n900/devkbd.c
@@ -1,0 +1,243 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "../port/error.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/i2c.h"
+
+enum {
+	Rctrl		= 0xd2,
+		Csoftreset	= 1<<0,
+		Csoftmode	= 1<<1,
+		Cenable		= 1<<6,
+	Rcode	= 0xdb,
+	Risr		= 0xe3,
+	Rimr		= 0xe4,
+		Ikp			= 1<<0,
+		Ilk			= 1<<1,
+		Ito			= 1<<2,
+	Rsir		= 0xe7,
+	Redr		= 0xe8,
+		Ekpfalling		= 1<<0,
+		Ekprising		= 1<<1,
+		Elkfalling		= 1<<2,
+		Elkrising		= 1<<3,
+		Etofalling		= 1<<4,
+		Etorising		= 1<<5,
+		Emisfalling	= 1<<6,
+		Emisrising	= 1<<7,
+	Rsih		= 0xe9,
+		Scor			= 1<<2,
+};
+
+enum {
+	Qdir,
+	Qscan,
+};
+
+typedef struct Ctlr Ctlr;
+struct Ctlr {
+	Ref;
+	Lock;
+
+	I2Cdev *dev;
+	Queue *q;
+
+	uchar cur[8];
+	uchar prev[8];
+};
+
+static Ctlr ctlr;
+static Dirtab kbdtab[] = {
+	".",			{Qdir, 0, QTDIR},		0, 0555,
+	"scancode",	{Qscan, 0, QTFILE},	0, 0440,
+};
+
+static u8int
+csr8r(Ctlr *ctlr, u8int r)
+{
+	uchar buf;
+
+	i2crecv(ctlr->dev, &buf, sizeof(buf), r);
+	return buf;
+}
+
+static u8int
+csr8w(Ctlr *ctlr, u8int r, u8int w)
+{
+	i2csend(ctlr->dev, &w, sizeof(w), r);
+	return w;
+}
+
+static void
+kbdinterrupt(Ureg *, void*)
+{
+	int i, j, c, k;
+
+	ilock(&ctlr);
+	if(!(csr8r(&ctlr, Risr) & Ikp)) {
+		iunlock(&ctlr);
+		return;
+	}
+
+	/* scan key columns */
+	for(i = 0; i < 8; i++) {
+		ctlr.prev[i] = ctlr.cur[i];
+		ctlr.cur[i] = csr8r(&ctlr, Rcode + i);
+
+		/* changed? */
+		c = ctlr.cur[i] ^ ctlr.prev[i];
+		if(!c)
+			continue;
+
+		/* scan key rows */
+		for(j = 0; j < 8; j++) {
+			if(!(c & (1 << j)))
+				continue;
+
+			/* pressed or released? */
+			k = i << 3 | j;
+			if(ctlr.prev[i] & (1 << j))
+				k |= 0x80;
+
+			qproduce(ctlr.q, &k, 1);
+		}
+	}
+
+	iunlock(&ctlr);
+}
+
+static void
+kbdreset(void)
+{
+	ilock(&ctlr);
+	ctlr.q = qopen(1024, Qcoalesce, 0, 0);
+	if(!ctlr.q) {
+		iunlock(&ctlr);
+		return;
+	}
+
+	ctlr.dev = i2cdev(i2cbus("i2c1"), 0x4a);
+	if(!ctlr.dev) {
+		iunlock(&ctlr);
+		return;
+	}
+
+	ctlr.dev->subaddr = 1;
+	ctlr.dev->size = 0x100;
+
+	csr8w(&ctlr, Rctrl, Csoftreset | Csoftmode | Cenable);
+	csr8w(&ctlr, Rsih, Scor);
+	csr8w(&ctlr, Rimr, ~Ikp);
+
+	intrenable(IRQTWL, kbdinterrupt, nil, BUSUNKNOWN, "kbd");
+	iunlock(&ctlr);
+}
+
+static void
+kbdshutdown(void)
+{
+}
+
+static Chan *
+kbdattach(char *spec)
+{
+	if(!ctlr.dev)
+		error(Enonexist);
+
+	return devattach(L'b', spec);
+}
+
+static Walkqid *
+kbdwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+	return devwalk(c, nc, name, nname, kbdtab, nelem(kbdtab), devgen);
+}
+
+static int
+kbdstat(Chan *c, uchar *dp, int n)
+{
+	return devstat(c, dp, n, kbdtab, nelem(kbdtab), devgen);
+}
+
+static Chan *
+kbdopen(Chan *c, int mode)
+{
+	if(!iseve)
+		error(Eperm);
+
+	if(c->qid.path == Qscan) {
+		if(waserror()) {
+			decref(&ctlr);
+			nexterror();
+		}
+
+		if(incref(&ctlr) != 1)
+			error(Einuse);
+
+		c = devopen(c, mode, kbdtab, nelem(kbdtab), devgen);
+		poperror();
+		return c;
+	}
+
+	return devopen(c, mode, kbdtab, nelem(kbdtab), devgen);
+}
+
+static void
+kbdclose(Chan *c)
+{
+	if((c->flag & COPEN) && c->qid.path == Qscan)
+		decref(&ctlr);
+}
+
+static Block*
+kbdbread(Chan *c, long n, ulong off)
+{
+	if(c->qid.path == Qscan)
+		return qbread(ctlr.q, n);
+
+	return devbread(c, n, off);
+}
+
+static long
+kbdread(Chan *c, void *a, long n, vlong)
+{
+	if(c->qid.path == Qscan)
+		return qread(ctlr.q, a, n);
+
+	if(c->qid.path == Qdir)
+		return devdirread(c, a, n, kbdtab, nelem(kbdtab), devgen);
+
+	error(Egreg);
+	return 0;
+}
+
+static long
+kbdwrite(Chan *, void *, long, vlong)
+{
+	error(Egreg);
+	return 0;
+}
+
+Dev kbddevtab = {
+	L'b',
+	"kbd",
+
+	kbdreset,
+	devinit,
+	kbdshutdown,
+	kbdattach,
+	kbdwalk,
+	kbdstat,
+	kbdopen,
+	devcreate,
+	kbdclose,
+	kbdread,
+	kbdbread,
+	kbdwrite,
+	devbwrite,
+	devremove,
+	devwstat,
+};
--- /dev/null
+++ b/sys/src/9/n900/devrtc.c
@@ -1,0 +1,202 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "../port/error.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/i2c.h"
+
+enum {
+	Rsec		= 0x1c,
+	Rmin	= 0x1d,
+	Rhour	= 0x1e,
+	Rday	= 0x1f,
+	Rmonth	= 0x20,
+	Ryear	= 0x21,
+	Rweeks	= 0x22,
+	Rctrl		= 0x29,
+		Cget		= 1<<6,
+
+	Qdir = 0,
+	Qrtc,
+
+	SecMin	= 60,
+	SecHour	= 60*SecMin,
+	SecDay	= 24*SecHour,
+};
+
+typedef struct Ctlr Ctlr;
+struct Ctlr {
+	I2Cdev *dev;
+
+	int sec;
+	int min;
+	int hour;
+	int day;
+	int month;
+	int year;
+};
+
+static Ctlr ctlr;
+static int dmsize[] = { 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static int ldmsize[] = { 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static Dirtab rtctab[] = {
+	".",		{Qdir, 0, QTDIR},	0, 0555,
+	"rtc",	{Qrtc, 0, QTFILE},	0, 0440,
+};
+
+#define bcddec(x) (((x) & 0xf) + ((x) >> 4) * 10)
+#define bcdenc(x) (((x / 10) << 4) + (x) % 10)
+#define leap(x) (((x) % 4) == 0 && ((x % 100) != 0 || (x % 400) == 0))
+
+static u8int
+csr8r(Ctlr *ctlr, u8int r)
+{
+	uchar buf;
+
+	i2crecv(ctlr->dev, &buf, sizeof(buf), r);
+	return buf;
+}
+
+static u8int
+csr8w(Ctlr *ctlr, u8int r, u8int w)
+{
+	i2csend(ctlr->dev, &w, sizeof(w), r);
+	return w;
+}
+
+static vlong
+rtcsnarf(void)
+{
+	vlong s;
+	int i;
+
+	/* latch and snarf */
+	csr8w(&ctlr, Rctrl, csr8r(&ctlr, Rctrl) | Cget);
+	ctlr.sec = bcddec(csr8r(&ctlr, Rsec)) % 60;
+	ctlr.min = bcddec(csr8r(&ctlr, Rmin)) % 60;
+	ctlr.hour = bcddec(csr8r(&ctlr, Rhour)) % 24;
+	ctlr.day = bcddec(csr8r(&ctlr, Rday));
+	ctlr.month = bcddec(csr8r(&ctlr, Rmonth));
+	ctlr.year = bcddec(csr8r(&ctlr, Ryear)) % 100;
+	ctlr.year += 2000;
+
+	/* seconds per year */
+	s = 0;
+	for(i = 1970; i < ctlr.year; i++) {
+		if(leap(i))
+			s += ldmsize[0] * SecDay;
+		else
+			s += dmsize[0] * SecDay;
+	}
+
+	/* seconds per month */
+	for(i = 1; i < ctlr.month; i++) {
+		if(leap(ctlr.year))
+			s += ldmsize[i] * SecDay;
+		else
+			s += dmsize[i] * SecDay;
+	}
+
+	/* days, hours, minutes, seconds */
+	s += (ctlr.day - 1) * SecDay;
+	s += ctlr.hour * SecHour;
+	s += ctlr.min * SecMin;
+	s += ctlr.sec;
+	return s;
+}
+
+static void
+rtcreset(void)
+{
+	ctlr.dev = i2cdev(i2cbus("i2c1"), 0x4b);
+	if(!ctlr.dev)
+		return;
+
+	ctlr.dev->subaddr = 1;
+	ctlr.dev->size = 0x100;
+}
+
+static void
+rtcshutdown(void)
+{
+}
+
+static Chan *
+rtcattach(char *spec)
+{
+	if(!ctlr.dev)
+		error(Enonexist);
+
+	return devattach('r', spec);
+}
+
+static Walkqid *
+rtcwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+	return devwalk(c, nc, name, nname, rtctab, nelem(rtctab), devgen);
+}
+
+static int
+rtcstat(Chan *c, uchar *dp, int n)
+{
+	return devstat(c, dp, n, rtctab, nelem(rtctab), devgen);
+}
+
+static Chan *
+rtcopen(Chan *c, int mode)
+{
+	mode = openmode(mode);
+	if(c->qid.path == Qrtc) {
+		if(!iseve() && mode != OREAD)
+			error(Eperm);
+	}
+
+	return devopen(c, mode, rtctab, nelem(rtctab), devgen);
+}
+
+static void
+rtcclose(Chan *)
+{
+}
+
+static long
+rtcread(Chan *c, void *a, long n, vlong off)
+{
+	if(c->qid.path == Qdir)
+		return devdirread(c, a, n, rtctab, nelem(rtctab), devgen);
+	if(c->qid.path == Qrtc)
+		return readnum(off, a, n, rtcsnarf(), 12);
+
+	error(Egreg);
+	return 0;
+}
+
+static long
+rtcwrite(Chan *, void *, long, vlong)
+{
+	error(Egreg);
+	return 0;
+}
+
+Dev rtcdevtab = {
+	'r',
+	"rtc",
+
+	rtcreset,
+	devinit,
+	rtcshutdown,
+	rtcattach,
+	rtcwalk,
+	rtcstat,
+	rtcopen,
+	devcreate,
+	rtcclose,
+	rtcread,
+	devbread,
+	rtcwrite,
+	devbwrite,
+	devremove,
+	devwstat,
+};
--- /dev/null
+++ b/sys/src/9/n900/fns.h
@@ -1,0 +1,77 @@
+#include "../port/portfns.h"
+
+#define KADDR(a) ((void*)(a))
+#define PADDR(a) ((uintptr)(a))
+
+#define userureg(ur) (((ur)->psr & PsrMask) == PsrMusr)
+
+void*	ucallocalign(usize, int, usize);
+void*	ucalloc(usize);
+
+int cmpswap(long *, long, long);
+int cas(long *, long, long);
+int tas(void *);
+
+void evenaddr(uintptr va);
+void procrestore(Proc *);
+void procsave(Proc *);
+void procsetup(Proc *);
+void procfork(Proc *);
+
+void coherence(void);
+void idlehands(void);
+void touser(void*);
+void setR13(uint, u32int*);
+ulong getdfsr(void);
+ulong getifsr(void);
+uintptr getdfar(void);
+uintptr getifar(void);
+void setvectors(uintptr);
+void breakpt(void);
+
+char* getconf(char*);
+int isaconfig(char *, int, ISAConf *);
+
+void mmuinvalidate(void);
+void* mmuuncache(void*, usize);
+uintptr cankaddr(uintptr);
+
+ulong µs(void);
+void delay(int);
+void microdelay(int);
+void cycles(uvlong*);
+
+void dumpureg(Ureg*);
+void dumpstackureg(Ureg*);
+
+void intrenable(int, void (*f)(Ureg *, void*), void *, int, char*);
+void intrdisable(int, void (*f)(Ureg *, void*), void *, int, char*);
+void intr(Ureg *);
+
+void uartinit(void);
+void mmuinit(void);
+void trapinit(void);
+void intrinit(void);
+void timerinit(void);
+void screeninit(void);
+
+void links(void);
+
+void l1icacheinv(void);
+void l1dcachewb(void);
+void l1dcacheinv(void);
+void l1dcachewbinv(void);
+void l1ucachewbinv(void);
+
+void l2idcacheinv(void);
+void l2idcachewb(void);
+void l2idcachewbinv(void);
+void l2ucachewbinv(void);
+
+
+void fpinit(void);
+void fpoff(void);
+void fpclear(void);
+
+void fpsave(FPsave *);
+void fprestore(FPsave *);
--- /dev/null
+++ b/sys/src/9/n900/i2cn900.c
@@ -1,0 +1,224 @@
+#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/i2c.h"
+
+enum {
+	Rrev	= 0x00,
+	Rie		= 0x04,
+	Ris		= 0x08,
+		Ial		= 1 << 0, /* arbitration lost */
+		Inack	= 1 << 1, /* no acknowledgement */
+		Iardy	= 1 << 2, /* address ready */
+		Irrdy		= 1 << 3, /* receive ready */
+		Ixrdy	= 1 << 4, /* transmit ready */
+		Ibb		= 1 << 12, /* bus busy */
+		Iall		= 0xffff,
+
+	Rwe		= 0x0c,
+	Rsyss	= 0x10,
+		SSreset	= 1 << 0, /* reset status */
+
+	Rbuf	= 0x14,
+	Rcnt	= 0x18,
+	Rdata	= 0x1c,
+	Rsysc	= 0x20,
+		SCreset	= 1 << 1, /* software reset */
+
+	Rcon	= 0x24,
+		Cstt		= 1 << 0, /* start condition */
+		Cstp		= 1 << 1, /* stop condiction */
+		Cxoa3	= 1 << 4, /* expand address */
+		Cxoa2	= 1 << 5,
+		Cxoa1	= 1 << 6,
+		Cxoa0	= 1 << 7,
+		Cxa		= 1 << 8,
+		Ctrx		= 1 << 9, /* transmit mode */
+		Cmst	= 1 << 10, /* master mode */
+		Cstb		= 1 << 11, /* start byte */
+		Cen		= 1 << 15, /* enable */
+
+	Raddr	= 0x2c,
+};
+
+#define csr32r(c, r) ((c)->io[(r)/4])
+#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
+
+typedef struct Ctlr Ctlr;
+struct Ctlr {
+	u32int *io;
+	ulong irq;
+
+	Rendez;
+};
+
+static Ctlr ctlr[] = {
+	{ .io = (u32int*) PHYSI2C1, .irq = IRQI2C1 },
+	{ .io = (u32int*) PHYSI2C2, .irq = IRQI2C2 },
+	{ .io = (u32int*) PHYSI2C3, .irq = IRQI2C3 },
+};
+
+static void
+n900i2cwaitbus(Ctlr *ctlr)
+{
+	/* FIXME: timeout here? */
+	while(csr32r(ctlr, Ris) & Ibb)
+		;
+}
+
+static int
+n900i2cwaitirq(void *arg)
+{
+	Ctlr *ctlr = arg; return csr32r(ctlr, Ris);
+}
+
+static uint
+n900i2cwait(Ctlr *ctlr)
+{
+	uint s;
+
+	/* FIXME: timeout here? */
+	while(!(s = csr32r(ctlr, Ris))) {
+		if(!up || !islo())
+			continue;
+
+		tsleep(ctlr, n900i2cwaitirq, ctlr, 5);
+	}
+
+	return s;
+}
+
+static void
+n900i2cflush(Ctlr *ctlr)
+{
+	while(csr32r(ctlr, Ris) & Irrdy) {
+		USED(csr32r(ctlr, Rdata));
+		csr32w(ctlr, Ris, Irrdy);
+	}
+}
+
+static void
+n900i2cintr(Ureg *, void *arg)
+{
+	Ctlr *ctlr;
+
+	ctlr = arg;
+	wakeup(ctlr);
+}
+
+static int
+n900i2cinit(I2Cbus *bus)
+{
+	Ctlr *ctlr;
+
+	/* reset the ctlr */
+	ctlr = bus->ctlr;
+	csr32w(ctlr, Rsysc, SCreset);
+	csr32w(ctlr, Rcon, Cen);
+
+	/* FIXME: timeout here? */
+	while(!(csr32r(ctlr, Rsyss) & SSreset))
+		;
+
+	intrenable(ctlr->irq, n900i2cintr, ctlr, 0, bus->name);
+	return 0;
+}
+
+static int
+n900i2cio(I2Cbus *bus, uchar *pkt, int olen, int ilen)
+{
+	Ctlr *ctlr;
+	uint con, addr, stat;
+	uint o;
+
+	ctlr = bus->ctlr;
+	if(olen <= 0 || pkt == nil)
+		return -1;
+
+	o = 0;
+	con = Cen | Cmst | Ctrx | Cstp | Cstt;
+	if((pkt[o] & 0xf8) == 0xf0) {
+		/* 10-bit address: qemu has bugs, nothing on the n900 needs them.
+		 * con |= Cxa;
+		 * addr = ((pkt[o++] & 6) << 7) | pkt[o++];
+		 */
+		return -1;
+	} else {
+		/* 7-bit address */
+		addr = pkt[o++] >> 1;
+	}
+
+	/* wait for bus */
+	n900i2cwaitbus(ctlr);
+
+	/* first attempt to probe, will get nack here if no dev */
+	csr32w(ctlr, Rcnt, olen);
+	csr32w(ctlr, Raddr, addr);
+	csr32w(ctlr, Rcon, con);
+	stat = n900i2cwait(ctlr);
+	if(stat & Inack || stat & Ial) {
+		o = -1; goto err;
+	}
+
+	/* transmit */
+	while(o < olen) {
+		stat = n900i2cwait(ctlr);
+		if(stat == 0 || stat & Inack || stat & Ial) {
+			o = -1; goto err;
+		}
+
+		if(stat & Iardy) {
+			csr32w(ctlr, Ris, Iardy);
+			break;
+		}
+
+		if(stat & Ixrdy) {
+			csr32w(ctlr, Rdata, pkt[o++]);
+			csr32w(ctlr, Ris, Ixrdy);
+		}
+	}
+
+	/* receive */
+	csr32w(ctlr, Rcnt, ilen);
+	csr32w(ctlr, Raddr, addr);
+	csr32w(ctlr, Rcon, Cen | Cmst | Cstp | Cstt);
+	while(o < olen + ilen) {
+		stat = n900i2cwait(ctlr);
+		if(stat == 0 || stat & Inack || stat & Ial) {
+			o = -1; goto err;
+		}
+
+		if(stat & Iardy) {
+			csr32w(ctlr, Ris, Iardy);
+			break;
+		}
+
+		if(stat & Irrdy) {
+			pkt[o++] = csr32r(ctlr, Rdata);
+			csr32w(ctlr, Ris, Irrdy);
+		}
+	}
+
+err:
+	n900i2cflush(ctlr);
+	csr32w(ctlr, Ris, Iall);
+	return o;
+}
+
+void
+i2cn900link(void)
+{
+	int i;
+	static I2Cbus bus[] = {
+		{ "i2c1", 4000000, &ctlr[0], n900i2cinit, n900i2cio },
+		{ "i2c2", 4000000, &ctlr[1], n900i2cinit, n900i2cio },
+		{ "i2c3", 4000000, &ctlr[2], n900i2cinit, n900i2cio },
+	};
+
+	for(i = 0; i < nelem(bus); i++)
+		addi2cbus(&bus[i]);
+}
--- /dev/null
+++ b/sys/src/9/n900/init9.s
@@ -1,0 +1,12 @@
+TEXT main(SB), 1, $8
+	MOVW $setR12(SB), R12
+	MOVW $boot(SB), R0
+
+	ADD $12, R13, R1
+
+	MOVW R0, 4(R13)
+	MOVW R1, 8(R13)
+
+	BL startboot(SB)
+_limbo:
+	B _limbo
--- /dev/null
+++ b/sys/src/9/n900/intr.c
@@ -1,0 +1,199 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+enum {
+	Rrev			= 0x00,
+	Rsysconf		= 0x10,
+	Rsysstat		= 0x14,
+	Rirq			= 0x40,
+	Rfiq			= 0x44,
+	Rcontrol		= 0x48,
+		Cnewirqgen		= 1<<0,
+	Rprot			= 0x4c,
+	Ridle			= 0x50,
+	Rirqprio		= 0x60,
+	Rfiqprio		= 0x64,
+	Rthreshold		= 0x68,
+
+	Ritr		= 0x80,
+	Rmir		= 0x84,
+	Rmirclear	= 0x88,
+	Rmirset		= 0x8c,
+	Risrset		= 0x90,
+	Risrclear	= 0x94,
+	Rirqpend	= 0x98,
+	Rfiqpend	= 0x9c,
+
+	Rilr		= 0x100,
+};
+
+enum {
+	Nmir = 3,
+	Nitr = 3,
+	Nintrs = 96,
+};
+
+#define Ritrn(n)		(Ritrn + 32*(n))
+#define Rmirn(n)		(Rmirn + 32*(n))
+#define Rmirclearn(n)	(Rmirclear + 32*(n))
+#define Rmirsetn(n)		(Rmirset + 32*(n))
+#define Rirqpendn(n)	(Rirqpend + 32*(n))
+#define Rfiqpendn(n)	(Rfiqpend + 32*(n))
+
+#define Rilrn(n)	(Rilr + 4*(n))
+
+#define csr32r(c, r) ((c)->io[(r)/4])
+#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
+
+typedef struct Intr Intr;
+typedef struct Ctlr Ctlr;
+
+struct Intr {
+	void (*f)(Ureg *, void *);
+	void *arg;
+	char *name;
+
+	Intr *next;
+};
+
+struct Ctlr {
+	Lock;
+
+	u32int *io;
+
+	Intr *intrs[Nintrs];
+};
+
+static Ctlr ctlrmpu = { .io = (u32int*) PHYSINTRMPU };
+
+void
+intrinit(void)
+{
+	Ctlr *ctlr = &ctlrmpu;
+	int i;
+
+	/* mask all interrupts */
+	for (i = 0; i < Nmir; i++)
+		csr32w(ctlr, Rmirsetn(i), ~0);
+
+	/* protection off, threshold off, set all intrs priority 0, mapped to irq */
+	csr32w(ctlr, Rcontrol, 0);
+	csr32w(ctlr, Rthreshold, 0xff);
+	for (i = 0; i < Nintrs; i++)
+		csr32w(ctlr, Rilrn(i), 0);
+
+	coherence();
+}
+
+void
+intrenable(int n, void (*f)(Ureg *, void *), void *arg, int, char *name)
+{
+	Ctlr *ctlr = &ctlrmpu;
+	Intr *intr;
+
+	if (n >= nelem(ctlr->intrs) || n < 0)
+		panic("intrenable %d", n);
+
+	intr = malloc(sizeof(*intr));
+	if(!intr)
+		panic("intrenable: no memory for interrupt");
+
+	intr->f = f;
+	intr->arg = arg;
+	intr->name = name;
+
+	lock(ctlr);
+
+	/* chain this interrupt */
+	intr->next = ctlr->intrs[n];
+	ctlr->intrs[n] = intr;
+
+	/* new handler assigned, unmask this interrupt */
+	csr32w(ctlr, Rmirclearn(n >> 5), 1 << (n & 31));
+
+	unlock(ctlr);
+	coherence();
+}
+
+void
+intrdisable(int n, void (*f)(Ureg *, void *), void *arg, int, char *name)
+{
+	Ctlr *ctlr = &ctlrmpu;
+	Intr *intr, **ip;
+
+	if (n >= nelem(ctlr->intrs) || n < 0)
+		panic("intrdisable %d", n);
+
+	lock(ctlr);
+	for(ip = &ctlr->intrs[n]; intr = *ip; ip = &intr->next) {
+		if(intr->f == f && intr->arg == arg && strcmp(intr->name, name) == 0) {
+			*ip = intr->next;
+			free(intr);
+			break;
+		}
+	}
+
+	/* no more handlers assigned, mask this interrupt */
+	if(ctlr->intrs[n] == nil)
+		csr32w(ctlr, Rmirsetn(n >> 5), 1 << (n & 31));
+
+	unlock(ctlr);
+	coherence();
+}
+
+void
+intr(Ureg *ureg)
+{
+	Ctlr *ctlr = &ctlrmpu;
+	Intr *intr;
+	int n, h, s;
+
+	h = 0;
+	n = csr32r(ctlr, Rirq) & 0x7f;
+	s = csr32r(ctlr, Rirq) & ~0x7f;
+	if(s) {
+		/* interrupt controller reports spurious interrupt flag. */
+		iprint("cpu%d: spurious interrupt\n", m->machno);
+		csr32w(ctlr, Rcontrol, Cnewirqgen);
+		return;
+	}
+
+	if(n >= nelem(ctlr->intrs)) {
+		iprint("cpu%d: invalid interrupt %d\n", m->machno, n);
+		csr32w(ctlr, Rcontrol, Cnewirqgen);
+		return;
+	}
+
+	/* call all handlers for this interrupt number */
+	for (intr = ctlr->intrs[n]; intr; intr = intr->next) {
+		if(intr->f) {
+			if(islo())
+				panic("trap: islo() in interrupt handler\n");
+
+			intr->f(ureg, intr->arg);
+			if(islo())
+				panic("trap: islo() after interrupt handler\n");
+		}
+
+		h++;
+	}
+
+	csr32w(ctlr, Rcontrol, Cnewirqgen);
+	coherence();
+
+	if(!h) iprint("cpu%d: spurious interrupt %d\n", m->machno, n);
+	if(up) {
+		if(n >= IRQTIMER1 && n <= IRQTIMER11) {
+			if(up->delaysched) {
+				splhi();
+				sched();
+			}
+		} else {
+			preempted();
+		}
+	}
+}
--- /dev/null
+++ b/sys/src/9/n900/io.h
@@ -1,0 +1,63 @@
+#define PHYSL4 0x40000000
+#define PHYSL4END 0x50000000
+
+#define PHYSTIMER1 0x48318000
+#define PHYSTIMER2 0x49032000
+#define PHYSTIMER3 0x49034000
+#define PHYSTIMER4 0x49036000
+#define PHYSTIMER5 0x49038000
+#define PHYSTIMER6 0x4903a000
+#define PHYSTIMER7 0x4903c000
+#define PHYSTIMER8 0x4903e000
+#define PHYSTIMER9 0x49040000
+#define PHYSTIMER10 0x48086000
+#define PHYSTIMER11 0x48088000
+
+#define PHYSUART1 0x4806a000
+#define PHYSUART2 0x4806c000
+#define PHYSUART3 0x49020000
+
+#define PHYSI2C1 0x48070000
+#define PHYSI2C2 0x48072000
+#define PHYSI2C3 0x48060000
+
+#define PHYSMMC1 0x4809c000
+#define PHYSMMC2 0x480b4000
+#define PHYSMMC3 0x480ad000
+
+#define PHYSDSS 0x48050000
+
+#define PHYSINTRMODEM 0x480c7000
+#define PHYSINTRMPU 0x48200000
+
+#define PHYSL3 0x68000000
+#define PHYSL3END 0x70000000
+
+#define PHYSMEM 0x80000000
+#define PHYSMEMEND 0x90000000
+
+#define IRQTIMER1 37
+#define IRQTIMER2 38
+#define IRQTIMER3 39
+#define IRQTIMER4 40
+#define IRQTIMER5 41
+#define IRQTIMER6 42
+#define IRQTIMER7 43
+#define IRQTIMER8 44
+#define IRQTIMER9 45
+#define IRQTIMER10 46
+#define IRQTIMER11 47
+
+#define IRQUART1 72
+#define IRQUART2 73
+#define IRQUART3 74
+
+#define IRQI2C1 56
+#define IRQI2C2 57
+#define IRQI2C3 61
+
+#define IRQMMC1 83
+#define IRQMMC2 86
+#define IRQMMC3 94
+
+#define IRQTWL 7
--- /dev/null
+++ b/sys/src/9/n900/l.s
@@ -1,0 +1,354 @@
+#include "mem.h"
+#include "io.h"
+
+TEXT _start(SB), $-4
+	/* load static base */
+	MOVW $setR12(SB), R12
+
+	/* fiqs and irqs off, svc mode (cortex a8 trm figure 2.12) */
+	MOVW $(PsrDfiq|PsrDirq|PsrMsvc), R0
+	MOVW R0, CPSR
+
+	/* mmu and l1 caches off (cortex a8 trm table 3.46) */
+	MRC 15, 0, R0, C1, C0, 0
+	BIC $(1<<12), R0 /* level 1 instruction cache */
+	BIC $(1<<1), R0 /* level 1 data cache */
+	BIC $(1<<0), R0 /* mmu */
+	MCR 15, 0, R0, C1, C0, 0
+	ISB
+
+	/* l2 caches off (cortex a8 trm table 3.49) */
+	MCR 15, 0, R0, C1, C0, 1
+	BIC $(1<<1), R0 /* level 2 cache */
+	MCR 15, 0, R0, C1, C0, 1
+	ISB
+
+	/* fill mach with 0 */
+	MOVW $0, R0
+	MOVW $MACH(0), R1
+	MOVW $MACH(MAXMACH), R2
+zeromach:
+	MOVW R0, (R1)
+	ADD $4, R1
+	CMP R1, R2
+	BNE zeromach
+
+	/* fill page tables with 0 */
+	MOVW R0, R0
+	MOVW $MACHL1(0), R1 /* bottom of l1 tables */
+	MOVW $MACHL1(MAXMACH), R2 /* top of l1 tables */
+zeropte:
+	MOVW R0, (R1)
+	ADD $4, R1
+	CMP R1, R2
+	BNE zeropte
+
+	/* fill bss with 0 */
+	MOVW $0, R0
+	MOVW $edata(SB), R1
+	MOVW $end(SB), R2
+zerobss:
+	MOVW R0, (R1)
+	ADD $4, R1
+	CMP R1, R2
+	BNE zerobss
+
+	/* fill page tables for memory:
+	 * 1mb section, cached, buffered, kernel read-write */
+	MOVW $((1<<1)|(1<<2)|(1<<3)|(1<<10)), R1
+	MOVW $PHYSMEM, R2
+	MOVW $(MACHL1(0)+L1X(PHYSMEM)), R3
+	MOVW $(MACHL1(0)+L1X(PHYSMEMEND)), R4
+ptemem:
+	ORR R2, R1, R0
+	MOVW R0, (R3)
+	ADD $(MiB), R2
+	ADD $4, R3
+	CMP R3, R4
+	BNE ptemem
+
+	/* fill page tables for l4 interconnect:
+	 * 1mb section, kernel read-write */
+	MOVW $((1<<1)|(1<<4)|(1<<10)), R1
+	MOVW $PHYSL4, R2
+	MOVW $(MACHL1(0)+L1X(PHYSL4)), R3
+	MOVW $(MACHL1(0)+L1X(PHYSL4END)), R4
+ptel4:
+	ORR R2, R1, R0
+	MOVW R0, (R3)
+	ADD $(MiB), R2
+	ADD $4, R3
+	CMP R3, R4
+	BNE ptel4
+
+	/* fill page tables for l3 interconnect:
+	 * 1mb section, kernel read-write */
+	MOVW $((1<<1)|(1<<4)|(1<<10)), R1
+	MOVW $PHYSL3, R2
+	MOVW $(MACHL1(0)+L1X(PHYSL3)), R3
+	MOVW $(MACHL1(0)+L1X(PHYSL3END)), R4
+ptel3:
+	ORR R2, R1, R0
+	MOVW R0, (R3)
+	ADD $(MiB), R2
+	ADD $4, R3
+	CMP R3, R4
+	BNE ptel3
+
+	/* fpu on (set bits 20-23 in CPACR) but disabled */
+	MRC 15, 0, R0, C1, C0, 2
+	ORR $(0xf<<20), R0
+	MCR 15, 0, R0, C1, C0, 2
+
+	VMRS(FPEXC, 0)
+	BIC $(FPEXCEX|FPEXCEN), R0
+	VMSR(0, FPEXC)
+
+	/* invalidate caches */
+	BL l1dcacheinv(SB)
+	BL l1icacheinv(SB)
+
+	/* l2 caches back on */
+	MRC 15, 0, R0, C1, C0, 1
+	ORR $(1<<1), R0
+	MCR 15, 0, R0, C1, C0, 1
+
+	/* l1 caches back on */
+	MRC 15, 0, R0, C1, C0, 0
+	ORR $(1<<12), R0
+	ORR $(1<<1), R0
+	MCR 15, 0, R0, C1, C0, 0
+
+	/* set domain access control to client. */
+	MOVW $1, R0
+	BL putdac(SB)
+
+	/* set translation table base */
+	MOVW $MACHL1(0), R0
+	BL putttb(SB)
+
+	/* mmu on, time to get virtual */
+	MOVW $virt(SB), R2
+	BL mmuinvalidate(SB)
+	BL mmuenable(SB)
+	MOVW R2, R15
+
+TEXT virt(SB), $-4
+	/* setup register variables */
+	MOVW $setR12(SB), R12
+	MOVW $(MACH(0)), R(Rmach)
+	MOVW $0, R(Rup)
+
+	/* setup stack in mach */
+	MOVW $(MACH(0)), R13
+	ADD $(MACHSZ), R13
+	SUB $4, R13
+
+	BL main(SB)
+
+_limbo:
+	BL idlehands(SB)
+	B _limbo
+
+	/* hack to load div */
+	BL _div(SB)
+
+
+TEXT mmuenable(SB), 1, $-4
+	MRC 15, 0, R0, C1, C0, 0
+	ORR $(1<<0), R0
+	MCR 15, 0, R0, C1, C0, 0
+	MCR 15, 0, R0, C7, C5, 6
+	DMB; DSB; ISB
+	RET
+
+TEXT mmudisable(SB), 1, $-4
+	MRC 15, 0, R0, C1, C0, 0
+	BIC $(1<<0), R0
+	MCR 15, 0, R0, C1, C0, 0
+	MCR 15, 0, R0, C7, C5, 6
+	DMB; DSB; ISB
+	RET
+
+TEXT mmuinvalidate(SB), 1, $-4
+	MOVW CPSR, R1
+	CPSID
+
+	MOVW R15, R0
+	MCR 15, 0, R0, C8, C7, 0
+	MCR 15, 0, R0, C7, C5, 6
+	DMB; DSB; ISB
+
+	MOVW R1, CPSR
+	RET
+
+/* get and put domain access control */
+TEXT getdac(SB), 1, $-4; MCR 15, 0, R0, C3, C0; RET
+TEXT putdac(SB), 1, $-4
+	MRC 15, 0, R0, C3, C0
+	ISB
+	RET
+
+
+/* get and put translation table base */
+TEXT getttb(SB), 1, $-4; MRC 15, 0, R0, C2, C0, 0; RET
+TEXT putttb(SB), 1, $-4
+	MCR 15, 0, R0, C2, C0, 0
+	MCR 15, 0, R0, C2, C0, 1
+	ISB
+	RET
+
+TEXT getdfsr(SB), $-4; MRC 15, 0, R0, C5, C0, 0; RET
+TEXT getifsr(SB), $-4; MRC 15, 0, R0, C5, C0, 1; RET
+TEXT getdfar(SB), $-4; MRC 15, 0, R0, C6, C0, 0; RET
+TEXT getifar(SB), $-4; MRC 15, 0, R0, C6, C0, 2; RET
+
+TEXT setvectors(SB), $-4;
+	MCR 15, 0, R0, C12, C0, 0
+	RET
+
+TEXT setlabel(SB), $-4
+	MOVW R13, 0(R0)
+	MOVW R14, 4(R0)
+	MOVW $0, R0
+	RET
+
+TEXT gotolabel(SB), $-4
+	MOVW 0(R0), R13
+	MOVW 4(R0), R14
+	MOVW $1, R0
+	RET
+
+TEXT cas(SB), $0
+TEXT cmpswap(SB), $0
+	MOVW ov+4(FP), R1
+	MOVW nv+8(FP), R2
+casspin:
+	LDREX (R0), R3
+	CMP R3, R1
+	BNE casfail
+	STREX R2, (R0), R4
+	CMP $0, R4
+	BNE casspin
+	MOVW $1, R0
+	DMB
+	RET
+casfail:
+	CLREX
+	MOVW $0, R0
+	RET
+
+TEXT tas(SB), $0
+TEXT _tas(SB), $0
+	MOVW $0xdeaddead, R2
+tasspin:
+	LDREX (R0), R1
+	STREX R2, (R0), R3
+	CMP $0, R3
+	BNE tasspin
+	MOVW R1, R0
+	DMB
+	RET
+
+TEXT idlehands(SB), $-4
+	DMB; DSB; ISB
+	WFI
+	RET
+
+TEXT coherence(SB), $-4
+	DMB; DSB; ISB
+	RET
+
+TEXT splhi(SB), $-4
+	MOVW R14, 4(R(Rmach))
+	MOVW CPSR, R0
+	CPSID
+	RET
+
+TEXT spllo(SB), $-4
+	MOVW CPSR, R0
+	CPSIE
+	RET
+
+TEXT splx(SB), $-4
+	MOVW R14, 4(R(Rmach))
+	MOVW R0, R1
+	MOVW CPSR, R0
+	MOVW R1, CPSR
+	RET
+
+TEXT spldone(SB), $-4
+	RET
+
+TEXT islo(SB), $0
+	MOVW CPSR, R0
+	AND $(PsrDirq), R0
+	EOR $(PsrDirq), R0
+	RET
+
+TEXT perfticks(SB), $0
+	MCR 15, 0, R0, C9, C13, 0
+	RET
+
+TEXT touser(SB), $-4
+	MOVM.DB.W [R0], (R13)
+	MOVM.S (R13), [R13]
+	ADD $4, R13
+
+	MOVW CPSR, R0
+	BIC $(PsrMask|PsrDirq|PsrDfiq), R0
+	ORR $PsrMusr, R0
+	MOVW R0, SPSR
+
+	MOVW $(UTZERO+0x20), R0
+	MOVM.DB.W [R0], (R13)
+
+	MOVM.IA.S.W (R13), [R15]
+
+TEXT forkret(SB), $-4
+	ADD $(15*4), R13
+	MOVW 8(R13), R14
+	MOVW 4(R13), R0
+	MOVW R0, SPSR
+	MOVM.DB.S (R13), [R0-R14]
+	ADD $8, R13
+	MOVM.IA.S.W (R13), [R15]
+
+TEXT peek(SB), $0
+	MOVW src+0(FP), R0
+	MOVW dst+4(FP), R1
+	MOVW cnt+8(FP), R2
+TEXT _peekinst(SB), $0
+_peekloop:
+	MOVB (R0), R3
+	MOVB R3, (R1)
+	SUB.S $1, R0
+	BNE _peekloop
+	RET
+
+TEXT fpinit(SB), $0
+	MOVW $FPEXCEN, R0
+	VMSR(0, FPEXC)
+	MOVW $0, R0
+	VMSR(0, FPSCR)
+	RET
+
+TEXT fpoff(SB), $0
+TEXT fpclear(SB), $0
+	MOVW $0, R1
+	VMSR(1, FPEXC)
+	RET
+
+TEXT fpsave(SB), $0
+	VMRS(FPEXC, 1)
+	VMRS(FPSCR, 2)
+	MOVM.IA.W [R1-R2], (R0)
+	VSTMIA
+	RET
+
+TEXT fprestore(SB), $0
+	MOVM.IA.W (R0), [R1-R2]
+	VMSR(1, FPEXC)
+	VMSR(2, FPSCR)
+	VLDMIA
+	RET
--- /dev/null
+++ b/sys/src/9/n900/lcache.s
@@ -1,0 +1,121 @@
+#include "mem.h"
+#include "io.h"
+
+/* l1 instruction cache invalidate */
+TEXT l1icacheinv(SB), $-4
+	MOVW $0, R0
+	MCR 15, 0, R0, C7, C5, 0
+	ISB
+	RET
+
+/* l1 data cache writeback */
+TEXT l1dcachewb(SB), $-4
+	MOVW $cacheopwb(SB), R0
+	MOVW $0, R1
+	B cacheop(SB)
+
+/* l1 data cache invalidate */
+TEXT l1dcacheinv(SB), $-4
+	MOVW $cacheopinv(SB), R0
+	MOVW $0, R1
+	B cacheop(SB)
+
+/* l1 data cache writeback + invalidate */
+TEXT l1dcachewbinv(SB), $-4
+	MOVW $cacheopwbinv(SB), R0
+	MOVW $0, R1
+	B cacheop(SB)
+
+/* l1 unified instruction + data cache writeback + invalidate */
+TEXT l1ucachewbinv(SB), $-4
+	MOVM.DB.W [R14], (SP)
+	BL l1dcachewbinv(SB)
+	BL l1icacheinv(SB)
+	MOVM.IA.W (SP), [R14]
+	RET
+
+/* l2 instruction + data cache writeback */
+TEXT l2idcachewb(SB), $-4
+	MOVW $cacheopwb(SB), R0
+	MOVW $1, R1
+	B cacheop(SB)
+
+/* l2 instruction + data cache invalidate */
+TEXT l2idcacheinv(SB), $-4
+	MOVW $cacheopinv(SB), R0
+	MOVW $1, R1
+	B cacheop(SB)
+
+/* l2 instruction + data cache writeback + invalidate */
+TEXT l2idcachewbinv(SB), $-4
+	MOVW $cacheopwbinv(SB), R0
+	MOVW $1, R1
+	B cacheop(SB)
+
+/* l1 unified instruction + data cache writeback + invalidate */
+TEXT l2ucachewbinv(SB), $-4
+	MOVM.DB.W [R14], (SP)
+	BL l2idcachewbinv(SB)
+	BL l2idcacheinv(SB)
+	MOVM.IA.W (SP), [R14]
+	RET
+
+/* set/way operations for cacheop */
+TEXT cacheopwb(SB), $-4;	MCR 15, 0, R0, C7, C10, 2; RET
+TEXT cacheopinv(SB), $-4;	MCR 15, 0, R0, C7, C6, 2; RET
+TEXT cacheopwbinv(SB), $-4;	MCR 15, 0, R0, C7, C14, 2; RET
+
+#define Rop R2
+#define Rcache R3
+#define Rways R4
+#define Rwayshift R5
+#define Rsets R6
+#define Rsetshift R7
+#define Rset R8
+
+/* apply a cache operation to the whole cache */
+TEXT cacheop(SB), $-4
+	/* stash */
+	MOVM.DB.W [R2,R14], (SP)
+	MOVW R0, Rop
+	MOVW R1, Rcache
+
+	/* get cache geometry */
+	MCR 15, 2, Rcache, C0, C0, 0; ISB
+	MRC 15, 1, R0, C0, C0, 0
+
+	/* compute ways = ((R0 >> 3) & 0x3ff) + 1) */
+	SRA $3, R0, Rways
+	AND $0x3ff, Rways
+	ADD $1, Rways
+
+	/* compute wayshift = log₂(ways) */
+	CLZ(4, 5) /* Rways, Rwayshift */
+	ADD $1, Rwayshift
+
+	/* compute sets = ((R0 >> 13) & 0x7fff) + 1) */
+	SRA $13, R0, Rsets
+	AND $0x7fff, Rsets
+	ADD $1, Rsets
+
+	/* compute setshift = log₂(cache line size) */
+	AND $0x7, R0, Rsetshift
+	ADD $4, Rsetshift
+
+cacheopways:
+	MOVW Rsets, Rset
+cacheopsets:
+	/* compute set / way register contents */
+	SLL Rwayshift, Rways, R0
+	SLL Rsetshift, Rset, R1
+	ORR R1, R0
+	SLL $1, Rcache, R1
+	ORR R1, R0
+
+	BL (Rop)
+	SUB $1, Rset; CMP $0, Rset; BEQ cacheopsets /* loop sets */
+	SUB $1, Rways; CMP $0, Rways; BEQ cacheopways /* loop ways */
+
+	/* restore */
+	MOVM.IA.W (SP), [R2,R14]
+	RET
--- /dev/null
+++ b/sys/src/9/n900/ltrap.s
@@ -1,0 +1,201 @@
+#include "mem.h"
+#include "io.h"
+
+TEXT vectors(SB), $-4
+	MOVW 24(R15), R15
+	MOVW 24(R15), R15
+	MOVW 24(R15), R15
+	MOVW 24(R15), R15
+	MOVW 24(R15), R15
+	MOVW 24(R15), R15
+	MOVW 24(R15), R15
+	MOVW 24(R15), R15
+
+TEXT vtable(SB), $-4
+	WORD $_vund(SB)
+	WORD $_vund(SB)
+	WORD $_vsvc(SB)
+	WORD $_viabt(SB)
+	WORD $_vdabt(SB)
+	WORD $_vund(SB)
+	WORD $_virq(SB)
+	WORD $_vfiq(SB)
+
+TEXT _vsvc(SB), $-4
+	CLREX
+	DSB
+
+	/* stash in ureg */
+	MOVM.DB.W [R14], (R13) /* ureg->pc */
+	MOVW SPSR, R14
+	MOVM.DB.W [R14], (R13) /* ureg->psr */
+	MOVW $PsrMsvc, R14
+	MOVM.DB.W [R14], (R13) /* ureg->type */
+
+	/* save user regs.
+	 * not MOVM.DB.W.S because the saved value of R13 is undefined.
+	 * (arm v7 manual §A8.8.199) */
+	MOVM.DB.S [R0-R14], (R13)
+	SUB $(15*4), R13
+
+	/* get our sb, mach, up */
+	MOVW $setR12(SB), R12
+	MOVW $(MACH(0)), R(Rmach)
+	MOVW 8(R(Rmach)), R(Rup)
+
+	/* make space for debugger and go to syscall passing ureg */
+	MOVW R13, R0
+	SUB $8, R13
+	BL syscall(SB)
+	ADD $8, R13
+
+	/* restore link, spsr */
+	ADD $(15*4), R13
+	MOVW 8(R13), R14
+	MOVW 4(R13), R0
+	MOVW R0, SPSR
+
+	/* restore user regs */
+	MOVM.DB.S (R13), [R0-R14]
+
+	/* pop past ureg->type, ureg->psr and restore ureg->pc.
+	 * omap and others have RFE here but 5a has no idea about newer instructions
+	 * and simulates it with the MOVM below */
+	ADD $8, R13
+	MOVM.IA.S.W (R13), [R15]
+
+TEXT _viabt(SB), $-4
+	CLREX
+	DSB
+	MOVM.IA [R0-R4], (R13)
+	MOVW $PsrMiabt, R0
+	B _vswitch
+
+TEXT _vdabt(SB), $-4
+	CLREX
+	DSB
+	MOVM.IA [R0-R4], (R13)
+	MOVW $PsrMdabt, R0
+	B _vswitch
+
+TEXT _virq(SB), $-4
+	CLREX
+	DSB
+	MOVM.IA [R0-R4], (R13)
+	MOVW $PsrMirq, R0
+	B _vswitch
+
+TEXT _vfiq(SB), $-4
+	CLREX
+	DSB
+	MOVM.IA [R0-R4], (R13)
+	MOVW $PsrMfiq, R0
+	B _vswitch
+
+TEXT _vund(SB), $-4
+	CLREX
+	DSB
+	MOVM.IA [R0-R4], (R13)
+	MOVW $PsrMund, R0
+	B _vswitch
+
+_vswitch:
+	/* stash pointer to previous R0-R4, stash SPSR and R14 for ureg */
+	MOVW SPSR, R1
+	MOVW R14, R2
+	MOVW R13, R3
+
+	/* back to svc mode */
+	MOVW CPSR, R14
+	BIC $PsrMask, R14
+	ORR $(PsrDirq|PsrDfiq|PsrMsvc), R14
+	MOVW R14, CPSR
+
+	/* from user or kernel mode? */
+	AND.S $0xf, R1, R4
+	BEQ _vuser
+
+	/* from kernel mode */
+	/* set ureg->type, ureg->psr, ureg->pc */
+	MOVM.DB.W [R0-R2], (R13)
+	MOVM.IA (R3), [R0-R4]
+
+	/* save kernel regs
+	 * not MOVM.DB.W.S because the saved value of R13 is undefined.
+	 * (arm v7 manual §A8.8.199) */
+	MOVM.DB [R0-R14], (R13)
+	SUB $(15*4), R13
+
+	/* get our sb, mach, up */
+	MOVW $setR12(SB), R12
+
+	/* make space for debugger and go to trap passing ureg */
+	MOVW R13, R0
+	SUB $8, R13
+	BL trap(SB)
+	ADD $8, R13
+
+	/* restore link, spsr */
+	ADD $(15*4), R13
+	MOVW 8(R13), R14
+	MOVW 4(R13), R0
+	MOVW R0, SPSR
+
+	/* restore kernel regs */
+	MOVM.DB (R13), [R0-R14]
+
+	/* pop past ureg->type, ureg->psr, and restore ureg->pc. */
+	ADD $8, R13
+	MOVM.IA.S.W (R13), [R15]
+
+_vuser:
+	/* from user mode */
+	/* set ureg->type, ureg->psr, ureg->pc */
+	MOVM.DB.W [R0-R2], (R13)
+	MOVM.IA (R3), [R0-R4]
+
+	/* save kernel regs
+	 * not MOVM.DB.W.S because the saved value of R13 is undefined.
+	 * (arm v7 manual §A8.8.199) */
+	MOVM.DB.S [R0-R14], (R13)
+	SUB $(15*4), R13
+
+	/* get our sb, mach, up */
+	MOVW $setR12(SB), R12
+	MOVW $(MACH(0)), R(Rmach)
+	MOVW 8(R(Rmach)), R(Rup)
+
+	/* make space for debugger and go to trap passing ureg */
+	MOVW R13, R0
+	SUB $8, R13
+	BL trap(SB)
+	ADD $8, R13
+
+	/* restore link, spsr */
+	ADD $(15*4), R13
+	MOVW 8(R13), R14
+	MOVW 4(R13), R0
+	MOVW R0, SPSR
+
+	/* restore kernel regs */
+	MOVM.DB.S (R13), [R0-R14]
+
+	/* pop past ureg->type, ureg->psr, and restore ureg->pc */
+	ADD $8, R13
+	MOVM.IA.S.W (R13), [R15]
+
+TEXT setR13(SB), $-4
+	MOVW 4(FP), R1
+
+	/* switch to new mode */
+	MOVW CPSR, R2
+	BIC $PsrMask, R2, R3
+	ORR R0, R3
+	MOVW R3, CPSR
+
+	/* set r13 */
+	MOVW R1, R13
+
+	/* back to old mode */
+	MOVW R2, CPSR
+	RET
--- /dev/null
+++ b/sys/src/9/n900/main.c
@@ -1,0 +1,222 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#include "tos.h"
+#include "ureg.h"
+#include "pool.h"
+
+#define MAXCONF 64
+
+static char *confname[MAXCONF];
+static char *confval[MAXCONF];
+static int nconf;
+
+Conf conf;
+
+char*
+getconf(char *name)
+{
+	int i;
+
+	for(i = 0; i < nconf; i++)
+		if(cistrcmp(confname[i], name) == 0)
+			return confval[i];
+
+	return nil;
+}
+
+int
+isaconfig(char *, int, ISAConf *)
+{
+	return 0;
+}
+
+void
+cpuidprint(void)
+{
+	/* FIXME: how fast are we really? */
+	print("cpu%d: %dMHz ARM Cortex-A8\n", m->machno, 600);
+}
+
+void
+plan9iniinit(void)
+{
+	char *c, *p, *q;
+	char *v[MAXCONF];
+	int i, n;
+
+	c = (char*) CONFADDR;
+	for(p = q = c; *q; q++) {
+		if(*q == '\r')
+			continue;
+		if(*q == '\t')
+			*q = ' ';
+		*p++ = *q;
+	}
+
+	*p = 0;
+	n = getfields(c, v, MAXCONF, 1, "\n");
+	for(i = 0; i < n; i++) {
+		if(v[i][0] == '#')
+			continue;
+
+		c = strchr(v[i], '=');
+		if(!c)
+			continue;
+
+		confname[nconf] = v[i];
+		confval[nconf] = c;
+		nconf++;
+	}
+}
+
+void
+confinit(void)
+{
+	int i;
+	uintptr pa;
+	ulong kp;
+
+	conf.nmach = 1;
+	conf.npage = 0;
+	conf.mem[0].base = PHYSMEM;
+	conf.mem[0].limit = PHYSMEMEND;
+
+	pa = PADDR(PGROUND((uintptr)end));
+	for(i = 0; i < nelem(conf.mem); i++) {
+		if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
+			conf.mem[i].base = pa;
+
+		conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
+		conf.npage += conf.mem[i].npage;
+	}
+
+	conf.upages = (conf.npage*80)/100;
+	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
+
+	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
+	if(cpuserver)
+		conf.nproc *= 3;
+	if(conf.nproc > 4000)
+		conf.nproc = 4000;
+
+	conf.nswap = conf.npage*3;
+	conf.nswppo = 4096;
+	conf.nimage = 200;
+	conf.copymode = 0;
+
+	kp = conf.npage - conf.upages;
+	kp *= BY2PG;
+	kp -= conf.upages * sizeof(Page)
+		+ conf.nproc * sizeof(Proc*)
+		+ conf.nimage * sizeof(Image)
+		+ conf.nswap
+		+ conf.nswppo * sizeof(Page*);
+
+	mainmem->maxsize = kp;
+	if(!cpuserver)
+		imagmem->maxsize = kp;
+}
+
+void
+machinit(void)
+{
+	m->machno = 0;
+
+	active.machs[0] = 1;
+	active.exiting = 0;
+
+	up = nil;
+}
+
+void
+init0(void)
+{
+	char **sp, buf[KNAMELEN];
+	int i;
+
+	chandevinit();
+	if(!waserror()) {
+		ksetenv("cputype", "arm", 0);
+		if(cpuserver)
+			ksetenv("service", "cpu", 0);
+		else
+			ksetenv("service", "terminal", 0);
+
+		snprint(buf, sizeof(buf), "nokia %s", conffile);
+		ksetenv("terminal", buf, 0);
+		ksetenv("console", "2", 0);
+		ksetenv("kbmap", "n900", 0);
+		for(i = 0; i < nconf; i++) {
+			if(*confname[i] != '*')
+				ksetenv(confname[i], confval[i], 0);
+			ksetenv(confname[i], confval[i], 1);
+		}
+
+		poperror();
+	}
+
+	kproc("alarm", alarmkproc, 0);
+
+	/* prepare stack for boot */
+	sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
+	sp[3] = sp[2] = sp[1] = nil;
+	strcpy(sp[0] = (char*)&sp[4], "boot");
+	touser(sp);
+}
+
+void
+main(void)
+{
+	uartinit();
+	machinit();
+	mmuinit();
+	plan9iniinit();
+	confinit();
+	printinit();
+	quotefmtinstall();
+	fmtinstall(L'H', encodefmt);
+	print("\nPlan 9\n");
+
+	xinit();
+	trapinit();
+	intrinit();
+	timerinit();
+	cpuidprint();
+	procinit0();
+	initseg();
+	links();
+
+	screeninit();
+	chandevreset();
+
+	pageinit();
+	userinit();
+	schedinit();
+
+	panic("schedinit returned");
+}
+
+void
+exit(int)
+{
+	for(;;)
+		idlehands();
+}
+
+void
+reboot(void *, void *, ulong)
+{
+}
+
+void
+setupwatchpts(Proc *, Watchpt *, int n)
+{
+	if(n > 0)
+		error("no watchpoints");
+}
--- /dev/null
+++ b/sys/src/9/n900/mem.h
@@ -1,0 +1,105 @@
+#define KiB (1024u)
+#define MiB (1024*1024u)
+#define GiB (1024*1024*1024u)
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define Rmach 10
+#define Rup 9
+
+#define HZ (100)
+#define MS2HZ (1000/HZ)
+#define TK2SEC(t) ((t)/HZ)
+
+#define CONFADDR 0x80010000
+
+#define KZERO 0x80000000
+#define KTZERO 0x80020000
+#define KSTACK (8*KiB)
+
+#define UZERO 0
+#define UTZERO BY2PG
+#define USTKTOP 0x20000000
+#define USTKSIZE (16*MiB)
+
+#define MAXMACH 1
+#define MACHSZ (16*KiB)
+#define L1SZ (4*4096)
+#define L2SZ (4*256)
+
+#define L1X(va) ((((va)>>20) & 0xfff) << 2)
+
+#define MACH(n) (KZERO+(n)*MACHSZ)
+#define MACHP(n) ((Mach*)MACH(n))
+#define MACHL1(n) (MACH(MAXMACH)+(n)*L1SZ)
+#define MACHVEC(n) (MACHL1(MAXMACH)+(n)*64*4)
+
+#define BY2PG (4*KiB)
+#define BY2SE 4
+#define BY2WD 4
+#define BY2V 8
+
+#define CACHELINEZ 64
+#define BLOCKALIGN 32
+
+#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1))
+#define PGROUND(s) ROUND(s, BY2PG)
+#define PGSHIFT 12
+
+#define PTEMAPMEM MiB
+#define PTEPERTAB (PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE 1984
+#define SSEGMAPSIZE 16
+
+#define PPN(p) ((p)&~(BY2PG-1))
+
+#define PTEVALID (1<<0)
+#define PTERONLY (0<<1)
+#define PTEWRITE (1<<1)
+#define PTECACHED (0<<2)
+#define PTEUNCACHED (1<<2)
+#define PTENOEXEC (1<<3)
+
+#define PsrDfiq 0x40
+#define PsrDirq 0x80
+
+#define PsrMusr 0x10
+#define PsrMfiq 0x11
+#define PsrMirq 0x12
+#define PsrMsvc 0x13
+#define PsrMmon 0x16
+#define PsrMiabt 0x17
+#define PsrMdabt 0x18
+#define PsrMund 0x1b
+#define PsrMsys 0x1f
+
+#define PsrMask 0x1f
+
+#define WFI WORD $0xe320f003
+#define DSB WORD $0xf57ff04f
+#define DMB WORD $0xf57ff05f
+#define ISB WORD $0xf57ff06f
+
+#define CPSIE WORD $0xf1080080
+#define CPSID WORD $0xf10c0080
+
+#define CLZ(s, d) WORD $(0xe16f0f10 | (d) << 12 | (s))
+#define VMSR(cpu, fp) WORD $(0xeee00a10|(fp)<<16|(cpu)<<12)
+#define VMRS(fp, cpu) WORD $(0xeef00a10|(fp)<<16|(cpu)<<12)
+
+#define FPSID 0x0
+#define FPSCR 0x1
+#define MVFR1 0x6
+#define MVFR0 0x7
+#define FPEXC 0x8
+#define FPEXCEX (1<<31)
+#define FPEXCEN (1<<30)
+
+/* vlmdia r0!, {d0-d15}
+ * vldmia r0!, {d16-d31} */
+#define VLDMIA WORD $0xecb00b20; WORD $0xecf00b20;
+
+/* vstmia r0!, {d0-d15}
+ * vstmia r0!, {d16-d31} */
+#define VSTMIA WORD $0xeca00b20; WORD $0xece00b20;
--- /dev/null
+++ b/sys/src/9/n900/mkfile
@@ -1,0 +1,82 @@
+CONF=n900
+CONFLIST=n900
+
+p=9
+objtype=arm
+ktzero=0x80020000
+
+</$objtype/mkfile
+
+DEVS=`{rc ../port/mkdevlist $CONF}
+PORT=\
+	alarm.$O\
+	alloc.$O\
+	allocb.$O\
+	auth.$O\
+	cache.$O\
+	chan.$O\
+	dev.$O\
+	edf.$O\
+	fault.$O\
+	mul64fract.$O\
+	rebootcmd.$O\
+	page.$O\
+	parse.$O\
+	pgrp.$O\
+	portclock.$O\
+	print.$O\
+	proc.$O\
+	qio.$O\
+	qlock.$O\
+	segment.$O\
+	sysfile.$O\
+	sysproc.$O\
+	taslock.$O\
+	tod.$O\
+	xalloc.$O\
+	random.$O\
+	rdb.$O\
+	syscallfmt.$O\
+	userinit.$O\
+	ucalloc.$O\
+
+OBJ=\
+	l.$O\
+	lcache.$O\
+	ltrap.$O\
+	main.$O\
+	mmu.$O\
+	timer.$O\
+	trap.$O\
+	intr.$O\
+	$CONF.root.$O\
+	$CONF.rootc.$O\
+	$DEVS\
+	$PORT\
+
+LIB=\
+	/$objtype/lib/libmemlayer.a\
+	/$objtype/lib/libmemdraw.a\
+	/$objtype/lib/libdraw.a\
+	/$objtype/lib/libip.a\
+	/$objtype/lib/libsec.a\
+	/$objtype/lib/libmp.a\
+	/$objtype/lib/libc.a\
+	/$objtype/lib/libdtracy.a\
+
+$p$CONF.u:D: $p$CONF
+	aux/aout2uimage -o $target -Z0 $prereq
+
+$p$CONF:D: $OBJ $CONF.$O $LIB
+	$LD -o $target -T$ktzero -l $prereq
+
+<../boot/bootmkfile
+<../port/portmkfile
+<|../port/mkbootrules $CONF
+
+initcode.out: init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R1 -s -o $target $prereq
+
+install:V: $p$CONF.u
+	cp $p$CONF /$objtype/
+	cp $p$CONF.u /$objtype/
--- /dev/null
+++ b/sys/src/9/n900/mmcn900.c
@@ -1,0 +1,308 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "../port/error.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+#include "../port/sd.h"
+
+enum {
+	Rsysc		= 0x10,
+		SCreset		= 1 << 1,
+	Rsyss		= 0x14,
+		SSreset		= 1 << 0,
+	Rcsre		= 0x24,
+	Rcon		= 0x28,
+	Rpwcnt		= 0x2c,
+	Rblk		= 0x104,
+	Rarg		= 0x108,
+	Rcmd		= 0x10c,
+		CRnone		= 0 << 16,
+		CR136		= 1 << 16,
+		CR48		= 2 << 16,
+		CR48busy	= 3 << 16,
+		CRmask		= 3 << 16,
+
+		CFcheckidx	= 1 << 19,
+		CFcheckcrc	= 1 << 20,
+		CFdata		= 1 << 21,
+		CFdataread	= 1 << 4,
+		CFdatamulti	= 1 << 5,
+
+		CTnone		= 0 << 22,
+		CTbus		= 1 << 22,
+		CTfunc		= 2 << 22,
+		CTio		= 3 << 22,
+	Rrsp10		= 0x110,
+	Rrsp32		= 0x114,
+	Rrsp54		= 0x118,
+	Rrsp76		= 0x11c,
+	Rdata		= 0x120,
+	Rpstate		= 0x124,
+	Rhctl		= 0x128,
+	Rsysctl		= 0x12c,
+	Rstatus		= 0x130,
+		STcmd		= 1 << 0,
+		STtransfer	= 1 << 1,
+		STbufwrite	= 1 << 4,
+		STbufread	= 1 << 5,
+
+		STmaskok	= 0xffff << 0,
+		STmaskerr	= 0xffff << 16,
+	Rie			= 0x134,
+	Rise		= 0x138,
+	Rac12		= 0x13c,
+	Rcapa		= 0x140,
+	Rcapacur	= 0x148,
+	Rrev		= 0x1fc,
+};
+
+#define csr32r(c, r) ((c)->io[(r)/4])
+#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
+
+typedef struct Ctlr Ctlr;
+struct Ctlr {
+	char *name;
+	u32int *io;
+	ulong irq;
+
+	struct {
+		uint bcount;
+		uint bsize;
+	} cmd;
+
+	Lock;
+	Rendez;
+};
+
+static int
+n900mmcinit(SDio *io)
+{
+	Ctlr *ctlr;
+
+	ctlr = io->aux;
+	csr32w(ctlr, Rsysc, SCreset);
+	while(!(csr32r(ctlr, Rsyss) & SSreset))
+		;
+
+	return 0;
+}
+
+static void
+n900mmcenable(SDio *)
+{
+}
+
+static int
+n900mmcinquiry(SDio *, char *inquiry, int len)
+{
+	return snprint(inquiry, len, "MMC Host Controller");
+}
+
+static void
+n900mmcintr(Ureg *, void *aux)
+{
+	Ctlr *ctlr;
+
+	ctlr = aux;
+	ilock(ctlr);
+	if(csr32r(ctlr, Rstatus) & STcmd)
+		wakeup(ctlr);
+
+	iunlock(ctlr);
+}
+
+static int
+n900mmcdone(void *aux)
+{
+	Ctlr *ctlr = aux;
+
+	if(csr32r(ctlr, Rstatus) & STcmd)
+		return 1;
+
+	return 0;
+}
+
+static int
+n900mmccmd(SDio *io, SDiocmd *iocmd, u32int arg, u32int *resp)
+{
+	Ctlr *ctlr;
+	u32int cmd;
+
+	/* prepare flags for this command */
+	ctlr = io->aux;
+	cmd = iocmd->index << 24;
+	switch(iocmd->resp) {
+	case 0: cmd |= CRnone; break;
+	case 2: cmd |= CR136 | CFcheckcrc; break;
+	case 3: cmd |= CR48; break;
+	case 1:
+		if(iocmd->busy) {
+			cmd |= CR48busy | CFcheckidx | CFcheckcrc;
+			break;
+		}
+
+	default:
+		cmd |= CR48 | CFcheckidx | CFcheckcrc;
+		break;
+	}
+
+	/* if there is data, set the data, read, and multi flags */
+	if(iocmd->data) {
+		cmd |= CFdata;
+		if(iocmd->data & 1)
+			cmd |= CFdataread;
+		if(iocmd->data > 2)
+			cmd |= CFdatamulti;
+	}
+
+	/* off it goes, wait for a response */
+	csr32w(ctlr, Rstatus, ~0);
+	csr32w(ctlr, Rarg, arg);
+	csr32w(ctlr, Rcmd, cmd);
+
+	/* wait for command to be done */
+	tsleep(ctlr, n900mmcdone, ctlr, 100);
+	if(csr32r(ctlr, Rstatus) & STmaskerr)
+		error(Eio);
+
+	/* unpack the response */
+	switch(cmd & CRmask) {
+	case CRnone:
+		resp[0] = 0;
+		break;
+
+	case CR136:
+		resp[0] = csr32r(ctlr, Rrsp10);
+		resp[1] = csr32r(ctlr, Rrsp32);
+		resp[2] = csr32r(ctlr, Rrsp54);
+		resp[3] = csr32r(ctlr, Rrsp76);
+		break;
+
+	case CR48:
+	case CR48busy:
+		resp[0] = csr32r(ctlr, Rrsp10);
+		break;
+	}
+
+	return 0;
+}
+
+static void
+n900mmciosetup(SDio *io, int, void *, int bsize, int bcount)
+{
+	Ctlr *ctlr;
+
+	ctlr = io->aux;
+	if(bsize == 0 || (bsize & 3) != 0)
+		error(Egreg);
+
+	ctlr->cmd.bsize = bsize;
+	ctlr->cmd.bcount = bcount;
+	csr32w(ctlr, Rblk, (bsize & 0x3ff) | (bcount << 16));
+}
+
+static void
+n900mmcbufread(Ctlr *ctlr, uchar *buf, int len)
+{
+	for(len >>= 2; len > 0; len--) {
+		*((u32int*)buf) = csr32r(ctlr, Rdata);
+		buf += 4;
+	}
+}
+
+static void
+n900mmcbufwrite(Ctlr *ctlr, uchar *buf, int len)
+{
+	for(len >>= 2; len > 0; len--) {
+		csr32w(ctlr, Rdata, *((u32int*)buf));
+		buf += 4;
+	}
+}
+
+static void
+n900mmcio(SDio *io, int write, uchar *buf, int len)
+{
+	Ctlr *ctlr;
+	u32int stat, n;
+
+	ctlr = io->aux;
+	if(len != ctlr->cmd.bsize * ctlr->cmd.bcount)
+		error(Egreg);
+
+	while(len > 0) {
+		stat = csr32r(ctlr, Rstatus);
+		if(stat & STmaskerr) {
+			csr32w(ctlr, Rstatus, STmaskerr);
+			error(Eio);
+		}
+
+		if(stat & STbufwrite) {
+			csr32w(ctlr, Rstatus, STbufwrite);
+			if(!write)
+				error(Eio);
+
+			n = len;
+			if(n > ctlr->cmd.bsize)
+				n = ctlr->cmd.bsize;
+
+			n900mmcbufwrite(ctlr, buf, n);
+			len -= n;
+			buf += n;
+		}
+
+		if(stat & STbufread) {
+			csr32w(ctlr, Rstatus, STbufread);
+			if(write)
+				error(Eio);
+
+			n = len;
+			if(n > ctlr->cmd.bsize)
+				n = ctlr->cmd.bsize;
+
+			n900mmcbufread(ctlr, buf, n);
+			len -= n;
+			buf += n;
+		}
+
+		if(stat & STtransfer) {
+			csr32w(ctlr, Rstatus, STtransfer);
+			if(len != 0)
+				error(Eio);
+		}
+	}
+}
+
+static void
+n900mmcbus(SDio *, int, int)
+{
+	/* FIXME: change bus width */
+}
+
+void
+mmcn900link(void)
+{
+	int i;
+	static Ctlr ctlr[2] = {
+		{ .name = "mmc1", .io = (u32int*) PHYSMMC1, .irq = IRQMMC1, },
+		{ .name = "mmc2", .io = (u32int*) PHYSMMC2, .irq = IRQMMC2, },
+	};
+
+	static SDio io[nelem(ctlr)];
+	for(i = 0; i < nelem(io); i++) {
+		io[i].name = "mmc",
+		io[i].init = n900mmcinit,
+		io[i].enable = n900mmcenable,
+		io[i].inquiry = n900mmcinquiry,
+		io[i].cmd = n900mmccmd,
+		io[i].iosetup = n900mmciosetup,
+		io[i].io = n900mmcio,
+		io[i].bus = n900mmcbus,
+		io[i].aux = &ctlr[i];
+
+		addmmcio(&io[i]);
+		intrenable(ctlr[i].irq, n900mmcintr, &ctlr[i], BUSUNKNOWN, ctlr[i].name);
+	}
+}
--- /dev/null
+++ b/sys/src/9/n900/mmu.c
@@ -1,0 +1,311 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+static int debug = 0;
+
+#define L1(va) (((va)>>20) & 0xfff)
+#define L2(va) (((va)>>12) & 0xff)
+#define L1AP(ap) (((ap) << 10) & 0xff) /* dont care about ap[2] */
+#define L2AP(ap) (((ap) << 4) & 0xff)
+
+enum {
+	/* l1 descriptor type (arm v7 manual fig. 12.4) */
+	L1coarse = 1,
+	L1section = 2,
+	L1fine = 3,
+
+	/* l2 descriptor type (arm v7 manual fig. 12.5) */
+	L2large = 1,
+	L2small = 2,
+	L2tiny = 3,
+
+	Fnoexec = 1<<0,
+	Fbuffered = 1<<2,
+	Fcached = 1<<3,
+
+	APkrw = 1, /* kernel read write */
+	APuro = 2, /* user read only */
+	APurw = 3, /* user read write */
+};
+
+void
+mmudebugl2(PTE *l2, uintptr va)
+{
+	uintptr startpa, pa;
+	uintptr startva, endva;
+	int i, t;
+
+	t = 0;
+	startpa = 0;
+	startva = endva = 0;
+	for(i = 0; i < 256; i++) {
+		pa = l2[i] & ~((4*KiB)-1);
+		if(l2[i] == 0) {
+			if(endva) {
+				iprint("mmudebug: l2 type %#ux %#lux %#lux -> %#lux\n", t, startva, endva, startpa);
+				endva = 0;
+			}
+		} else {
+			if(!endva) {
+				startva = va;
+				startpa = pa;
+				t = l2[i] & (L2large | L2small | L2tiny);
+			}
+
+			endva = va + (4*KiB);
+		}
+
+		va += (4*KiB);
+	}
+
+	if(endva)
+		iprint("mmudebug: l2 type %#ux %#lux %#lux -> %#lux\n", t, startva, endva, startpa);
+}
+
+void
+mmudebug(char *where)
+{
+	PTE *l1;
+	uintptr pa, startpa;
+	uintptr va, startva, endva;
+	int i, t;
+
+	if(!debug)
+		return;
+
+	iprint("mmudebug: %s pid %d\n", where, m->mmupid);
+
+	t = 0;
+	l1 = m->mmul1;
+	startpa = 0;
+	startva = endva = 0;
+	for(va = i = 0; i < 4096; i++) {
+		pa = l1[i] & ~(MiB-1);
+		if(l1[i] == 0) {
+			if(endva) {
+				iprint("mmudebug: l1 type %#ux %#lux %#lux -> %#lux\n", t, startva, endva, startpa);
+				endva = 0;
+			}
+		} else {
+			if(!endva) {
+				startva = va;
+				startpa = pa;
+				t = l1[i] & (L1coarse|L1section|L1fine);
+			}
+
+			if(t == L1coarse) {
+				mmudebugl2((PTE*) (l1[i] & ~(KiB-1)), startva);
+				endva = 0;
+			} else {
+				endva = va + MB;
+			}
+		}
+
+		va += MB;
+	}
+
+	if(endva)
+		iprint("mmudebug: l1 type %#ux %#lux %#lux -> %#lux\n", t, startva, endva, startpa);
+}
+
+void
+mmuinit(void)
+{
+	m->mmul1 = (PTE*)MACHL1(m->machno);
+}
+
+static void
+mmul1empty(void)
+{
+	memset(m->mmul1, 0, (ROUND(USTKTOP, MiB)/MiB)*sizeof(PTE));
+}
+
+static void
+mmul2empty(Proc *proc, int clear)
+{
+	PTE *l1;
+	Page **l2, *page;
+
+	l1 = m->mmul1;
+	l2 = &proc->mmul2;
+	for(page = *l2; page != nil; page = page->next) {
+		if(clear)
+			memset((void*)page->va, 0, BY2PG);
+
+		l1[page->daddr] = 0;
+		l2 = &page->next;
+	}
+
+	*l2 = proc->mmul2cache;
+	proc->mmul2cache = proc->mmul2;
+	proc->mmul2 = nil;
+}
+
+void
+mmuswitch(Proc *proc)
+{
+	PTE *l1;
+	Page *page;
+	int l1x;
+
+	if(m->mmupid == proc->pid && !proc->newtlb)
+		return;
+	m->mmupid = proc->pid;
+
+	/* write back and invalidate caches */
+	l1ucachewbinv();
+	l2ucachewbinv();
+
+	if(proc->newtlb) {
+		mmul2empty(proc, 1);
+		proc->newtlb = 0;
+	}
+
+	mmul1empty();
+
+	/* switch to new map */
+	l1 = m->mmul1;
+	for(page = proc->mmul2; page != nil; page = page->next) {
+		l1x = page->daddr;
+		l1[l1x] = PPN(page->pa)|L1coarse;
+	}
+
+	/* FIXME: excessive invalidation */
+	l1ucachewbinv();
+	l2ucachewbinv();
+	mmuinvalidate();
+	mmudebug("mmuswitch");
+}
+
+void
+mmurelease(Proc *proc)
+{
+	l1ucachewbinv();
+	l2ucachewbinv();
+
+	mmul2empty(proc, 0);
+
+	freepages(proc->mmul2cache, nil, 0);
+	proc->mmul2cache = nil;
+
+	mmul1empty();
+
+	/* FIXME: excessive invalidation */
+	l1ucachewbinv();
+	l2ucachewbinv();
+	mmuinvalidate();
+	mmudebug("mmurelease");
+}
+
+void*
+mmuuncache(void *v, usize s)
+{
+	PTE *l1;
+	uintptr va;
+
+	assert(!((uintptr)v & (MiB-1)) && s == MiB);
+
+	va = (uintptr)v;
+	l1 = &m->mmul1[L1(va)];
+	if((*l1 & (L1fine|L1section|L1coarse)) != L1section)
+		return nil;
+
+	*l1 &= ~(Fbuffered|Fcached);
+
+	/* FIXME: excessive invalidation */
+	l1ucachewbinv();
+	l2ucachewbinv();
+	mmuinvalidate();
+	mmudebug("mmuuncache");
+
+	return v;
+}
+
+void
+putmmu(uintptr va, uintptr pa, Page *page)
+{
+	int l1x, s, x;
+	PTE *l1, *l2;
+	Page *pg;
+
+	l1x = L1(va);
+	l1 = &m->mmul1[l1x];
+
+	/* put l1 for l2 table if needed */
+	if(*l1 == 0) {
+		if(up->mmul2cache == nil) {
+			pg = newpage(1, 0, 0);
+			pg->va = VA(kmap(pg));
+		} else {
+			pg = up->mmul2cache;
+			up->mmul2cache = pg->next;
+			memset((void*)pg->va, 0, BY2PG);
+		}
+
+		pg->daddr = l1x;
+		pg->next = up->mmul2;
+		up->mmul2 = pg;
+
+		/* FIXME: excessive invalidation */
+		s = splhi();
+		*l1 = PPN(pg->pa)|L1coarse;
+		l1ucachewbinv();
+		l2ucachewbinv();
+		splx(s);
+	}
+
+	/* put l2 entry */
+	x = L2small;
+	if(!(pa & PTEUNCACHED))
+		x |= Fbuffered|Fcached;
+	if(pa & PTENOEXEC)
+		x |= Fnoexec;
+	if(pa & PTEWRITE)
+		x |= L2AP(APurw);
+	else
+		x |= L2AP(APuro);
+
+	l2 = KADDR(PPN(*l1)); l2[L2(va)] = PPN(pa)|x;
+
+	/* FIXME: excessive invalidation */
+	s = splhi();
+	l1ucachewbinv();
+	l2ucachewbinv();
+	if(needtxtflush(page)) {
+		l1icacheinv();
+		donetxtflush(page);
+	}
+
+	splx(s);
+	mmuinvalidate();
+	mmudebug("putmmu");
+}
+
+void
+checkmmu(uintptr, uintptr)
+{
+	/* this page is intentionally left blank */
+}
+
+void
+flushmmu(void)
+{
+	uint s;
+
+	s = splhi();
+	up->newtlb = 1; mmuswitch(up);
+	splx(s);
+}
+
+uintptr
+cankaddr(uintptr pa)
+{
+	if(pa >= PHYSMEM && pa < PHYSMEMEND)
+		return PHYSMEMEND-pa;
+
+	return 0;
+}
--- /dev/null
+++ b/sys/src/9/n900/n900
@@ -1,0 +1,49 @@
+dev
+	root
+	cons
+	swap
+	env
+	pipe
+	proc
+	mnt
+	srv
+	shr
+	dup
+	tls
+	cap
+	sd
+	fs
+	dtracy
+
+	draw	screen
+
+	kbd		devi2c
+	rtc		devi2c
+
+	uart
+	usb
+	i2c
+
+misc
+	uartn900
+
+	sdmmc	mmcn900
+	sdloop
+	sdram
+
+	dtracysys
+	dtracytimer
+	dtracydev
+
+link
+	i2cn900		devi2c
+	mmcn900
+
+port
+	int cpuserver = 0;
+
+bootdir
+	/$objtype/bin/paqfs
+	/$objtype/bin/auth/factotum
+	boot
+	bootfs.paq
--- /dev/null
+++ b/sys/src/9/n900/screen.c
@@ -1,0 +1,373 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#define Image IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include "screen.h"
+
+enum {
+	/* display controller registers */
+	RDrev			= 0x400,
+	RDsysconf		= 0x410,
+		DSCidle			= 1<<0,
+		DSCreset		= 1<<1,
+		DSCidlesmart	= 2<<3,
+	RDsysstat		= 0x414,
+		DSSreset		= 1<<0,
+	RDirqstat		= 0x418,
+	RDirqen			= 0x41c,
+	RDcontrol		= 0x440,
+		DClcdon			= 1<<0,
+		DClcdactive		= 1<<3,
+		DClcdclockrun	= 1<<27,
+		DClcdenable		= 1<<28,
+		DClcdenablehi	= 1<<29,
+		DClcdbits24		= 3<<8,
+	RDconfig		= 0x444,
+		DCNgamma		= 1<<3,
+	RDdefcolor		= 0x44c,
+	RDtranscolor	= 0x454,
+	RDlinestat		= 0x45c,
+	RDlineintr		= 0x460,
+	RDtimeh			= 0x464,
+	RDtimev			= 0x468,
+	RDsize			= 0x47c,
+
+	/* display controller graphics layer registers */
+	RDgfxba				= 0x480,
+	RDgfxpos			= 0x488,
+	RDgfxsize			= 0x48c,
+	RDgfxattr			= 0x4a0,
+		DGAenable			= 1<<0,
+		DGAfmt				= 0x6<<1,
+		DGAburst			= 0x2<<6,
+	RDgfxrowinc			= 0x4ac,
+	RDgfxpixelinc		= 0x4b0,
+};
+
+enum {
+	Tab	= 4,
+	Scroll = 8,
+};
+
+#define RDdefcolorn(n)		(RDdefcolor + (n)*4)
+#define RDtranscolorn(n)	(RDtranscolor + (n)*4)
+
+#define RDgfxban(n)			(RDgfxba + (n)*4)
+
+#define TIME(s, f, b)		((s & 0xff) | (f & 0xfff) << 8 | (b & 0xfff) << 20)
+#define POS(x, y)			((x)<<16 | (y))
+#define SIZE(w, h)			((h-1)<<16 | (w-1))
+
+typedef struct Ctlr Ctlr;
+struct Ctlr {
+	Lock;
+
+	u32int *io;
+
+	Memdata scrdata;
+	Memimage *scrimg;
+	Memsubfont *scrfont;
+
+	Rectangle win;
+	Point font;
+	Point pos;
+};
+
+static Ctlr ctlr = {
+	.io = (u32int*) PHYSDSS,
+};
+
+#define csr32r(c, r) ((c)->io[(r)/4])
+#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
+
+static void myscreenputs(char *s, int n);
+
+static int
+screendatainit(Ctlr *ctlr)
+{
+	Rectangle r;
+
+	if(memimageinit() < 0)
+		return -1;
+
+	r = Rect(0, 0, 800, 480);
+	ctlr->scrdata.ref = 1;
+	ctlr->scrdata.bdata = ucalloc(r.max.x * r.max.y * 2);
+	if(!ctlr->scrdata.bdata)
+		return -1;
+
+	ctlr->scrimg = allocmemimaged(r, RGB16, &ctlr->scrdata);
+	if(!ctlr->scrimg)
+		return -1;
+
+	ctlr->scrfont = getmemdefont();
+	return 0;
+}
+
+static Memimage*
+screenmkcolor(Memimage *scr, ulong color)
+{
+	Memimage *i;
+
+	i = allocmemimage(Rect(0, 0, 1, 1), scr->chan);
+	if(i) {
+		i->flags |= Frepl;
+		i->clipr = scr->r;
+		memfillcolor(i, color);
+	}
+
+	return i;
+}
+
+static void
+screenwin(Ctlr *ctlr)
+{
+	Rectangle r;
+	Memimage *i;
+	Point p;
+	int h;
+
+	ctlr->font.y = h = ctlr->scrfont->height;
+	ctlr->font.x = ctlr->scrfont->info[' '].width;
+	
+	r = ctlr->scrimg->r;
+	if(i = screenmkcolor(ctlr->scrimg, 0x0D686BFF)) {
+		memimagedraw(ctlr->scrimg, r, i, ZP, memopaque, ZP, S);
+		freememimage(i);
+	}
+
+	r = insetrect(r, 16); memimagedraw(ctlr->scrimg, r, memblack, ZP, memopaque, ZP, S);
+	r = insetrect(r, 4); memimagedraw(ctlr->scrimg, r, memwhite, ZP, memopaque, ZP, S);
+	if(i = screenmkcolor(ctlr->scrimg, 0xaaaaaaff)) {
+		memimagedraw(ctlr->scrimg, Rpt(r.min, Pt(r.max.x, r.min.y+h+12)), i, ZP, memopaque, ZP, S);
+		freememimage(i);
+
+		r = insetrect(r, 6);
+		p = r.min;
+		memimagestring(ctlr->scrimg, p, memblack, ZP, getmemdefont(), " Plan 9 Console ");
+	}
+
+	ctlr->win = Rpt(addpt(r.min, Pt(0, h + 6)), subpt(r.max, Pt(6, 6)));
+	ctlr->pos = ctlr->win.min;
+	screenputs = myscreenputs;
+}
+
+void
+screeninit(void)
+{
+	Ctlr *c;
+
+	c = &ctlr;
+	if(screendatainit(c) < 0)
+		return;
+
+	screenwin(c);
+	screenputs(kmesg.buf, kmesg.n);
+
+	/* reset the display controller */
+	csr32w(c, RDsysconf, DSCreset);
+	while(!(csr32r(c, RDsysstat) & DSSreset))
+		;
+
+	/* configure the display controller */
+	csr32w(c, RDsysconf, DSCidle | DSCidlesmart);
+	csr32w(c, RDcontrol, DClcdbits24);
+	csr32w(c, RDconfig, DCNgamma);
+
+	/* configure display size and timings */
+	csr32w(c, RDtimeh, TIME(3, 15, 11));
+	csr32w(c, RDtimev, TIME(2, 3, 3));
+	csr32w(c, RDsize, SIZE(800, 480));
+
+	/* enable the lcd interface */
+	csr32w(c, RDcontrol, csr32r(c, RDcontrol) | DClcdactive | DClcdclockrun | DClcdenablehi);
+	csr32w(c, RDcontrol, csr32r(c, RDcontrol) | DClcdenable);
+
+	/* configure the graphics layer */
+	csr32w(c, RDgfxban(0), (uintptr) c->scrdata.bdata);
+	csr32w(c, RDgfxpos, POS(c->scrimg->r.min.x, c->scrimg->r.min.y));
+	csr32w(c, RDgfxsize, SIZE(c->scrimg->r.max.x, c->scrimg->r.max.y));
+	csr32w(c, RDgfxattr, DGAfmt | DGAburst);
+	csr32w(c, RDgfxrowinc, 1);
+	csr32w(c, RDgfxpixelinc, 1);
+
+	/* enable gfx pipeline and turn lcd on */
+	csr32w(c, RDgfxattr, csr32r(c, RDgfxattr) | DGAenable);
+	csr32w(c, RDcontrol, csr32r(c, RDcontrol) | DClcdon);
+
+	conf.monitor = 1;
+}
+
+static void
+screenscroll(Ctlr *ctlr)
+{
+	int o, h;
+	Point p;
+	Rectangle r;
+
+	h = ctlr->font.y;
+	o = Scroll * h;
+	r = Rpt(ctlr->win.min, Pt(ctlr->win.max.x, ctlr->win.max.y - o));
+	p = Pt(ctlr->win.min.x, ctlr->win.min.y + o);
+	memimagedraw(ctlr->scrimg, r, ctlr->scrimg, p, nil, p, S);
+	flushmemscreen(r);
+
+	r = Rpt(Pt(ctlr->win.min.x, ctlr->win.max.y - o), ctlr->win.max);
+	memimagedraw(ctlr->scrimg, r, memwhite, ZP, nil, ZP, S);
+	flushmemscreen(r);
+
+	ctlr->pos.y -= o;
+	
+}
+
+static void
+screenputc(Ctlr *ctlr, char *buf)
+{
+	Point p;
+	Rectangle r;
+	uint chr;
+	int w, h;
+	static int *xp;
+	static int xbuf[256];
+
+	w = ctlr->font.x;
+	h = ctlr->font.y;
+	if(xp < xbuf || xp >= &xbuf[nelem(xbuf)])
+		xp = xbuf;
+
+	switch(buf[0]) {
+	case '\n':
+		if(ctlr->pos.y + h >= ctlr->win.max.y)
+			screenscroll(ctlr);
+
+		ctlr->pos.y += h;
+		screenputc(ctlr, "\r");
+		break;
+
+	case '\r':
+		xp = xbuf;
+		ctlr->pos.x = ctlr->win.min.x;
+		break;
+
+	case '\t':
+		if(ctlr->pos.x >= ctlr->win.max.x - 4 * w)
+			screenputc(ctlr, "\n");
+
+		chr = (ctlr->pos.x - ctlr->win.min.x) / w;
+		chr = Tab - chr % Tab;
+		*xp++ = ctlr->pos.x;
+
+		r = Rect(ctlr->pos.x, ctlr->pos.y, ctlr->pos.x + chr * w, ctlr->pos.y + h);
+		memimagedraw(ctlr->scrimg, r, memwhite, ZP, memopaque, ZP, S);
+		flushmemscreen(r);
+		ctlr->pos.x += chr * w;
+		break;
+
+	case '\b':
+		if(xp <= xbuf)
+			break;
+
+		xp--;
+		r = Rect(*xp, ctlr->pos.y, ctlr->pos.x, ctlr->pos.y + h);
+		memimagedraw(ctlr->scrimg, r, memwhite, ZP, memopaque, ZP, S);
+		ctlr->pos.x = *xp;
+		break;
+
+	case '\0':
+		break;
+
+	default:
+		p = memsubfontwidth(getmemdefont(), buf); w = p.x;
+		if(ctlr->pos.x >= ctlr->win.max.x - w)
+			screenputc(ctlr, "\n");
+
+		*xp++ = ctlr->pos.x;
+		r = Rect(ctlr->pos.x, ctlr->pos.y, ctlr->pos.x + w, ctlr->pos.y + h);
+		memimagedraw(ctlr->scrimg, r, memwhite, ZP, memopaque, ZP, S);
+		memimagestring(ctlr->scrimg, ctlr->pos, memblack, ZP, getmemdefont(), buf);
+		ctlr->pos.x += w;
+		break;
+	}
+}
+
+static void
+myscreenputs(char *s, int n)
+{
+	Ctlr *c;
+	Rune r;
+	int i;
+	char buf[UTFmax];
+
+	c = &ctlr;
+	if(!c->scrimg)
+		return;
+
+	if(!islo()) {
+		/* don't deadlock trying to print in an interrupt */
+		if(!canlock(c))
+			return;
+	} else {
+		lock(c);
+	}
+
+	while(n > 0) {
+		i = chartorune(&r, s);
+		if(i == 0) {
+			s++; n--;
+			continue;
+		}
+
+		memmove(buf, s, i);
+		buf[i] = 0;
+		s += i; n -= i;
+		screenputc(c, buf);
+	}
+
+	unlock(c);
+}
+
+Memdata*
+attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen)
+{
+	Ctlr *c;
+
+	c = &ctlr;
+	if(!c->scrimg)
+		return nil;
+
+	*r = c->scrimg->r;
+	*d = c->scrimg->depth;
+	*chan = c->scrimg->chan;
+	*width = c->scrimg->width;
+	*softscreen = 1;
+
+	c->scrdata.ref++;
+	return &c->scrdata;
+}
+
+void
+getcolor(ulong, ulong *, ulong *, ulong *)
+{
+}
+
+int
+setcolor(ulong, ulong, ulong, ulong)
+{
+	return 0;
+}
+
+void
+flushmemscreen(Rectangle)
+{
+}
+
+void
+mouseresize(void)
+{
+}
--- /dev/null
+++ b/sys/src/9/n900/screen.h
@@ -1,0 +1,9 @@
+void screeninit(void);
+void flushmemscreen(Rectangle);
+Memdata *attachscreen(Rectangle *, ulong *, int *, int *, int *);
+
+#define ishwimage(i) 1
+
+void mousectl(Cmdbuf*);
+void mouseresize(void);
+void mouseredraw(void);
--- /dev/null
+++ b/sys/src/9/n900/timer.c
@@ -1,0 +1,172 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+enum {
+	Rrev		= 0x00,
+	Rsyscfg		= 0x10,
+		Cidle		= 1<<0,
+		Creset		= 1<<1,
+	Rsysstat	= 0x14,
+		Sreset		= 1<<0,
+	Risr		= 0x18,
+	Rier		= 0x1c,
+		Imatch		= 1<<0,
+		Ioverflow	= 1<<1,
+		Icapture	= 1<<2,
+	Rclr		= 0x24,
+		CLst		= 1<<0,
+		CLar		= 1<<1,
+		CLtgovf		= 1<<10,
+		CLtgmatch	= 1<<11,
+	Rcrr		= 0x28,
+	Rldr		= 0x2c,
+};
+
+typedef union Counter Counter;
+typedef struct Ctlr Ctlr;
+
+union Counter {
+	uvlong cnt;
+	struct {
+		ulong cntlo;
+		ulong cnthi;
+	};
+};
+
+struct Ctlr {
+	Lock;
+	Counter;
+
+	u32int *io;
+};
+
+static Ctlr timers[] = {
+	{ .io = (u32int*) PHYSTIMER1 }, /* for cycles */
+	{ .io = (u32int*) PHYSTIMER2 }, /* for interrupts */
+};
+
+#define csr32r(c, r) ((c)->io[(r)/4])
+#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
+
+static void
+timerreset(Ctlr *ctlr)
+{
+	int i;
+	int cfg;
+
+	cfg = csr32r(ctlr, Rsyscfg);
+	cfg |= Creset;
+	cfg &= ~Cidle;
+
+	ilock(ctlr);
+	csr32w(ctlr, Rsyscfg, cfg);
+	for(i = 40000; i > 0; i++) {
+		if(csr32r(ctlr, Rsysstat) & Sreset)
+			break;
+	}
+
+	if(i == 0)
+		panic("clock reset failed");
+
+	iunlock(ctlr);
+}
+
+static void
+timerstartcycles(Ctlr *ctlr)
+{
+	timerreset(ctlr);
+
+	/* configure this timer for measuring cycles */
+	ilock(ctlr);
+	csr32w(ctlr, Rldr, 0);
+	csr32w(ctlr, Rclr, CLst | CLar);
+	iunlock(ctlr);
+}
+
+static void
+timerstartintr(Ctlr *ctlr, ulong t)
+{
+	timerreset(ctlr);
+
+	/* configure this timer for periodic interrupts */
+	ilock(ctlr);
+	csr32w(ctlr, Rier, Ioverflow);
+	csr32w(ctlr, Rldr, -t);
+	csr32w(ctlr, Rcrr, -t);
+	csr32w(ctlr, Rclr, CLst | CLar);
+	iunlock(ctlr);
+}
+
+static void
+timerinterrupt(Ureg *u, void *arg)
+{
+	Ctlr *ctlr = arg;
+	csr32w(ctlr, Risr, Ioverflow);
+
+	timerintr(u, 0);
+}
+
+void
+timerinit(void)
+{
+	intrenable(IRQTIMER2, timerinterrupt, &timers[1], BUSUNKNOWN, "timer");
+
+	timerstartcycles(&timers[0]);
+	timerstartintr(&timers[1], 32);
+}
+
+uvlong
+fastticks(uvlong *hz)
+{
+	Counter c;
+	Ctlr *ctlr;
+
+	/* FIXME: this has poor precision, but qemu has no cycle counter */
+	ctlr = &timers[0];
+	if(hz)
+		*hz = 32*1024;
+
+	ilock(ctlr);
+	c.cnt = ctlr->cnt;
+	c.cntlo = csr32r(ctlr, Rcrr);
+	if(c.cnt < ctlr->cnt)
+		c.cnthi++;
+
+	ctlr->cnt = c.cnt;
+	iunlock(ctlr);
+
+	return ctlr->cnt;
+}
+
+ulong
+µs(void)
+{
+	return fastticks2us(fastticks(nil));
+}
+
+void
+microdelay(int n)
+{
+	ulong now;
+
+	now = µs();
+	while(µs() - now < n)
+		;
+}
+
+void
+delay(int n)
+{
+	while(--n >= 0)
+		microdelay(1000);
+}
+
+void
+timerset(Tval)
+{
+	/* FIXME: ? */
+}
--- /dev/null
+++ b/sys/src/9/n900/trap.c
@@ -1,0 +1,577 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "../port/systab.h"
+
+#include "tos.h"
+#include "ureg.h"
+
+void
+callwithureg(void (*f) (Ureg *))
+{
+	Ureg u;
+
+	u.pc = getcallerpc(&f);
+	u.sp = (uintptr) &f - 4;
+	f(&u);
+}
+
+void
+dumpstackureg(Ureg *ureg)
+{
+	uintptr l, v, i, estack;
+	int x;
+
+	x = 0;
+	x += iprint("ktrace /arm/9n900 %#.8lux %#.8lux %#.8lux <<EOF\n",
+		ureg->pc, ureg->sp, ureg->r14);
+
+	i = 0;
+	if(up)
+		estack = (uintptr)up;
+	else
+		estack = (uintptr)m+MACHSZ;
+
+	x += iprint("estackx %p\n", estack);
+	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)) {
+		v = *(uintptr*)l;
+		if((KTZERO < v && v < (uintptr)etext) || estack-l < 32) {
+			x += iprint("%.8p=%.8p ", l, v);
+			i++;
+		}
+
+		if(i == 4) {
+			i = 0;
+			x += iprint("\n");
+		}
+	}
+
+	if(i)
+		iprint("\n");
+	iprint("EOF\n");
+}
+
+void
+dumpstack(void)
+{
+	callwithureg(dumpstackureg);
+}
+
+void
+dumpureg(Ureg *ureg)
+{
+	if(up)
+		iprint("cpu%d: registers for %s %lud\n", m->machno, up->text, up->pid);
+	else
+		iprint("cpu%d: registers for kernel\n", m->machno);
+
+	iprint("r0 %#.8lux\tr1 %#.8lux\tr2 %#.8lux\tr3 %#.8lux\n", ureg->r0, ureg->r1, ureg->r2, ureg->r3);
+	iprint("r4 %#.8lux\tr5 %#.8lux\tr6 %#.8lux\tr7 %#.8lux\n", ureg->r4, ureg->r5, ureg->r6, ureg->r7);
+	iprint("r8 %#.8lux\tr9 %#.8lux\tr10 %#.8lux\tr11 %#.8lux\n", ureg->r8, ureg->r9, ureg->r10, ureg->r11);
+	iprint("r12 %#.8lux\tr13 %#.8lux\tr14 %#.8lux\tr15 %#.8lux\n", ureg->r12, ureg->r13, ureg->r14, ureg->pc);
+}
+
+
+uintptr
+userpc(void)
+{
+	return ((Ureg*)up->dbgreg)->pc;
+}
+
+uintptr
+dbgpc(Proc *)
+{
+	if(up->dbgreg)
+		return userpc();
+
+	return 0;
+}
+
+void
+procsetup(Proc *p)
+{
+	p->fpstate = FPinit;
+	fpoff();
+}
+
+void
+procsave(Proc *p)
+{
+	if(p->fpstate == FPactive) {
+		if(p->state == Moribund)
+			fpclear();
+		else
+			fpsave(p->fpsave);
+		p->fpstate = FPinactive;
+	}
+}
+
+void
+procrestore(Proc *)
+{
+}
+
+void
+procfork(Proc *p)
+{
+	ulong s;
+
+	s = splhi();
+	switch(up->fpstate & ~FPillegal) {
+	case FPactive:
+		fpsave(up->fpsave);
+		up->fpstate = FPinactive;
+	case FPinactive:
+		memmove(p->fpsave, up->fpsave, sizeof(FPsave));
+		p->fpstate = FPinactive;
+	}
+
+	splx(s);
+}
+
+void
+kprocchild(Proc *p, void (*entry)(void))
+{
+	p->sched.pc = (uintptr) entry;
+	p->sched.sp = (uintptr) p;
+}
+
+void
+forkchild(Proc *p, Ureg *ureg)
+{
+	Ureg *cureg;
+
+	p->sched.sp = (uintptr) p - sizeof(Ureg);
+	p->sched.pc = (uintptr) forkret;
+
+	cureg = (Ureg*) p->sched.sp;
+	memmove(cureg, ureg, sizeof(Ureg));
+	cureg->r0 = 0;
+}
+
+uintptr
+execregs(uintptr entry, ulong ssize, ulong nargs)
+{
+	ulong *sp;
+	Ureg *ureg;
+
+	sp = (ulong*)(USTKTOP - ssize); *--sp = nargs;
+	ureg = up->dbgreg;
+	ureg->sp = (uintptr) sp;
+	ureg->pc = entry;
+	ureg->r14 = 0;
+
+	return USTKTOP-sizeof(Tos);
+}
+
+void
+setkernur(Ureg *ureg, Proc *p)
+{
+	ureg->pc = p->sched.pc;
+	ureg->sp = p->sched.sp+4;
+	ureg->r14 = (uintptr) sched;
+}
+
+void
+setregisters(Ureg *ureg, char *pureg, char *uva, int n)
+{
+	uvlong v;
+
+	v = ureg->psr;
+	memmove(pureg, uva, n);
+	ureg->psr &= ~(PsrMask|PsrDfiq|PsrDirq);
+	ureg->psr |= v & (PsrMask|PsrDfiq|PsrDirq);
+}
+
+void
+evenaddr(uintptr addr)
+{
+	if(addr & 3) {
+		postnote(up, 1, "sys: odd address", NDebug);
+		error(Ebadarg);
+	}
+}
+
+int
+notify(Ureg *ureg)
+{
+	ulong s, sp;
+	char *msg;
+
+	if(up->procctl)
+		procctl();
+	if(up->nnote == 0)
+		return 0;
+	
+	if(up->fpstate == FPactive) {
+		fpsave(up->fpsave);
+		up->fpstate = FPinactive;
+	}
+	up->fpstate |= FPillegal;
+
+	s = spllo();
+	qlock(&up->debug);
+	msg = popnote(ureg);
+	if(msg == nil) {
+		qunlock(&up->debug);
+		splhi();
+		return 0;
+	}
+
+	sp = ureg->sp;
+	sp -= 256;
+	sp -= sizeof(Ureg);
+
+	if(!okaddr((uintptr)up->notify, 1, 0)
+	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
+	|| ((uintptr) up->notify & 3) != 0
+	|| (sp & 3) != 0) {
+		qunlock(&up->debug);
+		pprint("suicide: bad address in notify\n");
+		pexit("Suicide", 0);
+	}
+
+	memmove((Ureg*)sp, ureg, sizeof(Ureg));
+	*(Ureg**)(sp-BY2WD) = up->ureg;
+	up->ureg = (void*)sp;
+	sp -= BY2WD+ERRMAX;
+	memmove((char*)sp, msg, ERRMAX);
+	sp -= 3*BY2WD;
+	*(uintptr*)(sp+2*BY2WD) = sp+3*BY2WD;
+	*(uintptr*)(sp+1*BY2WD) = (uintptr)up->ureg;
+	ureg->r0 = (uintptr) up->ureg;
+	ureg->sp = sp;
+	ureg->pc = (uintptr) up->notify;
+	ureg->r14 = 0;
+
+	qunlock(&up->debug);
+	splx(s);
+	return 1;
+}
+
+void
+noted(Ureg *ureg, ulong arg0)
+{
+	Ureg *nureg;
+	ulong oureg, sp;
+
+	qlock(&up->debug);
+	if(arg0 != NRSTR && !up->notified) {
+		qunlock(&up->debug);
+		iprint("called to noted when not notified\n");
+		pexit("Suicide", 0);
+	}
+
+	up->notified = 0;
+	up->fpstate &= ~FPillegal;
+	nureg = up->ureg;
+	oureg = (ulong) nureg;
+	if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 3) != 0) {
+		qunlock(&up->debug);
+		pprint("bad ureg in noted or call to noted when not notifed\n");
+		pexit("Suicide", 0);
+	}
+
+	nureg->psr &= PsrMask|PsrDfiq|PsrDirq;
+	nureg->psr |= (ureg->psr & ~(PsrMask|PsrDfiq|PsrDirq));
+
+	memmove(ureg, nureg, sizeof(Ureg));
+	switch(arg0) {
+	case NCONT:
+	case NRSTR:
+		if(!okaddr(nureg->pc, BY2WD, 0) || (nureg->pc & 3) != 0
+		|| !okaddr(nureg->sp, BY2WD, 0) || (nureg->sp & 3) != 0) {
+			qunlock(&up->debug);
+			pprint("suicide: trap in noted\n");
+			pexit("Suicide", 0);
+		}
+
+		up->ureg = (Ureg *) (*(ulong*) (oureg - BY2WD));
+		qunlock(&up->debug);
+		break;
+
+	case NSAVE:
+		if(!okaddr(nureg->pc, BY2WD, 0) || (nureg->pc & 3) != 0
+		|| !okaddr(nureg->sp, BY2WD, 0) || (nureg->sp & 3) != 0) {
+			qunlock(&up->debug);
+			pprint("suicide: trap in noted\n");
+			pexit("Suicide", 0);
+		}
+
+		qunlock(&up->debug);
+		sp = oureg - 4 * BY2WD - ERRMAX;
+		splhi();
+		ureg->sp = sp;
+		ureg->r0 = (uintptr) oureg;
+		((ulong*) sp)[1] = oureg;
+		((ulong*) sp)[0] = 0;
+		break;
+
+	default:
+		up->lastnote->flag = NDebug;
+		/* wet floor */
+
+	case NDFLT:
+		qunlock(&up->debug);
+		if(up->lastnote->flag == NDebug)
+			pprint("suicide: %s\n", up->lastnote->msg);
+
+		pexit(up->lastnote->msg, up->lastnote->flag != NDebug);
+		break;
+	}
+}
+
+void
+trapinit(void)
+{
+	extern ulong vectors[];
+
+	/* install stack pointer for other exception modes */
+	setR13(PsrMfiq, m->save);
+	setR13(PsrMirq, m->save);
+	setR13(PsrMiabt, m->save);
+	setR13(PsrMund, m->save);
+	setR13(PsrMsys, m->save);
+
+	/* install vectors and vtable to MACHVEC because vectors must be
+	 * aligned on a 128 byte boundary */
+	memmove((ulong*)MACHVEC(m->machno), vectors, 64 * 4);
+
+	/* set vectors base address */
+	setvectors(MACHVEC(m->machno));
+}
+
+static void
+trapfpu(void)
+{
+	int s;
+
+	if((up->fpstate & FPillegal) != 0) {
+		postnote(up, 1, "sys: floating point in note handler", NDebug);
+		return;
+	}
+
+	switch(up->fpstate) {
+	case FPinit:
+		s = splhi();
+		fpinit(); up->fpstate = FPactive;
+		splx(s);
+		break;
+
+	case FPinactive:
+		s = splhi();
+		fprestore(up->fpsave); up->fpstate = FPactive;
+		splx(s);
+		break;
+
+	case FPactive:
+		postnote(up, 1, "sys: floating point error", NDebug);
+		break;
+	}
+}
+
+static void
+traparm(Ureg *ureg, ulong fsr, uintptr far)
+{
+	int user;
+	int read;
+	int syscall;
+
+	static char buf[ERRMAX];
+
+	read = (fsr & (1<<11)) == 0;
+	user = userureg(ureg);
+	if(!user) {
+		if(far >= USTKTOP)
+			panic("kernel fault: bad address pc=%#.8lux far=%#.8lux fsr=%#.8lux",
+				ureg->pc, far, fsr);
+		if(up == nil)
+			panic("kernel fault: no user process pc=%#.8lux far=%#.8lux fsr=%#.8lux",
+				ureg->pc, far, fsr);
+	}
+
+	if(up == nil) {
+		panic("user fault: up=nil pc=%#.8lux far=%#.8lux fsr=%#.8lux",
+			ureg->pc, far, fsr);
+	}
+
+	syscall = up->insyscall; up->insyscall = 1;
+	switch(fsr & 0x1f) {
+	case 0x03: /* l1 access flag fault */
+	case 0x05: /* l1 translation fault */
+	case 0x06: /* l2 access flag fault */
+	case 0x07: /* l2 translation fault */
+	case 0x09: /* l1 domain fault */
+	case 0x0b: /* l2 domain fault */
+	case 0x0d: /* l1 permission fault */
+	case 0x0f: /* l2 permission fault */
+		if(fault(far, ureg->pc, read) == 0)
+			break;
+
+	default:
+		if(!user)
+			panic("kernel fault: pc=%#.8lux far=%#.8lux fsr=%#.8lux",
+				ureg->pc, far, fsr);
+
+		dumpureg(ureg);
+		dumpstackureg(ureg);
+		snprint(buf, sizeof(buf), "sys: trap: fault %s far=%#.8lux fsr=%#.8lux",
+			read ? "read" : "write", far, fsr);
+		postnote(up, 1, buf, NDebug);
+	}
+
+	up->insyscall = syscall;
+}
+
+void
+trap(Ureg *ureg)
+{
+	int user;
+	u32int op, cp;
+
+	user = kenter(ureg);
+	switch(ureg->type) {
+	case PsrMfiq:
+	case PsrMirq:
+		ureg->pc -= 4;
+		intr(ureg);
+		break;
+
+	case PsrMiabt:
+		ureg->pc -= 4;
+		traparm(ureg, getifsr(), getifar());
+		break;
+
+	case PsrMdabt:
+		ureg->pc -= 8;
+		traparm(ureg, getdfsr(), getdfar());
+		break;
+
+	case PsrMund:
+		ureg->pc -= 4;
+		if(user) {
+			spllo();
+			if(okaddr(ureg->pc, 4, 0)) {
+				op = *(u32int*)ureg->pc;
+				if((op & 0x0f000000) == 0x0e000000 || (op & 0x0e000000) == 0x0c000000) {
+					cp = op >> 8 & 15;
+					if(cp == 10 || cp == 11) {
+						trapfpu();
+						break;
+					}
+				}
+			}
+				
+			postnote(up, 1, "sys: trap: invalid opcode", NDebug);
+			break;
+		}
+
+		panic("invalid opcode at pc=%#.8lux lr=%#.8lux", ureg->pc, ureg->r14);
+		break;
+
+	default:
+		panic("unknown trap at pc=%#.8lux lr=%#.8lux", ureg->pc, ureg->r14);
+		break;
+	}
+
+	splhi();
+	if(user) {
+		if(up->procctl || up->nnote)
+			notify(ureg);
+
+		kexit(ureg);
+	}
+}
+
+void
+syscall(Ureg *ureg)
+{
+	char *e;
+	uintptr sp;
+	long ret;
+	int i, s;
+	ulong scallnr;
+	vlong startns, stopns;
+
+	if(!kenter(ureg))
+		panic("syscall: from kernel: pc=%#.8lux", ureg->pc);
+
+	m->syscall++;
+	up->insyscall = 1;
+	up->pc = ureg->pc;
+
+	scallnr = up->scallnr = ureg->r0;
+	sp = ureg->sp;
+
+	spllo();
+
+	up->nerrlab = 0;
+	ret = -1;
+	if(!waserror()) {
+		if(scallnr >= nsyscall) {
+			pprint("bad sys call number %lux pc %#lux", scallnr, ureg->pc);
+			postnote(up, 1, "sys: bad sys call", NDebug);
+			error(Ebadarg);
+		}
+
+		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD)) {
+			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
+			evenaddr(sp);
+		}
+
+		up->s = *((Sargs*)(sp + BY2WD));
+		up->psstate = sysctab[scallnr];
+		if (up->procctl == Proc_tracesyscall) {
+			syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
+			s = splhi();
+			up->procctl = Proc_stopme;
+			procctl();
+			splx(s);
+			startns = todget(nil);
+		}
+
+		ret = systab[scallnr]((va_list)up->s.args);
+		poperror();
+	} else {
+		e = up->syserrstr;
+		up->syserrstr = up->errstr;
+		up->errstr = e;
+	}
+
+	if(up->nerrlab) {
+		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
+		for (i = 0; i < NERR; i++)
+			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
+
+		panic("error stack");
+	}
+
+	ureg->r0 = ret;
+	if(up->procctl == Proc_tracesyscall) {
+		stopns = todget(nil);
+		sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
+		s = splhi();
+		up->procctl = Proc_stopme;
+		procctl();
+		splx(s);
+	}
+
+	up->insyscall = 0;
+	up->psstate = 0;
+	if(scallnr == NOTED)
+		noted(ureg, *((ulong *)up->s.args));
+
+	if(scallnr != RFORK && (up->procctl || up->nnote)) {
+		splhi();
+		notify(ureg);
+	}
+
+	if(up->delaysched)
+		sched();
+
+	kexit(ureg);
+	splhi();
+}
--- /dev/null
+++ b/sys/src/9/n900/uartn900.c
@@ -1,0 +1,268 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+enum {
+	Rdll	= 0x00,
+	Rrhr	= 0x00,
+	Rthr	= 0x00,
+	Rdlh	= 0x04,
+	Rier	= 0x04,
+		IErhr	= 1 << 0,
+		IEthr	= 1 << 1,
+		IEls	= 1 << 2,
+		IEms	= 1 << 3,
+	Riir	= 0x08,
+		Ipending = 1 << 0,
+		Imodem	= 0x00,
+		Ithr	= 0x01,
+		Irhr	= 0x02,
+		Ils		= 0x03,
+		Irxt	= 0x06,
+		Ixoff	= 0x08,
+		Icts	= 0x10,
+		Imask 	= 0x1f,
+	Rfcr	= 0x08,
+		FCRen		= 1 << 0,
+	Refr	= 0x08,
+	Rlcr	= 0x0c,
+	Rmcr	= 0x10,
+	Rxon1	= 0x10,
+	Rlsr	= 0x14,
+		LSRrxempty	= 1 << 0,
+		LSRrxover	= 1 << 1,
+		LSRrxparity	= 1 << 2,
+		LSRrxframe	= 1 << 3,
+		LSRrxbreak	= 1 << 4,
+		LSRtxempty	= 1 << 5,
+		LSRtxshift	= 1 << 6,
+		LSRrxstat	= 1 << 7,
+	Rxon2	= 0x14,
+	Rmsr	= 0x18,
+	Rtcr	= 0x18,
+	Rxoff1	= 0x18,
+	Rspr	= 0x1c,
+	Rtlr	= 0x1c,
+	Rxoff2	= 0x1c,
+	Rmdr1	= 0x20,
+	Rmdr2	= 0x24,
+	Rsysc	= 0x54,
+		SCreset		= 1 << 1,
+	Rsyss	= 0x58,
+		SSreset		= 1 << 0,
+};
+
+#define csr32r(c, r) ((c)->io[(r)/4])
+#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
+
+typedef struct Ctlr Ctlr;
+struct Ctlr {
+	Lock;
+
+	u32int *io;
+	ulong irq;
+
+	int ie;
+};
+
+extern PhysUart n900physuart;
+
+static Ctlr ctlr[] = {
+	{ .io = (u32int*) PHYSUART1, .irq = IRQUART1, },
+	{ .io = (u32int*) PHYSUART2, .irq = IRQUART2, },
+	{ .io = (u32int*) PHYSUART3, .irq = IRQUART3, },
+};
+
+static Uart n900uart[] = {
+	{
+		.regs = &ctlr[0],
+		.name = "uart1",
+		.freq = 48000000,
+		.phys = &n900physuart,
+		.next = &n900uart[1],
+	},
+	{
+		.regs = &ctlr[1],
+		.name = "uart2",
+		.freq = 48000000,
+		.phys = &n900physuart,
+		.next = &n900uart[2],
+	},
+	{
+		.regs = &ctlr[2],
+		.name = "uart3",
+		.freq = 48000000,
+		.phys = &n900physuart,
+		.next = nil,
+	},
+};
+
+static Uart *
+n900uartpnp(void)
+{
+	return n900uart;
+}
+
+static long
+n900uartstatus(Uart *, void *, long, long)
+{
+	return 0;
+}
+
+static void
+n900uartintr(Ureg *, void *arg)
+{
+	Uart *uart;
+	Ctlr *ctlr;
+	int lsr;
+	char c;
+
+	uart = arg;
+	ctlr = uart->regs;
+
+	ilock(ctlr);
+	switch((csr32r(ctlr, Riir) >> 1) & Imask) {
+	case Ithr:
+		uartkick(uart);
+		break;
+
+	case Irhr:
+		while((lsr = csr32r(ctlr, Rlsr)) & LSRrxempty) {
+			c = csr32r(ctlr, Rrhr);
+
+			if(lsr & LSRrxover) { uart->oerr++; break; }
+			if(lsr & LSRrxparity) { uart->perr++; break; }
+			if(lsr & LSRrxframe) { uart->ferr++; break; }
+
+			uartrecv(uart, c);
+		}
+
+		break;
+	}
+
+	iunlock(ctlr);
+}
+
+static void
+n900uartenable(Uart *uart, int ie)
+{
+	Ctlr *ctlr;
+
+	ctlr = uart->regs;
+	ilock(ctlr);
+
+	csr32w(ctlr, Rsysc, SCreset);
+	while(!(csr32r(ctlr, Rsyss) & SSreset))
+		;
+
+	csr32w(ctlr, Rfcr, FCRen);
+	if(ie) {
+		if(!ctlr->ie) {
+			intrenable(ctlr->irq, n900uartintr, uart, 0, uart->name);
+			ctlr->ie = 1;
+		}
+
+		csr32w(ctlr, Rier, IErhr);
+	}
+
+	iunlock(ctlr);
+}
+
+static void
+n900uartdisable(Uart *uart)
+{
+	Ctlr *ctlr;
+
+	ctlr = uart->regs;
+
+	ilock(ctlr);
+	csr32w(ctlr, Rier, 0);
+	if(ctlr->ie) {
+		intrdisable(ctlr->irq, n900uartintr, uart, 0, uart->name);
+		ctlr->ie = 0;
+	}
+
+	iunlock(ctlr);
+}
+
+static void
+n900uartkick(Uart *uart)
+{
+	Ctlr *ctlr;
+	int i;
+
+	ctlr = uart->regs;
+	if(uart->blocked)
+		return;
+
+	for(i = 0; i < 128; i++) {
+		if(csr32r(ctlr, Rlsr) & LSRtxempty) {
+			if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
+				break;
+
+			csr32w(ctlr, Rthr, *uart->op++);
+		}
+	}
+}
+
+static int
+n900uartgetc(Uart *uart)
+{
+	Ctlr *ctlr;
+
+	ctlr = uart->regs;
+	while(!(csr32r(ctlr, Rlsr) & LSRrxempty))
+		;
+
+	return csr32r(ctlr, Rrhr);
+}
+
+static void
+n900uartputc(Uart *uart, int c)
+{
+	Ctlr *ctlr;
+
+	ctlr = uart->regs;
+	while(!(csr32r(ctlr, Rlsr) & LSRtxempty))
+		;
+
+	csr32w(ctlr, Rthr, c);
+}
+
+static void n900uartnop(Uart *, int) {}
+static int n900uartnope(Uart *, int) { return -1; }
+
+PhysUart n900physuart = {
+	.name = "n900",
+
+	.pnp = n900uartpnp,
+	.enable = n900uartenable,
+	.disable = n900uartdisable,
+	.kick = n900uartkick,
+	.status = n900uartstatus,
+	.getc = n900uartgetc,
+	.putc = n900uartputc,
+
+	.dobreak = n900uartnop,
+	.baud = n900uartnope,
+	.bits = n900uartnope,
+	.stop = n900uartnope,
+	.parity = n900uartnope,
+	.modemctl = n900uartnop,
+	.rts = n900uartnop,
+	.dtr = n900uartnop,
+	.fifo = n900uartnop,
+	.power = n900uartnop,
+};
+
+void
+uartinit(void)
+{
+	consuart = &n900uart[2];
+	consuart->console = 1;
+	uartputs(kmesg.buf, kmesg.n);
+}
--- a/timer.c
+++ /dev/null
@@ -1,172 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-
-enum {
-	Rrev		= 0x00,
-	Rsyscfg		= 0x10,
-		Cidle		= 1<<0,
-		Creset		= 1<<1,
-	Rsysstat	= 0x14,
-		Sreset		= 1<<0,
-	Risr		= 0x18,
-	Rier		= 0x1c,
-		Imatch		= 1<<0,
-		Ioverflow	= 1<<1,
-		Icapture	= 1<<2,
-	Rclr		= 0x24,
-		CLst		= 1<<0,
-		CLar		= 1<<1,
-		CLtgovf		= 1<<10,
-		CLtgmatch	= 1<<11,
-	Rcrr		= 0x28,
-	Rldr		= 0x2c,
-};
-
-typedef union Counter Counter;
-typedef struct Ctlr Ctlr;
-
-union Counter {
-	uvlong cnt;
-	struct {
-		ulong cntlo;
-		ulong cnthi;
-	};
-};
-
-struct Ctlr {
-	Lock;
-	Counter;
-
-	u32int *io;
-};
-
-static Ctlr timers[] = {
-	{ .io = (u32int*) PHYSTIMER1 }, /* for cycles */
-	{ .io = (u32int*) PHYSTIMER2 }, /* for interrupts */
-};
-
-#define csr32r(c, r) ((c)->io[(r)/4])
-#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
-
-static void
-timerreset(Ctlr *ctlr)
-{
-	int i;
-	int cfg;
-
-	cfg = csr32r(ctlr, Rsyscfg);
-	cfg |= Creset;
-	cfg &= ~Cidle;
-
-	ilock(ctlr);
-	csr32w(ctlr, Rsyscfg, cfg);
-	for(i = 40000; i > 0; i++) {
-		if(csr32r(ctlr, Rsysstat) & Sreset)
-			break;
-	}
-
-	if(i == 0)
-		panic("clock reset failed");
-
-	iunlock(ctlr);
-}
-
-static void
-timerstartcycles(Ctlr *ctlr)
-{
-	timerreset(ctlr);
-
-	/* configure this timer for measuring cycles */
-	ilock(ctlr);
-	csr32w(ctlr, Rldr, 0);
-	csr32w(ctlr, Rclr, CLst | CLar);
-	iunlock(ctlr);
-}
-
-static void
-timerstartintr(Ctlr *ctlr, ulong t)
-{
-	timerreset(ctlr);
-
-	/* configure this timer for periodic interrupts */
-	ilock(ctlr);
-	csr32w(ctlr, Rier, Ioverflow);
-	csr32w(ctlr, Rldr, -t);
-	csr32w(ctlr, Rcrr, -t);
-	csr32w(ctlr, Rclr, CLst | CLar);
-	iunlock(ctlr);
-}
-
-static void
-timerinterrupt(Ureg *u, void *arg)
-{
-	Ctlr *ctlr = arg;
-	csr32w(ctlr, Risr, Ioverflow);
-
-	timerintr(u, 0);
-}
-
-void
-timerinit(void)
-{
-	intrenable(IRQTIMER2, timerinterrupt, &timers[1], BUSUNKNOWN, "timer");
-
-	timerstartcycles(&timers[0]);
-	timerstartintr(&timers[1], 32);
-}
-
-uvlong
-fastticks(uvlong *hz)
-{
-	Counter c;
-	Ctlr *ctlr;
-
-	/* FIXME: this has poor precision, but qemu has no cycle counter */
-	ctlr = &timers[0];
-	if(hz)
-		*hz = 32*1024;
-
-	ilock(ctlr);
-	c.cnt = ctlr->cnt;
-	c.cntlo = csr32r(ctlr, Rcrr);
-	if(c.cnt < ctlr->cnt)
-		c.cnthi++;
-
-	ctlr->cnt = c.cnt;
-	iunlock(ctlr);
-
-	return ctlr->cnt;
-}
-
-ulong
-µs(void)
-{
-	return fastticks2us(fastticks(nil));
-}
-
-void
-microdelay(int n)
-{
-	ulong now;
-
-	now = µs();
-	while(µs() - now < n)
-		;
-}
-
-void
-delay(int n)
-{
-	while(--n >= 0)
-		microdelay(1000);
-}
-
-void
-timerset(Tval)
-{
-	/* FIXME: ? */
-}
--- a/trap.c
+++ /dev/null
@@ -1,577 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "../port/systab.h"
-
-#include "tos.h"
-#include "ureg.h"
-
-void
-callwithureg(void (*f) (Ureg *))
-{
-	Ureg u;
-
-	u.pc = getcallerpc(&f);
-	u.sp = (uintptr) &f - 4;
-	f(&u);
-}
-
-void
-dumpstackureg(Ureg *ureg)
-{
-	uintptr l, v, i, estack;
-	int x;
-
-	x = 0;
-	x += iprint("ktrace /arm/9n900 %#.8lux %#.8lux %#.8lux <<EOF\n",
-		ureg->pc, ureg->sp, ureg->r14);
-
-	i = 0;
-	if(up)
-		estack = (uintptr)up;
-	else
-		estack = (uintptr)m+MACHSZ;
-
-	x += iprint("estackx %p\n", estack);
-	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)) {
-		v = *(uintptr*)l;
-		if((KTZERO < v && v < (uintptr)etext) || estack-l < 32) {
-			x += iprint("%.8p=%.8p ", l, v);
-			i++;
-		}
-
-		if(i == 4) {
-			i = 0;
-			x += iprint("\n");
-		}
-	}
-
-	if(i)
-		iprint("\n");
-	iprint("EOF\n");
-}
-
-void
-dumpstack(void)
-{
-	callwithureg(dumpstackureg);
-}
-
-void
-dumpureg(Ureg *ureg)
-{
-	if(up)
-		iprint("cpu%d: registers for %s %lud\n", m->machno, up->text, up->pid);
-	else
-		iprint("cpu%d: registers for kernel\n", m->machno);
-
-	iprint("r0 %#.8lux\tr1 %#.8lux\tr2 %#.8lux\tr3 %#.8lux\n", ureg->r0, ureg->r1, ureg->r2, ureg->r3);
-	iprint("r4 %#.8lux\tr5 %#.8lux\tr6 %#.8lux\tr7 %#.8lux\n", ureg->r4, ureg->r5, ureg->r6, ureg->r7);
-	iprint("r8 %#.8lux\tr9 %#.8lux\tr10 %#.8lux\tr11 %#.8lux\n", ureg->r8, ureg->r9, ureg->r10, ureg->r11);
-	iprint("r12 %#.8lux\tr13 %#.8lux\tr14 %#.8lux\tr15 %#.8lux\n", ureg->r12, ureg->r13, ureg->r14, ureg->pc);
-}
-
-
-uintptr
-userpc(void)
-{
-	return ((Ureg*)up->dbgreg)->pc;
-}
-
-uintptr
-dbgpc(Proc *)
-{
-	if(up->dbgreg)
-		return userpc();
-
-	return 0;
-}
-
-void
-procsetup(Proc *p)
-{
-	p->fpstate = FPinit;
-	fpoff();
-}
-
-void
-procsave(Proc *p)
-{
-	if(p->fpstate == FPactive) {
-		if(p->state == Moribund)
-			fpclear();
-		else
-			fpsave(p->fpsave);
-		p->fpstate = FPinactive;
-	}
-}
-
-void
-procrestore(Proc *)
-{
-}
-
-void
-procfork(Proc *p)
-{
-	ulong s;
-
-	s = splhi();
-	switch(up->fpstate & ~FPillegal) {
-	case FPactive:
-		fpsave(up->fpsave);
-		up->fpstate = FPinactive;
-	case FPinactive:
-		memmove(p->fpsave, up->fpsave, sizeof(FPsave));
-		p->fpstate = FPinactive;
-	}
-
-	splx(s);
-}
-
-void
-kprocchild(Proc *p, void (*entry)(void))
-{
-	p->sched.pc = (uintptr) entry;
-	p->sched.sp = (uintptr) p;
-}
-
-void
-forkchild(Proc *p, Ureg *ureg)
-{
-	Ureg *cureg;
-
-	p->sched.sp = (uintptr) p - sizeof(Ureg);
-	p->sched.pc = (uintptr) forkret;
-
-	cureg = (Ureg*) p->sched.sp;
-	memmove(cureg, ureg, sizeof(Ureg));
-	cureg->r0 = 0;
-}
-
-uintptr
-execregs(uintptr entry, ulong ssize, ulong nargs)
-{
-	ulong *sp;
-	Ureg *ureg;
-
-	sp = (ulong*)(USTKTOP - ssize); *--sp = nargs;
-	ureg = up->dbgreg;
-	ureg->sp = (uintptr) sp;
-	ureg->pc = entry;
-	ureg->r14 = 0;
-
-	return USTKTOP-sizeof(Tos);
-}
-
-void
-setkernur(Ureg *ureg, Proc *p)
-{
-	ureg->pc = p->sched.pc;
-	ureg->sp = p->sched.sp+4;
-	ureg->r14 = (uintptr) sched;
-}
-
-void
-setregisters(Ureg *ureg, char *pureg, char *uva, int n)
-{
-	uvlong v;
-
-	v = ureg->psr;
-	memmove(pureg, uva, n);
-	ureg->psr &= ~(PsrMask|PsrDfiq|PsrDirq);
-	ureg->psr |= v & (PsrMask|PsrDfiq|PsrDirq);
-}
-
-void
-evenaddr(uintptr addr)
-{
-	if(addr & 3) {
-		postnote(up, 1, "sys: odd address", NDebug);
-		error(Ebadarg);
-	}
-}
-
-int
-notify(Ureg *ureg)
-{
-	ulong s, sp;
-	char *msg;
-
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
-	
-	if(up->fpstate == FPactive) {
-		fpsave(up->fpsave);
-		up->fpstate = FPinactive;
-	}
-	up->fpstate |= FPillegal;
-
-	s = spllo();
-	qlock(&up->debug);
-	msg = popnote(ureg);
-	if(msg == nil) {
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
-
-	sp = ureg->sp;
-	sp -= 256;
-	sp -= sizeof(Ureg);
-
-	if(!okaddr((uintptr)up->notify, 1, 0)
-	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
-	|| ((uintptr) up->notify & 3) != 0
-	|| (sp & 3) != 0) {
-		qunlock(&up->debug);
-		pprint("suicide: bad address in notify\n");
-		pexit("Suicide", 0);
-	}
-
-	memmove((Ureg*)sp, ureg, sizeof(Ureg));
-	*(Ureg**)(sp-BY2WD) = up->ureg;
-	up->ureg = (void*)sp;
-	sp -= BY2WD+ERRMAX;
-	memmove((char*)sp, msg, ERRMAX);
-	sp -= 3*BY2WD;
-	*(uintptr*)(sp+2*BY2WD) = sp+3*BY2WD;
-	*(uintptr*)(sp+1*BY2WD) = (uintptr)up->ureg;
-	ureg->r0 = (uintptr) up->ureg;
-	ureg->sp = sp;
-	ureg->pc = (uintptr) up->notify;
-	ureg->r14 = 0;
-
-	qunlock(&up->debug);
-	splx(s);
-	return 1;
-}
-
-void
-noted(Ureg *ureg, ulong arg0)
-{
-	Ureg *nureg;
-	ulong oureg, sp;
-
-	qlock(&up->debug);
-	if(arg0 != NRSTR && !up->notified) {
-		qunlock(&up->debug);
-		iprint("called to noted when not notified\n");
-		pexit("Suicide", 0);
-	}
-
-	up->notified = 0;
-	up->fpstate &= ~FPillegal;
-	nureg = up->ureg;
-	oureg = (ulong) nureg;
-	if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 3) != 0) {
-		qunlock(&up->debug);
-		pprint("bad ureg in noted or call to noted when not notifed\n");
-		pexit("Suicide", 0);
-	}
-
-	nureg->psr &= PsrMask|PsrDfiq|PsrDirq;
-	nureg->psr |= (ureg->psr & ~(PsrMask|PsrDfiq|PsrDirq));
-
-	memmove(ureg, nureg, sizeof(Ureg));
-	switch(arg0) {
-	case NCONT:
-	case NRSTR:
-		if(!okaddr(nureg->pc, BY2WD, 0) || (nureg->pc & 3) != 0
-		|| !okaddr(nureg->sp, BY2WD, 0) || (nureg->sp & 3) != 0) {
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-
-		up->ureg = (Ureg *) (*(ulong*) (oureg - BY2WD));
-		qunlock(&up->debug);
-		break;
-
-	case NSAVE:
-		if(!okaddr(nureg->pc, BY2WD, 0) || (nureg->pc & 3) != 0
-		|| !okaddr(nureg->sp, BY2WD, 0) || (nureg->sp & 3) != 0) {
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-
-		qunlock(&up->debug);
-		sp = oureg - 4 * BY2WD - ERRMAX;
-		splhi();
-		ureg->sp = sp;
-		ureg->r0 = (uintptr) oureg;
-		((ulong*) sp)[1] = oureg;
-		((ulong*) sp)[0] = 0;
-		break;
-
-	default:
-		up->lastnote->flag = NDebug;
-		/* wet floor */
-
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-
-		pexit(up->lastnote->msg, up->lastnote->flag != NDebug);
-		break;
-	}
-}
-
-void
-trapinit(void)
-{
-	extern ulong vectors[];
-
-	/* install stack pointer for other exception modes */
-	setR13(PsrMfiq, m->save);
-	setR13(PsrMirq, m->save);
-	setR13(PsrMiabt, m->save);
-	setR13(PsrMund, m->save);
-	setR13(PsrMsys, m->save);
-
-	/* install vectors and vtable to MACHVEC because vectors must be
-	 * aligned on a 128 byte boundary */
-	memmove((ulong*)MACHVEC(m->machno), vectors, 64 * 4);
-
-	/* set vectors base address */
-	setvectors(MACHVEC(m->machno));
-}
-
-static void
-trapfpu(void)
-{
-	int s;
-
-	if((up->fpstate & FPillegal) != 0) {
-		postnote(up, 1, "sys: floating point in note handler", NDebug);
-		return;
-	}
-
-	switch(up->fpstate) {
-	case FPinit:
-		s = splhi();
-		fpinit(); up->fpstate = FPactive;
-		splx(s);
-		break;
-
-	case FPinactive:
-		s = splhi();
-		fprestore(up->fpsave); up->fpstate = FPactive;
-		splx(s);
-		break;
-
-	case FPactive:
-		postnote(up, 1, "sys: floating point error", NDebug);
-		break;
-	}
-}
-
-static void
-traparm(Ureg *ureg, ulong fsr, uintptr far)
-{
-	int user;
-	int read;
-	int syscall;
-
-	static char buf[ERRMAX];
-
-	read = (fsr & (1<<11)) == 0;
-	user = userureg(ureg);
-	if(!user) {
-		if(far >= USTKTOP)
-			panic("kernel fault: bad address pc=%#.8lux far=%#.8lux fsr=%#.8lux",
-				ureg->pc, far, fsr);
-		if(up == nil)
-			panic("kernel fault: no user process pc=%#.8lux far=%#.8lux fsr=%#.8lux",
-				ureg->pc, far, fsr);
-	}
-
-	if(up == nil) {
-		panic("user fault: up=nil pc=%#.8lux far=%#.8lux fsr=%#.8lux",
-			ureg->pc, far, fsr);
-	}
-
-	syscall = up->insyscall; up->insyscall = 1;
-	switch(fsr & 0x1f) {
-	case 0x03: /* l1 access flag fault */
-	case 0x05: /* l1 translation fault */
-	case 0x06: /* l2 access flag fault */
-	case 0x07: /* l2 translation fault */
-	case 0x09: /* l1 domain fault */
-	case 0x0b: /* l2 domain fault */
-	case 0x0d: /* l1 permission fault */
-	case 0x0f: /* l2 permission fault */
-		if(fault(far, ureg->pc, read) == 0)
-			break;
-
-	default:
-		if(!user)
-			panic("kernel fault: pc=%#.8lux far=%#.8lux fsr=%#.8lux",
-				ureg->pc, far, fsr);
-
-		dumpureg(ureg);
-		dumpstackureg(ureg);
-		snprint(buf, sizeof(buf), "sys: trap: fault %s far=%#.8lux fsr=%#.8lux",
-			read ? "read" : "write", far, fsr);
-		postnote(up, 1, buf, NDebug);
-	}
-
-	up->insyscall = syscall;
-}
-
-void
-trap(Ureg *ureg)
-{
-	int user;
-	u32int op, cp;
-
-	user = kenter(ureg);
-	switch(ureg->type) {
-	case PsrMfiq:
-	case PsrMirq:
-		ureg->pc -= 4;
-		intr(ureg);
-		break;
-
-	case PsrMiabt:
-		ureg->pc -= 4;
-		traparm(ureg, getifsr(), getifar());
-		break;
-
-	case PsrMdabt:
-		ureg->pc -= 8;
-		traparm(ureg, getdfsr(), getdfar());
-		break;
-
-	case PsrMund:
-		ureg->pc -= 4;
-		if(user) {
-			spllo();
-			if(okaddr(ureg->pc, 4, 0)) {
-				op = *(u32int*)ureg->pc;
-				if((op & 0x0f000000) == 0x0e000000 || (op & 0x0e000000) == 0x0c000000) {
-					cp = op >> 8 & 15;
-					if(cp == 10 || cp == 11) {
-						trapfpu();
-						break;
-					}
-				}
-			}
-				
-			postnote(up, 1, "sys: trap: invalid opcode", NDebug);
-			break;
-		}
-
-		panic("invalid opcode at pc=%#.8lux lr=%#.8lux", ureg->pc, ureg->r14);
-		break;
-
-	default:
-		panic("unknown trap at pc=%#.8lux lr=%#.8lux", ureg->pc, ureg->r14);
-		break;
-	}
-
-	splhi();
-	if(user) {
-		if(up->procctl || up->nnote)
-			notify(ureg);
-
-		kexit(ureg);
-	}
-}
-
-void
-syscall(Ureg *ureg)
-{
-	char *e;
-	uintptr sp;
-	long ret;
-	int i, s;
-	ulong scallnr;
-	vlong startns, stopns;
-
-	if(!kenter(ureg))
-		panic("syscall: from kernel: pc=%#.8lux", ureg->pc);
-
-	m->syscall++;
-	up->insyscall = 1;
-	up->pc = ureg->pc;
-
-	scallnr = up->scallnr = ureg->r0;
-	sp = ureg->sp;
-
-	spllo();
-
-	up->nerrlab = 0;
-	ret = -1;
-	if(!waserror()) {
-		if(scallnr >= nsyscall) {
-			pprint("bad sys call number %lux pc %#lux", scallnr, ureg->pc);
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-
-		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD)) {
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-			evenaddr(sp);
-		}
-
-		up->s = *((Sargs*)(sp + BY2WD));
-		up->psstate = sysctab[scallnr];
-		if (up->procctl == Proc_tracesyscall) {
-			syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
-			s = splhi();
-			up->procctl = Proc_stopme;
-			procctl();
-			splx(s);
-			startns = todget(nil);
-		}
-
-		ret = systab[scallnr]((va_list)up->s.args);
-		poperror();
-	} else {
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
-	}
-
-	if(up->nerrlab) {
-		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
-		for (i = 0; i < NERR; i++)
-			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
-
-		panic("error stack");
-	}
-
-	ureg->r0 = ret;
-	if(up->procctl == Proc_tracesyscall) {
-		stopns = todget(nil);
-		sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
-		s = splhi();
-		up->procctl = Proc_stopme;
-		procctl();
-		splx(s);
-	}
-
-	up->insyscall = 0;
-	up->psstate = 0;
-	if(scallnr == NOTED)
-		noted(ureg, *((ulong *)up->s.args));
-
-	if(scallnr != RFORK && (up->procctl || up->nnote)) {
-		splhi();
-		notify(ureg);
-	}
-
-	if(up->delaysched)
-		sched();
-
-	kexit(ureg);
-	splhi();
-}
--- a/uartn900.c
+++ /dev/null
@@ -1,268 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-
-enum {
-	Rdll	= 0x00,
-	Rrhr	= 0x00,
-	Rthr	= 0x00,
-	Rdlh	= 0x04,
-	Rier	= 0x04,
-		IErhr	= 1 << 0,
-		IEthr	= 1 << 1,
-		IEls	= 1 << 2,
-		IEms	= 1 << 3,
-	Riir	= 0x08,
-		Ipending = 1 << 0,
-		Imodem	= 0x00,
-		Ithr	= 0x01,
-		Irhr	= 0x02,
-		Ils		= 0x03,
-		Irxt	= 0x06,
-		Ixoff	= 0x08,
-		Icts	= 0x10,
-		Imask 	= 0x1f,
-	Rfcr	= 0x08,
-		FCRen		= 1 << 0,
-	Refr	= 0x08,
-	Rlcr	= 0x0c,
-	Rmcr	= 0x10,
-	Rxon1	= 0x10,
-	Rlsr	= 0x14,
-		LSRrxempty	= 1 << 0,
-		LSRrxover	= 1 << 1,
-		LSRrxparity	= 1 << 2,
-		LSRrxframe	= 1 << 3,
-		LSRrxbreak	= 1 << 4,
-		LSRtxempty	= 1 << 5,
-		LSRtxshift	= 1 << 6,
-		LSRrxstat	= 1 << 7,
-	Rxon2	= 0x14,
-	Rmsr	= 0x18,
-	Rtcr	= 0x18,
-	Rxoff1	= 0x18,
-	Rspr	= 0x1c,
-	Rtlr	= 0x1c,
-	Rxoff2	= 0x1c,
-	Rmdr1	= 0x20,
-	Rmdr2	= 0x24,
-	Rsysc	= 0x54,
-		SCreset		= 1 << 1,
-	Rsyss	= 0x58,
-		SSreset		= 1 << 0,
-};
-
-#define csr32r(c, r) ((c)->io[(r)/4])
-#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))
-
-typedef struct Ctlr Ctlr;
-struct Ctlr {
-	Lock;
-
-	u32int *io;
-	ulong irq;
-
-	int ie;
-};
-
-extern PhysUart n900physuart;
-
-static Ctlr ctlr[] = {
-	{ .io = (u32int*) PHYSUART1, .irq = IRQUART1, },
-	{ .io = (u32int*) PHYSUART2, .irq = IRQUART2, },
-	{ .io = (u32int*) PHYSUART3, .irq = IRQUART3, },
-};
-
-static Uart n900uart[] = {
-	{
-		.regs = &ctlr[0],
-		.name = "uart1",
-		.freq = 48000000,
-		.phys = &n900physuart,
-		.next = &n900uart[1],
-	},
-	{
-		.regs = &ctlr[1],
-		.name = "uart2",
-		.freq = 48000000,
-		.phys = &n900physuart,
-		.next = &n900uart[2],
-	},
-	{
-		.regs = &ctlr[2],
-		.name = "uart3",
-		.freq = 48000000,
-		.phys = &n900physuart,
-		.next = nil,
-	},
-};
-
-static Uart *
-n900uartpnp(void)
-{
-	return n900uart;
-}
-
-static long
-n900uartstatus(Uart *, void *, long, long)
-{
-	return 0;
-}
-
-static void
-n900uartintr(Ureg *, void *arg)
-{
-	Uart *uart;
-	Ctlr *ctlr;
-	int lsr;
-	char c;
-
-	uart = arg;
-	ctlr = uart->regs;
-
-	ilock(ctlr);
-	switch((csr32r(ctlr, Riir) >> 1) & Imask) {
-	case Ithr:
-		uartkick(uart);
-		break;
-
-	case Irhr:
-		while((lsr = csr32r(ctlr, Rlsr)) & LSRrxempty) {
-			c = csr32r(ctlr, Rrhr);
-
-			if(lsr & LSRrxover) { uart->oerr++; break; }
-			if(lsr & LSRrxparity) { uart->perr++; break; }
-			if(lsr & LSRrxframe) { uart->ferr++; break; }
-
-			uartrecv(uart, c);
-		}
-
-		break;
-	}
-
-	iunlock(ctlr);
-}
-
-static void
-n900uartenable(Uart *uart, int ie)
-{
-	Ctlr *ctlr;
-
-	ctlr = uart->regs;
-	ilock(ctlr);
-
-	csr32w(ctlr, Rsysc, SCreset);
-	while(!(csr32r(ctlr, Rsyss) & SSreset))
-		;
-
-	csr32w(ctlr, Rfcr, FCRen);
-	if(ie) {
-		if(!ctlr->ie) {
-			intrenable(ctlr->irq, n900uartintr, uart, 0, uart->name);
-			ctlr->ie = 1;
-		}
-
-		csr32w(ctlr, Rier, IErhr);
-	}
-
-	iunlock(ctlr);
-}
-
-static void
-n900uartdisable(Uart *uart)
-{
-	Ctlr *ctlr;
-
-	ctlr = uart->regs;
-
-	ilock(ctlr);
-	csr32w(ctlr, Rier, 0);
-	if(ctlr->ie) {
-		intrdisable(ctlr->irq, n900uartintr, uart, 0, uart->name);
-		ctlr->ie = 0;
-	}
-
-	iunlock(ctlr);
-}
-
-static void
-n900uartkick(Uart *uart)
-{
-	Ctlr *ctlr;
-	int i;
-
-	ctlr = uart->regs;
-	if(uart->blocked)
-		return;
-
-	for(i = 0; i < 128; i++) {
-		if(csr32r(ctlr, Rlsr) & LSRtxempty) {
-			if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
-				break;
-
-			csr32w(ctlr, Rthr, *uart->op++);
-		}
-	}
-}
-
-static int
-n900uartgetc(Uart *uart)
-{
-	Ctlr *ctlr;
-
-	ctlr = uart->regs;
-	while(!(csr32r(ctlr, Rlsr) & LSRrxempty))
-		;
-
-	return csr32r(ctlr, Rrhr);
-}
-
-static void
-n900uartputc(Uart *uart, int c)
-{
-	Ctlr *ctlr;
-
-	ctlr = uart->regs;
-	while(!(csr32r(ctlr, Rlsr) & LSRtxempty))
-		;
-
-	csr32w(ctlr, Rthr, c);
-}
-
-static void n900uartnop(Uart *, int) {}
-static int n900uartnope(Uart *, int) { return -1; }
-
-PhysUart n900physuart = {
-	.name = "n900",
-
-	.pnp = n900uartpnp,
-	.enable = n900uartenable,
-	.disable = n900uartdisable,
-	.kick = n900uartkick,
-	.status = n900uartstatus,
-	.getc = n900uartgetc,
-	.putc = n900uartputc,
-
-	.dobreak = n900uartnop,
-	.baud = n900uartnope,
-	.bits = n900uartnope,
-	.stop = n900uartnope,
-	.parity = n900uartnope,
-	.modemctl = n900uartnop,
-	.rts = n900uartnop,
-	.dtr = n900uartnop,
-	.fifo = n900uartnop,
-	.power = n900uartnop,
-};
-
-void
-uartinit(void)
-{
-	consuart = &n900uart[2];
-	consuart->console = 1;
-	uartputs(kmesg.buf, kmesg.n);
-}