summaryrefslogtreecommitdiff
path: root/sys/src/9/alphapc
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/alphapc
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/alphapc')
-rwxr-xr-xsys/src/9/alphapc/apc66
-rwxr-xr-xsys/src/9/alphapc/apccpu60
-rwxr-xr-xsys/src/9/alphapc/arch164.c363
-rwxr-xr-xsys/src/9/alphapc/audio.h16
-rwxr-xr-xsys/src/9/alphapc/axp.h71
-rwxr-xr-xsys/src/9/alphapc/cga.c113
-rwxr-xr-xsys/src/9/alphapc/clock.c112
-rwxr-xr-xsys/src/9/alphapc/cycintr.c27
-rwxr-xr-xsys/src/9/alphapc/dat.h266
-rwxr-xr-xsys/src/9/alphapc/devarch.c533
-rwxr-xr-xsys/src/9/alphapc/devvga.c407
-rwxr-xr-xsys/src/9/alphapc/dma.c331
-rwxr-xr-xsys/src/9/alphapc/etherif.h41
-rwxr-xr-xsys/src/9/alphapc/faultalpha.c62
-rwxr-xr-xsys/src/9/alphapc/fdc37c93x.c66
-rwxr-xr-xsys/src/9/alphapc/floppy.h181
-rwxr-xr-xsys/src/9/alphapc/fns.h128
-rwxr-xr-xsys/src/9/alphapc/fptrap.c46
-rwxr-xr-xsys/src/9/alphapc/i8259.c152
-rwxr-xr-xsys/src/9/alphapc/initcode47
-rwxr-xr-xsys/src/9/alphapc/io.h176
-rwxr-xr-xsys/src/9/alphapc/kbd.c456
-rwxr-xr-xsys/src/9/alphapc/l.s457
-rwxr-xr-xsys/src/9/alphapc/main.c703
-rwxr-xr-xsys/src/9/alphapc/mem.h89
-rwxr-xr-xsys/src/9/alphapc/memmove.s197
-rwxr-xr-xsys/src/9/alphapc/memset.s61
-rwxr-xr-xsys/src/9/alphapc/mkfile109
-rwxr-xr-xsys/src/9/alphapc/mmu.c299
-rwxr-xr-xsys/src/9/alphapc/osf1pal.h78
-rwxr-xr-xsys/src/9/alphapc/pci.c412
-rwxr-xr-xsys/src/9/alphapc/screen.h171
-rwxr-xr-xsys/src/9/alphapc/sd53c8xx.c2261
-rwxr-xr-xsys/src/9/alphapc/sd53c8xx.i805
-rwxr-xr-xsys/src/9/alphapc/sio.c18
-rwxr-xr-xsys/src/9/alphapc/trap.c916
36 files changed, 10296 insertions, 0 deletions
diff --git a/sys/src/9/alphapc/apc b/sys/src/9/alphapc/apc
new file mode 100755
index 000000000..c91795f49
--- /dev/null
+++ b/sys/src/9/alphapc/apc
@@ -0,0 +1,66 @@
+dev
+ root
+ cons
+ arch
+ pnp pci
+ env
+ pipe
+ proc
+ mnt
+ srv
+ dup
+# rtc
+ ssl
+ cap
+ kprof
+# loopback
+
+ ether netif
+ ip arp chandial inferno ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum
+
+ draw screen vga vgax
+ mouse mouse
+ vga
+
+ sd
+ floppy dma
+
+ audio dma
+ uart
+
+link
+ ether2114x pci
+ ethermedium
+
+misc
+ arch164
+
+ sdata pci sdscsi
+# sd53c8xx pci sdscsi
+
+ uarti8250
+
+ vgargb524 =cur
+ vgas3 +cur
+ vgas3 +cur vgasavage
+ vgatvp3026 =cur
+
+ip
+ tcp
+ udp
+ ipifc
+ icmp
+ icmp6
+
+port
+ int cpuserver = 0;
+
+boot
+ tcp
+
+bootdir
+ bootapc.out boot
+ /alpha/bin/disk/kfs
+ /alpha/bin/auth/factotum
+ /alpha/bin/ip/ipconfig
+
diff --git a/sys/src/9/alphapc/apccpu b/sys/src/9/alphapc/apccpu
new file mode 100755
index 000000000..f8ed97149
--- /dev/null
+++ b/sys/src/9/alphapc/apccpu
@@ -0,0 +1,60 @@
+dev
+ root
+ cons
+ arch
+ pnp pci
+ env
+ pipe
+ proc
+ mnt
+ srv
+ dup
+# rtc
+ ssl
+ cap
+ kprof
+# loopback
+
+ ether netif
+ ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno
+
+ sd
+ floppy dma
+
+ audio dma
+ uart
+
+link
+ ether2114x pci
+ ethermedium
+ loopbackmedium
+
+misc
+ arch164
+
+ sdata pci sdscsi
+# sd53c8xx pci sdscsi
+
+ uarti8250
+
+ip
+ tcp
+ udp
+ ipifc
+ icmp
+ icmp6
+ gre
+ ipmux
+
+port
+ int cpuserver = 1;
+
+boot cpu
+ tcp
+
+bootdir
+ bootapccpu.out boot
+ /alpha/bin/ip/ipconfig
+ /alpha/bin/auth/factotum
+
+
diff --git a/sys/src/9/alphapc/arch164.c b/sys/src/9/alphapc/arch164.c
new file mode 100755
index 000000000..7860142bc
--- /dev/null
+++ b/sys/src/9/alphapc/arch164.c
@@ -0,0 +1,363 @@
+/*
+ * EB164 and similar
+ * CPU: 21164
+ * Core Logic: 21172 CIA or 21174 PYXIS
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+static ulong *core;
+static ulong *wind;
+
+static ulong windsave[16];
+static ulong coresave[1];
+
+ulong iobase0;
+ulong iobase1;
+#define iobase(p) (iobase0+(p))
+
+static int
+ident(void)
+{
+ return 0; /* bug! */
+}
+
+static uvlong* sgmap;
+
+static void
+sginit(void)
+{
+ ulong pa;
+ uvlong *pte;
+
+ sgmap = xspanalloc(BY2PG, BY2PG, 0);
+ memset(sgmap, 0, BY2PG);
+
+ /*
+ * Prepare scatter-gather map for 0-8MB.
+ */
+ pte = sgmap;
+ for(pa = 0; pa < 8*1024*1024; pa += BY2PG)
+ *pte++ = ((pa>>PGSHIFT)<<1)|1;
+
+ /*
+ * Set up a map for ISA DMA accesses to physical memory.
+ * Addresses presented by an ISA device between ISAWINDOW
+ * and ISAWINDOW+8MB will be translated to between 0 and
+ * 0+8MB of physical memory.
+ */
+ wind[0x400/4] = ISAWINDOW|2|1; /* window base */
+ wind[0x440/4] = 0x00700000; /* window mask */
+ wind[0x480/4] = PADDR(sgmap)>>2; /* <33:10> of sg map */
+
+ wind[0x100/4] = 3; /* invalidate tlb cache */
+}
+
+static void *
+kmapio(ulong space, ulong offset, int size)
+{
+ return kmapv(((uvlong)space<<32LL)|offset, size);
+}
+
+static void
+coreinit(void)
+{
+ int i;
+
+ core = kmapio(0x87, 0x40000000, 0x10000);
+ wind = kmapio(0x87, 0x60000000, 0x1000);
+
+ iobase0 = (ulong)kmapio(0x89, 0, 0x20000);
+
+ /* hae_io = core[0x440/4];
+ iobase1 = (ulong)kmapio(0x89, hae_io, 0x10000); */
+
+ /* save critical parts of hardware memory mapping */
+ for (i = 4; i < 8; i++) {
+ windsave[4*(i-4)+0] = wind[(i*0x100+0x00)/4];
+ windsave[4*(i-4)+1] = wind[(i*0x100+0x40)/4];
+ windsave[4*(i-4)+2] = wind[(i*0x100+0x80)/4];
+ }
+ coresave[0] = core[0x140/4];
+
+ /* disable windows */
+ wind[0x400/4] = 0;
+ wind[0x500/4] = 0;
+ wind[0x600/4] = 0;
+ wind[0x700/4] = 0;
+
+ sginit();
+
+ /*
+ * Set up a map for PCI DMA accesses to physical memory.
+ * Addresses presented by a PCI device between PCIWINDOW
+ * and PCIWINDOW+1GB will be translated to between 0 and
+ * 0+1GB of physical memory.
+ */
+ wind[0x500/4] = PCIWINDOW|1;
+ wind[0x540/4] = 0x3ff00000;
+ wind[0x580/4] = 0;
+
+ /* clear error state */
+ core[0x8200/4] = 0x7ff;
+
+ /* set config: byte/word enable, no monster window, etc. */
+ core[0x140/4] = 0x21;
+
+ /* turn off mcheck on master abort. now we can probe PCI space. */
+ core[0x8280/4] &= ~(1<<7);
+
+ /* set up interrupts. */
+ i8259init();
+ cserve(52, 4); /* enable SIO interrupt */
+}
+
+void
+ciaerror(void)
+{
+ print("cia error 0x%luX\n", core[0x8200/4]);
+}
+
+static void
+corehello(void)
+{
+ print("cpu%d: CIA revision %ld; cnfg %lux cntrl %lux\n",
+ 0, /* BUG */
+ core[0x80/4] & 0x7f, core[0x140/4], core[0x100/4]);
+ print("cpu%d: HAE_IO %lux\n", 0, core[0x440/4]);
+ print("\n");
+}
+
+static void
+coredetach(void)
+{
+ int i;
+
+ for (i = 4; i < 8; i++) {
+ wind[(i*0x100+0x00)/4] = windsave[4*(i-4)+0];
+ wind[(i*0x100+0x40)/4] = windsave[4*(i-4)+1];
+ wind[(i*0x100+0x80)/4] = windsave[4*(i-4)+2];
+ }
+ core[0x140/4] = coresave[0];
+/* for (i = 0; i < 4; i++)
+ if (i != 4)
+ cserve(53, i); /* disable interrupts */
+}
+
+static Lock pcicfgl;
+static ulong pcimap[256];
+
+static void*
+pcicfg2117x(int tbdf, int rno)
+{
+ int space, bus;
+ ulong base;
+
+ bus = BUSBNO(tbdf);
+ lock(&pcicfgl);
+ base = pcimap[bus];
+ if (base == 0) {
+ if(bus)
+ space = 0x8B;
+ else
+ space = 0x8A;
+ pcimap[bus] = base = (ulong)kmapio(space, MKBUS(0, bus, 0, 0), (1<<16));
+ }
+ unlock(&pcicfgl);
+ return (void*)(base + BUSDF(tbdf) + rno);
+}
+
+static void*
+pcimem2117x(int addr, int len)
+{
+ return kmapio(0x88, addr, len);
+}
+
+static int
+intrenable164(Vctl *v)
+{
+ int vec, irq;
+
+ irq = v->irq;
+ if(irq > MaxIrqPIC) {
+ print("intrenable: irq %d out of range\n", v->irq);
+ return -1;
+ }
+ if(BUSTYPE(v->tbdf) == BusPCI) {
+ vec = irq+VectorPCI;
+ cserve(52, irq);
+ }
+ else {
+ vec = irq+VectorPIC;
+ if(i8259enable(irq, v->tbdf, v) == -1)
+ return -1;
+ }
+ return vec;
+}
+
+/*
+ * I have a function pointer in PCArch for every one of these, because on
+ * some Alphas we have to use sparse mode, but on others we can use
+ * MOVB et al. Additionally, the PC164 documentation threatened us
+ * with the lie that the SIO is in region B, but everything else in region A.
+ * This turned out not to be the case. Given the cost of this solution, it
+ * may be better just to use sparse mode for I/O space on all platforms.
+ */
+int
+inb2117x(int port)
+{
+ mb();
+ return *(uchar*)(iobase(port));
+}
+
+ushort
+ins2117x(int port)
+{
+ mb();
+ return *(ushort*)(iobase(port));
+}
+
+ulong
+inl2117x(int port)
+{
+ mb();
+ return *(ulong*)(iobase(port));
+}
+
+void
+outb2117x(int port, int val)
+{
+ mb();
+ *(uchar*)(iobase(port)) = val;
+ mb();
+}
+
+void
+outs2117x(int port, ushort val)
+{
+ mb();
+ *(ushort*)(iobase(port)) = val;
+ mb();
+}
+
+void
+outl2117x(int port, ulong val)
+{
+ mb();
+ *(ulong*)(iobase(port)) = val;
+ mb();
+}
+
+void
+insb2117x(int port, void *buf, int len)
+{
+ int i;
+ uchar *p, *q;
+
+ p = (uchar*)iobase(port);
+ q = buf;
+ for(i = 0; i < len; i++){
+ mb();
+ *q++ = *p;
+ }
+}
+
+void
+inss2117x(int port, void *buf, int len)
+{
+ int i;
+ ushort *p, *q;
+
+ p = (ushort*)iobase(port);
+ q = buf;
+ for(i = 0; i < len; i++){
+ mb();
+ *q++ = *p;
+ }
+}
+
+void
+insl2117x(int port, void *buf, int len)
+{
+ int i;
+ ulong *p, *q;
+
+ p = (ulong*)iobase(port);
+ q = buf;
+ for(i = 0; i < len; i++){
+ mb();
+ *q++ = *p;
+ }
+}
+
+void
+outsb2117x(int port, void *buf, int len)
+{
+ int i;
+ uchar *p, *q;
+
+ p = (uchar*)iobase(port);
+ q = buf;
+ for(i = 0; i < len; i++){
+ mb();
+ *p = *q++;
+ }
+}
+
+void
+outss2117x(int port, void *buf, int len)
+{
+ int i;
+ ushort *p, *q;
+
+ p = (ushort*)iobase(port);
+ q = buf;
+ for(i = 0; i < len; i++){
+ mb();
+ *p = *q++;
+ }
+}
+
+void
+outsl2117x(int port, void *buf, int len)
+{
+ int i;
+ ulong *p, *q;
+
+ p = (ulong*)iobase(port);
+ q = buf;
+ for(i = 0; i < len; i++){
+ mb();
+ *p = *q++;
+ }
+}
+
+PCArch arch164 = {
+ "EB164",
+ ident,
+ coreinit,
+ corehello,
+ coredetach,
+ pcicfg2117x,
+ pcimem2117x,
+ intrenable164,
+ nil,
+ nil,
+
+ inb2117x,
+ ins2117x,
+ inl2117x,
+ outb2117x,
+ outs2117x,
+ outl2117x,
+ insb2117x,
+ inss2117x,
+ insl2117x,
+ outsb2117x,
+ outss2117x,
+ outsl2117x,
+};
diff --git a/sys/src/9/alphapc/audio.h b/sys/src/9/alphapc/audio.h
new file mode 100755
index 000000000..53d5a8afb
--- /dev/null
+++ b/sys/src/9/alphapc/audio.h
@@ -0,0 +1,16 @@
+enum
+{
+ Bufsize = 16*1024, /* 92 ms each */
+ Nbuf = 16, /* 1.5 seconds total */
+ Dma = 5,
+ IrqAUDIO = 5,
+ SBswab = 0,
+};
+
+#define seteisadma(a, b) dmainit(a, Bufsize);
+#define CACHELINESZ 128
+#define UNCACHED(type, v) (type*)((ulong)(v))
+#define dcflush(a, b)
+
+#define Int0vec
+#define setvec(v, f, a) intrenable(v, f, a, BUSUNKNOWN, "audio")
diff --git a/sys/src/9/alphapc/axp.h b/sys/src/9/alphapc/axp.h
new file mode 100755
index 000000000..102a6b66d
--- /dev/null
+++ b/sys/src/9/alphapc/axp.h
@@ -0,0 +1,71 @@
+typedef struct Hwrpb Hwrpb;
+typedef struct Hwcpu Hwcpu;
+typedef struct Hwdsr Hwdsr;
+
+struct Hwrpb
+{
+ uvlong phys;
+ uvlong sign;
+ uvlong rev;
+ uvlong size;
+ uvlong cpu0;
+ uvlong by2pg;
+ uvlong pabits;
+ uvlong maxasn;
+ char ssn[16];
+ uvlong systype;
+ uvlong sysvar;
+ uvlong sysrev;
+ uvlong ifreq;
+ uvlong cfreq;
+ uvlong vptb;
+ uvlong resv;
+ uvlong tbhint;
+ uvlong ncpu;
+ uvlong cpulen;
+ uvlong cpuoff;
+ uvlong nctb;
+ uvlong ctblen;
+ uvlong ctboff;
+ uvlong ccrboff;
+ uvlong memoff;
+ uvlong confoff;
+ uvlong fruoff;
+ uvlong termsaveva;
+ uvlong termsavex;
+ uvlong termrestva;
+ uvlong termrestx;
+ uvlong termresetva;
+ uvlong termresetx;
+ uvlong sysresv;
+ uvlong hardresv;
+ uvlong csum;
+ uvlong rxrdymsk;
+ uvlong txrdymsk;
+ uvlong dsroff; /* rev 6 or higher */
+};
+
+extern Hwrpb* hwrpb;
+
+struct Hwcpu
+{
+ uvlong hwpcb[16];
+ uvlong state;
+ uvlong palmainlen;
+ uvlong palscratchlen;
+ uvlong palmainpa;
+ uvlong palscratchpa;
+ uvlong palrev;
+ uvlong cputype;
+ uvlong cpuvar;
+ uvlong cpurev;
+ uvlong serial[2];
+ /* more crap ... */
+};
+
+struct Hwdsr
+{
+ vlong smm;
+ uvlong lurtoff;
+ uvlong sysnameoff;
+};
diff --git a/sys/src/9/alphapc/cga.c b/sys/src/9/alphapc/cga.c
new file mode 100755
index 000000000..c216617b7
--- /dev/null
+++ b/sys/src/9/alphapc/cga.c
@@ -0,0 +1,113 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "io.h"
+
+enum {
+ Width = 160,
+ Height = 25,
+
+ Attr = 0x4f, /* white on blue */
+};
+
+static ulong cgabase;
+#define CGASCREENBASE ((uchar*)cgabase)
+
+static int cgapos;
+static int screeninitdone;
+static Lock cgascreenlock;
+
+static uchar
+cgaregr(int index)
+{
+ outb(0x3D4, index);
+ return inb(0x3D4+1) & 0xFF;
+}
+
+static void
+cgaregw(int index, int data)
+{
+ outb(0x3D4, index);
+ outb(0x3D4+1, data);
+}
+
+static void
+movecursor(void)
+{
+ cgaregw(0x0E, (cgapos/2>>8) & 0xFF);
+ cgaregw(0x0F, cgapos/2 & 0xFF);
+ CGASCREENBASE[cgapos+1] = Attr;
+}
+
+static void
+cgascreenputc(int c)
+{
+ int i;
+
+ if(c == '\n'){
+ cgapos = cgapos/Width;
+ cgapos = (cgapos+1)*Width;
+ }
+ else if(c == '\t'){
+ i = 8 - ((cgapos/2)&7);
+ while(i-->0)
+ cgascreenputc(' ');
+ }
+ else if(c == '\b'){
+ if(cgapos >= 2)
+ cgapos -= 2;
+ cgascreenputc(' ');
+ cgapos -= 2;
+ }
+ else{
+ CGASCREENBASE[cgapos++] = c;
+ CGASCREENBASE[cgapos++] = Attr;
+ }
+ if(cgapos >= Width*Height){
+ memmove(CGASCREENBASE, &CGASCREENBASE[Width], Width*(Height-1));
+ for (i = Width*(Height-1); i < Width*Height;) {
+ CGASCREENBASE[i++] = 0x20;
+ CGASCREENBASE[i++] = Attr;
+ }
+ cgapos = Width*(Height-1);
+ }
+ movecursor();
+}
+
+void
+screeninit(void)
+{
+ cgabase = (ulong)arch->pcimem(0xB8000, 0x8000);
+
+ cgapos = cgaregr(0x0E)<<8;
+ cgapos |= cgaregr(0x0F);
+ cgapos *= 2;
+ screeninitdone = 1;
+}
+
+static void
+cgascreenputs(char* s, int n)
+{
+ if(!screeninitdone)
+ return;
+ if(!islo()){
+ /*
+ * Don't deadlock trying to
+ * print in an interrupt.
+ */
+ if(!canlock(&cgascreenlock))
+ return;
+ }
+ else
+ lock(&cgascreenlock);
+
+ while(n-- > 0)
+ cgascreenputc(*s++);
+
+ unlock(&cgascreenlock);
+}
+
+void (*screenputs)(char*, int) = cgascreenputs;
diff --git a/sys/src/9/alphapc/clock.c b/sys/src/9/alphapc/clock.c
new file mode 100755
index 000000000..1300e9338
--- /dev/null
+++ b/sys/src/9/alphapc/clock.c
@@ -0,0 +1,112 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "axp.h"
+#include "ureg.h"
+
+void
+clockinit(void)
+{
+}
+
+uvlong
+cycletimer(void)
+{
+ ulong pcc;
+ vlong delta;
+
+ pcc = rpcc(nil) & 0xFFFFFFFF;
+ if(m->cpuhz == 0){
+ /*
+ * pcclast is needed to detect wraparound of
+ * the cycle timer which is only 32-bits.
+ * m->cpuhz is set from the info passed from
+ * the firmware.
+ * This could be in clockinit if can
+ * guarantee no wraparound between then and now.
+ *
+ * All the clock stuff needs work.
+ */
+ m->cpuhz = hwrpb->cfreq;
+ m->pcclast = pcc;
+ }
+ delta = pcc - m->pcclast;
+ if(delta < 0)
+ delta += 0x100000000LL;
+ m->pcclast = pcc;
+ m->fastclock += delta;
+
+ return MACHP(0)->fastclock;
+}
+
+uvlong
+fastticks(uvlong* hz)
+{
+ uvlong ticks;
+ int x;
+
+ x = splhi();
+ ticks = cycletimer();
+ splx(x);
+
+ if(hz)
+ *hz = m->cpuhz;
+
+ return ticks;
+}
+
+ulong
+µs(void)
+{
+ return fastticks2us(cycletimer());
+}
+
+/*
+ * performance measurement ticks. must be low overhead.
+ * doesn't have to count over a second.
+ */
+ulong
+perfticks(void)
+{
+ return rpcc(nil);
+}
+
+void
+timerset(Tval)
+{
+}
+
+void
+microdelay(int us)
+{
+ uvlong eot;
+
+ eot = fastticks(nil) + (m->cpuhz/1000000)*us;
+ while(fastticks(nil) < eot)
+ ;
+}
+
+void
+delay(int millisecs)
+{
+ microdelay(millisecs*1000);
+}
+
+void
+clock(Ureg *ureg)
+{
+ static int count;
+
+ cycletimer();
+
+ /* HZ == 100, timer == 1024Hz. error < 1ms */
+ count += 100;
+ if (count < 1024)
+ return;
+ count -= 1024;
+
+ timerintr(ureg, 0);
+}
diff --git a/sys/src/9/alphapc/cycintr.c b/sys/src/9/alphapc/cycintr.c
new file mode 100755
index 000000000..d56edba80
--- /dev/null
+++ b/sys/src/9/alphapc/cycintr.c
@@ -0,0 +1,27 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+int
+havetimer(void)
+{
+ return 0;
+}
+
+void
+timeradd(Timer *)
+{
+}
+
+void
+timerdel(Timer *)
+{
+}
+
+void
+clockintrsched(void)
+{
+}
diff --git a/sys/src/9/alphapc/dat.h b/sys/src/9/alphapc/dat.h
new file mode 100755
index 000000000..5257a291e
--- /dev/null
+++ b/sys/src/9/alphapc/dat.h
@@ -0,0 +1,266 @@
+typedef struct Conf Conf;
+typedef struct Confmem Confmem;
+typedef struct FPsave FPsave;
+typedef struct ISAConf ISAConf;
+typedef struct Label Label;
+typedef struct Lock Lock;
+typedef struct Mach Mach;
+typedef struct Notsave Notsave;
+typedef struct Page Page;
+typedef struct PCArch PCArch;
+typedef struct PCB PCB;
+typedef struct Pcidev Pcidev;
+typedef struct PMMU PMMU;
+typedef struct Proc Proc;
+typedef struct Sys Sys;
+typedef struct Ureg Ureg;
+typedef struct Vctl Vctl;
+typedef vlong Tval;
+
+#define MAXSYSARG 6 /* for mount(fd, mpt, flag, arg, srv) */
+
+/*
+ * parameters for sysproc.c
+ */
+#define AOUT_MAGIC L_MAGIC
+
+/*
+ * machine dependent definitions used by ../port/dat.h
+ */
+
+struct Lock
+{
+ ulong key; /* semaphore (non-zero = locked) */
+ ulong sr;
+ ulong pc;
+ Proc *p;
+ Mach *m;
+ ulong pid;
+ ushort isilock;
+};
+
+struct Label
+{
+ ulong sp;
+ ulong pc;
+};
+
+/*
+ * Proc.fpstate
+ */
+enum
+{
+ /* floating point states */
+ FPinit,
+ FPactive,
+ FPinactive,
+
+ /* bit or'd with the state */
+ FPillegal= 0x100,
+};
+
+struct FPsave
+{
+ long fpreg[2*32];
+ long dummy; /* lower bits of FPCR, useless */
+ long fpstatus;
+};
+
+struct Confmem
+{
+ ulong base;
+ ulong npage;
+ ulong kbase;
+ ulong klimit;
+};
+
+struct Conf
+{
+ ulong nmach; /* processors */
+ ulong nproc; /* processes */
+ Confmem mem[2];
+ ulong npage; /* total physical pages of memory */
+ ulong upages; /* user page pool */
+ ulong nimage; /* number of page cache image headers */
+ ulong nswap; /* number of swap pages */
+ int nswppo; /* max # of pageouts per segment pass */
+ ulong copymode; /* 0 is copy on write, 1 is copy on reference */
+ int monitor; /* has display? */
+ ulong ialloc; /* bytes available for interrupt time allocation */
+ ulong pipeqsize; /* size in bytes of pipe queues */
+};
+
+/*
+ * mmu goo in the Proc structure
+ */
+struct PMMU
+{
+ Page *mmutop; /* 1st level table */
+ Page *mmulvl2; /* 2nd level table */
+ Page *mmufree; /* unused page table pages */
+ Page *mmuused; /* used page table pages, except for mmustk */
+};
+
+/*
+ * things saved in the Proc structure during a notify
+ */
+struct Notsave
+{
+ ulong UNUSED;
+};
+
+#include "../port/portdat.h"
+
+/*
+ * machine dependent definitions not used by ../port/dat.h
+ */
+/*
+ * Fake kmap
+ */
+typedef void KMap;
+#define VA(k) ((ulong)(k))
+#define kmap(p) (KMap*)((p)->pa|KZERO)
+#define kunmap(k)
+
+/*
+ * Process Control Block, used by PALcode
+ */
+struct PCB {
+ uvlong ksp;
+ uvlong usp;
+ uvlong ptbr;
+ ulong asn;
+ ulong pcc;
+ uvlong unique;
+ ulong fen;
+ ulong dummy;
+ uvlong rsrv1;
+ uvlong rsrv2;
+};
+
+struct Mach
+{
+ /* OFFSETS OF THE FOLLOWING KNOWN BY l.s */
+ int machno; /* physical id of processor */
+ ulong splpc; /* pc that called splhi() */
+ Proc *proc; /* current process on this processor */
+
+ /* ordering from here on irrelevant */
+
+ ulong ticks; /* of the clock since boot time */
+ Label sched; /* scheduler wakeup */
+ Lock alarmlock; /* access to alarm list */
+ void *alarm; /* alarms bound to this clock */
+ int inclockintr;
+
+ Proc* readied; /* for runproc */
+ ulong schedticks; /* next forced context switch */
+
+ vlong cpuhz; /* hwrpb->cfreq */
+ uvlong cyclefreq; /* Frequency of user readable cycle counter */
+ ulong pcclast;
+ uvlong fastclock;
+ Perf perf; /* performance counters */
+
+ int tlbfault; /* only used by devproc; no access to tlb */
+ int tlbpurge; /* ... */
+ int pfault;
+ int cs;
+ int syscall;
+ int load;
+ int intr;
+ int flushmmu; /* make current proc flush it's mmu state */
+ int ilockdepth;
+
+ ulong spuriousintr;
+ int lastintr;
+
+ PCB;
+
+ /* MUST BE LAST */
+ int stack[1];
+};
+
+struct
+{
+ Lock;
+ short machs;
+ short exiting;
+ short ispanic;
+}active;
+
+/*
+ * Implementation-dependant functions (outside of Alpha architecture proper).
+ * Called PCArch because that's what mkdevc calls it (for the PC).
+ */
+struct PCArch
+{
+ char* id;
+ int (*ident)(void);
+
+ void (*coreinit)(void); /* set up core logic, PCI mappings etc */
+ void (*corehello)(void); /* identify core logic to user */
+ void (*coredetach)(void); /* restore core logic before return to console */
+ void *(*pcicfg)(int, int); /* map and point to PCI cfg space */
+ void *(*pcimem)(int, int); /* map and point to PCI memory space */
+ int (*intrenable)(Vctl*);
+ int (*intrvecno)(int);
+ int (*intrdisable)(int);
+
+ int (*_inb)(int);
+ ushort (*_ins)(int);
+ ulong (*_inl)(int);
+ void (*_outb)(int, int);
+ void (*_outs)(int, ushort);
+ void (*_outl)(int, ulong);
+ void (*_insb)(int, void*, int);
+ void (*_inss)(int, void*, int);
+ void (*_insl)(int, void*, int);
+ void (*_outsb)(int, void*, int);
+ void (*_outss)(int, void*, int);
+ void (*_outsl)(int, void*, int);
+};
+
+/*
+ * a parsed plan9.ini line
+ */
+#define NISAOPT 8
+
+struct ISAConf {
+ char *type;
+ ulong port;
+ int irq;
+ ulong dma;
+ ulong mem;
+ ulong size;
+ ulong freq;
+
+ int nopt;
+ char *opt[NISAOPT];
+};
+
+extern PCArch *arch;
+
+#define MACHP(n) ((Mach *)((int)&mach0+n*BY2PG))
+extern Mach mach0;
+
+extern register Mach *m;
+extern register Proc *up;
+
+/*
+ * hardware info about a device
+ */
+typedef struct {
+ ulong port;
+ int size;
+} Devport;
+
+struct DevConf
+{
+ ulong intnum; /* interrupt number */
+ char *type; /* card type, malloced */
+ int nports; /* Number of ports */
+ Devport *ports; /* The ports themselves */
+};
+
+extern FPsave initfp;
diff --git a/sys/src/9/alphapc/devarch.c b/sys/src/9/alphapc/devarch.c
new file mode 100755
index 000000000..352e47c6f
--- /dev/null
+++ b/sys/src/9/alphapc/devarch.c
@@ -0,0 +1,533 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "axp.h"
+
+typedef struct IOMap IOMap;
+struct IOMap
+{
+ IOMap *next;
+ char tag[13];
+ ulong start;
+ ulong end;
+};
+
+static struct
+{
+ Lock;
+ IOMap *m;
+ IOMap *free;
+ IOMap maps[32]; // some initial free maps
+
+ QLock ql; // lock for reading map
+} iomap;
+
+enum {
+ Qdir = 0,
+ Qioalloc = 1,
+ Qiob,
+ Qiow,
+ Qiol,
+ Qbase,
+
+ Qmax = 16,
+};
+
+typedef long Rdwrfn(Chan*, void*, long, vlong);
+
+static Rdwrfn *readfn[Qmax];
+static Rdwrfn *writefn[Qmax];
+
+static Dirtab archdir[] = {
+ ".", { Qdir, 0, QTDIR }, 0, 0555,
+ "ioalloc", { Qioalloc, 0 }, 0, 0444,
+ "iob", { Qiob, 0 }, 0, 0660,
+ "iow", { Qiow, 0 }, 0, 0660,
+ "iol", { Qiol, 0 }, 0, 0660,
+};
+Lock archwlock; /* the lock is only for changing archdir */
+int narchdir = Qbase;
+int (*_pcmspecial)(char *, ISAConf *);
+void (*_pcmspecialclose)(int);
+
+/*
+ * Add a file to the #P listing. Once added, you can't delete it.
+ * You can't add a file with the same name as one already there,
+ * and you get a pointer to the Dirtab entry so you can do things
+ * like change the Qid version. Changing the Qid path is disallowed.
+ */
+Dirtab*
+addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
+{
+ int i;
+ Dirtab d;
+ Dirtab *dp;
+
+ memset(&d, 0, sizeof d);
+ strcpy(d.name, name);
+ d.perm = perm;
+
+ lock(&archwlock);
+ if(narchdir >= Qmax){
+ unlock(&archwlock);
+ return nil;
+ }
+
+ for(i=0; i<narchdir; i++)
+ if(strcmp(archdir[i].name, name) == 0){
+ unlock(&archwlock);
+ return nil;
+ }
+
+ d.qid.path = narchdir;
+ archdir[narchdir] = d;
+ readfn[narchdir] = rdfn;
+ writefn[narchdir] = wrfn;
+ dp = &archdir[narchdir++];
+ unlock(&archwlock);
+
+ return dp;
+}
+
+void
+ioinit(void)
+{
+ int i;
+
+ for(i = 0; i < nelem(iomap.maps)-1; i++)
+ iomap.maps[i].next = &iomap.maps[i+1];
+ iomap.maps[i].next = nil;
+ iomap.free = iomap.maps;
+
+ // a dummy entry at 2^17
+ ioalloc(0x20000, 1, 0, "dummy");
+}
+
+//
+// alloc some io port space and remember who it was
+// alloced to. if port < 0, find a free region.
+//
+int
+ioalloc(int port, int size, int align, char *tag)
+{
+ IOMap *m, **l;
+ int i;
+
+ lock(&iomap);
+ if(port < 0){
+ // find a free port above 0x400 and below 0x1000
+ port = 0x400;
+ for(l = &iomap.m; *l; l = &(*l)->next){
+ m = *l;
+ i = m->start - port;
+ if(i > size)
+ break;
+ if(align > 0)
+ port = ((port+align-1)/align)*align;
+ else
+ port = m->end;
+ }
+ if(*l == nil){
+ unlock(&iomap);
+ return -1;
+ }
+ } else {
+ // see if the space clashes with previously allocated ports
+ for(l = &iomap.m; *l; l = &(*l)->next){
+ m = *l;
+ if(m->end <= port)
+ continue;
+ if(m->start >= port+size)
+ break;
+ unlock(&iomap);
+ return -1;
+ }
+ }
+ m = iomap.free;
+ if(m == nil){
+ print("ioalloc: out of maps");
+ unlock(&iomap);
+ return port;
+ }
+ iomap.free = m->next;
+ m->next = *l;
+ m->start = port;
+ m->end = port + size;
+ strncpy(m->tag, tag, sizeof(m->tag));
+ m->tag[sizeof(m->tag)-1] = 0;
+ *l = m;
+
+ archdir[0].qid.vers++;
+
+ unlock(&iomap);
+ return m->start;
+}
+
+void
+iofree(int port)
+{
+ IOMap *m, **l;
+
+ lock(&iomap);
+ for(l = &iomap.m; *l; l = &(*l)->next){
+ if((*l)->start == port){
+ m = *l;
+ *l = m->next;
+ m->next = iomap.free;
+ iomap.free = m;
+ break;
+ }
+ if((*l)->start > port)
+ break;
+ }
+ archdir[0].qid.vers++;
+ unlock(&iomap);
+}
+
+int
+iounused(int start, int end)
+{
+ IOMap *m;
+
+ for(m = iomap.m; m; m = m->next){
+ if(start >= m->start && start < m->end
+ || start <= m->start && end > m->start)
+ return 0;
+ }
+ return 1;
+}
+
+static void
+checkport(int start, int end)
+{
+ /* standard vga regs are OK */
+ if(start >= 0x2b0 && end <= 0x2df+1)
+ return;
+ if(start >= 0x3c0 && end <= 0x3da+1)
+ return;
+
+ if(iounused(start, end))
+ return;
+ error(Eperm);
+}
+
+static Chan*
+archattach(char* spec)
+{
+ return devattach('P', spec);
+}
+
+Walkqid*
+archwalk(Chan* c, Chan *nc, char** name, int nname)
+{
+ return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
+}
+
+static int
+archstat(Chan* c, uchar* dp, int n)
+{
+ return devstat(c, dp, n, archdir, narchdir, devgen);
+}
+
+static Chan*
+archopen(Chan* c, int omode)
+{
+ return devopen(c, omode, archdir, nelem(archdir), devgen);
+}
+
+static void
+archclose(Chan*)
+{
+}
+
+enum
+{
+ Linelen= 31,
+};
+
+static long
+archread(Chan *c, void *a, long n, vlong offset)
+{
+ char buf[Linelen+1], *p;
+ int port;
+ ushort *sp;
+ ulong *lp;
+ IOMap *m;
+ Rdwrfn *fn;
+
+ switch((ulong)c->qid.path){
+
+ case Qdir:
+ return devdirread(c, a, n, archdir, nelem(archdir), devgen);
+
+ case Qiob:
+ port = offset;
+ checkport(offset, offset+n);
+ for(p = a; port < offset+n; port++)
+ *p++ = inb(port);
+ return n;
+
+ case Qiow:
+ if((n & 0x01) || (offset & 0x01))
+ error(Ebadarg);
+ checkport(offset, offset+n+1);
+ n /= 2;
+ sp = a;
+ for(port = offset; port < offset+n; port += 2)
+ *sp++ = ins(port);
+ return n*2;
+
+ case Qiol:
+ if((n & 0x03) || (offset & 0x03))
+ error(Ebadarg);
+ checkport(offset, offset+n+3);
+ n /= 4;
+ lp = a;
+ for(port = offset; port < offset+n; port += 4)
+ *lp++ = inl(port);
+ return n*4;
+
+ case Qioalloc:
+ break;
+
+ default:
+ if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
+ return fn(c, a, n, offset);
+ error(Eperm);
+ break;
+ }
+
+ offset = offset/Linelen;
+ n = n/Linelen;
+ p = a;
+ lock(&iomap);
+ for(m = iomap.m; n > 0 && m != nil; m = m->next){
+ if(offset-- > 0)
+ continue;
+ if(strcmp(m->tag, "dummy") == 0)
+ break;
+ sprint(buf, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
+ memmove(p, buf, Linelen);
+ p += Linelen;
+ n--;
+ }
+ unlock(&iomap);
+
+ return p - (char*)a;
+}
+
+static long
+archwrite(Chan *c, void *a, long n, vlong offset)
+{
+ char *p;
+ int port;
+ ushort *sp;
+ ulong *lp;
+ Rdwrfn *fn;
+
+ switch((ulong)c->qid.path){
+
+ case Qiob:
+ p = a;
+ checkport(offset, offset+n);
+ for(port = offset; port < offset+n; port++)
+ outb(port, *p++);
+ return n;
+
+ case Qiow:
+ if((n & 01) || (offset & 01))
+ error(Ebadarg);
+ checkport(offset, offset+n+1);
+ n /= 2;
+ sp = a;
+ for(port = offset; port < offset+n; port += 2)
+ outs(port, *sp++);
+ return n*2;
+
+ case Qiol:
+ if((n & 0x03) || (offset & 0x03))
+ error(Ebadarg);
+ checkport(offset, offset+n+3);
+ n /= 4;
+ lp = a;
+ for(port = offset; port < offset+n; port += 4)
+ outl(port, *lp++);
+ return n*4;
+
+ default:
+ if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
+ return fn(c, a, n, offset);
+ error(Eperm);
+ break;
+ }
+ return 0;
+}
+
+Dev archdevtab = {
+ 'P',
+ "arch",
+
+ devreset,
+ devinit,
+ devshutdown,
+ archattach,
+ archwalk,
+ archstat,
+ archopen,
+ devcreate,
+ archclose,
+ archread,
+ devbread,
+ archwrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
+
+PCArch* arch;
+extern PCArch* knownarch[];
+
+PCArch archgeneric = {
+ "generic", /* id */
+ 0, /* ident */
+
+ 0, /* coreinit */
+ 0, /* coredetach */
+};
+
+static char *sysnames[] =
+{
+[1] "Alpha Demo. Unit",
+[2] "DEC 4000; Cobra",
+[3] "DEC 7000; Ruby",
+[4] "DEC 3000/500; Flamingo family (TC)",
+[6] "DEC 2000/300; Jensen (EISA/ISA)",
+[7] "DEC 3000/300; Pelican (TC)",
+[8] "Avalon A12; Avalon Multicomputer",
+[9] "DEC 2100/A500; Sable",
+[10] "DEC APXVME/64; AXPvme (VME?)",
+[11] "DEC AXPPCI/33; NoName (PCI/ISA)",
+[12] "DEC 21000; TurboLaser (PCI/EISA)",
+[13] "DEC 2100/A50; Avanti (PCI/ISA)",
+[14] "DEC MUSTANG; Mustang",
+[15] "DEC KN20AA; kn20aa (PCI/EISA)",
+[17] "DEC 1000; Mikasa (PCI/ISA?)",
+[19] "EB66; EB66 (PCI/ISA?)", // DEC?
+[20] "EB64P; EB64+ (PCI/ISA?)", // DEC?
+[21] "Alphabook1; Alphabook",
+[22] "DEC 4100; Rawhide (PCI/EISA)",
+[23] "DEC EV45/PBP; Lego",
+[24] "DEC 2100A/A500; Lynx",
+[26] "DEC AlphaPC 164", // only supported one: "EB164 (PCI/ISA)"
+[27] "DEC 1000A; Noritake",
+[28] "DEC AlphaVME/224; Cortex",
+[30] "DEC 550; Miata (PCI/ISA)",
+[32] "DEC EV56/PBP; Takara",
+[33] "DEC AlphaVME/320; Yukon (VME?)",
+[34] "DEC 6600; MonetGoldrush",
+// 200 and up is Alpha Processor Inc. machines
+// [201] "API UP1000; Nautilus",
+};
+
+static char *cpunames[] =
+{
+[1] "EV3",
+[2] "EV4: 21064",
+[3] "Simulation",
+[4] "LCA4: 2106[68]",
+[5] "EV5: 21164",
+[6] "EV45: 21064A",
+[7] "21164A", /* only supported one: EV56 */
+[8] "EV6: 21264",
+[9] "PCA256: 21164PC",
+};
+
+void
+cpuidprint(void)
+{
+ int i, maj, min;
+ Hwcpu *cpu;
+ Hwdsr *dsr;
+ char *s;
+
+ print("\n");
+
+ if (hwrpb->rev >= 6) {
+ dsr = (Hwdsr*)((ulong)hwrpb + hwrpb->dsroff);
+
+ s = (char*)dsr + dsr->sysnameoff + 8;
+ print("%s\n", s);
+ }
+ else {
+ s = "<unknown>";
+ if (hwrpb->systype < nelem(sysnames))
+ s = sysnames[hwrpb->systype];
+ print("%s (%llux, %llux, %llux)\n", s, hwrpb->systype, hwrpb->sysvar, hwrpb->sysrev);
+ }
+
+ for (i = 0; i < hwrpb->ncpu; i++) {
+ cpu = (Hwcpu*) ((ulong)hwrpb + hwrpb->cpuoff + i*hwrpb->cpulen);
+ s = "<unknown>";
+ maj = (ulong)cpu->cputype;
+ min = (ulong)(cpu->cputype>>32);
+ if (maj < nelem(cpunames))
+ s = cpunames[maj];
+ print("cpu%d: %s-%d (%d.%d, %llux, %llux)\n",
+ i, s, min, maj, min, cpu->cpuvar, cpu->cpurev);
+ }
+
+ print("\n");
+}
+
+static long
+cputyperead(Chan*, void *a, long n, vlong offset)
+{
+ char str[32], *cputype;
+ ulong mhz, maj;
+ Hwcpu *cpu;
+
+ mhz = (m->cpuhz+999999)/1000000;
+ cpu = (Hwcpu*) ((ulong)hwrpb + hwrpb->cpuoff); /* NB CPU 0 */
+ cputype = "unknown";
+ maj = (ulong)cpu->cputype;
+ if (maj < nelem(cpunames))
+ cputype = cpunames[maj];
+
+ snprint(str, sizeof(str), "%s %lud\n", cputype, mhz);
+ return readstr(offset, a, n, str);
+}
+
+void
+archinit(void)
+{
+ PCArch **p;
+
+ arch = 0;
+ for(p = knownarch; *p; p++){
+ if((*p)->ident && (*p)->ident() == 0){
+ arch = *p;
+ break;
+ }
+ }
+ if(arch == 0)
+ arch = &archgeneric;
+
+ addarchfile("cputype", 0444, cputyperead, nil);
+}
+
+int
+pcmspecial(char *idstr, ISAConf *isa)
+{
+ return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;
+}
+
+void
+pcmspecialclose(int a)
+{
+ if (_pcmspecialclose != nil)
+ _pcmspecialclose(a);
+}
diff --git a/sys/src/9/alphapc/devvga.c b/sys/src/9/alphapc/devvga.c
new file mode 100755
index 000000000..551a19797
--- /dev/null
+++ b/sys/src/9/alphapc/devvga.c
@@ -0,0 +1,407 @@
+/*
+ * VGA controller
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#define Image IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+
+extern uchar *vgabios;
+
+enum {
+ Qdir,
+ Qvgactl,
+ Qvgabios,
+};
+
+static Dirtab vgadir[] = {
+ ".", { Qdir, 0, QTDIR }, 0, 0550,
+ "vgactl", { Qvgactl, 0 }, 0, 0660,
+ "vgabios", { Qvgabios, 0 }, 0x10000, 0440,
+};
+
+static void
+vgareset(void)
+{
+ /* reserve the 'standard' vga registers */
+ if(ioalloc(0x2b0, 0x2df-0x2b0+1, 0, "vga") < 0)
+ panic("vga ports already allocated");
+ if(ioalloc(0x3c0, 0x3da-0x3c0+1, 0, "vga") < 0)
+ panic("vga ports already allocated");
+ conf.monitor = 1;
+}
+
+static Chan*
+vgaattach(char* spec)
+{
+ if(*spec && strcmp(spec, "0"))
+ error(Eio);
+ return devattach('v', spec);
+}
+
+Walkqid*
+vgawalk(Chan* c, Chan *nc, char** name, int nname)
+{
+ return devwalk(c, nc, name, nname, vgadir, nelem(vgadir), devgen);
+}
+
+static int
+vgastat(Chan* c, uchar* dp, int n)
+{
+ return devstat(c, dp, n, vgadir, nelem(vgadir), devgen);
+}
+
+static Chan*
+vgaopen(Chan* c, int omode)
+{
+ return devopen(c, omode, vgadir, nelem(vgadir), devgen);
+}
+
+static void
+vgaclose(Chan*)
+{
+}
+
+static void
+checkport(int start, int end)
+{
+ /* standard vga regs are OK */
+ if(start >= 0x2b0 && end <= 0x2df+1)
+ return;
+ if(start >= 0x3c0 && end <= 0x3da+1)
+ return;
+
+ if(iounused(start, end))
+ return;
+ error(Eperm);
+}
+
+static long
+vgaread(Chan* c, void* a, long n, vlong off)
+{
+ int len;
+ char *p, *s;
+ VGAscr *scr;
+ ulong offset = off;
+ char chbuf[30];
+
+ switch((ulong)c->qid.path){
+
+ case Qdir:
+ return devdirread(c, a, n, vgadir, nelem(vgadir), devgen);
+
+ case Qvgactl:
+ scr = &vgascreen[0];
+
+ p = malloc(READSTR);
+ if(waserror()){
+ free(p);
+ nexterror();
+ }
+
+ len = 0;
+
+ if(scr->dev)
+ s = scr->dev->name;
+ else
+ s = "cga";
+ len += snprint(p+len, READSTR-len, "type %s\n", s);
+
+ if(scr->gscreen) {
+ len += snprint(p+len, READSTR-len, "size %dx%dx%d %s\n",
+ scr->gscreen->r.max.x, scr->gscreen->r.max.y,
+ scr->gscreen->depth, chantostr(chbuf, scr->gscreen->chan));
+
+ if(Dx(scr->gscreen->r) != Dx(physgscreenr)
+ || Dy(scr->gscreen->r) != Dy(physgscreenr))
+ len += snprint(p+len, READSTR-len, "actualsize %dx%d\n",
+ physgscreenr.max.x, physgscreenr.max.y);
+ }
+
+ len += snprint(p+len, READSTR-len, "blanktime %lud\n", blanktime);
+ len += snprint(p+len, READSTR-len, "hwaccel %s\n", hwaccel ? "on" : "off");
+ len += snprint(p+len, READSTR-len, "hwblank %s\n", hwblank ? "on" : "off");
+ snprint(p+len, READSTR-len, "addr 0x%lux\n", scr->paddr);
+ n = readstr(offset, a, n, p);
+ poperror();
+ free(p);
+
+ return n;
+
+ case Qvgabios:
+ if(vgabios == nil)
+ error(Egreg);
+ if(offset&0x80000000)
+ offset &= ~0x800E0000;
+ if(offset+n > 0x10000)
+ n = 0x10000-offset;
+ if(n < 0)
+ return 0;
+ memmove(a, vgabios+offset, n);
+ return n;
+
+ default:
+ error(Egreg);
+ break;
+ }
+
+ return 0;
+}
+
+static char Ebusy[] = "vga already configured";
+
+static void
+vgactl(char* a)
+{
+ int align, i, n, size, x, y, z;
+ char *chanstr, *field[6], *p;
+ ulong chan;
+ VGAscr *scr;
+ extern VGAdev *vgadev[];
+ extern VGAcur *vgacur[];
+ Rectangle r;
+
+ n = tokenize(a, field, nelem(field));
+ if(n < 1)
+ error(Ebadarg);
+
+ scr = &vgascreen[0];
+ if(strcmp(field[0], "hwgc") == 0){
+ if(n < 2)
+ error(Ebadarg);
+
+ if(strcmp(field[1], "off") == 0){
+ lock(&cursor);
+ if(scr->cur){
+ if(scr->cur->disable)
+ scr->cur->disable(scr);
+ scr->cur = nil;
+ }
+ unlock(&cursor);
+ return;
+ }
+
+ for(i = 0; vgacur[i]; i++){
+ if(strcmp(field[1], vgacur[i]->name))
+ continue;
+ lock(&cursor);
+ if(scr->cur && scr->cur->disable)
+ scr->cur->disable(scr);
+ scr->cur = vgacur[i];
+ if(scr->cur->enable)
+ scr->cur->enable(scr);
+ unlock(&cursor);
+ return;
+ }
+ }
+ else if(strcmp(field[0], "type") == 0){
+ if(n < 2)
+ error(Ebadarg);
+
+ for(i = 0; vgadev[i]; i++){
+ if(strcmp(field[1], vgadev[i]->name))
+ continue;
+ if(scr->dev && scr->dev->disable)
+ scr->dev->disable(scr);
+ scr->dev = vgadev[i];
+ if(scr->dev->enable)
+ scr->dev->enable(scr);
+ return;
+ }
+ }
+ else if(strcmp(field[0], "size") == 0){
+ if(n < 3)
+ error(Ebadarg);
+ if(drawhasclients())
+ error(Ebusy);
+
+ x = strtoul(field[1], &p, 0);
+ if(x == 0 || x > 2048)
+ error(Ebadarg);
+ if(*p)
+ p++;
+
+ y = strtoul(p, &p, 0);
+ if(y == 0 || y > 2048)
+ error(Ebadarg);
+ if(*p)
+ p++;
+
+ z = strtoul(p, &p, 0);
+
+ chanstr = field[2];
+ if((chan = strtochan(chanstr)) == 0)
+ error("bad channel");
+
+ if(chantodepth(chan) != z)
+ error("depth, channel do not match");
+
+ cursoroff(1);
+ deletescreenimage();
+ if(screensize(x, y, z, chan))
+ error(Egreg);
+ vgascreenwin(scr);
+ cursoron(1);
+ return;
+ }
+ else if(strcmp(field[0], "actualsize") == 0){
+ if(scr->gscreen == nil)
+ error("set the screen size first");
+
+ if(n < 2)
+ error(Ebadarg);
+ x = strtoul(field[1], &p, 0);
+ if(x == 0 || x > 2048)
+ error(Ebadarg);
+ if(*p)
+ p++;
+
+ y = strtoul(p, nil, 0);
+ if(y == 0 || y > 2048)
+ error(Ebadarg);
+
+ if(x > scr->gscreen->r.max.x || y > scr->gscreen->r.max.y)
+ error("physical screen bigger than virtual");
+
+ r = Rect(0,0,x,y);
+ if(!eqrect(r, scr->gscreen->r)){
+ if(scr->cur == nil || scr->cur->doespanning == 0)
+ error("virtual screen not supported");
+ }
+
+ physgscreenr = r;
+ return;
+ }
+ else if(strcmp(field[0], "palettedepth") == 0){
+ if(n < 2)
+ error(Ebadarg);
+
+ x = strtoul(field[1], &p, 0);
+ if(x != 8 && x != 6)
+ error(Ebadarg);
+
+ scr->palettedepth = x;
+ return;
+ }
+ else if(strcmp(field[0], "drawinit") == 0){
+ if(scr && scr->dev && scr->dev->drawinit)
+ scr->dev->drawinit(scr);
+ return;
+ }
+ else if(strcmp(field[0], "linear") == 0){
+ if(n < 2)
+ error(Ebadarg);
+
+ size = strtoul(field[1], 0, 0);
+ if(n < 3)
+ align = 0;
+ else
+ align = strtoul(field[2], 0, 0);
+ if(screenaperture(size, align))
+ error("not enough free address space");
+ return;
+ }
+/* else if(strcmp(field[0], "memset") == 0){
+ if(n < 4)
+ error(Ebadarg);
+ memset((void*)strtoul(field[1], 0, 0), atoi(field[2]), atoi(field[3]));
+ return;
+ }
+*/
+ else if(strcmp(field[0], "blank") == 0){
+ if(n < 1)
+ error(Ebadarg);
+ drawblankscreen(1);
+ return;
+ }
+ else if(strcmp(field[0], "blanktime") == 0){
+ if(n < 2)
+ error(Ebadarg);
+ blanktime = strtoul(field[1], 0, 0);
+ return;
+ }
+ else if(strcmp(field[0], "hwaccel") == 0){
+ if(n < 2)
+ error(Ebadarg);
+ if(strcmp(field[1], "on") == 0)
+ hwaccel = 1;
+ else if(strcmp(field[1], "off") == 0)
+ hwaccel = 0;
+ return;
+ }
+ else if(strcmp(field[0], "hwblank") == 0){
+ if(n < 2)
+ error(Ebadarg);
+ if(strcmp(field[1], "on") == 0)
+ hwblank = 1;
+ else if(strcmp(field[1], "off") == 0)
+ hwblank = 0;
+ return;
+ }
+
+ error(Ebadarg);
+}
+
+static long
+vgawrite(Chan* c, void* a, long n, vlong off)
+{
+ char *p;
+ ulong offset = off;
+
+ switch((ulong)c->qid.path){
+
+ case Qdir:
+ error(Eperm);
+
+ case Qvgactl:
+ if(offset || n >= READSTR)
+ error(Ebadarg);
+ p = malloc(READSTR);
+ if(waserror()){
+ free(p);
+ nexterror();
+ }
+ memmove(p, a, n);
+ p[n] = 0;
+ vgactl(p);
+ poperror();
+ free(p);
+ return n;
+
+ default:
+ error(Egreg);
+ break;
+ }
+
+ return 0;
+}
+
+Dev vgadevtab = {
+ 'v',
+ "vga",
+
+ vgareset,
+ devinit,
+ devshutdown,
+ vgaattach,
+ vgawalk,
+ vgastat,
+ vgaopen,
+ devcreate,
+ vgaclose,
+ vgaread,
+ devbread,
+ vgawrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
diff --git a/sys/src/9/alphapc/dma.c b/sys/src/9/alphapc/dma.c
new file mode 100755
index 000000000..6382c1beb
--- /dev/null
+++ b/sys/src/9/alphapc/dma.c
@@ -0,0 +1,331 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+#include "io.h"
+
+typedef struct DMAport DMAport;
+typedef struct DMA DMA;
+typedef struct DMAxfer DMAxfer;
+
+/*
+ * state of a dma transfer
+ */
+struct DMAxfer
+{
+ ulong bpa; /* bounce buffer physical address */
+ void* bva; /* bounce buffer virtual address */
+ int blen; /* bounce buffer length */
+ void* va; /* virtual address destination/src */
+ long len; /* bytes to be transferred */
+ int isread;
+};
+
+/*
+ * the dma controllers. the first half of this structure specifies
+ * the I/O ports used by the DMA controllers.
+ */
+struct DMAport
+{
+ uchar addr[4]; /* current address (4 channels) */
+ uchar count[4]; /* current count (4 channels) */
+ uchar page[4]; /* page registers (4 channels) */
+ uchar cmd; /* command status register */
+ uchar req; /* request registers */
+ uchar sbm; /* single bit mask register */
+ uchar mode; /* mode register */
+ uchar cbp; /* clear byte pointer */
+ uchar mc; /* master clear */
+ uchar cmask; /* clear mask register */
+ uchar wam; /* write all mask register bit */
+};
+
+struct DMA
+{
+ DMAport;
+ int shift;
+ Lock;
+ DMAxfer x[4];
+};
+
+DMA dma[2] = {
+ { 0x00, 0x02, 0x04, 0x06,
+ 0x01, 0x03, 0x05, 0x07,
+ 0x87, 0x83, 0x81, 0x82,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0 },
+
+ { 0xc0, 0xc4, 0xc8, 0xcc,
+ 0xc2, 0xc6, 0xca, 0xce,
+ 0x8f, 0x8b, 0x89, 0x8a,
+ 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
+ 1 },
+};
+
+extern int i8237dma;
+static void* i8237bva[2];
+static int i8237used;
+
+/*
+ * DMA must be in the first 16MB. This gets called early by the
+ * initialisation routines of any devices which require DMA to ensure
+ * the allocated bounce buffers are below the 16MB limit.
+ */
+void
+_i8237alloc(void)
+{
+ void* bva;
+
+ if(i8237dma <= 0)
+ return;
+ if(i8237dma > 2)
+ i8237dma = 2;
+
+ bva = xspanalloc(64*1024*i8237dma, BY2PG, 64*1024);
+ if(bva == nil || PADDR(bva)+64*1024*i8237dma > 16*MB){
+ /*
+ * This will panic with the current
+ * implementation of xspanalloc().
+ if(bva != nil)
+ xfree(bva);
+ */
+ return;
+ }
+
+ i8237bva[0] = bva;
+ if(i8237dma == 2)
+ i8237bva[1] = ((uchar*)i8237bva[0])+64*1024;
+}
+
+static void
+dmastatus(DMA *dp, int chan, char c)
+{
+ int a, l, s;
+
+ ilock(dp);
+ outb(dp->cbp, 0);
+ a = inb(dp->addr[chan]);
+ a |= inb(dp->addr[chan])<<8;
+ a |= inb(dp->page[chan])<<16;
+ a |= inb(0x400|dp->page[chan])<<24;
+ outb(dp->cbp, 0);
+ l = inb(dp->count[chan]);
+ l |= inb(dp->count[chan])<<8;
+ s = inb(dp->cmd);
+ iunlock(dp);
+ print("%c: addr %uX len %uX stat %uX\n", c, a, l, s);
+}
+
+int
+dmainit(int chan, int maxtransfer)
+{
+ DMA *dp;
+ DMAxfer *xp;
+ static int once;
+
+ if(once == 0){
+ if(ioalloc(0x00, 0x10, 0, "dma") < 0
+ || ioalloc(0x80, 0x10, 0, "dma") < 0
+ || ioalloc(0xd0, 0x10, 0, "dma") < 0)
+ panic("dmainit");
+ outb(dma[0].mc, 0);
+ outb(dma[1].mc, 0);
+ outb(dma[0].cmask, 0);
+ outb(dma[1].cmask, 0);
+ outb(dma[1].mode, 0xC0);
+ once = 1;
+ }
+
+ if(maxtransfer > 64*1024)
+ maxtransfer = 64*1024;
+
+ dp = &dma[(chan>>2)&1];
+ chan = chan & 3;
+ xp = &dp->x[chan];
+ if(xp->bva != nil){
+ if(xp->blen < maxtransfer)
+ return 1;
+ return 0;
+ }
+//dmastatus(dp, chan, 'I');
+
+ if(i8237used >= i8237dma || i8237bva[i8237used] == nil){
+ print("no i8237 DMA bounce buffer < 16MB\n");
+ return 1;
+ }
+ xp->bva = i8237bva[i8237used++];
+ xp->bpa = PADDR(xp->bva);
+ xp->blen = maxtransfer;
+ xp->len = 0;
+ xp->isread = 0;
+
+ return 0;
+}
+
+void
+xdmastatus(int chan)
+{
+ DMA *dp;
+
+ dp = &dma[(chan>>2)&1];
+ chan = chan & 3;
+
+ dmastatus(dp, chan, 'X');
+}
+
+/*
+ * setup a dma transfer. if the destination is not in kernel
+ * memory, allocate a page for the transfer.
+ *
+ * we assume BIOS has set up the command register before we
+ * are booted.
+ *
+ * return the updated transfer length (we can't transfer across 64k
+ * boundaries)
+ */
+long
+dmasetup(int chan, void *va, long len, int isread)
+{
+ DMA *dp;
+ ulong pa;
+ uchar mode;
+ DMAxfer *xp;
+
+ dp = &dma[(chan>>2)&1];
+ chan = chan & 3;
+ xp = &dp->x[chan];
+//print("va%lux+", va);
+#define tryPCI
+#ifndef PCIWADDR
+#define PCIWADDR(va) PADDR(va)
+#endif /* PCIWADDR */
+#ifdef notdef
+
+ /*
+ * if this isn't kernel memory or crossing 64k boundary or above 16 meg
+ * use the bounce buffer.
+ */
+ pa = PADDR(va);
+ if((((ulong)va)&0xF0000000) != KZERO
+ || (pa&0xFFFF0000) != ((pa+len)&0xFFFF0000)
+ || pa >= 16*MB) {
+ if(xp->bva == nil)
+ return -1;
+ if(len > xp->blen)
+ len = xp->blen;
+ if(!isread)
+ memmove(xp->bva, va, len);
+ xp->va = va;
+ xp->len = len;
+ xp->isread = isread;
+ pa = xp->bpa;
+ }
+ else
+ xp->len = 0;
+#endif /* notdef */
+#ifdef tryISA
+ pa = ISAWADDR(va);
+#endif /* tryISA */
+#ifdef tryPCI
+ pa = PCIWADDR(va);
+ if((((ulong)va)&0xF0000000) != KZERO){
+ if(xp->bva == nil)
+ return -1;
+ if(len > xp->blen)
+ len = xp->blen;
+ if(!isread)
+ memmove(xp->bva, va, len);
+ xp->va = va;
+ xp->len = len;
+ xp->isread = isread;
+ pa = PCIWADDR(xp->bva);
+ }
+ else
+ xp->len = 0;
+#endif /* tryPCI */
+
+ /*
+ * this setup must be atomic
+ */
+ mode = (isread ? 0x44 : 0x48) | chan;
+ ilock(dp);
+ outb(dp->cbp, 0); /* set count & address to their first byte */
+ outb(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */
+ outb(dp->addr[chan], pa>>dp->shift); /* set address */
+ outb(dp->addr[chan], pa>>(8+dp->shift));
+ outb(dp->page[chan], pa>>16);
+#ifdef tryPCI
+ outb(0x400|dp->page[chan], pa>>24);
+#endif /* tryPCI */
+ outb(dp->cbp, 0); /* set count & address to their first byte */
+ outb(dp->count[chan], (len>>dp->shift)-1); /* set count */
+ outb(dp->count[chan], ((len>>dp->shift)-1)>>8);
+ outb(dp->sbm, chan); /* enable the channel */
+ iunlock(dp);
+//dmastatus(dp, chan, 'S');
+
+ return len;
+}
+
+int
+dmadone(int chan)
+{
+ DMA *dp;
+
+ dp = &dma[(chan>>2)&1];
+ chan = chan & 3;
+
+ return inb(dp->cmd) & (1<<chan);
+}
+
+/*
+ * this must be called after a dma has been completed.
+ *
+ * if a page has been allocated for the dma,
+ * copy the data into the actual destination
+ * and free the page.
+ */
+void
+dmaend(int chan)
+{
+ DMA *dp;
+ DMAxfer *xp;
+
+ dp = &dma[(chan>>2)&1];
+ chan = chan & 3;
+
+//dmastatus(dp, chan, 'E');
+ /*
+ * disable the channel
+ */
+ ilock(dp);
+ outb(dp->sbm, 4|chan);
+ iunlock(dp);
+
+ xp = &dp->x[chan];
+ if(xp->len == 0 || !xp->isread)
+ return;
+
+ /*
+ * copy out of temporary page
+ */
+ memmove(xp->va, xp->bva, xp->len);
+ xp->len = 0;
+}
+
+/*
+int
+dmacount(int chan)
+{
+ int retval;
+ DMA *dp;
+
+ dp = &dma[(chan>>2)&1];
+ outb(dp->cbp, 0);
+ retval = inb(dp->count[chan]);
+ retval |= inb(dp->count[chan]) << 8;
+ return((retval<<dp->shift)+1);
+}
+ */
diff --git a/sys/src/9/alphapc/etherif.h b/sys/src/9/alphapc/etherif.h
new file mode 100755
index 000000000..c044e75ef
--- /dev/null
+++ b/sys/src/9/alphapc/etherif.h
@@ -0,0 +1,41 @@
+enum {
+ MaxEther = 24,
+ Ntypes = 8,
+};
+
+typedef struct Ether Ether;
+struct Ether {
+ ISAConf; /* hardware info */
+
+ int ctlrno;
+ int tbdf; /* type+busno+devno+funcno */
+ int minmtu;
+ int maxmtu;
+ uchar ea[Eaddrlen];
+
+ void (*attach)(Ether*); /* filled in by reset routine */
+ void (*detach)(Ether*); /* NEW, from ../pc */
+ void (*transmit)(Ether*);
+ void (*interrupt)(Ureg*, void*);
+ long (*ifstat)(Ether*, void*, long, ulong);
+ long (*ctl)(Ether*, void*, long); /* custom ctl messages */
+/* START NEW, from ../pc */
+ void (*power)(Ether*, int); /* power on/off */
+ void (*shutdown)(Ether*); /* shutdown hardware before reboot */
+/* END NEW */
+ void *ctlr;
+
+ Queue* oq;
+
+ Netif;
+};
+
+extern Block* etheriq(Ether*, Block*, int);
+extern void addethercard(char*, int(*)(Ether*));
+extern ulong ethercrc(uchar*, int);
+extern int parseether(uchar*, char*);
+
+#define NEXT(x, l) (((x)+1)%(l))
+#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
+#define HOWMANY(x, y) (((x)+((y)-1))/(y))
+#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
diff --git a/sys/src/9/alphapc/faultalpha.c b/sys/src/9/alphapc/faultalpha.c
new file mode 100755
index 000000000..c2d646905
--- /dev/null
+++ b/sys/src/9/alphapc/faultalpha.c
@@ -0,0 +1,62 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "ureg.h"
+#include "../port/error.h"
+
+/*
+ * find out fault address and type of access.
+ * Call common fault handler.
+ */
+void
+faultalpha(Ureg *ur)
+{
+ ulong addr, cause;
+ int read, user;
+ char buf[ERRMAX];
+ uvlong x;
+
+ x = ur->a0&0xffffffff80000000LL;
+ if (x != 0LL && x != 0xffffffff80000000LL)
+ iprint("faultalpha bad addr %llux pc %llux\n", ur->a0, ur->pc);
+
+ addr = (ulong)ur->a0;
+ cause = (ulong)ur->a2;
+ addr &= ~(BY2PG-1);
+ read = (cause !=1);
+ user = (ulong)ur->status&UMODE;
+
+/* print("fault %s pc=0x%lux addr=0x%lux 0x%lux\n",
+ read? (cause != 0) ? "ifetch" : "read" : "write", (ulong)ur->pc, addr, (ulong)ur->a1); /**/
+
+ if(fault(addr, read) == 0)
+ return;
+
+ if(user){
+ sprint(buf, "sys: trap: fault %s addr=0x%lux",
+ read? (cause != 0) ? "ifetch" : "read" : "write", (ulong)ur->a0);
+ postnote(up, 1, buf, NDebug);
+ return;
+ }
+
+ iprint("kernel %s vaddr=0x%lux\n", read? (cause != 0) ? "ifetch" : "read" : "write", (ulong)ur->a0);
+ if(0)
+ mmudump();
+ dumpregs(ur);
+ _dumpstack(ur);
+ exit(1);
+}
+
+/*
+ * called in sysfile.c
+ */
+void
+evenaddr(ulong addr)
+{
+ if(addr & 3){
+ postnote(up, 1, "sys: odd address", NDebug);
+ error(Ebadarg);
+ }
+}
diff --git a/sys/src/9/alphapc/fdc37c93x.c b/sys/src/9/alphapc/fdc37c93x.c
new file mode 100755
index 000000000..ce2a63963
--- /dev/null
+++ b/sys/src/9/alphapc/fdc37c93x.c
@@ -0,0 +1,66 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+/*
+ * SMC FDC37C93x Plug and Play Compatible Ultra I/O Controller.
+ */
+enum { /* I/O Ports */
+ Config = 0x370, /* could also be 0x3F0 */
+
+ Index = 0,
+ Data = 1,
+};
+
+static int fddregs[] = {
+ 0x30,
+ 0x60, 0x61,
+ 0x70,
+ 0x74,
+ 0xF0,
+ 0xF1,
+ 0xF2,
+ 0xF4,
+ 0xF5,
+ 0,
+};
+
+#define OUTB(p, d) outb(p, d); microdelay(10);
+
+void
+fdc37c93xdump(void)
+{
+ int config, i, x;
+
+ config = Config;
+
+ OUTB(config, 0x55);
+ OUTB(config, 0x55);
+
+ OUTB(config+Index, 0x20);
+ x = inb(config+Data);
+ print("fdc37c93x: Device ID 0x%2.2uX\n", x);
+ OUTB(config+Index, 0x22);
+ x = inb(config+Data);
+ print("fdc37c93x: Power/Control 0x%2.2uX\n", x);
+
+ OUTB(config+Index, 0x07);
+ OUTB(config+Data, 0);
+ for(i = 0; fddregs[i]; i++){
+ OUTB(config+Index, fddregs[i]);
+ x = inb(config+Data);
+ print("FDD%2.2uX: 0x%2.2uX\n", fddregs[i], x);
+ }
+
+ OUTB(config+Index, 0x70);
+ OUTB(config+Data, 0x06);
+ OUTB(config+Index, 0x74);
+ OUTB(config+Data, 0x02);
+ OUTB(config+Index, 0x30);
+ OUTB(config+Data, 0x01);
+
+ OUTB(config, 0xAA);
+}
diff --git a/sys/src/9/alphapc/floppy.h b/sys/src/9/alphapc/floppy.h
new file mode 100755
index 000000000..08dc1dd67
--- /dev/null
+++ b/sys/src/9/alphapc/floppy.h
@@ -0,0 +1,181 @@
+typedef struct FController FController;
+typedef struct FDrive FDrive;
+typedef struct FType FType;
+
+static void floppyintr(Ureg*);
+static int floppyon(FDrive*);
+static void floppyoff(FDrive*);
+static void floppysetdef(FDrive*);
+
+/*
+ * a floppy drive
+ */
+struct FDrive
+{
+ FType *t; /* floppy type */
+ int dt; /* drive type */
+ int dev;
+
+ ulong lasttouched; /* time last touched */
+ int cyl; /* current arm position */
+ int confused; /* needs to be recalibrated */
+ int vers;
+ int maxtries; /* max read attempts before Eio */
+
+ int tcyl; /* target cylinder */
+ int thead; /* target head */
+ int tsec; /* target sector */
+ long len; /* size of xfer */
+
+ uchar *cache; /* track cache */
+ int ccyl;
+ int chead;
+
+ Rendez r; /* waiting here for motor to spin up */
+};
+
+/*
+ * controller for 4 floppys
+ */
+struct FController
+{
+ QLock; /* exclusive access to the contoller */
+
+ int ndrive;
+ FDrive *d; /* the floppy drives */
+ FDrive *selected;
+ int rate; /* current rate selected */
+ uchar cmd[14]; /* command */
+ int ncmd; /* # command bytes */
+ uchar stat[14]; /* command status */
+ int nstat; /* # status bytes */
+ int confused; /* controler needs to be reset */
+ Rendez r; /* wait here for command termination */
+ int motor; /* bit mask of spinning disks */
+ Rendez kr; /* for motor watcher */
+};
+
+/*
+ * floppy types (all MFM encoding)
+ */
+struct FType
+{
+ char *name;
+ int dt; /* compatible drive type */
+ int bytes; /* bytes/sector */
+ int sectors; /* sectors/track */
+ int heads; /* number of heads */
+ int steps; /* steps per cylinder */
+ int tracks; /* tracks/disk */
+ int gpl; /* intersector gap length for read/write */
+ int fgpl; /* intersector gap length for format */
+ int rate; /* rate code */
+
+ /*
+ * these depend on previous entries and are set filled in
+ * by floppyinit
+ */
+ int bcode; /* coded version of bytes for the controller */
+ long cap; /* drive capacity in bytes */
+ long tsize; /* track size in bytes */
+};
+/* bits in the registers */
+enum
+{
+ /* status registers a & b */
+ Psra= 0x3f0,
+ Psrb= 0x3f1,
+
+ /* digital output register */
+ Pdor= 0x3f2,
+ Fintena= 0x8, /* enable floppy interrupt */
+ Fena= 0x4, /* 0 == reset controller */
+
+ /* main status register */
+ Pmsr= 0x3f4,
+ Fready= 0x80, /* ready to be touched */
+ Ffrom= 0x40, /* data from controller */
+ Ffloppybusy= 0x10, /* operation not over */
+
+ /* data register */
+ Pfdata= 0x3f5,
+ Frecal= 0x07, /* recalibrate cmd */
+ Fseek= 0x0f, /* seek cmd */
+ Fsense= 0x08, /* sense cmd */
+ Fread= 0x66, /* read cmd */
+ Freadid= 0x4a, /* read track id */
+ Fspec= 0x03, /* set hold times */
+ Fwrite= 0x45, /* write cmd */
+ Fformat= 0x4d, /* format cmd */
+ Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */
+ Fdumpreg= 0x0e, /* dump internal registers */
+
+ /* digital input register */
+ Pdir= 0x3F7, /* disk changed port (read only) */
+ Pdsr= 0x3F7, /* data rate select port (write only) */
+ Fchange= 0x80, /* disk has changed */
+
+ /* status 0 byte */
+ Drivemask= 3<<0,
+ Seekend= 1<<5,
+ Codemask= (3<<6)|(3<<3),
+ Cmdexec= 1<<6,
+
+ /* status 1 byte */
+ Overrun= 0x10,
+};
+
+
+static void
+pcfloppyintr(Ureg *ur, void *a)
+{
+ USED(a);
+
+ floppyintr(ur);
+}
+
+void
+floppysetup0(FController *fl)
+{
+ fl->ndrive = 0;
+ if(ioalloc(Psra, 6, 0, "floppy") < 0)
+ return;
+ if(ioalloc(Pdir, 1, 0, "floppy") < 0){
+ iofree(Psra);
+ return;
+ }
+ fl->ndrive = 1;
+}
+
+void
+floppysetup1(FController *fl)
+{
+ if(fl->ndrive > 0){
+ fl->d[0].dt = 4;
+ floppysetdef(&fl->d[0]);
+ }
+ if(fl->ndrive > 1){
+ fl->d[1].dt = 4;
+ floppysetdef(&fl->d[1]);
+ }
+
+ intrenable(IrqFLOPPY, pcfloppyintr, fl, BUSUNKNOWN, "floppy");
+}
+
+/*
+ * eject disk
+ */
+void
+floppyeject(FDrive *dp)
+{
+ floppyon(dp);
+ dp->vers++;
+ floppyoff(dp);
+}
+
+int
+floppyexec(char *a, long b, int c)
+{
+ USED(a, b, c);
+ return b;
+}
diff --git a/sys/src/9/alphapc/fns.h b/sys/src/9/alphapc/fns.h
new file mode 100755
index 000000000..88b0f3a68
--- /dev/null
+++ b/sys/src/9/alphapc/fns.h
@@ -0,0 +1,128 @@
+#include "../port/portfns.h"
+
+Dirtab* addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,void*,long,vlong));
+void archinit(void);
+void arginit(void);
+void arith(void);
+ulong cankaddr(ulong);
+void clock(Ureg*);
+void clockinit(void);
+void clockintrsched(void);
+#define coherence mb
+int cistrcmp(char*, char*);
+int cistrncmp(char*, char*, int);
+int cmpswap(long*, long, long);
+void cpuidprint(void);
+void cserve(ulong, ulong);
+#define cycles(x) do{}while(0)
+void timeradd(Timer *);
+void timerdel(Timer *);
+int dmacount(int);
+int dmadone(int);
+void dmaend(int);
+int dmainit(int, int);
+long dmasetup(int, void*, long, int);
+void _dumpstack(Ureg *);
+void evenaddr(ulong);
+void fataltrap(Ureg *, char *);
+void fault0(void);
+void faultalpha(Ureg*);
+ulong fcr31(void);
+void firmware(void);
+void fpenab(int);
+void fptrap(Ureg*);
+int getcfields(char*, char**, int, char*);
+char *getconf(char*);
+int havetimer(void);
+int i8042auxcmd(int);
+void i8042auxenable(void (*)(int, int));
+void i8042reset(void);
+void i8250console(void);
+void i8250mouse(char*, int(*)(Queue*,int), int);
+void i8250setmouseputc(char*, int (*)(Queue*, int));
+void i8259init(void);
+int i8259enable(int, int, Vctl*);
+#define idlehands() /* nothing to do in the runproc */
+void icflush(void);
+void illegal0(void);
+void intr0(void);
+void intrenable(int, void (*)(Ureg*, void*), void*, int, char*);
+int intrdisable(int, void (*)(Ureg *, void *), void*, int, char*);
+int ioalloc(int, int, int, char*);
+void iofree(int);
+void ioinit(void);
+int iounused(int, int);
+int irqallocread(char*, long, vlong);
+int isaconfig(char*, int, ISAConf*);
+void kbdinit(void);
+#define kexit(a)
+#define kmapinval()
+void *kmapv(uvlong, int);
+int kprint(char*, ...);
+void links(void);
+void mb(void);
+void memholes(void);
+ulong meminit(void);
+void mmudump(void);
+void mmuinit(void);
+void mmupark(void);
+#define mtrr(a, b, c)
+ulong pcibarsize(Pcidev*, int);
+int pcicfgr8(Pcidev*, int);
+int pcicfgr16(Pcidev*, int);
+int pcicfgr32(Pcidev*, int);
+void pcicfgw8(Pcidev*, int, int);
+void pcicfgw16(Pcidev*, int, int);
+void pcicfgw32(Pcidev*, int, int);
+void pciclrbme(Pcidev*);
+void pcihinv(Pcidev*);
+Pcidev* pcimatch(Pcidev*, int, int);
+Pcidev* pcimatchtbdf(int);
+void pcireset(void);
+void pcisetbme(Pcidev*);
+int pcmspecial(char*, ISAConf*);
+int (*_pcmspecial)(char *, ISAConf *);
+void pcmspecialclose(int);
+void (*_pcmspecialclose)(int);
+void prflush(void);
+void printinit(void);
+#define procrestore(p)
+void procsave(Proc*);
+void procsetup(Proc*);
+void restfpregs(FPsave*);
+uvlong rpcc(uvlong*);
+void screeninit(void);
+void (*screenputs)(char*, int);
+void setpcb(PCB *);
+PCB *swpctx(PCB *);
+void syscall0(void);
+int tas(ulong*);
+void tlbflush(int, ulong);
+void touser(void*);
+void trapinit(void);
+void unaligned(void);
+ulong upaalloc(int, int);
+void upafree(ulong, int);
+#define userureg(ur) ((ur)->status & UMODE)
+void* vmap(ulong, int);
+void wrent(int, void*);
+void wrvptptr(uvlong);
+void vunmap(void*, int);
+
+#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
+#define KADDR(a) ((void*)((ulong)(a)|KZERO))
+#define PADDR(a) ((ulong)(a)&~KZERO)
+
+#define inb(p) (arch->_inb)(p)
+#define ins(p) (arch->_ins)(p)
+#define inl(p) (arch->_inl)(p)
+#define outb(p, x) (arch->_outb)((p), (x))
+#define outs(p, x) (arch->_outs)((p), (x))
+#define outl(p, x) (arch->_outl)((p), (x))
+
+#define insb(p, buf, len) (arch->_insb)((p), (buf), (len))
+#define inss(p, buf, len) (arch->_inss)((p), (buf), (len))
+#define insl(p, buf, len) (arch->_insl)((p), (buf), (len))
+#define outsb(p, buf, len) (arch->_outsb)((p), (buf), (len))
+#define outss(p, buf, len) (arch->_outss)((p), (buf), (len))
+#define outsl(p, buf, len) (arch->_outsl)((p), (buf), (len))
diff --git a/sys/src/9/alphapc/fptrap.c b/sys/src/9/alphapc/fptrap.c
new file mode 100755
index 000000000..7b3c5a868
--- /dev/null
+++ b/sys/src/9/alphapc/fptrap.c
@@ -0,0 +1,46 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "ureg.h"
+#include "io.h"
+#include "../port/error.h"
+
+char *fpcause[] =
+{
+ "invalid operation",
+ "division by zero",
+ "overflow",
+ "underflow",
+ "inexact operation",
+ "integer overflow",
+};
+char *fpexcname(Ureg*, ulong, char*);
+
+void
+fptrap(Ureg *ur)
+{
+ char buf[ERRMAX];
+ int i;
+ ulong reason;
+
+ ur->pc &= ~2;
+ reason = (ulong)ur->a0;
+ for (i = 1; i < 6; i++)
+ if (reason & (1<<i)) {
+ sprint(buf, "fp: %s", fpcause[i-1]);
+ goto found;
+ }
+ sprint(buf, "fp: code 0x%lux", reason);
+
+found:
+ fataltrap(ur, buf);
+}
+
+char*
+fpexcname(Ureg *ur, ulong fcr31, char *buf)
+{
+ USED(ur, fcr31, buf);
+ return buf;
+}
diff --git a/sys/src/9/alphapc/i8259.c b/sys/src/9/alphapc/i8259.c
new file mode 100755
index 000000000..fe1f55708
--- /dev/null
+++ b/sys/src/9/alphapc/i8259.c
@@ -0,0 +1,152 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+/*
+ * 8259 interrupt controllers
+ */
+enum
+{
+ Int0ctl= 0x20, /* control port (ICW1, OCW2, OCW3) */
+ Int0aux= 0x21, /* everything else (ICW2, ICW3, ICW4, OCW1) */
+ Int1ctl= 0xA0, /* control port */
+ Int1aux= 0xA1, /* everything else (ICW2, ICW3, ICW4, OCW1) */
+
+ Icw1= 0x10, /* select bit in ctl register */
+ Ocw2= 0x00,
+ Ocw3= 0x08,
+
+ EOI= 0x20, /* non-specific end of interrupt */
+
+ Elcr1= 0x4D0, /* Edge/Level Triggered Register */
+ Elcr2= 0x4D1,
+};
+
+static int int0mask; /* interrupts enabled for first 8259 */
+static int int1mask; /* interrupts enabled for second 8259 */
+
+int elcr; /* mask of level-triggered interrupts */
+
+void
+i8259init(void)
+{
+ int /*elcr1, */ x;
+
+ ioalloc(Int0ctl, 2, 0, "i8259.0");
+ ioalloc(Int1ctl, 2, 0, "i8259.1");
+ int0mask = 0xFF;
+ int1mask = 0xFF;
+
+ /*
+ * Set up the first 8259 interrupt processor.
+ * Make 8259 interrupts start at CPU vector Int0vec.
+ * Set the 8259 as master with edge triggered
+ * input with fully nested interrupts.
+ */
+ outb(Int0ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered,
+ ICW4 will be sent */
+ outb(Int0aux, VectorPIC); /* ICW2 - interrupt vector offset */
+ outb(Int0aux, 0x04); /* ICW3 - have slave on level 2 */
+ outb(Int0aux, 0x01); /* ICW4 - 8086 mode, not buffered */
+
+ /*
+ * Set up the second 8259 interrupt processor.
+ * Make 8259 interrupts start at CPU vector VectorPIC+8.
+ * Set the 8259 as slave with edge triggered
+ * input with fully nested interrupts.
+ */
+ outb(Int1ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered,
+ ICW4 will be sent */
+ outb(Int1aux, VectorPIC+8); /* ICW2 - interrupt vector offset */
+ outb(Int1aux, 0x02); /* ICW3 - I am a slave on level 2 */
+ outb(Int1aux, 0x01); /* ICW4 - 8086 mode, not buffered */
+ outb(Int1aux, int1mask);
+
+ /*
+ * pass #2 8259 interrupts to #1
+ */
+ int0mask &= ~0x04;
+ outb(Int0aux, int0mask);
+
+ /*
+ * Set Ocw3 to return the ISR when ctl read.
+ * After initialisation status read is set to IRR.
+ * Read IRR first to possibly deassert an outstanding
+ * interrupt.
+ */
+ x = inb(Int0ctl); USED(x);
+ outb(Int0ctl, Ocw3|0x03);
+ x = inb(Int1ctl); USED(x);
+ outb(Int1ctl, Ocw3|0x03);
+
+ /*
+ * Check for Edge/Level register.
+ * This check may not work for all chipsets.
+ */
+/* elcr1 = inb(Elcr1);
+ outb(Elcr1, 0);
+ if(inb(Elcr1) == 0){
+ outb(Elcr1, 0x20);
+ if(inb(Elcr1) == 0x20)
+ elcr = (inb(Elcr2)<<8)|elcr1;
+ }
+ outb(Elcr1, elcr1);
+ if(elcr)
+ iprint("ELCR: %4.4uX\n", elcr);
+/**/
+}
+
+int
+i8259isr(int v)
+{
+ int isr;
+
+ /*
+ * tell the 8259 that we're done with the
+ * highest level interrupt (interrupts are still
+ * off at this point)
+ */
+ isr = 0;
+ if(v >= VectorPIC && v <= MaxVectorPIC){
+ isr = inb(Int0ctl);
+ outb(Int0ctl, EOI);
+ if(v >= VectorPIC+8){
+ isr |= inb(Int1ctl)<<8;
+ outb(Int1ctl, EOI);
+ }
+ }
+
+ return isr & (1<<(v-VectorPIC));
+}
+
+int
+i8259enable(int v, int, Vctl* vctl)
+{
+ if(v > MaxIrqPIC){
+ print("i8259enable: vector %d out of range\n", v);
+ return -1;
+ }
+
+ /*
+ * enable corresponding interrupt in 8259
+ */
+ if(v < 8){
+ int0mask &= ~(1<<v);
+ outb(Int0aux, int0mask);
+ }
+ else{
+ int1mask &= ~(1<<(v-8));
+ outb(Int1aux, int1mask);
+ }
+
+ if(elcr & (1<<v))
+ vctl->eoi = i8259isr;
+ else
+ vctl->isr = i8259isr;
+ vctl->isintr = 1;
+
+ return v;
+}
diff --git a/sys/src/9/alphapc/initcode b/sys/src/9/alphapc/initcode
new file mode 100755
index 000000000..a43139dea
--- /dev/null
+++ b/sys/src/9/alphapc/initcode
@@ -0,0 +1,47 @@
+#include "/sys/src/libc/9syscall/sys.h"
+
+/*
+ * we pass in the argument of the exec parameters as 0(FP)
+ */
+
+TEXT main(SB),$16
+
+ MOVQ $setSB(SB), R29
+ MOVQ $boot(SB), R0
+ ADDQ $24, R30, R1 /* get a pointer to 0(FP) */
+ MOVL R0, 8(R30)
+ MOVL R1, 12(R30)
+ JSR exec(SB)
+
+ MOVQ $(1<<4), R0
+ MOVL R0, 8(R30)
+ MOVQ $RFORK, R0
+ CALL_PAL $0x83
+ MOVQ $RFORK, R0
+ CALL_PAL $0x83
+ MOVQ $RFORK, R0
+ CALL_PAL $0x83
+again:
+ ADDL $1, R1
+ MOVQ $0, R0 /* print r1 */
+ CALL_PAL $0x83
+ MOVQ $100000000, R2
+foo:
+ SUBQ $1, R2
+ BNE R2, foo
+ MOVQ $1000, R0
+ MOVL R0, 8(R30)
+ MOVQ $SLEEP, R0
+ CALL_PAL $0x83
+ JMP again
+
+TEXT exec(SB), $0
+ MOVQ $EXEC, R0
+ CALL_PAL $0x83
+ RET
+
+DATA boot+0(SB)/5,$"/boot"
+DATA boot+5(SB)/5,$"/boot"
+DATA bootv+0(SB)/4,$boot+6(SB)
+GLOBL boot+0(SB),$11
+GLOBL bootv+0(SB),$8
diff --git a/sys/src/9/alphapc/io.h b/sys/src/9/alphapc/io.h
new file mode 100755
index 000000000..b4c29d3b2
--- /dev/null
+++ b/sys/src/9/alphapc/io.h
@@ -0,0 +1,176 @@
+enum {
+ IrqCLOCK = 0,
+ IrqKBD = 1,
+ IrqUART1 = 3,
+ IrqUART0 = 4,
+ IrqPCMCIA = 5,
+ IrqFLOPPY = 6,
+ IrqLPT = 7,
+ IrqIRQ7 = 7,
+ IrqAUX = 12, /* PS/2 port */
+ IrqIRQ13 = 13, /* coprocessor on 386 */
+ IrqATA0 = 14,
+ IrqATA1 = 15,
+ MaxIrqPIC = 15,
+
+ VectorPIC = 64,
+ MaxVectorPIC = VectorPIC+MaxIrqPIC,
+ VectorPCI = 16, /* PCI bus (PLD) */
+};
+
+typedef struct Vctl {
+ Vctl* next; /* handlers on this vector */
+
+ char name[KNAMELEN]; /* of driver */
+ int isintr; /* interrupt or fault/trap */
+ int irq;
+ int tbdf;
+ int (*isr)(int); /* get isr bit for this irq */
+ int (*eoi)(int); /* eoi */
+
+ void (*f)(Ureg*, void*); /* handler to call */
+ void* a; /* argument to call it with */
+} Vctl;
+
+enum {
+ BusCBUS = 0, /* Corollary CBUS */
+ BusCBUSII, /* Corollary CBUS II */
+ BusEISA, /* Extended ISA */
+ BusFUTURE, /* IEEE Futurebus */
+ BusINTERN, /* Internal bus */
+ BusISA, /* Industry Standard Architecture */
+ BusMBI, /* Multibus I */
+ BusMBII, /* Multibus II */
+ BusMCA, /* Micro Channel Architecture */
+ BusMPI, /* MPI */
+ BusMPSA, /* MPSA */
+ BusNUBUS, /* Apple Macintosh NuBus */
+ BusPCI, /* Peripheral Component Interconnect */
+ BusPCMCIA, /* PC Memory Card International Association */
+ BusTC, /* DEC TurboChannel */
+ BusVL, /* VESA Local bus */
+ BusVME, /* VMEbus */
+ BusXPRESS, /* Express System Bus */
+};
+
+#define MKBUS(t,b,d,f) (((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8))
+#define BUSFNO(tbdf) (((tbdf)>>8)&0x07)
+#define BUSDNO(tbdf) (((tbdf)>>11)&0x1F)
+#define BUSBNO(tbdf) (((tbdf)>>16)&0xFF)
+#define BUSTYPE(tbdf) ((tbdf)>>24)
+#define BUSDF(tbdf) ((tbdf)&0x000FF00)
+#define BUSBDF(tbdf) ((tbdf)&0x0FFFF00)
+#define BUSUNKNOWN (-1)
+
+enum {
+ MaxEISA = 16,
+ EISAconfig = 0xC80,
+};
+
+/*
+ * PCI support code.
+ */
+enum { /* type 0 and type 1 pre-defined header */
+ PciVID = 0x00, /* vendor ID */
+ PciDID = 0x02, /* device ID */
+ PciPCR = 0x04, /* command */
+ PciPSR = 0x06, /* status */
+ PciRID = 0x08, /* revision ID */
+ PciCCRp = 0x09, /* programming interface class code */
+ PciCCRu = 0x0A, /* sub-class code */
+ PciCCRb = 0x0B, /* base class code */
+ PciCLS = 0x0C, /* cache line size */
+ PciLTR = 0x0D, /* latency timer */
+ PciHDT = 0x0E, /* header type */
+ PciBST = 0x0F, /* BIST */
+
+ PciBAR0 = 0x10, /* base address */
+ PciBAR1 = 0x14,
+ PciROM = 0x30,
+
+ PciINTL = 0x3C, /* interrupt line */
+ PciINTP = 0x3D, /* interrupt pin */
+};
+
+enum { /* type 0 pre-defined header */
+ PciCIS = 0x28, /* cardbus CIS pointer */
+ PciSVID = 0x2C, /* subsystem vendor ID */
+ PciSID = 0x2E, /* cardbus CIS pointer */
+ PciEBAR0 = 0x30, /* xpansion ROM base address */
+ PciMGNT = 0x3E, /* burst period length */
+ PciMLT = 0x3F, /* maximum latency between bursts */
+};
+
+enum { /* type 1 pre-defined header */
+ PciPBN = 0x18, /* primary bus number */
+ PciSBN = 0x19, /* secondary bus number */
+ PciUBN = 0x1A, /* subordinate bus number */
+ PciSLTR = 0x1B, /* secondary latency timer */
+ PciIBR = 0x1C, /* I/O base */
+ PciILR = 0x1D, /* I/O limit */
+ PciSPSR = 0x1E, /* secondary status */
+ PciMBR = 0x20, /* memory base */
+ PciMLR = 0x22, /* memory limit */
+ PciPMBR = 0x24, /* prefetchable memory base */
+ PciPMLR = 0x26, /* prefetchable memory limit */
+ PciPUBR = 0x28, /* prefetchable base upper 32 bits */
+ PciPULR = 0x2C, /* prefetchable limit upper 32 bits */
+ PciIUBR = 0x30, /* I/O base upper 16 bits */
+ PciIULR = 0x32, /* I/O limit upper 16 bits */
+ PciEBAR1 = 0x28, /* expansion ROM base address */
+ PciBCR = 0x3E, /* bridge control register */
+};
+
+typedef struct Pcidev Pcidev;
+typedef struct Pcidev {
+ int tbdf; /* type+bus+device+function */
+ ushort vid; /* vendor ID */
+ ushort did; /* device ID */
+
+ ushort pcr;
+
+ uchar rid;
+ uchar ccrp;
+ uchar ccru;
+ uchar ccrb;
+ uchar cls;
+ uchar ltr;
+
+ struct {
+ ulong bar; /* base address */
+ int size;
+ } mem[6];
+
+ uchar intl; /* interrupt line */
+
+ Pcidev* list;
+ Pcidev* link; /* next device on this bno */
+
+ Pcidev* bridge; /* down a bus */
+ struct {
+ ulong bar;
+ int size;
+ } ioa, mema;
+
+ int pmrb; /* power management register block */
+};
+
+#define PCIWINDOW 0x40000000
+#define PCIWADDR(va) (PADDR(va)+PCIWINDOW)
+#define ISAWINDOW 0x00800000
+#define ISAWADDR(va) (PADDR(va)+ISAWINDOW)
+
+/*
+ * PCMCIA support code.
+ */
+/*
+ * Map between ISA memory space and PCMCIA card memory space.
+ */
+struct PCMmap {
+ ulong ca; /* card address */
+ ulong cea; /* card end address */
+ ulong isa; /* ISA address */
+ int len; /* length of the ISA area */
+ int attr; /* attribute memory */
+ int ref;
+};
diff --git a/sys/src/9/alphapc/kbd.c b/sys/src/9/alphapc/kbd.c
new file mode 100755
index 000000000..73ad3e1dd
--- /dev/null
+++ b/sys/src/9/alphapc/kbd.c
@@ -0,0 +1,456 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+enum {
+ Data= 0x60, /* data port */
+
+ Status= 0x64, /* status port */
+ Inready= 0x01, /* input character ready */
+ Outbusy= 0x02, /* output busy */
+ Sysflag= 0x04, /* system flag */
+ Cmddata= 0x08, /* cmd==0, data==1 */
+ Inhibit= 0x10, /* keyboard/mouse inhibited */
+ Minready= 0x20, /* mouse character ready */
+ Rtimeout= 0x40, /* general timeout */
+ Parity= 0x80,
+
+ Cmd= 0x64, /* command port (write only) */
+
+ Spec= 0x80,
+
+ PF= Spec|0x20, /* num pad function key */
+ View= Spec|0x00, /* view (shift window up) */
+ KF= 0xF000, /* function key (begin Unicode private space) */
+ Shift= Spec|0x60,
+ Break= Spec|0x61,
+ Ctrl= Spec|0x62,
+ Latin= Spec|0x63,
+ Caps= Spec|0x64,
+ Num= Spec|0x65,
+ Middle= Spec|0x66,
+ No= 0x00, /* peter */
+
+ Home= KF|13,
+ Up= KF|14,
+ Pgup= KF|15,
+ Print= KF|16,
+ Left= KF|17,
+ Right= KF|18,
+ End= '\r',
+ Down= View,
+ Pgdown= KF|19,
+ Ins= KF|20,
+ Scroll= KF|21,
+ Del= 0x7F,
+};
+
+/*
+ * The codes at 0x79 and 0x81 are produed by the PFU Happy Hacking keyboard.
+ * A 'standard' keyboard doesn't produce anything above 0x58.
+ */
+Rune kbtab[] =
+{
+[0x00] No, 0x1b, '1', '2', '3', '4', '5', '6',
+[0x08] '7', '8', '9', '0', '-', '=', '\b', '\t',
+[0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+[0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's',
+[0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+[0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v',
+[0x30] 'b', 'n', 'm', ',', '.', '/', Shift, '*',
+[0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
+[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7',
+[0x48] '8', '9', '-', '4', '5', '6', '+', '1',
+[0x50] '2', '3', '0', '.', No, No, No, KF|11,
+[0x58] KF|12, No, No, No, No, No, No, No,
+[0x60] No, No, No, No, No, No, No, No,
+[0x68] No, No, No, No, No, No, No, No,
+[0x70] No, No, No, No, No, No, No, No,
+[0x78] No, View, No, Up, No, No, No, No,
+};
+
+Rune kbtabshift[] =
+{
+[0x00] No, 0x1b, '!', '@', '#', '$', '%', '^',
+[0x08] '&', '*', '(', ')', '_', '+', '\b', '\t',
+[0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+[0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S',
+[0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+[0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V',
+[0x30] 'B', 'N', 'M', '<', '>', '?', Shift, '*',
+[0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
+[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7',
+[0x48] '8', '9', '-', '4', '5', '6', '+', '1',
+[0x50] '2', '3', '0', '.', No, No, No, KF|11,
+[0x58] KF|12, No, No, No, No, No, No, No,
+[0x60] No, No, No, No, No, No, No, No,
+[0x68] No, No, No, No, No, No, No, No,
+[0x70] No, No, No, No, No, No, No, No,
+[0x78] No, Up, No, Up, No, No, No, No,
+};
+
+Rune kbtabesc1[] =
+{
+[0x00] No, No, No, No, No, No, No, No,
+[0x08] No, No, No, No, No, No, No, No,
+[0x10] No, No, No, No, No, No, No, No,
+[0x18] No, No, No, No, '\n', Ctrl, No, No,
+[0x20] No, No, No, No, No, No, No, No,
+[0x28] No, No, Shift, No, No, No, No, No,
+[0x30] No, No, No, No, No, '/', No, Print,
+[0x38] Latin, No, No, No, No, No, No, No,
+[0x40] No, No, No, No, No, No, Break, Home,
+[0x48] Up, Pgup, No, Left, No, Right, No, End,
+[0x50] Down, Pgdown, Ins, Del, No, No, No, No,
+[0x58] No, No, No, No, No, No, No, No,
+[0x60] No, No, No, No, No, No, No, No,
+[0x68] No, No, No, No, No, No, No, No,
+[0x70] No, No, No, No, No, No, No, No,
+[0x78] No, Up, No, No, No, No, No, No,
+};
+
+enum
+{
+ /* controller command byte */
+ Cscs1= (1<<6), /* scan code set 1 */
+ Cauxdis= (1<<5), /* mouse disable */
+ Ckbddis= (1<<4), /* kbd disable */
+ Csf= (1<<2), /* system flag */
+ Cauxint= (1<<1), /* mouse interrupt enable */
+ Ckbdint= (1<<0), /* kbd interrupt enable */
+};
+
+static Lock i8042lock;
+static uchar ccc;
+static void (*auxputc)(int, int);
+
+/*
+ * wait for output no longer busy
+ */
+static int
+outready(void)
+{
+ int tries;
+
+ for(tries = 0; (inb(Status) & Outbusy); tries++){
+ if(tries > 500)
+ return -1;
+ delay(2);
+ }
+ return 0;
+}
+
+/*
+ * wait for input
+ */
+static int
+inready(void)
+{
+ int tries;
+
+ for(tries = 0; !(inb(Status) & Inready); tries++){
+ if(tries > 500)
+ return -1;
+ delay(2);
+ }
+ return 0;
+}
+
+/*
+ * ask 8042 to reset the machine
+ */
+void
+i8042reset(void)
+{
+ ushort *s = KADDR(0x472);
+ int i, x;
+
+ *s = 0x1234; /* BIOS warm-boot flag */
+
+ /*
+ * newer reset the machine command
+ */
+ outready();
+ outb(Cmd, 0xFE);
+ outready();
+
+ /*
+ * Pulse it by hand (old somewhat reliable)
+ */
+ x = 0xDF;
+ for(i = 0; i < 5; i++){
+ x ^= 1;
+ outready();
+ outb(Cmd, 0xD1);
+ outready();
+ outb(Data, x); /* toggle reset */
+ delay(100);
+ }
+}
+
+int
+i8042auxcmd(int cmd)
+{
+ unsigned int c;
+ int tries;
+
+ c = 0;
+ tries = 0;
+
+ ilock(&i8042lock);
+ do{
+ if(tries++ > 2)
+ break;
+ if(outready() < 0)
+ break;
+ outb(Cmd, 0xD4);
+ if(outready() < 0)
+ break;
+ outb(Data, cmd);
+ if(outready() < 0)
+ break;
+ if(inready() < 0)
+ break;
+ c = inb(Data);
+ } while(c == 0xFE || c == 0);
+ iunlock(&i8042lock);
+
+ if(c != 0xFA){
+ print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * keyboard interrupt
+ */
+static void
+i8042intr(Ureg*, void*)
+{
+ int s, c, i;
+ static int esc1, esc2;
+ static int alt, caps, ctl, num, shift;
+ static int collecting, nk;
+ static Rune kc[5];
+ int keyup;
+
+ /*
+ * get status
+ */
+ lock(&i8042lock);
+ s = inb(Status);
+ if(!(s&Inready)){
+ unlock(&i8042lock);
+ return;
+ }
+
+ /*
+ * get the character
+ */
+ c = inb(Data);
+ unlock(&i8042lock);
+
+ /*
+ * if it's the aux port...
+ */
+ if(s & Minready){
+ if(auxputc != nil)
+ auxputc(c, shift);
+ return;
+ }
+
+ /*
+ * e0's is the first of a 2 character sequence
+ */
+ if(c == 0xe0){
+ esc1 = 1;
+ return;
+ } else if(c == 0xe1){
+ esc2 = 2;
+ return;
+ }
+
+ keyup = c&0x80;
+ c &= 0x7f;
+ if(c > sizeof kbtab){
+ c |= keyup;
+ if(c != 0xFF) /* these come fairly often: CAPSLOCK U Y */
+ print("unknown key %ux\n", c);
+ return;
+ }
+
+ if(esc1){
+ c = kbtabesc1[c];
+ esc1 = 0;
+ } else if(esc2){
+ esc2--;
+ return;
+ } else if(shift)
+ c = kbtabshift[c];
+ else
+ c = kbtab[c];
+
+ if(caps && c<='z' && c>='a')
+ c += 'A' - 'a';
+
+ /*
+ * keyup only important for shifts
+ */
+ if(keyup){
+ switch(c){
+ case Latin:
+ alt = 0;
+ break;
+ case Shift:
+ shift = 0;
+ break;
+ case Ctrl:
+ ctl = 0;
+ break;
+ }
+ return;
+ }
+
+ /*
+ * normal character
+ */
+ if(!(c & (Spec|KF))){
+ if(ctl){
+ if(alt && c == Del)
+ exit(0);
+ c &= 0x1f;
+ }
+ if(!collecting){
+ kbdputc(kbdq, c);
+ return;
+ }
+ kc[nk++] = c;
+ c = latin1(kc, nk);
+ if(c < -1) /* need more keystrokes */
+ return;
+ if(c != -1) /* valid sequence */
+ kbdputc(kbdq, c);
+ else /* dump characters */
+ for(i=0; i<nk; i++)
+ kbdputc(kbdq, kc[i]);
+ nk = 0;
+ collecting = 0;
+ return;
+ } else {
+ switch(c){
+ case Caps:
+ caps ^= 1;
+ return;
+ case Num:
+ num ^= 1;
+ return;
+ case Shift:
+ shift = 1;
+ return;
+ case Latin:
+ alt = 1;
+ collecting = 1;
+ nk = 0;
+ return;
+ case Ctrl:
+ ctl = 1;
+ return;
+ }
+ }
+ kbdputc(kbdq, c);
+}
+
+void
+i8042auxenable(void (*putc)(int, int))
+{
+ char *err = "i8042: aux init failed\n";
+
+ /* enable kbd/aux xfers and interrupts */
+ ccc &= ~Cauxdis;
+ ccc |= Cauxint;
+
+ ilock(&i8042lock);
+ if(outready() < 0)
+ print(err);
+ outb(Cmd, 0x60); /* write control register */
+ if(outready() < 0)
+ print(err);
+ outb(Data, ccc);
+ if(outready() < 0)
+ print(err);
+ outb(Cmd, 0xA8); /* auxilliary device enable */
+ if(outready() < 0){
+ iunlock(&i8042lock);
+ return;
+ }
+ auxputc = putc;
+ intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
+ iunlock(&i8042lock);
+}
+
+static void
+setscan(int code)
+{
+ char *err = "setscan: set scan code failed\n";
+
+ outb(Data, 0xF0);
+ if(inready() < 0 || inb(Data) != 0xFA || outready() < 0) {
+ print(err);
+ return;
+ }
+ outb(Data, code);
+ if(inready() < 0) {
+ print(err);
+ return;
+ }
+ inb(Data);
+ if(outready() < 0)
+ print(err);
+}
+
+void
+kbdinit(void)
+{
+ int c;
+
+ kbdq = qopen(4*1024, 0, 0, 0);
+ if(kbdq == nil)
+ panic("kbdinit");
+ qnoblock(kbdq, 1);
+
+ ioalloc(Data, 1, 0, "kbd");
+ ioalloc(Cmd, 1, 0, "kbd");
+
+ intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");
+
+ /* wait for a quiescent controller */
+ while((c = inb(Status)) & (Outbusy | Inready))
+ if(c & Inready)
+ inb(Data);
+
+ /* get current controller command byte */
+ outb(Cmd, 0x20);
+ if(inready() < 0){
+ print("kbdinit: can't read ccc\n");
+ ccc = 0;
+ } else
+ ccc = inb(Data);
+
+ /* enable kbd xfers and interrupts */
+ /* disable mouse */
+ ccc &= ~Ckbddis;
+ ccc |= Csf | Ckbdint | Cscs1;
+ if(outready() < 0)
+ print("kbd init failed\n");
+ outb(Cmd, 0x60);
+ if(outready() < 0)
+ print("kbd init failed\n");
+ outb(Data, ccc);
+ outready();
+ setscan(0x02);
+}
diff --git a/sys/src/9/alphapc/l.s b/sys/src/9/alphapc/l.s
new file mode 100755
index 000000000..a5c17c32b
--- /dev/null
+++ b/sys/src/9/alphapc/l.s
@@ -0,0 +1,457 @@
+#include "mem.h"
+#include "osf1pal.h"
+
+#define SP R30
+
+#define HI_IPL 6 /* use 7 to disable mchecks */
+
+TEXT _main(SB), $-8
+ MOVQ $setSB(SB), R29
+ MOVQ R29, R16
+ CALL_PAL $PALwrkgp
+ MOVQ $mach0(SB), R(MACH)
+ MOVQ $(BY2PG-8)(R(MACH)), R30
+ MOVQ R31, R(USER)
+ MOVQ R31, 0(R(MACH))
+
+ MOVQ $edata(SB), R1
+ MOVQ $end(SB), R2
+clrbss:
+ MOVQ R31, (R1)
+ ADDQ $8, R1
+ CMPUGT R1, R2, R3
+ BEQ R3, clrbss
+
+ MOVL R0, bootconf(SB) /* passed in from boot loader */
+
+_fpinit:
+ MOVQ $1, R16
+ CALL_PAL $PALwrfen
+
+ MOVQ initfpcr(SB), R1 /* MOVQ $0x2800800000000000, R1 */
+ MOVQ R1, (R30)
+ MOVT (R30), F1
+ MOVT F1, FPCR
+
+ MOVT $0.5, F28
+ ADDT F28, F28, F29
+ ADDT F29, F29, F30
+
+ MOVT F31, F1
+ MOVT F31, F2
+ MOVT F31, F3
+ MOVT F31, F4
+ MOVT F31, F5
+ MOVT F31, F6
+ MOVT F31, F7
+ MOVT F31, F8
+ MOVT F31, F9
+ MOVT F31, F10
+ MOVT F31, F11
+ MOVT F31, F12
+ MOVT F31, F13
+ MOVT F31, F14
+ MOVT F31, F15
+ MOVT F31, F16
+ MOVT F31, F17
+ MOVT F31, F18
+ MOVT F31, F19
+ MOVT F31, F20
+ MOVT F31, F21
+ MOVT F31, F22
+ MOVT F31, F23
+ MOVT F31, F24
+ MOVT F31, F25
+ MOVT F31, F26
+ MOVT F31, F27
+
+ JSR main(SB)
+ MOVQ $_divq(SB), R31 /* touch _divq etc.; doesn't need to execute */
+ MOVQ $_divl(SB), R31 /* touch _divl etc.; doesn't need to execute */
+ RET
+
+TEXT setpcb(SB), $-8
+ MOVQ R30, (R0)
+ AND $0x7FFFFFFF, R0, R16 /* make address physical */
+ CALL_PAL $PALswpctx
+ RET
+
+GLOBL mach0(SB), $(MAXMACH*BY2PG)
+GLOBL init_ptbr(SB), $8
+
+TEXT firmware(SB), $-8
+ CALL_PAL $PALhalt
+
+TEXT xxfirmware(SB), $-8
+ CALL_PAL $PALhalt
+
+TEXT splhi(SB), $0
+
+ MOVL R26, 4(R(MACH)) /* save PC in m->splpc */
+ MOVQ $HI_IPL, R16
+ CALL_PAL $PALswpipl
+ RET
+
+TEXT spllo(SB), $0
+ MOVQ R31, R16
+ CALL_PAL $PALswpipl
+ RET
+
+TEXT splx(SB), $0
+ MOVL R26, 4(R(MACH)) /* save PC in m->splpc */
+
+TEXT splxpc(SB), $0 /* for iunlock */
+ MOVQ R0, R16
+ CALL_PAL $PALswpipl
+ RET
+
+TEXT spldone(SB), $0
+ RET
+
+TEXT islo(SB), $0
+ CALL_PAL $PALrdps
+ AND $IPL, R0
+ XOR $HI_IPL, R0
+ RET
+
+TEXT mb(SB), $-8
+ MB
+ RET
+
+TEXT icflush(SB), $-8
+ CALL_PAL $PALimb
+ RET
+
+TEXT tlbflush(SB), $-8
+ MOVQ R0, R16
+ MOVL 4(FP), R17
+ CALL_PAL $PALtbi
+ RET
+
+TEXT swpctx(SB), $-8
+ MOVQ R0, R16
+ AND $0x7FFFFFFF, R16 /* make address physical */
+ CALL_PAL $PALswpctx
+ RET
+
+TEXT wrent(SB), $-8
+ MOVQ R0, R17
+ MOVL 4(FP), R16
+ CALL_PAL $PALwrent
+ RET
+
+TEXT wrvptptr(SB), $-8
+ MOVQ R0, R16
+ CALL_PAL $PALwrvptptr
+ RET
+
+TEXT cserve(SB), $-8
+ MOVQ R0, R16
+ MOVL 4(FP), R17
+ CALL_PAL $PALcserve
+ RET
+
+TEXT setlabel(SB), $-8
+ MOVL R30, 0(R0)
+ MOVL R26, 4(R0)
+ MOVQ $0, R0
+ RET
+
+TEXT gotolabel(SB), $-8
+ MOVL 0(R0), R30
+ MOVL 4(R0), R26
+ MOVQ $1, R0
+ RET
+
+TEXT tas(SB), $-8
+ MOVQ R0, R1 /* l */
+tas1:
+ MOVLL (R1), R0 /* l->key */
+ BNE R0, tas2
+ MOVQ $1, R2
+ MOVLC R2, (R1) /* l->key = 1 */
+ BEQ R2, tas1 /* write failed, try again? */
+tas2:
+ RET
+
+TEXT _xdec(SB), $-8
+ MOVQ R0, R1 /* p */
+dec1:
+ MOVLL (R1), R0 /* *p */
+ SUBL $1, R0
+ MOVQ R0, R2
+ MOVLC R2, (R1) /* --(*p) */
+ BEQ R2, dec1 /* write failed, retry */
+ RET
+
+TEXT _xinc(SB), $-8
+ MOVQ R0, R1 /* p */
+inc1:
+ MOVLL (R1), R0 /* *p */
+ ADDL $1, R0
+ MOVLC R0, (R1) /* (*p)++ */
+ BEQ R0, inc1 /* write failed, retry */
+ RET
+
+TEXT cmpswap(SB), $-8
+ MOVQ R0, R1 /* p */
+ MOVL old+4(FP), R2
+ MOVL new+8(FP), R3
+ MOVLL (R1), R0
+ CMPEQ R0, R2, R4
+ BEQ R4, fail /* if R0 != [sic] R2, goto fail */
+ MOVQ R3, R0
+ MOVLC R0, (R1)
+ RET
+fail:
+ MOVL $0, R0
+ RET
+
+TEXT fpenab(SB), $-8
+ MOVQ R0, R16
+ CALL_PAL $PALwrfen
+ RET
+
+TEXT rpcc(SB), $0
+ MOVL R0, R1
+ MOVL $0, R0
+ WORD $0x6000C000 /* RPCC R0 */
+ BEQ R1, _ret
+ MOVQ R0, (R1)
+_ret:
+ RET
+
+/*
+ * Exception handlers. The stack frame looks like this:
+ *
+ * R30+0: (unused) link reg storage (R26) (32 bits)
+ * R30+4: padding for alignment (32 bits)
+ * R30+8: trap()'s first arg storage (R0) (32 bits -- type Ureg*)
+ * R30+12: padding for alignment (32 bits)
+ * R30+16: first 31 fields of Ureg, saved here (31*64 bits)
+ * R30+264: other 6 fields of Ureg, saved by PALcode (6*64 bits)
+ * R30+312: previous value of KSP before trap
+ */
+
+TEXT arith(SB), $-8
+ SUBQ $(4*BY2WD+31*BY2V), R30
+ MOVQ R0, (4*BY2WD+4*BY2V)(R30)
+ MOVQ $1, R0
+ JMP trapcommon
+
+TEXT illegal0(SB), $-8
+ SUBQ $(4*BY2WD+31*BY2V), R30
+ MOVQ R0, (4*BY2WD+4*BY2V)(R30)
+ MOVQ $2, R0
+ JMP trapcommon
+
+TEXT fault0(SB), $-8
+ SUBQ $(4*BY2WD+31*BY2V), R30
+ MOVQ R0, (4*BY2WD+4*BY2V)(R30)
+ MOVQ $4, R0
+ JMP trapcommon
+
+TEXT unaligned(SB), $-8
+ SUBQ $(4*BY2WD+31*BY2V), R30
+ MOVQ R0, (4*BY2WD+4*BY2V)(R30)
+ MOVQ $6, R0
+ JMP trapcommon
+
+TEXT intr0(SB), $-8
+ SUBQ $(4*BY2WD+31*BY2V), R30
+ MOVQ R0, (4*BY2WD+4*BY2V)(R30)
+ MOVQ $3, R0
+
+trapcommon:
+ MOVQ R0, (4*BY2WD+0*BY2V)(R30)
+ MOVQ R16, (4*BY2WD+1*BY2V)(R30)
+ MOVQ R17, (4*BY2WD+2*BY2V)(R30)
+ MOVQ R18, (4*BY2WD+3*BY2V)(R30)
+
+ /* R0 already saved, (4*BY2WD+4*BY2V)(R30) */
+ MOVQ R1, (4*BY2WD+5*BY2V)(R30)
+ MOVQ R2, (4*BY2WD+6*BY2V)(R30)
+ MOVQ R3, (4*BY2WD+7*BY2V)(R30)
+ MOVQ R4, (4*BY2WD+8*BY2V)(R30)
+ MOVQ R5, (4*BY2WD+9*BY2V)(R30)
+ MOVQ R6, (4*BY2WD+10*BY2V)(R30)
+ MOVQ R7, (4*BY2WD+11*BY2V)(R30)
+ MOVQ R8, (4*BY2WD+12*BY2V)(R30)
+ MOVQ R9, (4*BY2WD+13*BY2V)(R30)
+ MOVQ R10, (4*BY2WD+14*BY2V)(R30)
+ MOVQ R11, (4*BY2WD+15*BY2V)(R30)
+ MOVQ R12, (4*BY2WD+16*BY2V)(R30)
+ MOVQ R13, (4*BY2WD+17*BY2V)(R30)
+ MOVQ R14, (4*BY2WD+18*BY2V)(R30)
+ MOVQ R15, (4*BY2WD+19*BY2V)(R30)
+ MOVQ R19, (4*BY2WD+20*BY2V)(R30)
+ MOVQ R20, (4*BY2WD+21*BY2V)(R30)
+ MOVQ R21, (4*BY2WD+22*BY2V)(R30)
+ MOVQ R22, (4*BY2WD+23*BY2V)(R30)
+ MOVQ R23, (4*BY2WD+24*BY2V)(R30)
+ MOVQ R24, (4*BY2WD+25*BY2V)(R30)
+ MOVQ R25, (4*BY2WD+26*BY2V)(R30)
+ MOVQ R26, (4*BY2WD+27*BY2V)(R30)
+ MOVQ R27, (4*BY2WD+28*BY2V)(R30)
+ MOVQ R28, (4*BY2WD+29*BY2V)(R30)
+
+ MOVQ $HI_IPL, R16
+ CALL_PAL $PALswpipl
+
+ CALL_PAL $PALrdusp
+ MOVQ R0, (4*BY2WD+30*BY2V)(R30) /* save USP */
+
+ MOVQ $mach0(SB), R(MACH)
+ MOVQ $(4*BY2WD)(R30), R0
+ JSR trap(SB)
+trapret:
+ MOVQ (4*BY2WD+30*BY2V)(R30), R16 /* USP */
+ CALL_PAL $PALwrusp /* ... */
+ MOVQ (4*BY2WD+4*BY2V)(R30), R0
+ MOVQ (4*BY2WD+5*BY2V)(R30), R1
+ MOVQ (4*BY2WD+6*BY2V)(R30), R2
+ MOVQ (4*BY2WD+7*BY2V)(R30), R3
+ MOVQ (4*BY2WD+8*BY2V)(R30), R4
+ MOVQ (4*BY2WD+9*BY2V)(R30), R5
+ MOVQ (4*BY2WD+10*BY2V)(R30), R6
+ MOVQ (4*BY2WD+11*BY2V)(R30), R7
+ MOVQ (4*BY2WD+12*BY2V)(R30), R8
+ MOVQ (4*BY2WD+13*BY2V)(R30), R9
+ MOVQ (4*BY2WD+14*BY2V)(R30), R10
+ MOVQ (4*BY2WD+15*BY2V)(R30), R11
+ MOVQ (4*BY2WD+16*BY2V)(R30), R12
+ MOVQ (4*BY2WD+17*BY2V)(R30), R13
+ MOVQ (4*BY2WD+18*BY2V)(R30), R14
+ MOVQ (4*BY2WD+19*BY2V)(R30), R15
+ MOVQ (4*BY2WD+20*BY2V)(R30), R19
+ MOVQ (4*BY2WD+21*BY2V)(R30), R20
+ MOVQ (4*BY2WD+22*BY2V)(R30), R21
+ MOVQ (4*BY2WD+23*BY2V)(R30), R22
+ MOVQ (4*BY2WD+24*BY2V)(R30), R23
+ MOVQ (4*BY2WD+25*BY2V)(R30), R24
+ MOVQ (4*BY2WD+26*BY2V)(R30), R25
+ MOVQ (4*BY2WD+27*BY2V)(R30), R26
+ MOVQ (4*BY2WD+28*BY2V)(R30), R27
+ MOVQ (4*BY2WD+29*BY2V)(R30), R28
+ /* USP already restored from (4*BY2WD+30*BY2V)(R30) */
+ ADDQ $(4*BY2WD+31*BY2V), R30
+ CALL_PAL $PALrti
+
+TEXT forkret(SB), $0
+ MOVQ R31, R0 /* Fake out system call return */
+ JMP systrapret
+
+TEXT syscall0(SB), $-8
+ SUBQ $(4*BY2WD+31*BY2V), R30
+ MOVQ R0, (4*BY2WD+4*BY2V)(R30) /* save scallnr in R0 */
+ MOVQ $HI_IPL, R16
+ CALL_PAL $PALswpipl
+ MOVQ $mach0(SB), R(MACH)
+ CALL_PAL $PALrdusp
+ MOVQ R0, (4*BY2WD+30*BY2V)(R30) /* save USP */
+ MOVQ R26, (4*BY2WD+27*BY2V)(R30) /* save last return address */
+ MOVQ $(4*BY2WD)(R30), R0 /* pass address of Ureg */
+ JSR syscall(SB)
+systrapret:
+ MOVQ (4*BY2WD+30*BY2V)(R30), R16 /* USP */
+ CALL_PAL $PALwrusp /* consider doing this in execregs... */
+ MOVQ (4*BY2WD+27*BY2V)(R30), R26 /* restore last return address */
+ ADDQ $(4*BY2WD+31*BY2V), R30
+ CALL_PAL $PALretsys
+
+/*
+ * Take first processor into user mode
+ * - argument is stack pointer to user
+ */
+
+TEXT touser(SB), $-8
+ MOVQ R0, R16
+ CALL_PAL $PALwrusp /* set USP to value passed */
+ SUBQ $(6*BY2V), R30 /* create frame for retsys */
+ MOVQ $(UTZERO+32), R26 /* header appears in text */
+ MOVQ R26, (1*BY2V)(R30) /* PC -- only reg that matters */
+ CALL_PAL $PALretsys
+
+TEXT rfnote(SB), $0
+ SUBL $(2*BY2WD), R0, SP
+ JMP trapret
+
+TEXT savefpregs(SB), $-8
+ MOVT F0, 0x00(R0)
+ MOVT F1, 0x08(R0)
+ MOVT F2, 0x10(R0)
+ MOVT F3, 0x18(R0)
+ MOVT F4, 0x20(R0)
+ MOVT F5, 0x28(R0)
+ MOVT F6, 0x30(R0)
+ MOVT F7, 0x38(R0)
+ MOVT F8, 0x40(R0)
+ MOVT F9, 0x48(R0)
+ MOVT F10, 0x50(R0)
+ MOVT F11, 0x58(R0)
+ MOVT F12, 0x60(R0)
+ MOVT F13, 0x68(R0)
+ MOVT F14, 0x70(R0)
+ MOVT F15, 0x78(R0)
+ MOVT F16, 0x80(R0)
+ MOVT F17, 0x88(R0)
+ MOVT F18, 0x90(R0)
+ MOVT F19, 0x98(R0)
+ MOVT F20, 0xA0(R0)
+ MOVT F21, 0xA8(R0)
+ MOVT F22, 0xB0(R0)
+ MOVT F23, 0xB8(R0)
+ MOVT F24, 0xC0(R0)
+ MOVT F25, 0xC8(R0)
+ MOVT F26, 0xD0(R0)
+ MOVT F27, 0xD8(R0)
+ MOVT F28, 0xE0(R0)
+ MOVT F29, 0xE8(R0)
+ MOVT F30, 0xF0(R0)
+ MOVT F31, 0xF8(R0)
+ MOVT FPCR, F0
+ MOVT F0, 0x100(R0)
+
+ MOVQ $0, R16
+ CALL_PAL $PALwrfen /* disable */
+ RET
+
+TEXT restfpregs(SB), $-8
+ MOVQ $1, R16
+ CALL_PAL $PALwrfen /* enable */
+
+ MOVT 0x100(R0), F0
+ MOVT F0, FPCR
+ MOVT 0x00(R0), F0
+ MOVT 0x08(R0), F1
+ MOVT 0x10(R0), F2
+ MOVT 0x18(R0), F3
+ MOVT 0x20(R0), F4
+ MOVT 0x28(R0), F5
+ MOVT 0x30(R0), F6
+ MOVT 0x38(R0), F7
+ MOVT 0x40(R0), F8
+ MOVT 0x48(R0), F9
+ MOVT 0x50(R0), F10
+ MOVT 0x58(R0), F11
+ MOVT 0x60(R0), F12
+ MOVT 0x68(R0), F13
+ MOVT 0x70(R0), F14
+ MOVT 0x78(R0), F15
+ MOVT 0x80(R0), F16
+ MOVT 0x88(R0), F17
+ MOVT 0x90(R0), F18
+ MOVT 0x98(R0), F19
+ MOVT 0xA0(R0), F20
+ MOVT 0xA8(R0), F21
+ MOVT 0xB0(R0), F22
+ MOVT 0xB8(R0), F23
+ MOVT 0xC0(R0), F24
+ MOVT 0xC8(R0), F25
+ MOVT 0xD0(R0), F26
+ MOVT 0xD8(R0), F27
+ MOVT 0xE0(R0), F28
+ MOVT 0xE8(R0), F29
+ MOVT 0xF0(R0), F30
+ MOVT 0xF8(R0), F31
+ RET
diff --git a/sys/src/9/alphapc/main.c b/sys/src/9/alphapc/main.c
new file mode 100755
index 000000000..c9f0dcc6e
--- /dev/null
+++ b/sys/src/9/alphapc/main.c
@@ -0,0 +1,703 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "init.h"
+#include "pool.h"
+#include "/sys/src/boot/alphapc/conf.h"
+#include "axp.h"
+
+char argbuf[128]; /* arguments passed to initcode and /boot */
+
+Hwrpb *hwrpb;
+Bootconf *bootconf;
+Conf conf;
+FPsave initfp;
+ /* setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPOVFL) */
+uvlong initfpcr = (1LL<62)|(1LL<61)|(1LL<60)|(2LL<<58)|(1LL<48);
+
+char bootargs[BOOTARGSLEN];
+char *confname[MAXCONF];
+char *confval[MAXCONF];
+int nconf;
+
+static void
+options(void)
+{
+ long i, n;
+ char *cp, *line[MAXCONF], *p, *q;
+
+ cp = bootargs;
+ strncpy(cp, bootconf->bootargs, BOOTARGSLEN);
+ cp[BOOTARGSLEN-1] = 0;
+ /* can't print in this routine, see below in main() */
+
+ /*
+ * Strip out '\r', change '\t' -> ' '.
+ */
+ p = cp;
+ for(q = cp; *q; q++){
+ if(*q == '\r')
+ continue;
+ if(*q == '\t')
+ *q = ' ';
+ *p++ = *q;
+ }
+ *p = 0;
+
+ n = getfields(cp, line, MAXCONF, 1, "\n");
+ for(i = 0; i < n; i++){
+ if(*line[i] == '#')
+ continue;
+ cp = strchr(line[i], '=');
+ if(cp == nil)
+ continue;
+ *cp++ = '\0';
+ confname[nconf] = line[i];
+ confval[nconf] = cp;
+ nconf++;
+ }
+}
+
+/* debugging only */
+static void
+dumpopts(void)
+{
+ int i;
+
+ print("dumpopts: found /alpha/conf options at %#p\n",
+ bootconf->bootargs);
+ for(i = 0; i < nconf; i++)
+ print("dumpopts: read %s=%s\n", confname[i], confval[i]);
+}
+
+extern void (*i8237alloc)(void);
+
+void
+main(void)
+{
+ hwrpb = (Hwrpb*)0x10000000;
+ hwrpb = (Hwrpb*)(KZERO|hwrpb->phys);
+ arginit();
+ machinit();
+ options();
+ ioinit();
+ clockinit();
+ confinit();
+ archinit();
+ xinit();
+ memholes();
+ if(i8237alloc != nil)
+ i8237alloc();
+ mmuinit();
+ if(arch->coreinit)
+ arch->coreinit();
+ trapinit();
+ screeninit();
+ printinit();
+ /* it's now safe to print */
+ /* dumpopts(); /* DEBUG */
+ kbdinit();
+ i8250console();
+ quotefmtinstall();
+ print("\nPlan 9\n");
+
+ cpuidprint();
+ if(arch->corehello)
+ arch->corehello();
+
+ procinit0();
+ initseg();
+ timersinit();
+ links();
+ chandevreset();
+ pageinit();
+ swapinit();
+ savefpregs(&initfp);
+initfp.fpstatus = 0x68028000;
+ userinit();
+ schedinit();
+}
+
+/* cpu->state bits */
+enum {
+ Cpubootinprog = 1, /* boot in progress */
+ Cpucanrestart = 2, /* restart possible */
+ Cpuavail = 4, /* processor available */
+ Cpuexists = 8, /* processor present */
+ Cpuuserhalted = 0x10, /* user halted */
+ Cpuctxtokay = 0x20, /* context valid */
+ Cpupalokay = 0x40, /* PALcode valid */
+ Cpupalmemokay = 0x80, /* PALcode memory valid */
+ Cpupalloaded = 0x100, /* PALcode loaded */
+ Cpuhaltmask = 0xff0000, /* halt request mask */
+ Cpuhaltdflt = 0,
+ Cpuhaltsaveexit = 0x10000,
+ Cpuhaltcoldboot = 0x20000,
+ Cpuhaltwarmboot = 0x30000,
+ Cpuhaltstayhalted = 0x40000,
+ Cpumustbezero = 0xffffffffff000000ULL, /* 24:63 -- must be zero */
+};
+
+/*
+ * initialize a processor's mach structure. each processor does this
+ * for itself.
+ */
+void
+machinit(void)
+{
+ int n;
+ Hwcpu *cpu;
+
+ icflush();
+ n = m->machno;
+ memset(m, 0, sizeof(Mach));
+ m->machno = n;
+
+ active.exiting = 0;
+ active.machs = 1;
+
+ cpu = (Hwcpu*) ((ulong)hwrpb + hwrpb->cpuoff + n*hwrpb->cpulen);
+ cpu->state &= ~Cpubootinprog;
+ if (0)
+ cpu->state |= Cpuhaltstayhalted;
+}
+
+void
+init0(void)
+{
+ int i;
+ char buf[2*KNAMELEN];
+
+ up->nerrlab = 0;
+
+ spllo();
+
+ /*
+ * These are o.k. because rootinit is null.
+ * Then early kproc's will have a root and dot.
+ */
+ up->slash = namec("#/", Atodir, 0, 0);
+ pathclose(up->slash->path);
+ up->slash->path = newpath("/");
+ up->dot = cclone(up->slash);
+
+ chandevinit();
+
+ if(!waserror()){
+ snprint(buf, sizeof(buf), "alpha %s alphapc", conffile);
+ ksetenv("terminal", buf, 0);
+ ksetenv("cputype", "alpha", 0);
+ if(cpuserver)
+ ksetenv("service", "cpu", 0);
+ else
+ ksetenv("service", "terminal", 0);
+ for(i = 0; i < nconf; i++)
+ if(confname[i]){
+ if(confname[i][0] != '*')
+ ksetenv(confname[i], confval[i], 0);
+ ksetenv(confname[i], confval[i], 1);
+ }
+ poperror();
+ }
+
+ kproc("alarm", alarmkproc, 0);
+ touser((uchar*)(USTKTOP - sizeof(argbuf)));
+}
+
+void
+userinit(void)
+{
+ Proc *p;
+ Segment *s;
+ KMap *k;
+ char **av;
+ Page *pg;
+
+ p = newproc();
+ p->pgrp = newpgrp();
+ p->egrp = smalloc(sizeof(Egrp));
+ p->egrp->ref = 1;
+ p->fgrp = dupfgrp(nil);
+ p->rgrp = newrgrp();
+ p->procmode = 0640;
+
+ kstrdup(&eve, "");
+ kstrdup(&p->text, "*init*");
+ kstrdup(&p->user, eve);
+
+ procsetup(p);
+
+ /*
+ * Kernel Stack
+ */
+ p->sched.pc = (ulong)init0;
+ p->sched.sp = (ulong)p->kstack+KSTACK-MAXSYSARG*BY2WD;
+ /*
+ * User Stack, pass input arguments to boot process
+ */
+ s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
+ p->seg[SSEG] = s;
+ pg = newpage(1, 0, USTKTOP-BY2PG);
+ segpage(s, pg);
+ k = kmap(pg);
+ for(av = (char**)argbuf; *av; av++)
+ *av += (USTKTOP - sizeof(argbuf)) - (ulong)argbuf;
+
+ memmove((uchar*)VA(k) + BY2PG - sizeof(argbuf), argbuf, sizeof argbuf);
+ kunmap(k);
+
+ /*
+ * Text
+ */
+ s = newseg(SG_TEXT, UTZERO, 1);
+ s->flushme++;
+ p->seg[TSEG] = s;
+ pg = newpage(1, 0, UTZERO);
+ memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
+ segpage(s, pg);
+ k = kmap(s->map[0]->pages[0]);
+ memmove((uchar*)VA(k), initcode, sizeof initcode);
+ kunmap(k);
+
+ ready(p);
+}
+
+void
+procsetup(Proc *p)
+{
+ p->fpstate = FPinit;
+ fpenab(0);
+}
+
+void
+procsave(Proc *p)
+{
+ if(p->fpstate == FPactive){
+ if(p->state == Moribund)
+ fpenab(0);
+ else
+ savefpregs(&up->fpsave);
+ p->fpstate = FPinactive;
+ }
+
+ /*
+ * Switch to the prototype page tables for this processor.
+ * While this processor is in the scheduler, the process could run
+ * on another processor and exit, returning the page tables to
+ * the free list where they could be reallocated and overwritten.
+ * When this processor eventually has to get an entry from the
+ * trashed page tables it will crash.
+ */
+ mmupark();
+}
+
+void
+setupboot(int halt)
+{
+ int n = 0; // cpu id of primary cpu, not just m->machno
+ Hwcpu *cpu = (Hwcpu*)((ulong)hwrpb + hwrpb->cpuoff + n*hwrpb->cpulen);
+
+ cpu->state &= ~(Cpucanrestart | Cpuhaltmask);
+ cpu->state |= (halt? Cpuhaltstayhalted: Cpuhaltwarmboot);
+}
+
+/* from ../pc */
+static void
+shutdown(int ispanic)
+{
+ int ms, once;
+
+ lock(&active);
+ if(ispanic)
+ active.ispanic = ispanic;
+ else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
+ active.ispanic = 0;
+ once = active.machs & (1<<m->machno);
+ active.machs &= ~(1<<m->machno);
+ active.exiting = 1;
+ unlock(&active);
+
+ if(once)
+ print("cpu%d: exiting\n", m->machno);
+ spllo();
+ for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
+ delay(TK2MS(2));
+ if(active.machs == 0 && consactive() == 0)
+ break;
+ }
+
+ if(active.ispanic && m->machno == 0) {
+ if(cpuserver)
+ delay(10000);
+ else
+ for (;;)
+ continue;
+ } else
+ delay(1000);
+}
+
+/* from ../pc: */
+void
+reboot(void *entry, void *code, ulong size)
+{
+ // writeconf(); // pass kernel environment to next kernel
+ shutdown(0);
+
+ /*
+ * should be the only processor running now
+ */
+ print("shutting down...\n");
+ delay(200);
+
+ splhi();
+
+ /* turn off buffered serial console */
+ serialoq = nil;
+
+ /* shutdown devices */
+ chandevshutdown();
+
+#ifdef FUTURE
+{
+ ulong *pdb;
+ /*
+ * Modify the machine page table to directly map the low 4MB of memory
+ * This allows the reboot code to turn off the page mapping
+ */
+ pdb = m->pdb;
+ pdb[PDX(0)] = pdb[PDX(KZERO)];
+ mmuflushtlb(PADDR(pdb));
+}
+ /* setup reboot trampoline function */
+{
+ void (*f)(ulong, ulong, ulong) = (void*)REBOOTADDR;
+
+ memmove(f, rebootcode, sizeof(rebootcode));
+#else
+ USED(entry, code, size);
+#endif
+
+ print("rebooting...\n");
+#ifdef FUTURE
+ /* off we go - never to return */
+ (*f)(PADDR(entry), PADDR(code), size);
+}
+#endif
+ setupboot(0); // reboot, don't halt
+ exit(0);
+}
+
+void
+exit(int ispanic)
+{
+ canlock(&active);
+ active.machs &= ~(1<<m->machno);
+ active.exiting = 1;
+ unlock(&active);
+
+ spllo();
+ print("cpu %d exiting\n", m->machno);
+ do
+ delay(100);
+ while(consactive());
+
+ splhi();
+ delay(1000); /* give serial fifo time to finish flushing */
+ if (getconf("*debug") != nil) {
+ USED(ispanic);
+ delay(60*1000); /* give us time to read the screen */
+ }
+ if(arch->coredetach)
+ arch->coredetach();
+ setupboot(1); // set up to halt
+ for (; ; )
+ firmware();
+
+ // on PC is just:
+ //if (0) {
+ // shutdown(ispanic);
+ // arch->reset();
+ //}
+}
+
+void
+confinit(void)
+{
+ ulong ktop, kpages;
+ Bank *b, *eb;
+ extern void _main(void);
+ int userpcnt;
+ char *p;
+
+ if(p = getconf("*kernelpercent"))
+ userpcnt = 100 - strtol(p, 0, 0);
+ else
+ userpcnt = 0;
+
+ /*
+ * The console firmware divides memory into 1 or more banks.
+ * FInd the bank with the kernel in it.
+ */
+ b = bootconf->bank;
+ eb = b+bootconf->nbank;
+ ktop = PGROUND((ulong)end);
+ ktop = PADDR(ktop);
+ while(b < eb) {
+ if(b->min < ktop && ktop < b->max)
+ break;
+ b++;
+ }
+ if(b == eb)
+ panic("confinit");
+
+ /*
+ * Split the bank of memory into 2 banks to fool the allocator into
+ * allocating low memory pages from bank 0 for any peripherals
+ * which only have a 24bit address counter.
+ */
+ conf.mem[0].npage = (8*1024*1024)/BY2PG;
+ conf.mem[0].base = 0;
+
+ conf.mem[1].npage = (b->max-8*1024*1024)/BY2PG;
+ conf.mem[1].base = 8*1024*1024;
+
+ conf.npage = conf.mem[0].npage+conf.mem[1].npage;
+ conf.upages = (conf.npage*70)/100;
+
+ conf.mem[0].npage -= ktop/BY2PG;
+ conf.mem[0].base += ktop;
+ conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
+
+ /*
+ * Fix up the bank we found to be the remnant, below the kernel.
+ * This, and the other banks, will be passed to xhole() later.
+ * BUG: conf.upages needs to be adjusted, but how? In practice,
+ * we only have 1 bank, and the remnant is small.
+ */
+ b->max = (uvlong)_main & ~(BY2PG-1);
+
+ conf.nmach = 1;
+ conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
+ if(cpuserver)
+ conf.nproc *= 3;
+ if(conf.nproc > 2000)
+ conf.nproc = 2000;
+ conf.nimage = 200;
+ conf.nswap = conf.nproc*80;
+ conf.nswppo = 4096;
+ conf.copymode = 0; /* copy on write */
+
+ if(cpuserver) {
+ if(userpcnt < 10)
+ userpcnt = 70;
+ kpages = conf.npage - (conf.npage*userpcnt)/100;
+
+ /*
+ * Hack for the big boys. Only good while physmem < 4GB.
+ * Give the kernel a max. of 16MB + enough to allocate the
+ * page pool.
+ * This is an overestimate as conf.upages < conf.npages.
+ * The patch of nimage is a band-aid, scanning the whole
+ * page list in imagereclaim just takes too long.
+ */
+ if(kpages > (16*MB + conf.npage*sizeof(Page))/BY2PG){
+ kpages = (16*MB + conf.npage*sizeof(Page))/BY2PG;
+ conf.nimage = 2000;
+ kpages += (conf.nproc*KSTACK)/BY2PG;
+ }
+ } else {
+ if(userpcnt < 10) {
+ if(conf.npage*BY2PG < 16*MB)
+ userpcnt = 40;
+ else
+ userpcnt = 60;
+ }
+ kpages = conf.npage - (conf.npage*userpcnt)/100;
+
+ /*
+ * Make sure terminals with low memory get at least
+ * 4MB on the first Image chunk allocation.
+ */
+ if(conf.npage*BY2PG < 16*MB)
+ imagmem->minarena = 4*1024*1024;
+ }
+ conf.upages = conf.npage - kpages;
+ conf.ialloc = (kpages/2)*BY2PG;
+
+ /*
+ * Guess how much is taken by the large permanent
+ * datastructures. Mntcache and Mntrpc are not accounted for
+ * (probably ~300KB).
+ */
+ kpages *= BY2PG;
+ kpages -= conf.upages*sizeof(Page)
+ + conf.nproc*sizeof(Proc)
+ + conf.nimage*sizeof(Image)
+ + conf.nswap
+ + conf.nswppo*sizeof(Page);
+ mainmem->maxsize = kpages;
+ if(!cpuserver){
+ /*
+ * give terminals lots of image memory, too; the dynamic
+ * allocation will balance the load properly, hopefully.
+ * be careful with 32-bit overflow.
+ */
+ imagmem->maxsize = kpages;
+ }
+
+// conf.monitor = 1; /* BUG */
+}
+
+void
+memholes(void)
+{
+ Bank *b, *eb;
+
+ b = bootconf->bank;
+ eb = b+bootconf->nbank;
+ while(b < eb) {
+ if(b->min < (1LL<<32) && b->max < (1LL<<32))
+ xhole(b->min, b->max-b->min);
+ b++;
+ }
+}
+
+char *sp;
+
+char *
+pusharg(char *p)
+{
+ int n;
+
+ n = strlen(p)+1;
+ sp -= n;
+ memmove(sp, p, n);
+ return sp;
+}
+
+void
+arginit(void)
+{
+ char **av;
+
+ av = (char**)argbuf;
+ sp = argbuf + sizeof(argbuf);
+ *av++ = pusharg("boot");
+ *av = 0;
+}
+
+char *
+getconf(char *name)
+{
+ int n;
+
+ for(n = 0; n < nconf; n++)
+ if(cistrcmp(confname[n], name) == 0) {
+ return confval[n];
+ }
+ return 0;
+}
+
+int
+isaconfig(char *class, int ctlrno, ISAConf *isa)
+{
+ char cc[32], *p;
+ int i, n;
+
+ snprint(cc, sizeof cc, "%s%d", class, ctlrno);
+ for(n = 0; n < nconf; n++){
+ if(cistrcmp(confname[n], cc) != 0)
+ continue;
+ isa->nopt = tokenize(confval[n], isa->opt, NISAOPT);
+ for(i = 0; i < isa->nopt; i++){
+ p = isa->opt[i];
+ if(cistrncmp(p, "type=", 5) == 0)
+ isa->type = p + 5;
+ else if(cistrncmp(p, "port=", 5) == 0)
+ isa->port = strtoul(p+5, &p, 0);
+ else if(cistrncmp(p, "irq=", 4) == 0)
+ isa->irq = strtoul(p+4, &p, 0);
+ else if(cistrncmp(p, "dma=", 4) == 0)
+ isa->dma = strtoul(p+4, &p, 0);
+ else if(cistrncmp(p, "mem=", 4) == 0)
+ isa->mem = strtoul(p+4, &p, 0);
+ else if(cistrncmp(p, "size=", 5) == 0)
+ isa->size = strtoul(p+5, &p, 0);
+ else if(cistrncmp(p, "freq=", 5) == 0)
+ isa->freq = strtoul(p+5, &p, 0);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int
+cistrcmp(char *a, char *b)
+{
+ int ac, bc;
+
+ for(;;){
+ ac = *a++;
+ bc = *b++;
+
+ if(ac >= 'A' && ac <= 'Z')
+ ac = 'a' + (ac - 'A');
+ if(bc >= 'A' && bc <= 'Z')
+ bc = 'a' + (bc - 'A');
+ ac -= bc;
+ if(ac)
+ return ac;
+ if(bc == 0)
+ break;
+ }
+ return 0;
+}
+
+int
+cistrncmp(char *a, char *b, int n)
+{
+ unsigned ac, bc;
+
+ while(n > 0){
+ ac = *a++;
+ bc = *b++;
+ n--;
+
+ if(ac >= 'A' && ac <= 'Z')
+ ac = 'a' + (ac - 'A');
+ if(bc >= 'A' && bc <= 'Z')
+ bc = 'a' + (bc - 'A');
+
+ ac -= bc;
+ if(ac)
+ return ac;
+ if(bc == 0)
+ break;
+ }
+
+ return 0;
+}
+
+int
+getcfields(char* lp, char** fields, int n, char* sep)
+{
+ int i;
+
+ for(i = 0; lp && *lp && i < n; i++){
+ while(*lp && strchr(sep, *lp) != 0)
+ *lp++ = 0;
+ if(*lp == 0)
+ break;
+ fields[i] = lp;
+ while(*lp && strchr(sep, *lp) == 0){
+ if(*lp == '\\' && *(lp+1) == '\n')
+ *lp++ = ' ';
+ lp++;
+ }
+ }
+
+ return i;
+}
diff --git a/sys/src/9/alphapc/mem.h b/sys/src/9/alphapc/mem.h
new file mode 100755
index 000000000..be8cbd6c6
--- /dev/null
+++ b/sys/src/9/alphapc/mem.h
@@ -0,0 +1,89 @@
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+
+/*
+ * Sizes
+ */
+#define BI2BY 8 /* bits per byte */
+#define BI2WD 32 /* bits per word */
+#define BY2WD 4 /* bytes per word */
+#define BY2V 8 /* bytes per vlong */
+#define BY2PG 8192 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 13 /* log(BY2PG) */
+#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1))
+#define PGROUND(s) ROUND(s, BY2PG)
+#define BLOCKALIGN 8
+
+#define BY2PTE 8 /* bytes per pte entry */
+#define PTE2PG (BY2PG/BY2PTE) /* pte entries per page */
+
+#define MAXMACH 1 /* max # cpus system can run */
+#define KSTACK 4096 /* Size of kernel stack */
+
+/*
+ * Time
+ */
+#define HZ 100 /* clock frequency */
+#define MS2HZ (1000/HZ)
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+
+/*
+ * Magic registers
+ */
+#define MACH 15 /* R15 is m-> */
+#define USER 14 /* R14 is up-> */
+
+
+/*
+ * Fundamental addresses
+ */
+/* XXX MACHADDR, MACHP(n) */
+
+/*
+ * MMU
+ *
+ * A PTE is 64 bits, but a ulong is 32! Hence we encode
+ * the PTEs specially for fault.c, and decode them in putmmu().
+ * This means that we can only map the first 2G of physical
+ * space via putmmu() - ie only physical memory, not devices.
+ */
+#define PTEVALID 0x3301
+#define PTEKVALID 0x1101
+#define PTEASM 0x0010
+#define PTEGH(s) ((s)<<5)
+#define PTEWRITE 0
+#define PTERONLY 0x4
+#define PTEUNCACHED 0
+#define PPN(n) (((n)>>PGSHIFT)<<14)
+#define FIXPTE(x) ((((uvlong)(x)>>14)<<32)|((x) & 0x3fff))
+#define PTEPFN(pa) (((uvlong)(pa)>>PGSHIFT)<<32)
+#define NCOLOR 1
+#define getpgcolor(a) 0
+
+#define PTEMAPMEM (1024*1024)
+#define PTEPERTAB (PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE 512
+#define SSEGMAPSIZE 16
+
+/*
+ * Address spaces
+ */
+#define UZERO 0 /* base of user address space */
+#define UTZERO (UZERO+BY2PG) /* first address in user text */
+#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
+#define TSTKTOP KZERO /* top of temporary stack */
+#define TSTKSIZ 100
+#define KZERO 0x80000000 /* base of kernel address space */
+#define KTZERO (KZERO+0x400000) /* first address in kernel text */
+#define USTKSIZE (4*1024*1024) /* size of user stack */
+
+/*
+ * Processor Status (as returned by rdps)
+ */
+#define UMODE 0x8
+#define IPL 0x7
+
+
+#define isphys(x) (((ulong)x&KZERO)!=0)
diff --git a/sys/src/9/alphapc/memmove.s b/sys/src/9/alphapc/memmove.s
new file mode 100755
index 000000000..0fafb752d
--- /dev/null
+++ b/sys/src/9/alphapc/memmove.s
@@ -0,0 +1,197 @@
+#define QUAD 8
+#define ALIGN 64
+#define BLOCK 64
+
+TEXT memmove(SB), $0
+ MOVL from+4(FP), R7
+ MOVL n+8(FP), R10
+ MOVQ R0, R6
+
+ CMPUGE R7, R0, R5
+ BNE R5, _forward
+
+ MOVQ R6, R8 /* end to address */
+ ADDL R10, R6, R6 /* to+n */
+ ADDL R10, R7, R7 /* from+n */
+
+ CMPUGE $ALIGN, R10, R1 /* need at least ALIGN bytes */
+ BNE R1, _b1tail
+
+_balign:
+ AND $(ALIGN-1), R6, R1
+ BEQ R1, _baligned
+
+ MOVBU -1(R7), R2
+ ADDL $-1, R6, R6
+ MOVB R2, (R6)
+ ADDL $-1, R7, R7
+ JMP _balign
+
+_baligned:
+ AND $(QUAD-1), R7, R1 /* is the source quad-aligned */
+ BNE R1, _bunaligned
+
+ ADDL $(BLOCK-1), R8, R9
+_bblock:
+ CMPUGE R9, R6, R1
+ BNE R1, _b8tail
+
+ MOVQ -64(R7), R22
+ MOVQ -56(R7), R23
+ MOVQ -48(R7), R24
+ MOVQ -40(R7), R25
+ MOVQ -32(R7), R2
+ MOVQ -24(R7), R3
+ MOVQ -16(R7), R4
+ MOVQ -8(R7), R5
+
+ SUBL $64, R6, R6
+ SUBL $64, R7, R7
+
+ MOVQ R22, (R6)
+ MOVQ R23, 8(R6)
+ MOVQ R24, 16(R6)
+ MOVQ R25, 24(R6)
+ MOVQ R2, 32(R6)
+ MOVQ R3, 40(R6)
+ MOVQ R4, 48(R6)
+ MOVQ R5, 56(R6)
+ JMP _bblock
+
+_b8tail:
+ ADDL $(QUAD-1), R8, R9
+_b8block:
+ CMPUGE R9, R6, R1
+ BNE R1, _b1tail
+
+ MOVQ -8(R7), R2
+ SUBL $8, R6
+ MOVQ R2, (R6)
+ SUBL $8, R7
+ JMP _b8block
+
+_b1tail:
+ CMPUGE R8, R6, R1
+ BNE R1, _ret
+
+ MOVBU -1(R7), R2
+ SUBL $1, R6, R6
+ MOVB R2, (R6)
+ SUBL $1, R7, R7
+ JMP _b1tail
+_ret:
+ RET
+
+_bunaligned:
+ ADDL $(16-1), R8, R9
+
+_bu8block:
+ CMPUGE R9, R6, R1
+ BNE R1, _b1tail
+
+ MOVQU -16(R7), R4
+ MOVQU -8(R7), R3
+ MOVQU (R7), R2
+ SUBL $16, R6
+ EXTQH R7, R2, R2
+ EXTQL R7, R3, R5
+ OR R5, R2, R11
+ EXTQH R7, R3, R3
+ EXTQL R7, R4, R4
+ OR R3, R4, R13
+ MOVQ R11, 8(R6)
+ MOVQ R13, (R6)
+ SUBL $16, R7
+ JMP _bu8block
+
+_forward:
+ ADDL R10, R6, R8 /* end to address */
+
+ CMPUGE $ALIGN, R10, R1 /* need at least ALIGN bytes */
+ BNE R1, _f1tail
+
+_falign:
+ AND $(ALIGN-1), R6, R1
+ BEQ R1, _faligned
+
+ MOVBU (R7), R2
+ ADDL $1, R6, R6
+ ADDL $1, R7, R7
+ MOVB R2, -1(R6)
+ JMP _falign
+
+_faligned:
+ AND $(QUAD-1), R7, R1 /* is the source quad-aligned */
+ BNE R1, _funaligned
+
+ SUBL $(BLOCK-1), R8, R9
+_fblock:
+ CMPUGT R9, R6, R1
+ BEQ R1, _f8tail
+
+ MOVQ (R7), R2
+ MOVQ 8(R7), R3
+ MOVQ 16(R7), R4
+ MOVQ 24(R7), R5
+ MOVQ 32(R7), R22
+ MOVQ 40(R7), R23
+ MOVQ 48(R7), R24
+ MOVQ 56(R7), R25
+
+ ADDL $64, R6, R6
+ ADDL $64, R7, R7
+
+ MOVQ R2, -64(R6)
+ MOVQ R3, -56(R6)
+ MOVQ R4, -48(R6)
+ MOVQ R5, -40(R6)
+ MOVQ R22, -32(R6)
+ MOVQ R23, -24(R6)
+ MOVQ R24, -16(R6)
+ MOVQ R25, -8(R6)
+ JMP _fblock
+
+_f8tail:
+ SUBL $(QUAD-1), R8, R9
+_f8block:
+ CMPUGT R9, R6, R1
+ BEQ R1, _f1tail
+
+ MOVQ (R7), R2
+ ADDL $8, R6
+ ADDL $8, R7
+ MOVQ R2, -8(R6)
+ JMP _f8block
+
+_f1tail:
+ CMPUGT R8, R6, R1
+ BEQ R1, _fret
+ MOVBU (R7), R2
+ ADDL $1, R6, R6
+ ADDL $1, R7, R7
+ MOVB R2, -1(R6)
+ JMP _f1tail
+
+_fret:
+ RET
+
+_funaligned:
+ SUBL $(16-1), R8, R9
+_fu8block:
+ CMPUGT R9, R6, R1
+ BEQ R1, _f1tail
+
+ MOVQU (R7), R2
+ MOVQU 8(R7), R3
+ MOVQU 16(R7), R4
+ EXTQL R7, R2, R2
+ EXTQH R7, R3, R5
+ OR R5, R2, R11
+ EXTQL R7, R3, R3
+ MOVQ R11, (R6)
+ EXTQH R7, R4, R4
+ OR R3, R4, R11
+ MOVQ R11, 8(R6)
+ ADDL $16, R6
+ ADDL $16, R7
+ JMP _fu8block
diff --git a/sys/src/9/alphapc/memset.s b/sys/src/9/alphapc/memset.s
new file mode 100755
index 000000000..e3cfd468b
--- /dev/null
+++ b/sys/src/9/alphapc/memset.s
@@ -0,0 +1,61 @@
+TEXT memset(SB), $0
+ MOVL R0, R6
+ MOVBU data+4(FP), R2
+ MOVL n+8(FP), R10
+
+ ADDL R10, R0, R8
+
+ CMPUGE $8, R10, R1 /* need at least 8 bytes */
+ BNE R1, _1loop
+
+ SLLQ $8, R2, R1 /* replicate the byte */
+ OR R1, R2
+ SLLQ $16, R2, R1
+ OR R1, R2
+ SLLQ $32, R2, R1
+ OR R1, R2
+
+_align:
+ AND $(8-1), R6, R1
+ BEQ R1, _aligned
+
+ MOVB R2, (R6)
+ ADDL $1, R6, R6
+ JMP _align
+
+_aligned:
+ SUBL $(64-1), R8, R9 /* end pointer minus slop */
+_64loop:
+ CMPUGT R9, R6, R1
+ BEQ R1, _8tail
+
+ MOVQ R2, (R6)
+ MOVQ R2, 8(R6)
+ MOVQ R2, 16(R6)
+ MOVQ R2, 24(R6)
+ MOVQ R2, 32(R6)
+ MOVQ R2, 40(R6)
+ MOVQ R2, 48(R6)
+ MOVQ R2, 56(R6)
+ ADDL $64, R6, R6
+ JMP _64loop
+
+_8tail:
+ SUBL $(8-1), R8, R9
+_8loop:
+ CMPUGT R9, R6, R1
+ BEQ R1, _1loop
+
+ MOVQ R2, (R6)
+ ADDL $8, R6
+ JMP _8loop
+
+_1loop:
+ CMPUGT R8, R6, R1
+ BEQ R1, _ret
+ MOVB R2, (R6)
+ ADDL $1, R6
+ JMP _1loop
+
+_ret:
+ RET
diff --git a/sys/src/9/alphapc/mkfile b/sys/src/9/alphapc/mkfile
new file mode 100755
index 000000000..7accffead
--- /dev/null
+++ b/sys/src/9/alphapc/mkfile
@@ -0,0 +1,109 @@
+CONF=apc
+CONFLIST=apc apccpu
+
+objtype=alpha
+</$objtype/mkfile
+p=9
+
+DEVS=`{rc ../port/mkdevlist $CONF}
+
+PORT=\
+ alarm.$O\
+ alloc.$O\
+ allocb.$O\
+ auth.$O\
+ cache.$O\
+ chan.$O\
+ dev.$O\
+ fault.$O\
+ latin1.$O\
+ log.$O\
+ edf.$O\
+ mul64fract.$O\
+ page.$O\
+ parse.$O\
+ pgrp.$O\
+ portclock.$O\
+ print.$O\
+ proc.$O\
+ qio.$O\
+ qlock.$O\
+ rdb.$O\
+ rebootcmd.$O\
+ segment.$O\
+ swap.$O\
+ sysfile.$O\
+ sysproc.$O\
+ taslock.$O\
+ tod.$O\
+ xalloc.$O\
+
+OBJ=\
+ l.$O\
+ cga.$O\
+ clock.$O\
+ faultalpha.$O\
+ fdc37c93x.$O\
+ fptrap.$O\
+ i8259.$O\
+ kbd.$O\
+ main.$O\
+ mmu.$O\
+ random.$O\
+ trap.$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/libc.a\
+ /$objtype/lib/libsec.a\
+
+ETHER=`{echo devether.c ether*.c | sed 's/\.c/.'$O'/g'}
+VGA=`{echo devvga.c screen.c vga*.c | sed 's/\.c/.'$O'/g'}
+SDEV=`{echo devsd.c sd*.c | sed 's/\.c/.'$O'/g'}
+
+loadaddr = 0x80400020
+
+$p$CONF: $CONF.c $OBJ $LIB
+ $CC $CFLAGS '-DKERNDATE='`{date -n} $CONF.c
+ $LD -o $target -H3 -R8 -T$loadaddr -l $OBJ $CONF.$O $LIB
+ size $target
+
+install:V: $p$CONF
+ cp $p$CONF /$objtype/$p$CONF
+
+<../boot/bootmkfile
+<../port/portmkfile
+<|../port/mkbootrules $CONF
+<../pc/pcmkfile
+
+init.h: initcode /sys/src/libc/9syscall/sys.h
+ $AS initcode
+ $LD -l -s -R8 -o init.out initcode.$O -lc
+ {echo 'uchar initcode[]={'
+ xd -r -1x init.out |
+ sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
+ echo '};'} > init.h
+
+clock.$O: /$objtype/include/ureg.h axp.h
+devarch.$O: axp.h
+faultalpha.$O: /$objtype/include/ureg.h
+fptrap.$O: /$objtype/include/ureg.h
+kbd.$O: /$objtype/include/ureg.h
+l.$O: osf1pal.h
+main.$O: /$objtype/include/ureg.h errstr.h init.h
+mmu.$O: /sys/src/boot/alphapc/conf.h
+sd53c8xx.$O: /$objtype/include/ureg.h ../port/sd.h sd53c8xx.i
+trap.$O: /$objtype/include/ureg.h ../port/error.h ../port/systab.h
+
+sd53c8xx.i: ../pc/sd53c8xx.n
+ aux/na $prereq > $target
+
+acid:V:
+ $CC -a -w -I. ../port/qio.c>acid
diff --git a/sys/src/9/alphapc/mmu.c b/sys/src/9/alphapc/mmu.c
new file mode 100755
index 000000000..05ff63a5e
--- /dev/null
+++ b/sys/src/9/alphapc/mmu.c
@@ -0,0 +1,299 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "/sys/src/boot/alphapc/conf.h"
+
+static uvlong origlvl1; /* physical address */
+static uvlong klvl2; /* physical, as created by boot loader */
+static uchar *nextio; /* next virtual address to be allocated by kmapv */
+extern Bootconf *bootconf;
+
+#define LVL2OFF(v) ((((long)(v))>>(2*PGSHIFT-3))&(PTE2PG-1))
+#define LVL3OFF(v) ((((long)(v))>>(PGSHIFT))&(PTE2PG-1))
+
+static void
+setptb(ulong pa)
+{
+ m->ptbr = (uvlong)pa>>PGSHIFT;
+ swpctx(m);
+}
+
+void
+mmuinit(void)
+{
+ uvlong *plvl2;
+
+ /* set PCB to new one in mach structure before stomping on old one */
+ m->usp = 0;
+ m->fen = 1;
+ m->ptbr = bootconf->pcb->ptbr;
+ origlvl1 = (m->ptbr << PGSHIFT);
+ setpcb(m);
+
+ plvl2 = (uvlong*) (KZERO|origlvl1|(BY2PG-8));
+ klvl2 = (*plvl2 >> 32)<<PGSHIFT;
+
+ nextio = (uchar*) (KZERO|bootconf->maxphys);
+}
+
+static void
+mmuptefree(Proc* proc)
+{
+ uvlong *lvl2;
+ Page **last, *page;
+
+ if(proc->mmutop && proc->mmuused){
+ lvl2 = (uvlong*)proc->mmulvl2->va;
+ last = &proc->mmuused;
+ for(page = *last; page; page = page->next){
+ lvl2[page->daddr] = 0;
+ last = &page->next;
+ }
+ *last = proc->mmufree;
+ proc->mmufree = proc->mmuused;
+ proc->mmuused = 0;
+ }
+}
+
+void
+mmuswitch(Proc *proc)
+{
+ if(proc->newtlb){
+ mmuptefree(proc);
+ proc->newtlb = 0;
+ }
+
+ /* tell processor about new page table and flush cached entries */
+ if(proc->mmutop == 0)
+ setptb(origlvl1);
+ else
+ setptb(proc->mmutop->pa);
+ tlbflush(-1, 0);
+ icflush();
+}
+
+/* point to protoype page map */
+void
+mmupark(void)
+{
+ setptb(origlvl1);
+ icflush();
+}
+
+/*
+ * give all page table pages back to the free pool. This is called in sched()
+ * with palloc locked.
+ */
+void
+mmurelease(Proc *proc)
+{
+ Page *page, *next;
+
+ mmupark();
+ mmuptefree(proc);
+ proc->mmuused = 0;
+ if(proc->mmutop) {
+ proc->mmutop->next = proc->mmufree;
+ proc->mmufree = proc->mmutop;
+ proc->mmutop = 0;
+ }
+ if(proc->mmulvl2) {
+ proc->mmulvl2->next = proc->mmufree;
+ proc->mmufree = proc->mmulvl2;
+ proc->mmulvl2 = 0;
+ }
+ for(page = proc->mmufree; page; page = next){
+ next = page->next;
+ if(--page->ref)
+ panic("mmurelease: page->ref %d\n", page->ref);
+ pagechainhead(page);
+ }
+ if(proc->mmufree && palloc.r.p)
+ wakeup(&palloc.r);
+ proc->mmufree = 0;
+}
+
+void
+mmunewtop(void)
+{
+ Page *top, *lvl2;
+ uvlong *ppte;
+
+ top = newpage(1, 0, 0);
+ top->va = VA(kmap(top));
+ lvl2 = newpage(1, 0, 0);
+ lvl2->va = VA(kmap(lvl2));
+
+ ppte = (uvlong *)top->va;
+ ppte[0] = PTEPFN(lvl2->pa) | PTEKVALID;
+ ppte[PTE2PG-2] = PTEPFN(top->pa) | PTEKVALID;
+ ppte[PTE2PG-1] = PTEPFN(klvl2) | PTEKVALID;
+
+ up->mmutop = top;
+ up->mmulvl2 = lvl2;
+ setptb(top->pa);
+ tlbflush(-1, 0);
+ icflush();
+}
+
+void
+putmmu(ulong va, ulong pa, Page *pg)
+{
+ int lvl2off;
+ uvlong *lvl2, *pt;
+ int s;
+
+ if(up->mmutop == 0)
+ mmunewtop();
+
+ lvl2 = (uvlong*)up->mmulvl2->va;
+ lvl2off = LVL2OFF(va);
+
+ /*
+ * if bottom level page table missing, allocate one
+ * and point the top level page at it.
+ */
+ s = splhi();
+ if(lvl2[lvl2off] == 0){
+ if(up->mmufree == 0){
+ spllo();
+ pg = newpage(1, 0, 0);
+ pg->va = VA(kmap(pg));
+ splhi();
+ } else {
+ pg = up->mmufree;
+ up->mmufree = pg->next;
+ memset((void*)pg->va, 0, BY2PG);
+ }
+ lvl2[lvl2off] = PTEPFN(pg->pa) | PTEVALID;
+ pg->daddr = lvl2off;
+ pg->next = up->mmuused;
+ up->mmuused = pg;
+ }
+
+ /*
+ * put in new mmu entry
+ */
+ pt = (uvlong*)(((lvl2[lvl2off] >> 32)<<PGSHIFT)|KZERO);
+ pt[LVL3OFF(va)] = FIXPTE(pa);
+
+ /* flush cached mmu entries */
+ tlbflush(3, va);
+ icflush();
+ splx(s);
+}
+
+void *
+kmapv(uvlong pa, int size)
+{
+ void *va, *new;
+ int lvl2off, i, npage, offset;
+ uvlong *lvl2, *pt;
+
+ offset = pa&(BY2PG-1);
+ npage = ((size+offset+BY2PG-1)>>PGSHIFT);
+
+ va = nextio+offset;
+ lvl2 = (uvlong*)(KZERO|klvl2);
+ for (i = 0; i < npage; i++) {
+ lvl2off = LVL2OFF(nextio);
+ if (lvl2[lvl2off] == 0) {
+ new = xspanalloc(BY2PG, BY2PG, 0);
+ memset(new, 0, BY2PG);
+ lvl2[lvl2off] = PTEPFN(PADDR(new)) | PTEKVALID | PTEASM;
+ }
+ pt = (uvlong*)(((lvl2[lvl2off] >> 32)<<PGSHIFT)|KZERO);
+ pt[LVL3OFF(nextio)] = PTEPFN(pa) | PTEKVALID | PTEASM;
+ nextio += BY2PG;
+ pa += BY2PG;
+ }
+ return va;
+}
+
+void
+flushmmu(void)
+{
+ int s;
+
+ s = splhi();
+ up->newtlb = 1;
+ mmuswitch(up);
+ splx(s);
+
+}
+
+void*
+vmap(ulong pa, int size)
+{
+ void *va;
+
+ /*
+ * Viability hack. Only for PCI framebuffers.
+ */
+ if(pa == 0)
+ return 0;
+ va = kmapv(((uvlong)0x88<<32LL)|pa, size);
+ if(va == nil)
+ return 0;
+ return (void*)va;
+}
+
+void
+vunmap(void*, int)
+{
+ print("vunmap: virtual mapping not freed\n");
+}
+
+void
+mmudump(void)
+{
+ Page *top, *lvl2;
+
+ iprint("ptbr %lux up %#p\n", (ulong)m->ptbr, up);
+ if(up) {
+ top = up->mmutop;
+ if(top != nil)
+ iprint("top %lux top[N-1] %llux\n", top->va, ((uvlong *)top->va)[PTE2PG-1]);
+ lvl2 = up->mmulvl2;
+ if(lvl2 != nil)
+ iprint("lvl2 %lux\n", lvl2->va);
+ }
+}
+
+ulong
+upaalloc(int, int)
+{
+ return 0;
+}
+
+void
+upafree(ulong, int)
+{
+}
+
+void
+checkmmu(ulong, ulong)
+{
+}
+
+void
+countpagerefs(ulong*, int)
+{
+}
+
+/*
+ * Return the number of bytes that can be accessed via KADDR(pa).
+ * If pa is not a valid argument to KADDR, return 0.
+ */
+ulong
+cankaddr(ulong pa)
+{
+ ulong kzero;
+
+ kzero = -KZERO;
+ if(pa >= kzero)
+ return 0;
+ return kzero - pa;
+}
diff --git a/sys/src/9/alphapc/osf1pal.h b/sys/src/9/alphapc/osf1pal.h
new file mode 100755
index 000000000..0ee9e67ee
--- /dev/null
+++ b/sys/src/9/alphapc/osf1pal.h
@@ -0,0 +1,78 @@
+/*
+ * OSF/1 PALcode instructions, in numerical order.
+ * Values are from Digital EBSDK and FreeBSD/Alpha.
+ */
+
+/* Privilaged PAL functions */
+#define PALhalt 0x00 /* required per Alpha architecture */
+#define PALcflush 0x01
+#define PALdraina 0x02 /* required per Alpha architecture */
+/*
+ * ... 0x03 to 0x08 ?
+ */
+#define PALcserve 0x09
+#define PALswppal 0x0a
+/*
+ * ... 0x0b to 0x0c ?
+ */
+#define PALwripir 0x0d
+/*
+ * ... 0x0e to 0x0f ?
+ */
+#define PALrdmces 0x10
+#define PALwrmces 0x11
+/*
+ * ... 0x12 to 0x2a ?
+ */
+#define PALwrfen 0x2b
+ /* 0x2c OSF/1 ? */
+#define PALwrvptptr 0x2d
+/*
+ * ... 0x2e to 0x2f ?
+ */
+#define PALswpctx 0x30
+#define PALwrval 0x31
+#define PALrdval 0x32
+#define PALtbi 0x33
+#define PALwrent 0x34
+#define PALswpipl 0x35
+#define PALrdps 0x36
+#define PALwrkgp 0x37
+#define PALwrusp 0x38
+#define PALwrperfmon 0x39
+#define PALrdusp 0x3a
+ /* 0x3b OSF/1 ? */
+#define PALwhami 0x3c
+#define PALretsys 0x3d
+#define PALwtint 0x3e
+#define PALrti 0x3f
+
+/* Unprivileged PAL functions */
+#define PALbpt 0x80
+#define PALbugchk 0x81
+#define PALcallsys 0x83
+#define PALimb 0x86 /* required per Alpha architecture */
+/*
+ * ... 0x89 to 0x91 ?
+ */
+#define PALurti 0x92
+/*
+ * ... 0x93 to 0x9d ?
+ */
+#define PALrdunique 0x9e
+#define PALwrunique 0x9f
+/*
+ * ... 0xa0 to 0xa9 ?
+ */
+#define PALgentrap 0xaa
+/*
+ * ... 0xab to 0xac ?
+ */
+#define PALdbgstop 0xad
+#define PALclrfen 0xae
+/*
+ * ... 0xaf to 0xbd ?
+ */
+#define PALnphalt 0xbe
+#define PALcopypal 0xbf
+
diff --git a/sys/src/9/alphapc/pci.c b/sys/src/9/alphapc/pci.c
new file mode 100755
index 000000000..13d431c1a
--- /dev/null
+++ b/sys/src/9/alphapc/pci.c
@@ -0,0 +1,412 @@
+/*
+ * PCI support code.
+ * To do:
+ * initialise bridge mappings if the PCI BIOS didn't.
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+enum {
+ MaxFNO = 7,
+ MaxUBN = 255,
+};
+
+enum
+{ /* command register */
+ IOen = (1<<0),
+ MEMen = (1<<1),
+ MASen = (1<<2),
+ MemWrInv = (1<<4),
+ PErrEn = (1<<6),
+ SErrEn = (1<<8),
+};
+
+static Lock pcicfglock;
+static Lock pcicfginitlock;
+static int pcicfgmode = -1;
+static int pcimaxdno;
+static Pcidev* pciroot;
+static Pcidev* pcilist;
+static Pcidev* pcitail;
+
+static int pcicfgrw32(int, int, int, int);
+
+uchar *vgabios;
+
+static int
+pciscan(int bno, Pcidev** list)
+{
+ ulong v;
+ Pcidev *p, *head, *tail;
+ int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
+
+ maxubn = bno;
+ head = nil;
+ tail = nil;
+ for(dno = 0; dno <= pcimaxdno; dno++){
+ maxfno = 0;
+ for(fno = 0; fno <= maxfno; fno++){
+ /*
+ * For this possible device, form the
+ * bus+device+function triplet needed to address it
+ * and try to read the vendor and device ID.
+ * If successful, allocate a device struct and
+ * start to fill it in with some useful information
+ * from the device's configuration space.
+ */
+ tbdf = MKBUS(BusPCI, bno, dno, fno);
+ l = pcicfgrw32(tbdf, PciVID, 0, 1);
+ if(l == 0xFFFFFFFF || l == 0)
+ continue;
+/* optional safety checks:
+ if(l == pcicfgrw32(tbdf, PciPCR, 0, 1))
+ continue;
+ if(l != pcicfgrw32(tbdf, PciVID, 0, 1))
+ continue;
+ if(l == pcicfgrw32(tbdf, PciPCR, 0, 1))
+ continue;
+*/
+ p = malloc(sizeof(*p));
+ p->tbdf = tbdf;
+ p->vid = l;
+ p->did = l>>16;
+
+ if(pcilist != nil)
+ pcitail->list = p;
+ else
+ pcilist = p;
+ pcitail = p;
+
+ p->rid = pcicfgr8(p, PciRID);
+ p->ccrp = pcicfgr8(p, PciCCRp);
+ p->ccru = pcicfgr8(p, PciCCRu);
+ p->ccrb = pcicfgr8(p, PciCCRb);
+ p->pcr = pcicfgr32(p, PciPCR);
+
+ p->intl = pcicfgr8(p, PciINTL);
+
+ /*
+ * If the device is a multi-function device adjust the
+ * loop count so all possible functions are checked.
+ */
+ hdt = pcicfgr8(p, PciHDT);
+ if(hdt & 0x80)
+ maxfno = MaxFNO;
+
+ /*
+ * If appropriate, read the base address registers
+ * and work out the sizes.
+ */
+ switch(p->ccrb){
+
+ case 0x03: /* display controller */
+ if(vgabios == nil) {
+ v = pcicfgr32(p, PciROM);
+ pcicfgw32(p, PciROM, v|1); /* enable decode */
+ vgabios = kmapv(((uvlong)0x88<<32LL)|(v&~0xffff), 0x10000);
+ // print("VGA BIOS %lux -> %lux\n", v, vgabios);
+ }
+ /* fall through */
+ case 0x01: /* mass storage controller */
+ case 0x02: /* network controller */
+ case 0x04: /* multimedia device */
+ case 0x07: /* simple communication controllers */
+ case 0x08: /* base system peripherals */
+ case 0x09: /* input devices */
+ case 0x0A: /* docking stations */
+ case 0x0B: /* processors */
+ case 0x0C: /* serial bus controllers */
+ if((hdt & 0x7F) != 0)
+ break;
+ rno = PciBAR0 - 4;
+ for(i = 0; i < nelem(p->mem); i++){
+ rno += 4;
+ p->mem[i].bar = pcicfgr32(p, rno);
+ pcicfgw32(p, rno, -1);
+ v = pcicfgr32(p, rno);
+ pcicfgw32(p, rno, p->mem[i].bar);
+ p->mem[i].size = -(v & ~0xF);
+ }
+ break;
+
+ case 0x00:
+ case 0x05: /* memory controller */
+ case 0x06: /* bridge device */
+ default:
+ break;
+ }
+
+ if(head != nil)
+ tail->link = p;
+ else
+ head = p;
+ tail = p;
+ }
+ }
+
+ *list = head;
+ for(p = head; p != nil; p = p->link){
+ /*
+ * Find PCI-PCI bridges and recursively descend the tree.
+ */
+ if(p->ccrb != 0x06 || p->ccru != 0x04)
+ continue;
+
+ /*
+ * If the secondary or subordinate bus number is not initialised
+ * try to do what the PCI BIOS should have done and fill in the
+ * numbers as the tree is descended. On the way down the subordinate
+ * bus number is set to the maximum as it's not known how many
+ * buses are behind this one; the final value is set on the way
+ * back up.
+ */
+ sbn = pcicfgr8(p, PciSBN);
+ ubn = pcicfgr8(p, PciUBN);
+ if(sbn == 0 || ubn == 0){
+ sbn = maxubn+1;
+ /*
+ * Make sure memory, I/O and master enables are off,
+ * set the primary, secondary and subordinate bus numbers
+ * and clear the secondary status before attempting to
+ * scan the secondary bus.
+ *
+ * Initialisation of the bridge should be done here.
+ */
+ pcicfgw32(p, PciPCR, 0xFFFF0000);
+ l = (MaxUBN<<16)|(sbn<<8)|bno;
+ pcicfgw32(p, PciPBN, l);
+ pcicfgw16(p, PciSPSR, 0xFFFF);
+ maxubn = pciscan(sbn, &p->bridge);
+ l = (maxubn<<16)|(sbn<<8)|bno;
+ pcicfgw32(p, PciPBN, l);
+ }
+ else{
+ maxubn = ubn;
+ pciscan(sbn, &p->bridge);
+ }
+ }
+
+ return maxubn;
+}
+
+static void
+pcicfginit(void)
+{
+ char *p;
+
+ lock(&pcicfginitlock);
+ if(pcicfgmode == -1){
+ pcicfgmode = 0;
+ pcimaxdno = 15; /* was 20; what is correct value??? */
+ if(p = getconf("*pcimaxdno"))
+ pcimaxdno = strtoul(p, 0, 0);
+ pciscan(0, &pciroot);
+ }
+ unlock(&pcicfginitlock);
+}
+
+static int
+pcicfgrw8(int tbdf, int rno, int data, int read)
+{
+ int x;
+ uchar *p;
+
+ if(pcicfgmode == -1)
+ pcicfginit();
+ x = -1;
+ if(BUSDNO(tbdf) > pcimaxdno)
+ return x;
+
+ p = (uchar*)arch->pcicfg(tbdf, rno);
+ if(read)
+ x = *p;
+ else
+ *p = data;
+
+ return x;
+}
+
+int
+pcicfgr8(Pcidev* pcidev, int rno)
+{
+ return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
+}
+
+void
+pcicfgw8(Pcidev* pcidev, int rno, int data)
+{
+ pcicfgrw8(pcidev->tbdf, rno, data, 0);
+}
+
+static int
+pcicfgrw16(int tbdf, int rno, int data, int read)
+{
+ int x;
+ ushort *p;
+
+ if(pcicfgmode == -1)
+ pcicfginit();
+ x = -1;
+ if(BUSDNO(tbdf) > pcimaxdno)
+ return x;
+
+ p = (ushort*)arch->pcicfg(tbdf, rno);
+ if(read)
+ x = *p;
+ else
+ *p = data;
+
+ return x;
+}
+
+int
+pcicfgr16(Pcidev* pcidev, int rno)
+{
+ return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
+}
+
+void
+pcicfgw16(Pcidev* pcidev, int rno, int data)
+{
+ pcicfgrw16(pcidev->tbdf, rno, data, 0);
+}
+
+static int
+pcicfgrw32(int tbdf, int rno, int data, int read)
+{
+ int x;
+ ulong *p;
+
+ if(pcicfgmode == -1)
+ pcicfginit();
+ x = -1;
+ if(BUSDNO(tbdf) > pcimaxdno)
+ return x;
+
+ p = (ulong*)arch->pcicfg(tbdf, rno);
+ if(read)
+ x = *p;
+ else
+ *p = data;
+
+ return x;
+}
+
+int
+pcicfgr32(Pcidev* pcidev, int rno)
+{
+ return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
+}
+
+void
+pcicfgw32(Pcidev* pcidev, int rno, int data)
+{
+ pcicfgrw32(pcidev->tbdf, rno, data, 0);
+}
+
+Pcidev*
+pcimatch(Pcidev* prev, int vid, int did)
+{
+ if(pcicfgmode == -1)
+ pcicfginit();
+
+ if(prev == nil)
+ prev = pcilist;
+ else
+ prev = prev->list;
+
+ while(prev != nil) {
+ if((vid == 0 || prev->vid == vid)
+ && (did == 0 || prev->did == did))
+ break;
+ prev = prev->list;
+ }
+ return prev;
+}
+
+Pcidev*
+pcimatchtbdf(int tbdf)
+{
+ Pcidev *pcidev;
+
+ if(pcicfgmode == -1)
+ pcicfginit();
+
+ for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
+ if(pcidev->tbdf == tbdf)
+ break;
+ }
+ return pcidev;
+}
+
+void
+pcihinv(Pcidev* p)
+{
+ int i;
+ Pcidev *t;
+
+ if(pcicfgmode == -1)
+ pcicfginit();
+ if(p == nil) {
+ p = pciroot;
+ print("bus dev type vid did intl memory\n");
+ }
+ for(t = p; t != nil; t = t->link) {
+ print("%d %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %2d ",
+ BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
+ t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
+
+ for(i = 0; i < nelem(p->mem); i++) {
+ if(t->mem[i].size == 0)
+ continue;
+ print("%d:%.8lux %d ", i,
+ t->mem[i].bar, t->mem[i].size);
+ }
+ print("\n");
+ }
+ while(p != nil) {
+ if(p->bridge != nil)
+ pcihinv(p->bridge);
+ p = p->link;
+ }
+}
+
+void
+pcireset(void)
+{
+ Pcidev *p;
+ int pcr;
+
+ if(pcicfgmode == -1)
+ pcicfginit();
+
+ for(p = pcilist; p != nil; p = p->list){
+ pcr = pcicfgr16(p, PciPSR);
+ pcicfgw16(p, PciPSR, pcr & ~0x04);
+ }
+}
+
+void
+pcisetbme(Pcidev* p)
+{
+ int pcr;
+
+ pcr = pcicfgr16(p, PciPCR);
+ pcr |= MASen;
+ pcicfgw16(p, PciPCR, pcr);
+}
+
+void
+pciclrbme(Pcidev* p)
+{
+ int pcr;
+
+ pcr = pcicfgr16(p, PciPCR);
+ pcr &= ~MASen;
+ pcicfgw16(p, PciPCR, pcr);
+}
diff --git a/sys/src/9/alphapc/screen.h b/sys/src/9/alphapc/screen.h
new file mode 100755
index 000000000..190b49152
--- /dev/null
+++ b/sys/src/9/alphapc/screen.h
@@ -0,0 +1,171 @@
+typedef struct Cursor Cursor;
+typedef struct Cursorinfo Cursorinfo;
+struct Cursorinfo {
+ Cursor;
+ Lock;
+};
+
+/* devmouse.c */
+extern void mousetrack(int, int, int, int);
+extern Point mousexy(void);
+
+extern void mouseaccelerate(int);
+extern int m3mouseputc(Queue*, int);
+extern int m5mouseputc(Queue*, int);
+extern int mouseputc(Queue*, int);
+
+extern Cursorinfo cursor;
+extern Cursor arrow;
+
+/*
+ * Generic VGA registers.
+ */
+enum {
+ MiscW = 0x03C2, /* Miscellaneous Output (W) */
+ MiscR = 0x03CC, /* Miscellaneous Output (R) */
+ Status0 = 0x03C2, /* Input status 0 (R) */
+ Status1 = 0x03DA, /* Input Status 1 (R) */
+ FeatureR = 0x03CA, /* Feature Control (R) */
+ FeatureW = 0x03DA, /* Feature Control (W) */
+
+ Seqx = 0x03C4, /* Sequencer Index, Data at Seqx+1 */
+ Crtx = 0x03D4, /* CRT Controller Index, Data at Crtx+1 */
+ Grx = 0x03CE, /* Graphics Controller Index, Data at Grx+1 */
+ Attrx = 0x03C0, /* Attribute Controller Index and Data */
+
+ PaddrW = 0x03C8, /* Palette Address Register, write */
+ Pdata = 0x03C9, /* Palette Data Register */
+ Pixmask = 0x03C6, /* Pixel Mask Register */
+ PaddrR = 0x03C7, /* Palette Address Register, read */
+ Pstatus = 0x03C7, /* DAC Status (RO) */
+
+ Pcolours = 256, /* Palette */
+ Pred = 0,
+ Pgreen = 1,
+ Pblue = 2,
+
+ Pblack = 0x00,
+ Pwhite = 0xFF,
+};
+
+#define VGAMEM() PADDR(arch->pcimem(0xA0000, 1<<16))
+
+#define vgai(port) inb(port)
+#define vgao(port, data) outb(port, data)
+
+extern int vgaxi(long, uchar);
+extern int vgaxo(long, uchar, uchar);
+
+/*
+ */
+typedef struct VGAdev VGAdev;
+typedef struct VGAcur VGAcur;
+typedef struct VGAscr VGAscr;
+
+struct VGAdev {
+ char* name;
+
+ void (*enable)(VGAscr*);
+ void (*disable)(VGAscr*);
+ void (*page)(VGAscr*, int);
+ void (*linear)(VGAscr*, int, int);
+ void (*drawinit)(VGAscr*);
+ int (*fill)(VGAscr*, Rectangle, ulong);
+ void (*flush)(VGAscr*, Rectangle);
+
+};
+
+struct VGAcur {
+ char* name;
+
+ void (*enable)(VGAscr*);
+ void (*disable)(VGAscr*);
+ void (*load)(VGAscr*, Cursor*);
+ int (*move)(VGAscr*, Point);
+
+ int doespanning;
+};
+
+/*
+ */
+struct VGAscr {
+ Lock devlock;
+ VGAdev* dev;
+ Pcidev* pci;
+
+ VGAcur* cur;
+ ulong storage;
+ Cursor;
+
+ int useflush;
+
+ ulong paddr; /* frame buffer */
+ void* vaddr;
+ int apsize;
+
+ ulong io; /* device specific registers */
+ ulong *mmio;
+
+ ulong colormap[Pcolours][3];
+ int palettedepth;
+
+ Memimage* gscreen;
+ Memdata* gscreendata;
+ Memsubfont* memdefont;
+
+ int (*fill)(VGAscr*, Rectangle, ulong);
+ int (*scroll)(VGAscr*, Rectangle, Rectangle);
+ void (*blank)(VGAscr*, int);
+ ulong id; /* internal identifier for driver use */
+};
+
+extern VGAscr vgascreen[];
+
+enum {
+ Backgnd = 0, /* black */
+};
+
+/* mouse.c */
+extern void mousectl(Cmdbuf*);
+
+/* screen.c */
+extern int hwaccel; /* use hw acceleration; default on */
+extern int hwblank; /* use hw blanking; default on */
+extern void addvgaseg(char*, ulong, ulong);
+extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*);
+extern void flushmemscreen(Rectangle);
+extern int cursoron(int);
+extern void cursoroff(int);
+extern void setcursor(Cursor*);
+extern int screensize(int, int, int, ulong);
+extern int screenaperture(int, int);
+extern Rectangle physgscreenr; /* actual monitor size */
+extern void blankscreen(int);
+
+extern VGAcur swcursor;
+extern void swcursorinit(void);
+extern void swcursorhide(void);
+extern void swcursoravoid(Rectangle);
+extern void swcursorunhide(void);
+
+/* devdraw.c */
+extern void deletescreenimage(void);
+extern int drawhasclients(void);
+extern ulong blanktime;
+extern QLock drawlock;
+
+/* vga.c */
+extern void vgascreenwin(VGAscr*);
+extern void vgaimageinit(ulong);
+extern void vgalinearpciid(VGAscr*, int, int);
+extern void vgalinearpci(VGAscr*);
+extern void vgalinearaddr(VGAscr*, ulong, int);
+
+extern void drawblankscreen(int);
+extern void vgablank(VGAscr*, int);
+
+extern Lock vgascreenlock;
+
+#define ishwimage(i) (vgascreen[0].gscreendata && (i)->data->bdata == vgascreen[0].gscreendata->bdata)
+
+
diff --git a/sys/src/9/alphapc/sd53c8xx.c b/sys/src/9/alphapc/sd53c8xx.c
new file mode 100755
index 000000000..b16c0a0a9
--- /dev/null
+++ b/sys/src/9/alphapc/sd53c8xx.c
@@ -0,0 +1,2261 @@
+/*
+ * NCR/Symbios/LSI Logic 53c8xx driver for Plan 9
+ * Nigel Roles (nigel@9fs.org)
+ *
+ * 27/5/02 Fixed problems with transfers >= 256 * 512
+ *
+ * 13/3/01 Fixed microcode to support targets > 7
+ *
+ * 01/12/00 Removed previous comments. Fixed a small problem in
+ * mismatch recovery for targets with synchronous offsets of >=16
+ * connected to >=875s. Thanks, Jean.
+ *
+ * Known problems
+ *
+ * Read/write mismatch recovery may fail on 53c1010s. Really need to get a manual.
+ */
+
+#define MAXTARGET 16 /* can be 8 or 16 */
+
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "../port/sd.h"
+extern SDifc sd53c8xxifc;
+
+/**********************************/
+/* Portable configuration macros */
+/**********************************/
+
+//#define BOOTDEBUG
+//#define ASYNC_ONLY
+//#define INTERNAL_SCLK
+//#define ALWAYS_DO_WDTR
+#define WMR_DEBUG
+
+/**********************************/
+/* CPU specific macros */
+/**********************************/
+
+#define PRINTPREFIX "sd53c8xx: "
+
+#ifdef BOOTDEBUG
+
+#define KPRINT oprint
+#define IPRINT intrprint
+#define DEBUG(n) 1
+#define IFLUSH() iflush()
+
+#else
+
+static int idebug = 1;
+#define KPRINT if(0) iprint
+#define IPRINT if(idebug) iprint
+#define DEBUG(n) (0)
+#define IFLUSH()
+
+#endif /* BOOTDEBUG */
+
+/*******************************/
+/* General */
+/*******************************/
+
+#ifndef DMASEG
+#define DMASEG(x) PCIWADDR(x)
+#define legetl(x) (*(ulong*)(x))
+#define lesetl(x,v) (*(ulong*)(x) = (v))
+#define swabl(a,b,c)
+#else
+#endif /*DMASEG */
+#define DMASEG_TO_KADDR(x) KADDR((x)-PCIWINDOW)
+#define KPTR(x) ((x) == 0 ? 0 : DMASEG_TO_KADDR(x))
+
+#define MEGA 1000000L
+#ifdef INTERNAL_SCLK
+#define SCLK (33 * MEGA)
+#else
+#define SCLK (40 * MEGA)
+#endif /* INTERNAL_SCLK */
+#define ULTRA_NOCLOCKDOUBLE_SCLK (80 * MEGA)
+
+#define MAXSYNCSCSIRATE (5 * MEGA)
+#define MAXFASTSYNCSCSIRATE (10 * MEGA)
+#define MAXULTRASYNCSCSIRATE (20 * MEGA)
+#define MAXULTRA2SYNCSCSIRATE (40 * MEGA)
+#define MAXASYNCCORERATE (25 * MEGA)
+#define MAXSYNCCORERATE (25 * MEGA)
+#define MAXFASTSYNCCORERATE (50 * MEGA)
+#define MAXULTRASYNCCORERATE (80 * MEGA)
+#define MAXULTRA2SYNCCORERATE (160 * MEGA)
+
+
+#define X_MSG 1
+#define X_MSG_SDTR 1
+#define X_MSG_WDTR 3
+
+struct na_patch {
+ unsigned lwoff;
+ unsigned char type;
+};
+
+typedef struct Ncr {
+ uchar scntl0; /* 00 */
+ uchar scntl1;
+ uchar scntl2;
+ uchar scntl3;
+
+ uchar scid; /* 04 */
+ uchar sxfer;
+ uchar sdid;
+ uchar gpreg;
+
+ uchar sfbr; /* 08 */
+ uchar socl;
+ uchar ssid;
+ uchar sbcl;
+
+ uchar dstat; /* 0c */
+ uchar sstat0;
+ uchar sstat1;
+ uchar sstat2;
+
+ uchar dsa[4]; /* 10 */
+
+ uchar istat; /* 14 */
+ uchar istatpad[3];
+
+ uchar ctest0; /* 18 */
+ uchar ctest1;
+ uchar ctest2;
+ uchar ctest3;
+
+ uchar temp[4]; /* 1c */
+
+ uchar dfifo; /* 20 */
+ uchar ctest4;
+ uchar ctest5;
+ uchar ctest6;
+
+ uchar dbc[3]; /* 24 */
+ uchar dcmd; /* 27 */
+
+ uchar dnad[4]; /* 28 */
+ uchar dsp[4]; /* 2c */
+ uchar dsps[4]; /* 30 */
+
+ uchar scratcha[4]; /* 34 */
+
+ uchar dmode; /* 38 */
+ uchar dien;
+ uchar dwt;
+ uchar dcntl;
+
+ uchar adder[4]; /* 3c */
+
+ uchar sien0; /* 40 */
+ uchar sien1;
+ uchar sist0;
+ uchar sist1;
+
+ uchar slpar; /* 44 */
+ uchar slparpad0;
+ uchar macntl;
+ uchar gpcntl;
+
+ uchar stime0; /* 48 */
+ uchar stime1;
+ uchar respid;
+ uchar respidpad0;
+
+ uchar stest0; /* 4c */
+ uchar stest1;
+ uchar stest2;
+ uchar stest3;
+
+ uchar sidl; /* 50 */
+ uchar sidlpad[3];
+
+ uchar sodl; /* 54 */
+ uchar sodlpad[3];
+
+ uchar sbdl; /* 58 */
+ uchar sbdlpad[3];
+
+ uchar scratchb[4]; /* 5c */
+} Ncr;
+
+typedef struct Movedata {
+ uchar dbc[4];
+ uchar pa[4];
+} Movedata;
+
+typedef enum NegoState {
+ NeitherDone, WideInit, WideResponse, WideDone,
+ SyncInit, SyncResponse, BothDone
+} NegoState;
+
+typedef enum State {
+ Allocated, Queued, Active, Done
+} State;
+
+typedef struct Dsa {
+ uchar stateb;
+ uchar result;
+ uchar dmablks;
+ uchar flag; /* setbyte(state,3,...) */
+
+ union {
+ ulong dmancr; /* For block transfer: NCR order (little-endian) */
+ uchar dmaaddr[4];
+ };
+
+ uchar target; /* Target */
+ uchar pad0[3];
+
+ uchar lun; /* Logical Unit Number */
+ uchar pad1[3];
+
+ uchar scntl3;
+ uchar sxfer;
+ uchar pad2[2];
+
+ uchar next[4]; /* chaining for SCRIPT (NCR byte order) */
+ struct Dsa *freechain; /* chaining for freelist */
+ Rendez;
+ uchar scsi_id_buf[4];
+ Movedata msg_out_buf;
+ Movedata cmd_buf;
+ Movedata data_buf;
+ Movedata status_buf;
+ uchar msg_out[10]; /* enough to include SDTR */
+ uchar status;
+ int p9status;
+ uchar parityerror;
+} Dsa;
+
+typedef enum Feature {
+ BigFifo = 1, /* 536 byte fifo */
+ BurstOpCodeFetch = 2, /* burst fetch opcodes */
+ Prefetch = 4, /* prefetch 8 longwords */
+ LocalRAM = 8, /* 4K longwords of local RAM */
+ Differential = 16, /* Differential support */
+ Wide = 32, /* Wide capable */
+ Ultra = 64, /* Ultra capable */
+ ClockDouble = 128, /* Has clock doubler */
+ ClockQuad = 256, /* Has clock quadrupler (same as Ultra2) */
+ Ultra2 = 256,
+} Feature;
+
+typedef enum Burst {
+ Burst2 = 0,
+ Burst4 = 1,
+ Burst8 = 2,
+ Burst16 = 3,
+ Burst32 = 4,
+ Burst64 = 5,
+ Burst128 = 6
+} Burst;
+
+typedef struct Variant {
+ ushort did;
+ uchar maxrid; /* maximum allowed revision ID */
+ char *name;
+ Burst burst; /* codings for max burst */
+ uchar maxsyncoff; /* max synchronous offset */
+ uchar registers; /* number of 32 bit registers */
+ unsigned feature;
+} Variant;
+
+static unsigned char cf2[] = { 6, 2, 3, 4, 6, 8, 12, 16 };
+#define NULTRA2SCF (sizeof(cf2)/sizeof(cf2[0]))
+#define NULTRASCF (NULTRA2SCF - 2)
+#define NSCF (NULTRASCF - 1)
+
+typedef struct Controller {
+ Lock;
+ struct {
+ uchar scntl3;
+ uchar stest2;
+ } bios;
+ uchar synctab[NULTRA2SCF - 1][8];/* table of legal tpfs */
+ NegoState s[MAXTARGET];
+ uchar scntl3[MAXTARGET];
+ uchar sxfer[MAXTARGET];
+ uchar cap[MAXTARGET]; /* capabilities byte from Identify */
+ ushort capvalid; /* bit per target for validity of cap[] */
+ ushort wide; /* bit per target set if wide negotiated */
+ ulong sclk; /* clock speed of controller */
+ uchar clockmult; /* set by synctabinit */
+ uchar ccf; /* CCF bits */
+ uchar tpf; /* best tpf value for this controller */
+ uchar feature; /* requested features */
+ int running; /* is the script processor running? */
+ int ssm; /* single step mode */
+ Ncr *n; /* pointer to registers */
+ Variant *v; /* pointer to variant type */
+ ulong *script; /* where the real script is */
+ ulong scriptpa; /* where the real script is */
+ Pcidev* pcidev;
+ SDev* sdev;
+
+ struct {
+ Lock;
+ uchar head[4]; /* head of free list (NCR byte order) */
+ Dsa *freechain;
+ } dsalist;
+
+ QLock q[MAXTARGET]; /* queues for each target */
+} Controller;
+
+#define SYNCOFFMASK(c) (((c)->v->maxsyncoff * 2) - 1)
+#define SSIDMASK(c) (((c)->v->feature & Wide) ? 15 : 7)
+
+/* ISTAT */
+enum { Abrt = 0x80, Srst = 0x40, Sigp = 0x20, Sem = 0x10, Con = 0x08, Intf = 0x04, Sip = 0x02, Dip = 0x01 };
+
+/* DSTAT */
+enum { Dfe = 0x80, Mdpe = 0x40, Bf = 0x20, Abrted = 0x10, Ssi = 0x08, Sir = 0x04, Iid = 0x01 };
+
+/* SSTAT */
+enum { DataOut, DataIn, Cmd, Status, ReservedOut, ReservedIn, MessageOut, MessageIn };
+
+static void setmovedata(Movedata*, ulong, ulong);
+static void advancedata(Movedata*, long);
+static int bios_set_differential(Controller *c);
+
+static char *phase[] = {
+ "data out", "data in", "command", "status",
+ "reserved out", "reserved in", "message out", "message in"
+};
+
+#ifdef BOOTDEBUG
+#define DEBUGSIZE 10240
+char debugbuf[DEBUGSIZE];
+char *debuglast;
+
+static void
+intrprint(char *format, ...)
+{
+ if (debuglast == 0)
+ debuglast = debugbuf;
+ debuglast = vseprint(debuglast, debugbuf + (DEBUGSIZE - 1), format, (&format + 1));
+}
+
+static void
+iflush()
+{
+ int s;
+ char *endp;
+ s = splhi();
+ if (debuglast == 0)
+ debuglast = debugbuf;
+ if (debuglast == debugbuf) {
+ splx(s);
+ return;
+ }
+ endp = debuglast;
+ splx(s);
+ screenputs(debugbuf, endp - debugbuf);
+ s = splhi();
+ memmove(debugbuf, endp, debuglast - endp);
+ debuglast -= endp - debugbuf;
+ splx(s);
+}
+
+static void
+oprint(char *format, ...)
+{
+ int s;
+
+ iflush();
+ s = splhi();
+ if (debuglast == 0)
+ debuglast = debugbuf;
+ debuglast = vseprint(debuglast, debugbuf + (DEBUGSIZE - 1), format, (&format + 1));
+ splx(s);
+ iflush();
+}
+#endif
+
+#include "sd53c8xx.i"
+
+/*
+ * We used to use a linked list of Dsas with nil as the terminator,
+ * but occasionally the 896 card seems not to notice that the 0
+ * is really a 0, and then it tries to reference the Dsa at address 0.
+ * To address this, we use a sentinel dsa that links back to itself
+ * and has state A_STATE_END. If the card takes an iteration or
+ * two to notice that the state says A_STATE_END, that's no big
+ * deal. Clearly this isn't the right approach, but I'm just
+ * stumped. Even with this, we occasionally get prints about
+ * "WSR set", usually with about the same frequency that the
+ * card used to walk past 0.
+ */
+static Dsa *dsaend;
+
+static Dsa*
+dsaallocnew(Controller *c)
+{
+ Dsa *d;
+
+ /* c->dsalist must be ilocked */
+ d = xalloc(sizeof *d);
+ lesetl(d->next, legetl(c->dsalist.head));
+ lesetl(&d->stateb, A_STATE_FREE);
+ coherence();
+ lesetl(c->dsalist.head, DMASEG(d));
+ coherence();
+ return d;
+}
+
+static Dsa *
+dsaalloc(Controller *c, int target, int lun)
+{
+ Dsa *d;
+
+ ilock(&c->dsalist);
+ if ((d = c->dsalist.freechain) != 0) {
+ if (DEBUG(1))
+ IPRINT(PRINTPREFIX "%d/%d: reused dsa %lux\n", target, lun, (ulong)d);
+ } else {
+ d = dsaallocnew(c);
+ if (DEBUG(1))
+ IPRINT(PRINTPREFIX "%d/%d: allocated dsa %lux\n", target, lun, (ulong)d);
+ }
+ c->dsalist.freechain = d->freechain;
+ lesetl(&d->stateb, A_STATE_ALLOCATED);
+ iunlock(&c->dsalist);
+ d->target = target;
+ d->lun = lun;
+ return d;
+}
+
+static void
+dsafree(Controller *c, Dsa *d)
+{
+ ilock(&c->dsalist);
+ d->freechain = c->dsalist.freechain;
+ c->dsalist.freechain = d;
+ lesetl(&d->stateb, A_STATE_FREE);
+ iunlock(&c->dsalist);
+}
+
+static void
+dsadump(Controller *c)
+{
+ Dsa *d;
+ u32int *a;
+
+ iprint("dsa controller list: c=%p head=%.8lux\n", c, legetl(c->dsalist.head));
+ for(d=KPTR(legetl(c->dsalist.head)); d != dsaend; d=KPTR(legetl(d->next))){
+ if(d == (void*)-1){
+ iprint("\t dsa %p\n", d);
+ break;
+ }
+ a = (u32int*)d;
+ iprint("\tdsa %p %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux\n", a, a[0], a[1], a[2], a[3], a[4], a[5]);
+ }
+
+/*
+ a = KPTR(c->scriptpa+E_dsa_addr);
+ iprint("dsa_addr: %.8ux %.8ux %.8ux %.8ux %.8ux\n",
+ a[0], a[1], a[2], a[3], a[4]);
+ a = KPTR(c->scriptpa+E_issue_addr);
+ iprint("issue_addr: %.8ux %.8ux %.8ux %.8ux %.8ux\n",
+ a[0], a[1], a[2], a[3], a[4]);
+
+ a = KPTR(c->scriptpa+E_issue_test_begin);
+ e = KPTR(c->scriptpa+E_issue_test_end);
+ iprint("issue_test code (at offset %.8ux):\n", E_issue_test_begin);
+
+ i = 0;
+ for(; a<e; a++){
+ iprint(" %.8ux", *a);
+ if(++i%8 == 0)
+ iprint("\n");
+ }
+ if(i%8)
+ iprint("\n");
+*/
+}
+
+static Dsa *
+dsafind(Controller *c, uchar target, uchar lun, uchar state)
+{
+ Dsa *d;
+ for (d = KPTR(legetl(c->dsalist.head)); d != dsaend; d = KPTR(legetl(d->next))) {
+ if (d->target != 0xff && d->target != target)
+ continue;
+ if (lun != 0xff && d->lun != lun)
+ continue;
+ if (state != 0xff && d->stateb != state)
+ continue;
+ break;
+ }
+ return d;
+}
+
+static void
+dumpncrregs(Controller *c, int intr)
+{
+ int i;
+ Ncr *n = c->n;
+ int depth = c->v->registers / 4;
+
+ if (intr) {
+ IPRINT("sa = %.8lux\n", c->scriptpa);
+ }
+ else {
+ KPRINT("sa = %.8lux\n", c->scriptpa);
+ }
+ for (i = 0; i < depth; i++) {
+ int j;
+ for (j = 0; j < 4; j++) {
+ int k = j * depth + i;
+ uchar *p;
+
+ /* display little-endian to make 32-bit values readable */
+ p = (uchar*)n+k*4;
+ if (intr) {
+ IPRINT(" %.2x%.2x%.2x%.2x %.2x %.2x", p[3], p[2], p[1], p[0], k * 4, (k * 4) + 0x80);
+ }
+ else {
+ KPRINT(" %.2x%.2x%.2x%.2x %.2x %.2x", p[3], p[2], p[1], p[0], k * 4, (k * 4) + 0x80);
+ }
+ USED(p);
+ }
+ if (intr) {
+ IPRINT("\n");
+ }
+ else {
+ KPRINT("\n");
+ }
+ }
+}
+
+static int
+chooserate(Controller *c, int tpf, int *scfp, int *xferpp)
+{
+ /* find lowest entry >= tpf */
+ int besttpf = 1000;
+ int bestscfi = 0;
+ int bestxferp = 0;
+ int scf, xferp;
+ int maxscf;
+
+ if (c->v->feature & Ultra2)
+ maxscf = NULTRA2SCF;
+ else if (c->v->feature & Ultra)
+ maxscf = NULTRASCF;
+ else
+ maxscf = NSCF;
+
+ /*
+ * search large clock factors first since this should
+ * result in more reliable transfers
+ */
+ for (scf = maxscf; scf >= 1; scf--) {
+ for (xferp = 0; xferp < 8; xferp++) {
+ unsigned char v = c->synctab[scf - 1][xferp];
+ if (v == 0)
+ continue;
+ if (v >= tpf && v < besttpf) {
+ besttpf = v;
+ bestscfi = scf;
+ bestxferp = xferp;
+ }
+ }
+ }
+ if (besttpf == 1000)
+ return 0;
+ if (scfp)
+ *scfp = bestscfi;
+ if (xferpp)
+ *xferpp = bestxferp;
+ return besttpf;
+}
+
+static void
+synctabinit(Controller *c)
+{
+ int scf;
+ unsigned long scsilimit;
+ int xferp;
+ unsigned long cr, sr;
+ int tpf;
+ int fast;
+ int maxscf;
+
+ if (c->v->feature & Ultra2)
+ maxscf = NULTRA2SCF;
+ else if (c->v->feature & Ultra)
+ maxscf = NULTRASCF;
+ else
+ maxscf = NSCF;
+
+ /*
+ * for chips with no clock doubler, but Ultra capable (e.g. 860, or interestingly the
+ * first spin of the 875), assume 80MHz
+ * otherwise use the internal (33 Mhz) or external (40MHz) default
+ */
+
+ if ((c->v->feature & Ultra) != 0 && (c->v->feature & (ClockDouble | ClockQuad)) == 0)
+ c->sclk = ULTRA_NOCLOCKDOUBLE_SCLK;
+ else
+ c->sclk = SCLK;
+
+ /*
+ * otherwise, if the chip is Ultra capable, but has a slow(ish) clock,
+ * invoke the doubler
+ */
+
+ if (SCLK <= 40000000) {
+ if (c->v->feature & ClockDouble) {
+ c->sclk *= 2;
+ c->clockmult = 1;
+ }
+ else if (c->v->feature & ClockQuad) {
+ c->sclk *= 4;
+ c->clockmult = 1;
+ }
+ else
+ c->clockmult = 0;
+ }
+ else
+ c->clockmult = 0;
+
+ /* derive CCF from sclk */
+ /* woebetide anyone with SCLK < 16.7 or > 80MHz */
+ if (c->sclk <= 25 * MEGA)
+ c->ccf = 1;
+ else if (c->sclk <= 3750000)
+ c->ccf = 2;
+ else if (c->sclk <= 50 * MEGA)
+ c->ccf = 3;
+ else if (c->sclk <= 75 * MEGA)
+ c->ccf = 4;
+ else if ((c->v->feature & ClockDouble) && c->sclk <= 80 * MEGA)
+ c->ccf = 5;
+ else if ((c->v->feature & ClockQuad) && c->sclk <= 120 * MEGA)
+ c->ccf = 6;
+ else if ((c->v->feature & ClockQuad) && c->sclk <= 160 * MEGA)
+ c->ccf = 7;
+
+ for (scf = 1; scf < maxscf; scf++) {
+ /* check for legal core rate */
+ /* round up so we run slower for safety */
+ cr = (c->sclk * 2 + cf2[scf] - 1) / cf2[scf];
+ if (cr <= MAXSYNCCORERATE) {
+ scsilimit = MAXSYNCSCSIRATE;
+ fast = 0;
+ }
+ else if (cr <= MAXFASTSYNCCORERATE) {
+ scsilimit = MAXFASTSYNCSCSIRATE;
+ fast = 1;
+ }
+ else if ((c->v->feature & Ultra) && cr <= MAXULTRASYNCCORERATE) {
+ scsilimit = MAXULTRASYNCSCSIRATE;
+ fast = 2;
+ }
+ else if ((c->v->feature & Ultra2) && cr <= MAXULTRA2SYNCCORERATE) {
+ scsilimit = MAXULTRA2SYNCSCSIRATE;
+ fast = 3;
+ }
+ else
+ continue;
+ for (xferp = 11; xferp >= 4; xferp--) {
+ int ok;
+ int tp;
+ /* calculate scsi rate - round up again */
+ /* start from sclk for accuracy */
+ int totaldivide = xferp * cf2[scf];
+ sr = (c->sclk * 2 + totaldivide - 1) / totaldivide;
+ if (sr > scsilimit)
+ break;
+ /*
+ * now work out transfer period
+ * round down now so that period is pessimistic
+ */
+ tp = (MEGA * 1000) / sr;
+ /*
+ * bounds check it
+ */
+ if (tp < 25 || tp > 255 * 4)
+ continue;
+ /*
+ * spot stupid special case for Ultra or Ultra2
+ * while working out factor
+ */
+ if (tp == 25)
+ tpf = 10;
+ else if (tp == 50)
+ tpf = 12;
+ else if (tp < 52)
+ continue;
+ else
+ tpf = tp / 4;
+ /*
+ * now check tpf looks sensible
+ * given core rate
+ */
+ switch (fast) {
+ case 0:
+ /* scf must be ccf for SCSI 1 */
+ ok = tpf >= 50 && scf == c->ccf;
+ break;
+ case 1:
+ ok = tpf >= 25 && tpf < 50;
+ break;
+ case 2:
+ /*
+ * must use xferp of 4, or 5 at a pinch
+ * for an Ultra transfer
+ */
+ ok = xferp <= 5 && tpf >= 12 && tpf < 25;
+ break;
+ case 3:
+ ok = xferp == 4 && (tpf == 10 || tpf == 11);
+ break;
+ default:
+ ok = 0;
+ }
+ if (!ok)
+ continue;
+ c->synctab[scf - 1][xferp - 4] = tpf;
+ }
+ }
+
+#ifndef NO_ULTRA2
+ if (c->v->feature & Ultra2)
+ tpf = 10;
+ else
+#endif
+ if (c->v->feature & Ultra)
+ tpf = 12;
+ else
+ tpf = 25;
+ for (; tpf < 256; tpf++) {
+ if (chooserate(c, tpf, &scf, &xferp) == tpf) {
+ unsigned tp = tpf == 10 ? 25 : (tpf == 12 ? 50 : tpf * 4);
+ unsigned long khz = (MEGA + tp - 1) / (tp);
+ KPRINT(PRINTPREFIX "tpf=%d scf=%d.%.1d xferp=%d mhz=%ld.%.3ld\n",
+ tpf, cf2[scf] / 2, (cf2[scf] & 1) ? 5 : 0,
+ xferp + 4, khz / 1000, khz % 1000);
+ USED(khz);
+ if (c->tpf == 0)
+ c->tpf = tpf; /* note lowest value for controller */
+ }
+ }
+}
+
+static void
+synctodsa(Dsa *dsa, Controller *c)
+{
+/*
+ KPRINT("synctodsa(dsa=%lux, target=%d, scntl3=%.2lx sxfer=%.2x)\n",
+ dsa, dsa->target, c->scntl3[dsa->target], c->sxfer[dsa->target]);
+*/
+ dsa->scntl3 = c->scntl3[dsa->target];
+ dsa->sxfer = c->sxfer[dsa->target];
+}
+
+static void
+setsync(Dsa *dsa, Controller *c, int target, uchar ultra, uchar scf, uchar xferp, uchar reqack)
+{
+ c->scntl3[target] =
+ (c->scntl3[target] & 0x08) | (((scf << 4) | c->ccf | (ultra << 7)) & ~0x08);
+ c->sxfer[target] = (xferp << 5) | reqack;
+ c->s[target] = BothDone;
+ if (dsa) {
+ synctodsa(dsa, c);
+ c->n->scntl3 = c->scntl3[target];
+ c->n->sxfer = c->sxfer[target];
+ }
+}
+
+static void
+setasync(Dsa *dsa, Controller *c, int target)
+{
+ setsync(dsa, c, target, 0, c->ccf, 0, 0);
+}
+
+static void
+setwide(Dsa *dsa, Controller *c, int target, uchar wide)
+{
+ c->scntl3[target] = wide ? (1 << 3) : 0;
+ setasync(dsa, c, target);
+ c->s[target] = WideDone;
+}
+
+static int
+buildsdtrmsg(uchar *buf, uchar tpf, uchar offset)
+{
+ *buf++ = X_MSG;
+ *buf++ = 3;
+ *buf++ = X_MSG_SDTR;
+ *buf++ = tpf;
+ *buf = offset;
+ return 5;
+}
+
+static int
+buildwdtrmsg(uchar *buf, uchar expo)
+{
+ *buf++ = X_MSG;
+ *buf++ = 2;
+ *buf++ = X_MSG_WDTR;
+ *buf = expo;
+ return 4;
+}
+
+static void
+start(Controller *c, long entry)
+{
+ ulong p;
+
+ if (c->running)
+ panic(PRINTPREFIX "start called while running");
+ c->running = 1;
+ p = c->scriptpa + entry;
+ lesetl(c->n->dsp, p);
+ coherence();
+ if (c->ssm)
+ c->n->dcntl |= 0x4; /* start DMA in SSI mode */
+}
+
+static void
+ncrcontinue(Controller *c)
+{
+ if (c->running)
+ panic(PRINTPREFIX "ncrcontinue called while running");
+ /* set the start DMA bit to continue execution */
+ c->running = 1;
+ coherence();
+ c->n->dcntl |= 0x4;
+}
+
+static void
+softreset(Controller *c)
+{
+ Ncr *n = c->n;
+
+ n->istat = Srst; /* software reset */
+ n->istat = 0;
+ /* general initialisation */
+ n->scid = (1 << 6) | 7; /* respond to reselect, ID 7 */
+ n->respid = 1 << 7; /* response ID = 7 */
+
+#ifdef INTERNAL_SCLK
+ n->stest1 = 0x80; /* disable external scsi clock */
+#else
+ n->stest1 = 0x00;
+#endif
+
+ n->stime0 = 0xdd; /* about 0.5 second timeout on each device */
+ n->scntl0 |= 0x8; /* Enable parity checking */
+
+ /* continued setup */
+ n->sien0 = 0x8f;
+ n->sien1 = 0x04;
+ n->dien = 0x7d;
+ n->stest3 = 0x80; /* TolerANT enable */
+ c->running = 0;
+
+ if (c->v->feature & BigFifo)
+ n->ctest5 = (1 << 5);
+ n->dmode = c->v->burst << 6; /* set burst length bits */
+ if (c->v->burst & 4)
+ n->ctest5 |= (1 << 2); /* including overflow into ctest5 bit 2 */
+ if (c->v->feature & Prefetch)
+ n->dcntl |= (1 << 5); /* prefetch enable */
+ else if (c->v->feature & BurstOpCodeFetch)
+ n->dmode |= (1 << 1); /* burst opcode fetch */
+ if (c->v->feature & Differential) {
+ /* chip capable */
+ if ((c->feature & Differential) || bios_set_differential(c)) {
+ /* user enabled, or some evidence bios set differential */
+ if (n->sstat2 & (1 << 2))
+ print(PRINTPREFIX "can't go differential; wrong cable\n");
+ else {
+ n->stest2 = (1 << 5);
+ print(PRINTPREFIX "differential mode set\n");
+ }
+ }
+ }
+ if (c->clockmult) {
+ n->stest1 |= (1 << 3); /* power up doubler */
+ delay(2);
+ n->stest3 |= (1 << 5); /* stop clock */
+ n->stest1 |= (1 << 2); /* enable doubler */
+ n->stest3 &= ~(1 << 5); /* start clock */
+ /* pray */
+ }
+}
+
+static void
+msgsm(Dsa *dsa, Controller *c, int msg, int *cont, int *wakeme)
+{
+ uchar histpf, hisreqack;
+ int tpf;
+ int scf, xferp;
+ int len;
+
+ Ncr *n = c->n;
+
+ switch (c->s[dsa->target]) {
+ case SyncInit:
+ switch (msg) {
+ case A_SIR_MSG_SDTR:
+ /* reply to my SDTR */
+ histpf = n->scratcha[2];
+ hisreqack = n->scratcha[3];
+ KPRINT(PRINTPREFIX "%d: SDTN response %d %d\n",
+ dsa->target, histpf, hisreqack);
+
+ if (hisreqack == 0)
+ setasync(dsa, c, dsa->target);
+ else {
+ /* hisreqack should be <= c->v->maxsyncoff */
+ tpf = chooserate(c, histpf, &scf, &xferp);
+ KPRINT(PRINTPREFIX "%d: SDTN: using %d %d\n",
+ dsa->target, tpf, hisreqack);
+ setsync(dsa, c, dsa->target, tpf < 25, scf, xferp, hisreqack);
+ }
+ *cont = -2;
+ return;
+ case A_SIR_EV_PHASE_SWITCH_AFTER_ID:
+ /* target ignored ATN for message after IDENTIFY - not SCSI-II */
+ KPRINT(PRINTPREFIX "%d: illegal phase switch after ID message - SCSI-1 device?\n", dsa->target);
+ KPRINT(PRINTPREFIX "%d: SDTN: async\n", dsa->target);
+ setasync(dsa, c, dsa->target);
+ *cont = E_to_decisions;
+ return;
+ case A_SIR_MSG_REJECT:
+ /* rejection of my SDTR */
+ KPRINT(PRINTPREFIX "%d: SDTN: rejected SDTR\n", dsa->target);
+ //async:
+ KPRINT(PRINTPREFIX "%d: SDTN: async\n", dsa->target);
+ setasync(dsa, c, dsa->target);
+ *cont = -2;
+ return;
+ }
+ break;
+ case WideInit:
+ switch (msg) {
+ case A_SIR_MSG_WDTR:
+ /* reply to my WDTR */
+ KPRINT(PRINTPREFIX "%d: WDTN: response %d\n",
+ dsa->target, n->scratcha[2]);
+ setwide(dsa, c, dsa->target, n->scratcha[2]);
+ *cont = -2;
+ return;
+ case A_SIR_EV_PHASE_SWITCH_AFTER_ID:
+ /* target ignored ATN for message after IDENTIFY - not SCSI-II */
+ KPRINT(PRINTPREFIX "%d: illegal phase switch after ID message - SCSI-1 device?\n", dsa->target);
+ setwide(dsa, c, dsa->target, 0);
+ *cont = E_to_decisions;
+ return;
+ case A_SIR_MSG_REJECT:
+ /* rejection of my SDTR */
+ KPRINT(PRINTPREFIX "%d: WDTN: rejected WDTR\n", dsa->target);
+ setwide(dsa, c, dsa->target, 0);
+ *cont = -2;
+ return;
+ }
+ break;
+
+ case NeitherDone:
+ case WideDone:
+ case BothDone:
+ switch (msg) {
+ case A_SIR_MSG_WDTR: {
+ uchar hiswide, mywide;
+ hiswide = n->scratcha[2];
+ mywide = (c->v->feature & Wide) != 0;
+ KPRINT(PRINTPREFIX "%d: WDTN: target init %d\n",
+ dsa->target, hiswide);
+ if (hiswide < mywide)
+ mywide = hiswide;
+ KPRINT(PRINTPREFIX "%d: WDTN: responding %d\n",
+ dsa->target, mywide);
+ setwide(dsa, c, dsa->target, mywide);
+ len = buildwdtrmsg(dsa->msg_out, mywide);
+ setmovedata(&dsa->msg_out_buf, DMASEG(dsa->msg_out), len);
+ *cont = E_response;
+ c->s[dsa->target] = WideResponse;
+ return;
+ }
+ case A_SIR_MSG_SDTR:
+#ifdef ASYNC_ONLY
+ *cont = E_reject;
+ return;
+#else
+ /* target decides to renegotiate */
+ histpf = n->scratcha[2];
+ hisreqack = n->scratcha[3];
+ KPRINT(PRINTPREFIX "%d: SDTN: target init %d %d\n",
+ dsa->target, histpf, hisreqack);
+ if (hisreqack == 0) {
+ /* he wants asynchronous */
+ setasync(dsa, c, dsa->target);
+ tpf = 0;
+ }
+ else {
+ /* he wants synchronous */
+ tpf = chooserate(c, histpf, &scf, &xferp);
+ if (hisreqack > c->v->maxsyncoff)
+ hisreqack = c->v->maxsyncoff;
+ KPRINT(PRINTPREFIX "%d: using %d %d\n",
+ dsa->target, tpf, hisreqack);
+ setsync(dsa, c, dsa->target, tpf < 25, scf, xferp, hisreqack);
+ }
+ /* build my SDTR message */
+ len = buildsdtrmsg(dsa->msg_out, tpf, hisreqack);
+ setmovedata(&dsa->msg_out_buf, DMASEG(dsa->msg_out), len);
+ *cont = E_response;
+ c->s[dsa->target] = SyncResponse;
+ return;
+#endif
+ }
+ break;
+ case WideResponse:
+ switch (msg) {
+ case A_SIR_EV_RESPONSE_OK:
+ c->s[dsa->target] = WideDone;
+ KPRINT(PRINTPREFIX "%d: WDTN: response accepted\n", dsa->target);
+ *cont = -2;
+ return;
+ case A_SIR_MSG_REJECT:
+ setwide(dsa, c, dsa->target, 0);
+ KPRINT(PRINTPREFIX "%d: WDTN: response REJECTed\n", dsa->target);
+ *cont = -2;
+ return;
+ }
+ break;
+ case SyncResponse:
+ switch (msg) {
+ case A_SIR_EV_RESPONSE_OK:
+ c->s[dsa->target] = BothDone;
+ KPRINT(PRINTPREFIX "%d: SDTN: response accepted (%s)\n",
+ dsa->target, phase[n->sstat1 & 7]);
+ *cont = -2;
+ return; /* chf */
+ case A_SIR_MSG_REJECT:
+ setasync(dsa, c, dsa->target);
+ KPRINT(PRINTPREFIX "%d: SDTN: response REJECTed\n", dsa->target);
+ *cont = -2;
+ return;
+ }
+ break;
+ }
+ KPRINT(PRINTPREFIX "%d: msgsm: state %d msg %d\n",
+ dsa->target, c->s[dsa->target], msg);
+ *wakeme = 1;
+ return;
+}
+
+static void
+calcblockdma(Dsa *d, ulong base, ulong count)
+{
+ ulong blocks;
+ if (DEBUG(3))
+ blocks = 0;
+ else {
+ blocks = count / A_BSIZE;
+ if (blocks > 255)
+ blocks = 255;
+ }
+ d->dmablks = blocks;
+ d->dmaaddr[0] = base;
+ d->dmaaddr[1] = base >> 8;
+ d->dmaaddr[2] = base >> 16;
+ d->dmaaddr[3] = base >> 24;
+ setmovedata(&d->data_buf, base + blocks * A_BSIZE, count - blocks * A_BSIZE);
+ d->flag = legetl(d->data_buf.dbc) == 0;
+}
+
+static ulong
+read_mismatch_recover(Controller *c, Ncr *n, Dsa *dsa)
+{
+ ulong dbc;
+ uchar dfifo = n->dfifo;
+ int inchip;
+
+ dbc = (n->dbc[2]<<16)|(n->dbc[1]<<8)|n->dbc[0];
+ if (n->ctest5 & (1 << 5))
+ inchip = ((dfifo | ((n->ctest5 & 3) << 8)) - (dbc & 0x3ff)) & 0x3ff;
+ else
+ inchip = ((dfifo & 0x7f) - (dbc & 0x7f)) & 0x7f;
+ if (inchip) {
+ IPRINT(PRINTPREFIX "%d/%d: read_mismatch_recover: DMA FIFO = %d\n",
+ dsa->target, dsa->lun, inchip);
+ }
+ if (n->sxfer & SYNCOFFMASK(c)) {
+ /* SCSI FIFO */
+ uchar fifo = n->sstat1 >> 4;
+ if (c->v->maxsyncoff > 8)
+ fifo |= (n->sstat2 & (1 << 4));
+ if (fifo) {
+ inchip += fifo;
+ IPRINT(PRINTPREFIX "%d/%d: read_mismatch_recover: SCSI FIFO = %d\n",
+ dsa->target, dsa->lun, fifo);
+ }
+ }
+ else {
+ if (n->sstat0 & (1 << 7)) {
+ inchip++;
+ IPRINT(PRINTPREFIX "%d/%d: read_mismatch_recover: SIDL full\n",
+ dsa->target, dsa->lun);
+ }
+ if (n->sstat2 & (1 << 7)) {
+ inchip++;
+ IPRINT(PRINTPREFIX "%d/%d: read_mismatch_recover: SIDL msb full\n",
+ dsa->target, dsa->lun);
+ }
+ }
+ USED(inchip);
+ return dbc;
+}
+
+static ulong
+write_mismatch_recover(Controller *c, Ncr *n, Dsa *dsa)
+{
+ ulong dbc;
+ uchar dfifo = n->dfifo;
+ int inchip;
+
+ dbc = (n->dbc[2]<<16)|(n->dbc[1]<<8)|n->dbc[0];
+ USED(dsa);
+ if (n->ctest5 & (1 << 5))
+ inchip = ((dfifo | ((n->ctest5 & 3) << 8)) - (dbc & 0x3ff)) & 0x3ff;
+ else
+ inchip = ((dfifo & 0x7f) - (dbc & 0x7f)) & 0x7f;
+#ifdef WMR_DEBUG
+ if (inchip) {
+ IPRINT(PRINTPREFIX "%d/%d: write_mismatch_recover: DMA FIFO = %d\n",
+ dsa->target, dsa->lun, inchip);
+ }
+#endif
+ if (n->sstat0 & (1 << 5)) {
+ inchip++;
+#ifdef WMR_DEBUG
+ IPRINT(PRINTPREFIX "%d/%d: write_mismatch_recover: SODL full\n", dsa->target, dsa->lun);
+#endif
+ }
+ if (n->sstat2 & (1 << 5)) {
+ inchip++;
+#ifdef WMR_DEBUG
+ IPRINT(PRINTPREFIX "%d/%d: write_mismatch_recover: SODL msb full\n", dsa->target, dsa->lun);
+#endif
+ }
+ if (n->sxfer & SYNCOFFMASK(c)) {
+ /* synchronous SODR */
+ if (n->sstat0 & (1 << 6)) {
+ inchip++;
+#ifdef WMR_DEBUG
+ IPRINT(PRINTPREFIX "%d/%d: write_mismatch_recover: SODR full\n",
+ dsa->target, dsa->lun);
+#endif
+ }
+ if (n->sstat2 & (1 << 6)) {
+ inchip++;
+#ifdef WMR_DEBUG
+ IPRINT(PRINTPREFIX "%d/%d: write_mismatch_recover: SODR msb full\n",
+ dsa->target, dsa->lun);
+#endif
+ }
+ }
+ /* clear the dma fifo */
+ n->ctest3 |= (1 << 2);
+ /* wait till done */
+ while ((n->dstat & Dfe) == 0)
+ ;
+ return dbc + inchip;
+}
+
+static void
+sd53c8xxinterrupt(Ureg *ur, void *a)
+{
+ uchar istat;
+ ushort sist;
+ uchar dstat;
+ int wakeme = 0;
+ int cont = -1;
+ Dsa *dsa;
+ ulong dsapa;
+ Controller *c = a;
+ Ncr *n = c->n;
+
+ USED(ur);
+ if (DEBUG(1)) {
+ IPRINT(PRINTPREFIX "int\n");
+ }
+ ilock(c);
+ istat = n->istat;
+ if (istat & Intf) {
+ Dsa *d;
+ int wokesomething = 0;
+ if (DEBUG(1)) {
+ IPRINT(PRINTPREFIX "Intfly\n");
+ }
+ n->istat = Intf;
+ /* search for structures in A_STATE_DONE */
+ for (d = KPTR(legetl(c->dsalist.head)); d != dsaend; d = KPTR(legetl(d->next))) {
+ if (d->stateb == A_STATE_DONE) {
+ d->p9status = d->status;
+ if (DEBUG(1)) {
+ IPRINT(PRINTPREFIX "waking up dsa %lux\n", (ulong)d);
+ }
+ wakeup(d);
+ wokesomething = 1;
+ }
+ }
+ if (!wokesomething) {
+ IPRINT(PRINTPREFIX "nothing to wake up\n");
+ }
+ }
+
+ if ((istat & (Sip | Dip)) == 0) {
+ if (DEBUG(1)) {
+ IPRINT(PRINTPREFIX "int end %x\n", istat);
+ }
+ iunlock(c);
+ return;
+ }
+
+ sist = (n->sist1<<8)|n->sist0; /* BUG? can two-byte read be inconsistent? */
+ dstat = n->dstat;
+ dsapa = legetl(n->dsa);
+
+ /*
+ * Can't compute dsa until we know that dsapa is valid.
+ */
+ if(dsapa < -KZERO)
+ dsa = (Dsa*)DMASEG_TO_KADDR(dsapa);
+ else{
+ dsa = nil;
+ /*
+ * happens at startup on some cards but we
+ * don't actually deref dsa because none of the
+ * flags we are about are set.
+ * still, print in case that changes and we're
+ * about to dereference nil.
+ */
+ iprint("sd53c8xxinterrupt: dsa=%.8lux istat=%ux sist=%ux dstat=%ux\n", dsapa, istat, sist, dstat);
+ }
+
+ c->running = 0;
+ if (istat & Sip) {
+ if (DEBUG(1)) {
+ IPRINT("sist = %.4x\n", sist);
+ }
+ if (sist & 0x80) {
+ ulong addr;
+ ulong sa;
+ ulong dbc;
+ ulong tbc;
+ int dmablks;
+ ulong dmaaddr;
+
+ addr = legetl(n->dsp);
+ sa = addr - c->scriptpa;
+ if (DEBUG(1) || DEBUG(2)) {
+ IPRINT(PRINTPREFIX "%d/%d: Phase Mismatch sa=%.8lux\n",
+ dsa->target, dsa->lun, sa);
+ }
+ /*
+ * now recover
+ */
+ if (sa == E_data_in_mismatch) {
+ /*
+ * though this is a failure in the residue, there may have been blocks
+ * as well. if so, dmablks will not have been zeroed, since the state
+ * was not saved by the microcode.
+ */
+ dbc = read_mismatch_recover(c, n, dsa);
+ tbc = legetl(dsa->data_buf.dbc) - dbc;
+ dsa->dmablks = 0;
+ n->scratcha[2] = 0;
+ advancedata(&dsa->data_buf, tbc);
+ if (DEBUG(1) || DEBUG(2)) {
+ IPRINT(PRINTPREFIX "%d/%d: transferred = %ld residue = %ld\n",
+ dsa->target, dsa->lun, tbc, legetl(dsa->data_buf.dbc));
+ }
+ cont = E_data_mismatch_recover;
+ }
+ else if (sa == E_data_in_block_mismatch) {
+ dbc = read_mismatch_recover(c, n, dsa);
+ tbc = A_BSIZE - dbc;
+ /* recover current state from registers */
+ dmablks = n->scratcha[2];
+ dmaaddr = legetl(n->scratchb);
+ /* we have got to dmaaddr + tbc */
+ /* we have dmablks * A_BSIZE - tbc + residue left to do */
+ /* so remaining transfer is */
+ IPRINT("in_block_mismatch: dmaaddr = 0x%lux tbc=%lud dmablks=%d\n",
+ dmaaddr, tbc, dmablks);
+ calcblockdma(dsa, dmaaddr + tbc,
+ dmablks * A_BSIZE - tbc + legetl(dsa->data_buf.dbc));
+ /* copy changes into scratch registers */
+ IPRINT("recalc: dmablks %d dmaaddr 0x%lx pa 0x%lx dbc %ld\n",
+ dsa->dmablks, legetl(dsa->dmaaddr),
+ legetl(dsa->data_buf.pa), legetl(dsa->data_buf.dbc));
+ n->scratcha[2] = dsa->dmablks;
+ lesetl(n->scratchb, dsa->dmancr);
+ cont = E_data_block_mismatch_recover;
+ }
+ else if (sa == E_data_out_mismatch) {
+ dbc = write_mismatch_recover(c, n, dsa);
+ tbc = legetl(dsa->data_buf.dbc) - dbc;
+ dsa->dmablks = 0;
+ n->scratcha[2] = 0;
+ advancedata(&dsa->data_buf, tbc);
+ if (DEBUG(1) || DEBUG(2)) {
+ IPRINT(PRINTPREFIX "%d/%d: transferred = %ld residue = %ld\n",
+ dsa->target, dsa->lun, tbc, legetl(dsa->data_buf.dbc));
+ }
+ cont = E_data_mismatch_recover;
+ }
+ else if (sa == E_data_out_block_mismatch) {
+ dbc = write_mismatch_recover(c, n, dsa);
+ tbc = legetl(dsa->data_buf.dbc) - dbc;
+ /* recover current state from registers */
+ dmablks = n->scratcha[2];
+ dmaaddr = legetl(n->scratchb);
+ /* we have got to dmaaddr + tbc */
+ /* we have dmablks blocks - tbc + residue left to do */
+ /* so remaining transfer is */
+ IPRINT("out_block_mismatch: dmaaddr = %lux tbc=%lud dmablks=%d\n",
+ dmaaddr, tbc, dmablks);
+ calcblockdma(dsa, dmaaddr + tbc,
+ dmablks * A_BSIZE - tbc + legetl(dsa->data_buf.dbc));
+ /* copy changes into scratch registers */
+ n->scratcha[2] = dsa->dmablks;
+ lesetl(n->scratchb, dsa->dmancr);
+ cont = E_data_block_mismatch_recover;
+ }
+ else if (sa == E_id_out_mismatch) {
+ /*
+ * target switched phases while attention held during
+ * message out. The possibilities are:
+ * 1. It didn't like the last message. This is indicated
+ * by the new phase being message_in. Use script to recover
+ *
+ * 2. It's not SCSI-II compliant. The new phase will be other
+ * than message_in. We should also indicate that the device
+ * is asynchronous, if it's the SDTR that got ignored
+ *
+ * For now, if the phase switch is not to message_in, and
+ * and it happens after IDENTIFY and before SDTR, we
+ * notify the negotiation state machine.
+ */
+ ulong lim = legetl(dsa->msg_out_buf.dbc);
+ uchar p = n->sstat1 & 7;
+ dbc = write_mismatch_recover(c, n, dsa);
+ tbc = lim - dbc;
+ IPRINT(PRINTPREFIX "%d/%d: msg_out_mismatch: %lud/%lud sent, phase %s\n",
+ dsa->target, dsa->lun, tbc, lim, phase[p]);
+ if (p != MessageIn && tbc == 1) {
+ msgsm(dsa, c, A_SIR_EV_PHASE_SWITCH_AFTER_ID, &cont, &wakeme);
+ }
+ else
+ cont = E_id_out_mismatch_recover;
+ }
+ else if (sa == E_cmd_out_mismatch) {
+ /*
+ * probably the command count is longer than the device wants ...
+ */
+ ulong lim = legetl(dsa->cmd_buf.dbc);
+ uchar p = n->sstat1 & 7;
+ dbc = write_mismatch_recover(c, n, dsa);
+ tbc = lim - dbc;
+ IPRINT(PRINTPREFIX "%d/%d: cmd_out_mismatch: %lud/%lud sent, phase %s\n",
+ dsa->target, dsa->lun, tbc, lim, phase[p]);
+ USED(p, tbc);
+ cont = E_to_decisions;
+ }
+ else {
+ IPRINT(PRINTPREFIX "%d/%d: ma sa=%.8lux wanted=%s got=%s\n",
+ dsa->target, dsa->lun, sa,
+ phase[n->dcmd & 7],
+ phase[n->sstat1 & 7]);
+ dumpncrregs(c, 1);
+ dsa->p9status = SDeio; /* chf */
+ wakeme = 1;
+ }
+ }
+ /*else*/ if (sist & 0x400) {
+ if (DEBUG(0)) {
+ IPRINT(PRINTPREFIX "%d/%d Sto\n", dsa->target, dsa->lun);
+ }
+ dsa->p9status = SDtimeout;
+ dsa->stateb = A_STATE_DONE;
+ coherence();
+ softreset(c);
+ cont = E_issue_check;
+ wakeme = 1;
+ }
+ if (sist & 0x1) {
+ IPRINT(PRINTPREFIX "%d/%d: parity error\n", dsa->target, dsa->lun);
+ dsa->parityerror = 1;
+ }
+ if (sist & 0x4) {
+ IPRINT(PRINTPREFIX "%d/%d: unexpected disconnect\n",
+ dsa->target, dsa->lun);
+ dumpncrregs(c, 1);
+ //wakeme = 1;
+ dsa->p9status = SDeio;
+ }
+ }
+ if (istat & Dip) {
+ if (DEBUG(1)) {
+ IPRINT("dstat = %.2x\n", dstat);
+ }
+ /*else*/ if (dstat & Ssi) {
+ ulong w = legetl(n->dsp) - c->scriptpa;
+ IPRINT("[%lux]", w);
+ USED(w);
+ cont = -2; /* restart */
+ }
+ if (dstat & Sir) {
+ switch (legetl(n->dsps)) {
+ case A_SIR_MSG_IO_COMPLETE:
+ dsa->p9status = dsa->status;
+ wakeme = 1;
+ break;
+ case A_SIR_MSG_SDTR:
+ case A_SIR_MSG_WDTR:
+ case A_SIR_MSG_REJECT:
+ case A_SIR_EV_RESPONSE_OK:
+ msgsm(dsa, c, legetl(n->dsps), &cont, &wakeme);
+ break;
+ case A_SIR_MSG_IGNORE_WIDE_RESIDUE:
+ /* back up one in the data transfer */
+ IPRINT(PRINTPREFIX "%d/%d: ignore wide residue %d, WSR = %d\n",
+ dsa->target, dsa->lun, n->scratcha[1], n->scntl2 & 1);
+ if (dsa->flag == 2) {
+ IPRINT(PRINTPREFIX "%d/%d: transfer over; residue ignored\n",
+ dsa->target, dsa->lun);
+ }
+ else {
+ calcblockdma(dsa, legetl(dsa->dmaaddr) - 1,
+ dsa->dmablks * A_BSIZE + legetl(dsa->data_buf.dbc) + 1);
+ }
+ cont = -2;
+ break;
+ case A_SIR_ERROR_NOT_MSG_IN_AFTER_RESELECT:
+ IPRINT(PRINTPREFIX "%d: not msg_in after reselect (%s)",
+ n->ssid & SSIDMASK(c), phase[n->sstat1 & 7]);
+ dsa = dsafind(c, n->ssid & SSIDMASK(c), -1, A_STATE_DISCONNECTED);
+ dumpncrregs(c, 1);
+ wakeme = 1;
+ break;
+ case A_SIR_NOTIFY_LOAD_STATE:
+ IPRINT(PRINTPREFIX ": load_state dsa=%p\n", dsa);
+ if (dsa == (void*)KZERO || dsa == (void*)-1) {
+ dsadump(c);
+ dumpncrregs(c, 1);
+ panic("bad dsa in load_state");
+ }
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_MSG_IN:
+ IPRINT(PRINTPREFIX "%d/%d: msg_in %d\n",
+ dsa->target, dsa->lun, n->sfbr);
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_DISC:
+ IPRINT(PRINTPREFIX "%d/%d: disconnect:", dsa->target, dsa->lun);
+ goto dsadump;
+ case A_SIR_NOTIFY_STATUS:
+ IPRINT(PRINTPREFIX "%d/%d: status\n", dsa->target, dsa->lun);
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_COMMAND:
+ IPRINT(PRINTPREFIX "%d/%d: commands\n", dsa->target, dsa->lun);
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_DATA_IN:
+ IPRINT(PRINTPREFIX "%d/%d: data in a %lx b %lx\n",
+ dsa->target, dsa->lun, legetl(n->scratcha), legetl(n->scratchb));
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_BLOCK_DATA_IN:
+ IPRINT(PRINTPREFIX "%d/%d: block data in: a2 %x b %lx\n",
+ dsa->target, dsa->lun, n->scratcha[2], legetl(n->scratchb));
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_DATA_OUT:
+ IPRINT(PRINTPREFIX "%d/%d: data out\n", dsa->target, dsa->lun);
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_DUMP:
+ IPRINT(PRINTPREFIX "%d/%d: dump\n", dsa->target, dsa->lun);
+ dumpncrregs(c, 1);
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_DUMP2:
+ IPRINT(PRINTPREFIX "%d/%d: dump2:", dsa->target, dsa->lun);
+ IPRINT(" sa %lux", legetl(n->dsp) - c->scriptpa);
+ IPRINT(" dsa %lux", legetl(n->dsa));
+ IPRINT(" sfbr %ux", n->sfbr);
+ IPRINT(" a %lux", legetl(n->scratcha));
+ IPRINT(" b %lux", legetl(n->scratchb));
+ IPRINT(" ssid %ux", n->ssid);
+ IPRINT("\n");
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_WAIT_RESELECT:
+ IPRINT(PRINTPREFIX "wait reselect\n");
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_RESELECT:
+ IPRINT(PRINTPREFIX "reselect: ssid %.2x sfbr %.2x at %ld\n",
+ n->ssid, n->sfbr, TK2MS(m->ticks));
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_ISSUE:
+ IPRINT(PRINTPREFIX "%d/%d: issue dsa=%p end=%p:", dsa->target, dsa->lun, dsa, dsaend);
+ dsadump:
+ IPRINT(" tgt=%d", dsa->target);
+ IPRINT(" time=%ld", TK2MS(m->ticks));
+ IPRINT("\n");
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_ISSUE_CHECK:
+ IPRINT(PRINTPREFIX "issue check\n");
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_SIGP:
+ IPRINT(PRINTPREFIX "responded to SIGP\n");
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_DUMP_NEXT_CODE: {
+ ulong *dsp = c->script + (legetl(n->dsp)-c->scriptpa)/4;
+ int x;
+ IPRINT(PRINTPREFIX "code at %lux", dsp - c->script);
+ for (x = 0; x < 6; x++) {
+ IPRINT(" %.8lux", dsp[x]);
+ }
+ IPRINT("\n");
+ USED(dsp);
+ cont = -2;
+ break;
+ }
+ case A_SIR_NOTIFY_WSR:
+ IPRINT(PRINTPREFIX "%d/%d: WSR set\n", dsa->target, dsa->lun);
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_LOAD_SYNC:
+ IPRINT(PRINTPREFIX "%d/%d: scntl=%.2x sxfer=%.2x\n",
+ dsa->target, dsa->lun, n->scntl3, n->sxfer);
+ cont = -2;
+ break;
+ case A_SIR_NOTIFY_RESELECTED_ON_SELECT:
+ if (DEBUG(2)) {
+ IPRINT(PRINTPREFIX "%d/%d: reselected during select\n",
+ dsa->target, dsa->lun);
+ }
+ cont = -2;
+ break;
+ case A_error_reselected: /* dsa isn't valid here */
+ iprint(PRINTPREFIX "reselection error\n");
+ dumpncrregs(c, 1);
+ for (dsa = KPTR(legetl(c->dsalist.head)); dsa != dsaend; dsa = KPTR(legetl(dsa->next))) {
+ IPRINT(PRINTPREFIX "dsa target %d lun %d state %d\n", dsa->target, dsa->lun, dsa->stateb);
+ }
+ break;
+ default:
+ IPRINT(PRINTPREFIX "%d/%d: script error %ld\n",
+ dsa->target, dsa->lun, legetl(n->dsps));
+ dumpncrregs(c, 1);
+ wakeme = 1;
+ }
+ }
+ /*else*/ if (dstat & Iid) {
+ int i, target, lun;
+ ulong addr, dbc, *v;
+
+ addr = legetl(n->dsp);
+ if(dsa){
+ target = dsa->target;
+ lun = dsa->lun;
+ }else{
+ target = -1;
+ lun = -1;
+ }
+ dbc = (n->dbc[2]<<16)|(n->dbc[1]<<8)|n->dbc[0];
+
+ // if(dsa == nil)
+ idebug++;
+ IPRINT(PRINTPREFIX "%d/%d: Iid pa=%.8lux sa=%.8lux dbc=%lux\n",
+ target, lun,
+ addr, addr - c->scriptpa, dbc);
+ addr = (ulong)c->script + addr - c->scriptpa;
+ addr -= 64;
+ addr &= ~63;
+ v = (ulong*)addr;
+ for(i=0; i<8; i++){
+ IPRINT("%.8lux: %.8lux %.8lux %.8lux %.8lux\n",
+ addr, v[0], v[1], v[2], v[3]);
+ addr += 4*4;
+ v += 4;
+ }
+ USED(addr, dbc);
+ if(dsa == nil){
+ dsadump(c);
+ dumpncrregs(c, 1);
+ panic("bad dsa");
+ }
+ dsa->p9status = SDeio;
+ wakeme = 1;
+ }
+ /*else*/ if (dstat & Bf) {
+ IPRINT(PRINTPREFIX "%d/%d: Bus Fault\n", dsa->target, dsa->lun);
+ dumpncrregs(c, 1);
+ dsa->p9status = SDeio;
+ wakeme = 1;
+ }
+ }
+ if (cont == -2)
+ ncrcontinue(c);
+ else if (cont >= 0)
+ start(c, cont);
+ if (wakeme){
+ if(dsa->p9status == SDnostatus)
+ dsa->p9status = SDeio;
+ wakeup(dsa);
+ }
+ iunlock(c);
+ if (DEBUG(1)) {
+ IPRINT(PRINTPREFIX "int end 1\n");
+ }
+}
+
+static int
+done(void *arg)
+{
+ return ((Dsa *)arg)->p9status != SDnostatus;
+}
+
+static void
+setmovedata(Movedata *d, ulong pa, ulong bc)
+{
+ d->pa[0] = pa;
+ d->pa[1] = pa>>8;
+ d->pa[2] = pa>>16;
+ d->pa[3] = pa>>24;
+ d->dbc[0] = bc;
+ d->dbc[1] = bc>>8;
+ d->dbc[2] = bc>>16;
+ d->dbc[3] = bc>>24;
+}
+
+static void
+advancedata(Movedata *d, long v)
+{
+ lesetl(d->pa, legetl(d->pa) + v);
+ lesetl(d->dbc, legetl(d->dbc) - v);
+}
+
+static void
+dumpwritedata(uchar *data, int datalen)
+{
+ int i;
+ uchar *bp;
+ if (!DEBUG(0)){
+ USED(data, datalen);
+ return;
+ }
+
+ if (datalen) {
+ KPRINT(PRINTPREFIX "write:");
+ for (i = 0, bp = data; i < 50 && i < datalen; i++, bp++) {
+ KPRINT("%.2ux", *bp);
+ }
+ if (i < datalen) {
+ KPRINT("...");
+ }
+ KPRINT("\n");
+ }
+}
+
+static void
+dumpreaddata(uchar *data, int datalen)
+{
+ int i;
+ uchar *bp;
+ if (!DEBUG(0)){
+ USED(data, datalen);
+ return;
+ }
+
+ if (datalen) {
+ KPRINT(PRINTPREFIX "read:");
+ for (i = 0, bp = data; i < 50 && i < datalen; i++, bp++) {
+ KPRINT("%.2ux", *bp);
+ }
+ if (i < datalen) {
+ KPRINT("...");
+ }
+ KPRINT("\n");
+ }
+}
+
+static void
+busreset(Controller *c)
+{
+ int x, ntarget;
+
+ /* bus reset */
+ c->n->scntl1 |= (1 << 3);
+ delay(500);
+ c->n->scntl1 &= ~(1 << 3);
+ if(!(c->v->feature & Wide))
+ ntarget = 8;
+ else
+ ntarget = MAXTARGET;
+ for (x = 0; x < ntarget; x++) {
+ setwide(0, c, x, 0);
+#ifndef ASYNC_ONLY
+ c->s[x] = NeitherDone;
+#endif
+ }
+ c->capvalid = 0;
+}
+
+static void
+reset(Controller *c)
+{
+ /* should wakeup all pending tasks */
+ softreset(c);
+ busreset(c);
+}
+
+static int
+sd53c8xxrio(SDreq* r)
+{
+ Dsa *d;
+ uchar *bp;
+ Controller *c;
+ uchar target_expo, my_expo;
+ int bc, check, i, status, target;
+
+ if((target = r->unit->subno) == 0x07)
+ return r->status = SDtimeout; /* assign */
+
+ c = r->unit->dev->ctlr;
+
+ check = 0;
+ d = dsaalloc(c, target, r->lun);
+
+ qlock(&c->q[target]); /* obtain access to target */
+docheck:
+ /* load the transfer control stuff */
+ d->scsi_id_buf[0] = 0;
+ d->scsi_id_buf[1] = c->sxfer[target];
+ d->scsi_id_buf[2] = target;
+ d->scsi_id_buf[3] = c->scntl3[target];
+ synctodsa(d, c);
+
+ bc = 0;
+
+ d->msg_out[bc] = 0x80 | r->lun;
+
+#ifndef NO_DISCONNECT
+ d->msg_out[bc] |= (1 << 6);
+#endif
+ bc++;
+
+ /* work out what to do about negotiation */
+ switch (c->s[target]) {
+ default:
+ KPRINT(PRINTPREFIX "%d: strange nego state %d\n", target, c->s[target]);
+ c->s[target] = NeitherDone;
+ /* fall through */
+ case NeitherDone:
+ if ((c->capvalid & (1 << target)) == 0)
+ break;
+ target_expo = (c->cap[target] >> 5) & 3;
+ my_expo = (c->v->feature & Wide) != 0;
+ if (target_expo < my_expo)
+ my_expo = target_expo;
+#ifdef ALWAYS_DO_WDTR
+ bc += buildwdtrmsg(d->msg_out + bc, my_expo);
+ KPRINT(PRINTPREFIX "%d: WDTN: initiating expo %d\n", target, my_expo);
+ c->s[target] = WideInit;
+ break;
+#else
+ if (my_expo) {
+ bc += buildwdtrmsg(d->msg_out + bc, (c->v->feature & Wide) ? 1 : 0);
+ KPRINT(PRINTPREFIX "%d: WDTN: initiating expo %d\n", target, my_expo);
+ c->s[target] = WideInit;
+ break;
+ }
+ KPRINT(PRINTPREFIX "%d: WDTN: narrow\n", target);
+ /* fall through */
+#endif
+ case WideDone:
+ if (c->cap[target] & (1 << 4)) {
+ KPRINT(PRINTPREFIX "%d: SDTN: initiating %d %d\n", target, c->tpf, c->v->maxsyncoff);
+ bc += buildsdtrmsg(d->msg_out + bc, c->tpf, c->v->maxsyncoff);
+ c->s[target] = SyncInit;
+ break;
+ }
+ KPRINT(PRINTPREFIX "%d: SDTN: async only\n", target);
+ c->s[target] = BothDone;
+ break;
+
+ case BothDone:
+ break;
+ }
+
+ setmovedata(&d->msg_out_buf, DMASEG(d->msg_out), bc);
+ setmovedata(&d->cmd_buf, DMASEG(r->cmd), r->clen);
+ calcblockdma(d, r->data ? DMASEG(r->data) : 0, r->dlen);
+
+ if (DEBUG(0)) {
+ KPRINT(PRINTPREFIX "%d/%d: exec: ", target, r->lun);
+ for (bp = r->cmd; bp < &r->cmd[r->clen]; bp++) {
+ KPRINT("%.2ux", *bp);
+ }
+ KPRINT("\n");
+ if (!r->write) {
+ KPRINT(PRINTPREFIX "%d/%d: exec: limit=(%d)%ld\n",
+ target, r->lun, d->dmablks, legetl(d->data_buf.dbc));
+ }
+ else
+ dumpwritedata(r->data, r->dlen);
+ }
+
+ setmovedata(&d->status_buf, DMASEG(&d->status), 1);
+
+ d->p9status = SDnostatus;
+ d->parityerror = 0;
+ coherence();
+ d->stateb = A_STATE_ISSUE; /* start operation */
+ coherence();
+
+ ilock(c);
+ if (c->ssm)
+ c->n->dcntl |= 0x10; /* single step */
+ if (c->running) {
+ c->n->istat = Sigp;
+ }
+ else {
+ start(c, E_issue_check);
+ }
+ iunlock(c);
+
+ while(waserror())
+ ;
+ tsleep(d, done, d, 600 * 1000);
+ poperror();
+
+ if (!done(d)) {
+ KPRINT(PRINTPREFIX "%d/%d: exec: Timed out\n", target, r->lun);
+ dumpncrregs(c, 0);
+ dsafree(c, d);
+ reset(c);
+ qunlock(&c->q[target]);
+ r->status = SDtimeout;
+ return r->status = SDtimeout; /* assign */
+ }
+
+ if((status = d->p9status) == SDeio)
+ c->s[target] = NeitherDone;
+ if (d->parityerror) {
+ status = SDeio;
+ }
+
+ /*
+ * adjust datalen
+ */
+ r->rlen = r->dlen;
+ if (DEBUG(0)) {
+ KPRINT(PRINTPREFIX "%d/%d: exec: before rlen adjust: dmablks %d flag %d dbc %lud\n",
+ target, r->lun, d->dmablks, d->flag, legetl(d->data_buf.dbc));
+ }
+ r->rlen = r->dlen;
+ if (d->flag != 2) {
+ r->rlen -= d->dmablks * A_BSIZE;
+ r->rlen -= legetl(d->data_buf.dbc);
+ }
+ if(!r->write)
+ dumpreaddata(r->data, r->rlen);
+ if (DEBUG(0)) {
+ KPRINT(PRINTPREFIX "%d/%d: exec: p9status=%d status %d rlen %ld\n",
+ target, r->lun, d->p9status, status, r->rlen);
+ }
+ /*
+ * spot the identify
+ */
+ if ((c->capvalid & (1 << target)) == 0
+ && (status == SDok || status == SDcheck)
+ && r->cmd[0] == 0x12 && r->dlen >= 8) {
+ c->capvalid |= 1 << target;
+ bp = r->data;
+ c->cap[target] = bp[7];
+ KPRINT(PRINTPREFIX "%d: capabilities %.2x\n", target, bp[7]);
+ }
+ if(!check && status == SDcheck && !(r->flags & SDnosense)){
+ check = 1;
+ r->write = 0;
+ memset(r->cmd, 0, sizeof(r->cmd));
+ r->cmd[0] = 0x03;
+ r->cmd[1] = r->lun<<5;
+ r->cmd[4] = sizeof(r->sense)-1;
+ r->clen = 6;
+ r->data = r->sense;
+ r->dlen = sizeof(r->sense)-1;
+ /*
+ * Clear out the microcode state
+ * so the Dsa can be re-used.
+ */
+ lesetl(&d->stateb, A_STATE_ALLOCATED);
+ coherence();
+ goto docheck;
+ }
+ qunlock(&c->q[target]);
+ dsafree(c, d);
+
+ if(status == SDok && check){
+ status = SDcheck;
+ r->flags |= SDvalidsense;
+ }
+ if(DEBUG(0))
+ KPRINT(PRINTPREFIX "%d: r flags %8.8uX status %d rlen %ld\n",
+ target, r->flags, status, r->rlen);
+ if(r->flags & SDvalidsense){
+ if(!DEBUG(0))
+ KPRINT(PRINTPREFIX "%d: r flags %8.8uX status %d rlen %ld\n",
+ target, r->flags, status, r->rlen);
+ for(i = 0; i < r->rlen; i++)
+ KPRINT(" %2.2uX", r->sense[i]);
+ KPRINT("\n");
+ }
+ return r->status = status;
+}
+
+#define vpt ((ulong*)VPT)
+#define VPTX(va) (((ulong)(va))>>12)
+static void
+cribbios(Controller *c)
+{
+ c->bios.scntl3 = c->n->scntl3;
+ c->bios.stest2 = c->n->stest2;
+ print(PRINTPREFIX "bios scntl3(%.2x) stest2(%.2x)\n", c->bios.scntl3, c->bios.stest2);
+}
+
+static int
+bios_set_differential(Controller *c)
+{
+ /* Concept lifted from FreeBSD - thanks Gerard */
+ /* basically, if clock conversion factors are set, then there is
+ * evidence the bios had a go at the chip, and if so, it would
+ * have set the differential enable bit in stest2
+ */
+ return (c->bios.scntl3 & 7) != 0 && (c->bios.stest2 & 0x20) != 0;
+}
+
+#define NCR_VID 0x1000
+#define NCR_810_DID 0x0001
+#define NCR_820_DID 0x0002 /* don't know enough about this one to support it */
+#define NCR_825_DID 0x0003
+#define NCR_815_DID 0x0004
+#define SYM_810AP_DID 0x0005
+#define SYM_860_DID 0x0006
+#define SYM_896_DID 0x000b
+#define SYM_895_DID 0x000c
+#define SYM_885_DID 0x000d /* ditto */
+#define SYM_875_DID 0x000f /* ditto */
+#define SYM_1010_DID 0x0020
+#define SYM_1011_DID 0x0021
+#define SYM_875J_DID 0x008f
+
+static Variant variant[] = {
+{ NCR_810_DID, 0x0f, "NCR53C810", Burst16, 8, 24, 0 },
+{ NCR_810_DID, 0x1f, "SYM53C810ALV", Burst16, 8, 24, Prefetch },
+{ NCR_810_DID, 0xff, "SYM53C810A", Burst16, 8, 24, Prefetch },
+{ SYM_810AP_DID, 0xff, "SYM53C810AP", Burst16, 8, 24, Prefetch },
+{ NCR_815_DID, 0xff, "NCR53C815", Burst16, 8, 24, BurstOpCodeFetch },
+{ NCR_825_DID, 0x0f, "NCR53C825", Burst16, 8, 24, Wide|BurstOpCodeFetch|Differential },
+{ NCR_825_DID, 0xff, "SYM53C825A", Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Differential|Wide },
+{ SYM_860_DID, 0x0f, "SYM53C860", Burst16, 8, 24, Prefetch|Ultra },
+{ SYM_860_DID, 0xff, "SYM53C860LV", Burst16, 8, 24, Prefetch|Ultra },
+{ SYM_875_DID, 0x01, "SYM53C875r1", Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Differential|Wide|Ultra },
+{ SYM_875_DID, 0xff, "SYM53C875", Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Differential|Wide|Ultra|ClockDouble },
+{ SYM_875J_DID, 0xff, "SYM53C875j", Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Differential|Wide|Ultra|ClockDouble },
+{ SYM_885_DID, 0xff, "SYM53C885", Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Wide|Ultra|ClockDouble },
+{ SYM_895_DID, 0xff, "SYM53C895", Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Wide|Ultra|Ultra2 },
+{ SYM_896_DID, 0xff, "SYM53C896", Burst128, 16, 64, Prefetch|LocalRAM|BigFifo|Wide|Ultra|Ultra2 },
+{ SYM_1010_DID, 0xff, "SYM53C1010", Burst128, 16, 64, Prefetch|LocalRAM|BigFifo|Wide|Ultra|Ultra2 },
+{ SYM_1011_DID, 0xff, "SYM53C1010", Burst128, 16, 64, Prefetch|LocalRAM|BigFifo|Wide|Ultra|Ultra2 },
+};
+
+static int
+xfunc(Controller *c, enum na_external x, unsigned long *v)
+{
+ switch (x)
+ {
+ case X_scsi_id_buf:
+ *v = offsetof(Dsa, scsi_id_buf[0]); return 1;
+ case X_msg_out_buf:
+ *v = offsetof(Dsa, msg_out_buf); return 1;
+ case X_cmd_buf:
+ *v = offsetof(Dsa, cmd_buf); return 1;
+ case X_data_buf:
+ *v = offsetof(Dsa, data_buf); return 1;
+ case X_status_buf:
+ *v = offsetof(Dsa, status_buf); return 1;
+ case X_dsa_head:
+ *v = DMASEG(&c->dsalist.head[0]); return 1;
+ case X_ssid_mask:
+ *v = SSIDMASK(c); return 1;
+ default:
+ print("xfunc: can't find external %d\n", x);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+na_fixup(Controller *c, ulong pa_reg,
+ struct na_patch *patch, int patches,
+ int (*externval)(Controller*, int, ulong*))
+{
+ int p;
+ int v;
+ ulong *script, pa_script;
+ unsigned long lw, lv;
+
+ script = c->script;
+ pa_script = c->scriptpa;
+ for (p = 0; p < patches; p++) {
+ switch (patch[p].type) {
+ case 1:
+ /* script relative */
+ script[patch[p].lwoff] += pa_script;
+ break;
+ case 2:
+ /* register i/o relative */
+ script[patch[p].lwoff] += pa_reg;
+ break;
+ case 3:
+ /* data external */
+ lw = script[patch[p].lwoff];
+ v = (lw >> 8) & 0xff;
+ if (!(*externval)(c, v, &lv))
+ return 0;
+ v = lv & 0xff;
+ script[patch[p].lwoff] = (lw & 0xffff00ffL) | (v << 8);
+ break;
+ case 4:
+ /* 32 bit external */
+ lw = script[patch[p].lwoff];
+ if (!(*externval)(c, lw, &lv))
+ return 0;
+ script[patch[p].lwoff] = lv;
+ break;
+ case 5:
+ /* 24 bit external */
+ lw = script[patch[p].lwoff];
+ if (!(*externval)(c, lw & 0xffffff, &lv))
+ return 0;
+ script[patch[p].lwoff] = (lw & 0xff000000L) | (lv & 0xffffffL);
+ break;
+ }
+ }
+ return 1;
+}
+
+static SDev*
+sd53c8xxpnp(void)
+{
+ char *cp;
+ Pcidev *p;
+ Variant *v;
+ int ba, nctlr;
+ void *scriptma;
+ Controller *ctlr;
+ SDev *sdev, *head, *tail;
+ ulong regpa, *script, scriptpa;
+ void *regva, *scriptva;
+
+ if(cp = getconf("*maxsd53c8xx"))
+ nctlr = strtoul(cp, 0, 0);
+ else
+ nctlr = 32;
+
+ p = nil;
+ head = tail = nil;
+ while((p = pcimatch(p, NCR_VID, 0)) != nil && nctlr > 0){
+ for(v = variant; v < &variant[nelem(variant)]; v++){
+ if(p->did == v->did && p->rid <= v->maxrid)
+ break;
+ }
+ if(v >= &variant[nelem(variant)]) {
+ print("no match\n");
+ continue;
+ }
+ print(PRINTPREFIX "%s rev. 0x%2.2x intr=%d command=%4.4uX\n",
+ v->name, p->rid, p->intl, p->pcr);
+
+ regpa = p->mem[1].bar;
+ ba = 2;
+ if(regpa & 0x04){
+ if(p->mem[2].bar)
+ continue;
+ ba++;
+ }
+ if(regpa == 0)
+ print("regpa 0\n");
+ regpa &= ~0xF;
+ regva = vmap(regpa, p->mem[1].size);
+ if(regva == 0)
+ continue;
+
+ script = nil;
+ scriptpa = 0;
+ scriptva = nil;
+ scriptma = nil;
+ if((v->feature & LocalRAM) && sizeof(na_script) <= 4096){
+ scriptpa = p->mem[ba].bar;
+ if((scriptpa & 0x04) && p->mem[ba+1].bar){
+ vunmap(regva, p->mem[1].size);
+ continue;
+ }
+ scriptpa &= ~0x0F;
+ scriptva = vmap(scriptpa, p->mem[ba].size);
+ if(scriptva)
+ script = scriptva;
+ }
+ if(scriptpa == 0){
+ /*
+ * Either the map failed, or this chip does not have
+ * local RAM. It will need a copy of the microcode.
+ */
+ scriptma = malloc(sizeof(na_script));
+ if(scriptma == nil){
+ vunmap(regva, p->mem[1].size);
+ continue;
+ }
+ scriptpa = DMASEG(scriptma);
+ script = scriptma;
+ }
+
+ ctlr = malloc(sizeof(Controller));
+ sdev = malloc(sizeof(SDev));
+ if(ctlr == nil || sdev == nil){
+buggery:
+ if(ctlr)
+ free(ctlr);
+ if(sdev)
+ free(sdev);
+ if(scriptma)
+ free(scriptma);
+ else if(scriptva)
+ vunmap(scriptva, p->mem[ba].size);
+ if(regva)
+ vunmap(regva, p->mem[1].size);
+ continue;
+ }
+
+ if(dsaend == nil)
+ dsaend = xalloc(sizeof *dsaend);
+ lesetl(&dsaend->stateb, A_STATE_END);
+ // lesetl(dsaend->next, DMASEG(dsaend));
+ coherence();
+ lesetl(ctlr->dsalist.head, DMASEG(dsaend));
+ coherence();
+ ctlr->dsalist.freechain = 0;
+
+ ctlr->n = regva;
+ ctlr->v = v;
+ ctlr->script = script;
+ memmove(ctlr->script, na_script, sizeof(na_script));
+
+ /*
+ * Because we don't yet have an abstraction for the
+ * addresses as seen from the controller side (and on
+ * the 386 it doesn't matter), the following three lines
+ * are different between the 386 and alpha copies of
+ * this driver.
+ */
+ USED(scriptpa);
+ ctlr->scriptpa = p->mem[ba].bar & ~0x0F;
+ if(!na_fixup(ctlr, p->mem[1].bar & ~0x0F, na_patches, NA_PATCHES, xfunc)){
+ print("script fixup failed\n");
+ goto buggery;
+ }
+ swabl(ctlr->script, ctlr->script, sizeof(na_script));
+
+ ctlr->pcidev = p;
+
+ sdev->ifc = &sd53c8xxifc;
+ sdev->ctlr = ctlr;
+ sdev->idno = '0';
+ if(!(v->feature & Wide))
+ sdev->nunit = 8;
+ else
+ sdev->nunit = MAXTARGET;
+ ctlr->sdev = sdev;
+
+ if(head != nil)
+ tail->next = sdev;
+ else
+ head = sdev;
+ tail = sdev;
+
+ nctlr--;
+ }
+
+ return head;
+}
+
+static int
+sd53c8xxenable(SDev* sdev)
+{
+ Pcidev *pcidev;
+ Controller *ctlr;
+ char name[32];
+
+ ctlr = sdev->ctlr;
+ pcidev = ctlr->pcidev;
+
+ pcisetbme(pcidev);
+
+ ilock(ctlr);
+ synctabinit(ctlr);
+ cribbios(ctlr);
+ reset(ctlr);
+ snprint(name, sizeof(name), "%s (%s)", sdev->name, sdev->ifc->name);
+ intrenable(pcidev->intl, sd53c8xxinterrupt, ctlr, pcidev->tbdf, name);
+ iunlock(ctlr);
+
+ return 1;
+}
+
+SDifc sd53c8xxifc = {
+ "53c8xx", /* name */
+
+ sd53c8xxpnp, /* pnp */
+ nil, /* legacy */
+ sd53c8xxenable, /* enable */
+ nil, /* disable */
+
+ scsiverify, /* verify */
+ scsionline, /* online */
+ sd53c8xxrio, /* rio */
+ nil, /* rctl */
+ nil, /* wctl */
+
+ scsibio, /* bio */
+ nil, /* probe */
+ nil, /* clear */
+ nil, /* stat */
+};
diff --git a/sys/src/9/alphapc/sd53c8xx.i b/sys/src/9/alphapc/sd53c8xx.i
new file mode 100755
index 000000000..ca562394d
--- /dev/null
+++ b/sys/src/9/alphapc/sd53c8xx.i
@@ -0,0 +1,805 @@
+unsigned long na_script[] = {
+ /* extern scsi_id_buf */
+ /* extern msg_out_buf */
+ /* extern cmd_buf */
+ /* extern data_buf */
+ /* extern status_buf */
+ /* extern msgin_buf */
+ /* extern dsa_0 */
+ /* extern dsa_1 */
+ /* extern dsa_head */
+ /* extern ssid_mask */
+ /* SIR_MSG_IO_COMPLETE = 0 */
+ /* error_not_cmd_complete = 1 */
+ /* error_disconnected = 2 */
+ /* error_reselected = 3 */
+ /* error_unexpected_phase = 4 */
+ /* error_weird_message = 5 */
+ /* SIR_ERROR_NOT_MSG_IN_AFTER_RESELECT = 6 */
+ /* error_not_identify_after_reselect = 7 */
+ /* error_too_much_data = 8 */
+ /* error_too_little_data = 9 */
+ /* SIR_MSG_REJECT = 10 */
+ /* SIR_MSG_SDTR = 11 */
+ /* SIR_EV_RESPONSE_OK = 12 */
+ /* error_sigp_set = 13 */
+ /* SIR_EV_PHASE_SWITCH_AFTER_ID = 14 */
+ /* SIR_MSG_WDTR = 15 */
+ /* SIR_MSG_IGNORE_WIDE_RESIDUE = 16 */
+ /* SIR_NOTIFY_DISC = 100 */
+ /* SIR_NOTIFY_RESELECT = 101 */
+ /* SIR_NOTIFY_MSG_IN = 102 */
+ /* SIR_NOTIFY_STATUS = 103 */
+ /* SIR_NOTIFY_DUMP = 104 */
+ /* SIR_NOTIFY_DUMP2 = 105 */
+ /* SIR_NOTIFY_SIGP = 106 */
+ /* SIR_NOTIFY_ISSUE = 107 */
+ /* SIR_NOTIFY_WAIT_RESELECT = 108 */
+ /* SIR_NOTIFY_ISSUE_CHECK = 109 */
+ /* SIR_NOTIFY_DUMP_NEXT_CODE = 110 */
+ /* SIR_NOTIFY_COMMAND = 111 */
+ /* SIR_NOTIFY_DATA_IN = 112 */
+ /* SIR_NOTIFY_DATA_OUT = 113 */
+ /* SIR_NOTIFY_BLOCK_DATA_IN = 114 */
+ /* SIR_NOTIFY_WSR = 115 */
+ /* SIR_NOTIFY_LOAD_SYNC = 116 */
+ /* SIR_NOTIFY_RESELECTED_ON_SELECT = 117 */
+ /* SIR_NOTIFY_LOAD_STATE = 118 */
+ /* STATE_FREE = 0 */
+ /* STATE_ALLOCATED = 1 */
+ /* STATE_ISSUE = 2 */
+ /* STATE_DISCONNECTED = 3 */
+ /* STATE_DONE = 4 */
+ /* STATE_END = 5 */
+ /* RESULT_OK = 0 */
+ /* MSG_IDENTIFY = 0x80 */
+ /* MSG_DISCONNECT = 0x04 */
+ /* MSG_SAVE_DATA_POINTER = 0x02 */
+ /* MSG_RESTORE_POINTERS = 0x03 */
+ /* MSG_IGNORE_WIDE_RESIDUE = 0x23 */
+ /* X_MSG = 0x01 */
+ /* X_MSG_SDTR = 0x01 */
+ /* X_MSG_WDTR = 0x03 */
+ /* MSG_REJECT = 0x07 */
+ /* BSIZE = 512 */
+/* 0000 */ 0x80880000L, /* jump wait_for_reselection */
+/* 0004 */ 0x00000514L,
+/* 0008 */ 0x88880000L, /* call load_sync */
+/* 000c */ 0x00000790L,
+/* 0010 */ 0x60000200L, /* clear target */
+/* 0014 */ 0x00000000L,
+/* 0018 */ 0x47000000L, /* select atn from scsi_id_buf, reselected_on_select */
+/* 001c */ 0x000004ecL,
+/* 0020 */ 0x878b0000L, /* jump start1, when msg_in */
+/* 0024 */ 0x00000000L,
+/* 0028 */ 0x1e000000L, /* move from msg_out_buf, when msg_out */
+/* 002c */ 0x00000001L,
+/* 0030 */ 0x868b0000L, /* jump start1, when msg_out */
+/* 0034 */ 0x00fffff0L,
+/* 0038 */ 0x82830000L, /* jump to_decisions, when not cmd */
+/* 003c */ 0x000005b8L,
+/* 0040 */ 0x60000008L, /* clear atn */
+/* 0044 */ 0x00000000L,
+/* 0048 */ 0x1a000000L, /* move from cmd_buf, when cmd */
+/* 004c */ 0x00000002L,
+/* 0050 */ 0x81830000L, /* jump to_decisions, when not data_in */
+/* 0054 */ 0x000005a0L,
+/* 0058 */ 0xc0000004L, /* move memory 4, state, scratcha */
+/* 005c */ 0x00000640L,
+/* 0060 */ 0x00000034L,
+/* 0064 */ 0xc0000004L, /* move memory 4, dmaaddr, scratchb */
+/* 0068 */ 0x00000644L,
+/* 006c */ 0x0000005cL,
+/* 0070 */ 0x72360000L, /* move scratcha2 to sfbr */
+/* 0074 */ 0x00000000L,
+/* 0078 */ 0x808c0000L, /* jump data_in_normal, if 0 */
+/* 007c */ 0x00000078L,
+/* 0080 */ 0x29000200L, /* move BSIZE, ptr dmaaddr, when data_in */
+/* 0084 */ 0x00000644L,
+/* 0088 */ 0x7e5d0200L, /* move scratchb1 + BSIZE / 256 to scratchb1 */
+/* 008c */ 0x00000000L,
+/* 0090 */ 0x7f5e0000L, /* move scratchb2 + 0 to scratchb2 with carry */
+/* 0094 */ 0x00000000L,
+/* 0098 */ 0x7f5f0000L, /* move scratchb3 + 0 to scratchb3 with carry */
+/* 009c */ 0x00000000L,
+/* 00a0 */ 0x7e36ff00L, /* move scratcha2 + 255 to scratcha2 */
+/* 00a4 */ 0x00000000L,
+/* 00a8 */ 0xc0000004L, /* move memory 4, scratchb, dmaaddr */
+/* 00ac */ 0x0000005cL,
+/* 00b0 */ 0x00000644L,
+/* 00b4 */ 0x818b0000L, /* jump data_in_block_loop, when data_in */
+/* 00b8 */ 0x00ffffb4L,
+/* 00bc */ 0xc0000004L, /* move memory 4, scratcha, state */
+/* 00c0 */ 0x00000034L,
+/* 00c4 */ 0x00000640L,
+/* 00c8 */ 0x88880000L, /* call save_state */
+/* 00cc */ 0x0000065cL,
+/* 00d0 */ 0x80880000L, /* jump to_decisions */
+/* 00d4 */ 0x00000520L,
+/* 00d8 */ 0xc0000004L, /* move memory 4, scratchb, dmaaddr */
+/* 00dc */ 0x0000005cL,
+/* 00e0 */ 0x00000644L,
+/* 00e4 */ 0xc0000004L, /* move memory 4, scratcha, state */
+/* 00e8 */ 0x00000034L,
+/* 00ec */ 0x00000640L,
+/* 00f0 */ 0x80880000L, /* jump to_decisions */
+/* 00f4 */ 0x00000500L,
+/* 00f8 */ 0x72370000L, /* move scratcha3 to sfbr */
+/* 00fc */ 0x00000000L,
+/* 0100 */ 0x98040000L, /* int error_too_much_data, if not 0 */
+/* 0104 */ 0x00000008L,
+/* 0108 */ 0x19000000L, /* move from data_buf, when data_in */
+/* 010c */ 0x00000003L,
+/* 0110 */ 0x78370200L, /* move 2 to scratcha3 */
+/* 0114 */ 0x00000000L,
+/* 0118 */ 0xc0000004L, /* move memory 4, scratcha, state */
+/* 011c */ 0x00000034L,
+/* 0120 */ 0x00000640L,
+/* 0124 */ 0x88880000L, /* call save_state */
+/* 0128 */ 0x00000600L,
+/* 012c */ 0x80880000L, /* jump post_data_to_decisions */
+/* 0130 */ 0x000004f4L,
+/* 0134 */ 0xc0000004L, /* move memory 4, state, scratcha */
+/* 0138 */ 0x00000640L,
+/* 013c */ 0x00000034L,
+/* 0140 */ 0xc0000004L, /* move memory 4, dmaaddr, scratchb */
+/* 0144 */ 0x00000644L,
+/* 0148 */ 0x0000005cL,
+/* 014c */ 0x72360000L, /* move scratcha2 to sfbr */
+/* 0150 */ 0x00000000L,
+/* 0154 */ 0x808c0000L, /* jump data_out_normal, if 0 */
+/* 0158 */ 0x0000005cL,
+/* 015c */ 0xc0000004L, /* move memory 4, dmaaddr, scratchb */
+/* 0160 */ 0x00000644L,
+/* 0164 */ 0x0000005cL,
+/* 0168 */ 0x28000200L, /* move BSIZE, ptr dmaaddr, when data_out */
+/* 016c */ 0x00000644L,
+/* 0170 */ 0x7e5d0200L, /* move scratchb1 + BSIZE / 256 to scratchb1 */
+/* 0174 */ 0x00000000L,
+/* 0178 */ 0x7f5e0000L, /* move scratchb2 + 0 to scratchb2 with carry */
+/* 017c */ 0x00000000L,
+/* 0180 */ 0x7f5f0000L, /* move scratchb3 + 0 to scratchb3 with carry */
+/* 0184 */ 0x00000000L,
+/* 0188 */ 0x7e36ff00L, /* move scratcha2 + 255 to scratcha2 */
+/* 018c */ 0x00000000L,
+/* 0190 */ 0xc0000004L, /* move memory 4, scratchb, dmaaddr */
+/* 0194 */ 0x0000005cL,
+/* 0198 */ 0x00000644L,
+/* 019c */ 0x808b0000L, /* jump data_out_block_loop, when data_out */
+/* 01a0 */ 0x00ffffa8L,
+/* 01a4 */ 0xc0000004L, /* move memory 4, scratcha, state */
+/* 01a8 */ 0x00000034L,
+/* 01ac */ 0x00000640L,
+/* 01b0 */ 0x80880000L, /* jump to_decisions */
+/* 01b4 */ 0x00000440L,
+/* 01b8 */ 0x72370000L, /* move scratcha3 to sfbr */
+/* 01bc */ 0x00000000L,
+/* 01c0 */ 0x98040000L, /* int error_too_little_data, if not 0 */
+/* 01c4 */ 0x00000009L,
+/* 01c8 */ 0x18000000L, /* move from data_buf, when data_out */
+/* 01cc */ 0x00000003L,
+/* 01d0 */ 0x78370200L, /* move 2 to scratcha3 */
+/* 01d4 */ 0x00000000L,
+/* 01d8 */ 0xc0000004L, /* move memory 4, scratcha, state */
+/* 01dc */ 0x00000034L,
+/* 01e0 */ 0x00000640L,
+/* 01e4 */ 0x88880000L, /* call save_state */
+/* 01e8 */ 0x00000540L,
+/* 01ec */ 0x80880000L, /* jump post_data_to_decisions */
+/* 01f0 */ 0x00000434L,
+/* 01f4 */ 0x1b000000L, /* move from status_buf, when status */
+/* 01f8 */ 0x00000004L,
+/* 01fc */ 0x9f030000L, /* int error_unexpected_phase, when not msg_in */
+/* 0200 */ 0x00000004L,
+/* 0204 */ 0x0f000001L, /* move 1, scratcha, when msg_in */
+/* 0208 */ 0x00000034L,
+/* 020c */ 0x808c0007L, /* jump rejected, if MSG_REJECT */
+/* 0210 */ 0x00000088L,
+/* 0214 */ 0x808c0004L, /* jump disconnected, if MSG_DISCONNECT */
+/* 0218 */ 0x00000298L,
+/* 021c */ 0x808c0002L, /* jump msg_in_skip, if MSG_SAVE_DATA_POINTER */
+/* 0220 */ 0x00000090L,
+/* 0224 */ 0x808c0003L, /* jump msg_in_skip, if MSG_RESTORE_POINTERS */
+/* 0228 */ 0x00000088L,
+/* 022c */ 0x808c0023L, /* jump ignore_wide, if MSG_IGNORE_WIDE_RESIDUE */
+/* 0230 */ 0x000001f0L,
+/* 0234 */ 0x808c0001L, /* jump extended, if X_MSG */
+/* 0238 */ 0x00000088L,
+/* 023c */ 0x98040000L, /* int error_not_cmd_complete, if not 0 */
+/* 0240 */ 0x00000001L,
+/* 0244 */ 0x7c027e00L, /* move scntl2&0x7e to scntl2 */
+/* 0248 */ 0x00000000L,
+/* 024c */ 0x60000040L, /* clear ack */
+/* 0250 */ 0x00000000L,
+/* 0254 */ 0x48000000L, /* wait disconnect */
+/* 0258 */ 0x00000000L,
+/* 025c */ 0xc0000004L, /* move memory 4, state, scratcha */
+/* 0260 */ 0x00000640L,
+/* 0264 */ 0x00000034L,
+/* 0268 */ 0x78340400L, /* move STATE_DONE to scratcha0 */
+/* 026c */ 0x00000000L,
+/* 0270 */ 0x78350000L, /* move RESULT_OK to scratcha1 */
+/* 0274 */ 0x00000000L,
+/* 0278 */ 0xc0000004L, /* move memory 4, scratcha, state */
+/* 027c */ 0x00000034L,
+/* 0280 */ 0x00000640L,
+/* 0284 */ 0x88880000L, /* call save_state */
+/* 0288 */ 0x000004a0L,
+/* 028c */ 0x98180000L, /* intfly 0 */
+/* 0290 */ 0x00000000L,
+/* 0294 */ 0x80880000L, /* jump issue_check */
+/* 0298 */ 0x000004b8L,
+/* 029c */ 0x98080000L, /* int SIR_MSG_REJECT */
+/* 02a0 */ 0x0000000aL,
+/* 02a4 */ 0x60000040L, /* clear ack */
+/* 02a8 */ 0x00000000L,
+/* 02ac */ 0x80880000L, /* jump to_decisions */
+/* 02b0 */ 0x00000344L,
+/* 02b4 */ 0x60000040L, /* clear ack */
+/* 02b8 */ 0x00000000L,
+/* 02bc */ 0x80880000L, /* jump to_decisions */
+/* 02c0 */ 0x00000334L,
+/* 02c4 */ 0x60000040L, /* clear ack */
+/* 02c8 */ 0x00000000L,
+/* 02cc */ 0x9f030000L, /* int error_unexpected_phase, when not msg_in */
+/* 02d0 */ 0x00000004L,
+/* 02d4 */ 0x0f000001L, /* move 1, scratcha1, when msg_in */
+/* 02d8 */ 0x00000035L,
+/* 02dc */ 0x808c0003L, /* jump ext_3, if 3 */
+/* 02e0 */ 0x00000030L,
+/* 02e4 */ 0x808c0002L, /* jump ext_2, if 2 */
+/* 02e8 */ 0x00000098L,
+/* 02ec */ 0x98040001L, /* int error_weird_message, if not 1 */
+/* 02f0 */ 0x00000005L,
+/* 02f4 */ 0x60000040L, /* clear ack */
+/* 02f8 */ 0x00000000L,
+/* 02fc */ 0x9f030000L, /* int error_unexpected_phase, when not msg_in */
+/* 0300 */ 0x00000004L,
+/* 0304 */ 0x0f000001L, /* move 1, scratcha1, when msg_in */
+/* 0308 */ 0x00000035L,
+/* 030c */ 0x80880000L, /* jump ext_done */
+/* 0310 */ 0x000000c8L,
+/* 0314 */ 0x60000040L, /* ext_3: clear ack */
+/* 0318 */ 0x00000000L,
+/* 031c */ 0x9f030000L, /* int error_unexpected_phase, when not msg_in */
+/* 0320 */ 0x00000004L,
+/* 0324 */ 0x0f000001L, /* move 1, scratcha1, when msg_in */
+/* 0328 */ 0x00000035L,
+/* 032c */ 0x60000040L, /* clear ack */
+/* 0330 */ 0x00000000L,
+/* 0334 */ 0x9f030000L, /* int error_unexpected_phase, when not msg_in */
+/* 0338 */ 0x00000004L,
+/* 033c */ 0x0f000001L, /* move 1, scratcha2, when msg_in */
+/* 0340 */ 0x00000036L,
+/* 0344 */ 0x60000040L, /* clear ack */
+/* 0348 */ 0x00000000L,
+/* 034c */ 0x9f030000L, /* int error_unexpected_phase, when not msg_in */
+/* 0350 */ 0x00000004L,
+/* 0354 */ 0x0f000001L, /* move 1, scratcha3, when msg_in */
+/* 0358 */ 0x00000037L,
+/* 035c */ 0x72350000L, /* move scratcha1 to sfbr */
+/* 0360 */ 0x00000000L,
+/* 0364 */ 0x80840001L, /* jump ext_done, if not X_MSG_SDTR */
+/* 0368 */ 0x00000070L,
+/* 036c */ 0x98080000L, /* sdtr: int SIR_MSG_SDTR */
+/* 0370 */ 0x0000000bL,
+/* 0374 */ 0x60000040L, /* clear ack */
+/* 0378 */ 0x00000000L,
+/* 037c */ 0x80880000L, /* jump to_decisions */
+/* 0380 */ 0x00000274L,
+/* 0384 */ 0x60000040L, /* ext_2: clear ack */
+/* 0388 */ 0x00000000L,
+/* 038c */ 0x9f030000L, /* int error_unexpected_phase, when not msg_in */
+/* 0390 */ 0x00000004L,
+/* 0394 */ 0x0f000001L, /* move 1, scratcha1, when msg_in */
+/* 0398 */ 0x00000035L,
+/* 039c */ 0x60000040L, /* clear ack */
+/* 03a0 */ 0x00000000L,
+/* 03a4 */ 0x9f030000L, /* int error_unexpected_phase, when not msg_in */
+/* 03a8 */ 0x00000004L,
+/* 03ac */ 0x0f000001L, /* move 1, scratcha2, when msg_in */
+/* 03b0 */ 0x00000036L,
+/* 03b4 */ 0x72350000L, /* move scratcha1 to sfbr */
+/* 03b8 */ 0x00000000L,
+/* 03bc */ 0x80840003L, /* jump ext_done, if not X_MSG_WDTR */
+/* 03c0 */ 0x00000018L,
+/* 03c4 */ 0x98080000L, /* wdtr: int SIR_MSG_WDTR */
+/* 03c8 */ 0x0000000fL,
+/* 03cc */ 0x60000040L, /* clear ack */
+/* 03d0 */ 0x00000000L,
+/* 03d4 */ 0x80880000L, /* jump to_decisions */
+/* 03d8 */ 0x0000021cL,
+/* 03dc */ 0x58000008L, /* set atn */
+/* 03e0 */ 0x00000000L,
+/* 03e4 */ 0x60000040L, /* clear ack */
+/* 03e8 */ 0x00000000L,
+/* 03ec */ 0x78340700L, /* move MSG_REJECT to scratcha */
+/* 03f0 */ 0x00000000L,
+/* 03f4 */ 0x9e030000L, /* int error_unexpected_phase, when not msg_out */
+/* 03f8 */ 0x00000004L,
+/* 03fc */ 0x60000008L, /* clear atn */
+/* 0400 */ 0x00000000L,
+/* 0404 */ 0x0e000001L, /* move 1, scratcha, when msg_out */
+/* 0408 */ 0x00000034L,
+/* 040c */ 0x60000040L, /* clear ack */
+/* 0410 */ 0x00000000L,
+/* 0414 */ 0x868b0000L, /* jump reject, when msg_out */
+/* 0418 */ 0x00ffffc0L,
+/* 041c */ 0x80880000L, /* jump to_decisions */
+/* 0420 */ 0x000001d4L,
+/* 0424 */ 0x60000040L, /* clear ack */
+/* 0428 */ 0x00000000L,
+/* 042c */ 0x9f030000L, /* int error_unexpected_phase, when not msg_in */
+/* 0430 */ 0x00000004L,
+/* 0434 */ 0x0f000001L, /* move 1, scratcha1, when msg_in */
+/* 0438 */ 0x00000035L,
+/* 043c */ 0x98080000L, /* int SIR_MSG_IGNORE_WIDE_RESIDUE */
+/* 0440 */ 0x00000010L,
+/* 0444 */ 0x60000040L, /* clear ack */
+/* 0448 */ 0x00000000L,
+/* 044c */ 0x80880000L, /* jump to_decisions */
+/* 0450 */ 0x000001a4L,
+/* 0454 */ 0x58000008L, /* set atn */
+/* 0458 */ 0x00000000L,
+/* 045c */ 0x60000040L, /* clear ack */
+/* 0460 */ 0x00000000L,
+/* 0464 */ 0x9e030000L, /* int error_unexpected_phase, when not msg_out */
+/* 0468 */ 0x00000004L,
+/* 046c */ 0x1e000000L, /* move from msg_out_buf, when msg_out */
+/* 0470 */ 0x00000001L,
+/* 0474 */ 0x868b0000L, /* jump response_repeat, when msg_out */
+/* 0478 */ 0x00fffff0L,
+/* 047c */ 0x878b0000L, /* jump response_msg_in, when msg_in */
+/* 0480 */ 0x00000010L,
+/* 0484 */ 0x98080000L, /* int SIR_EV_RESPONSE_OK */
+/* 0488 */ 0x0000000cL,
+/* 048c */ 0x80880000L, /* jump to_decisions */
+/* 0490 */ 0x00000164L,
+/* 0494 */ 0x0f000001L, /* move 1, scratcha, when msg_in */
+/* 0498 */ 0x00000034L,
+/* 049c */ 0x808c0007L, /* jump rejected, if MSG_REJECT */
+/* 04a0 */ 0x00fffdf8L,
+/* 04a4 */ 0x98080000L, /* int SIR_EV_RESPONSE_OK */
+/* 04a8 */ 0x0000000cL,
+/* 04ac */ 0x80880000L, /* jump msg_in_not_reject */
+/* 04b0 */ 0x00fffd60L,
+/* 04b4 */ 0x7c027e00L, /* move scntl2&0x7e to scntl2 */
+/* 04b8 */ 0x00000000L,
+/* 04bc */ 0x60000040L, /* clear ack */
+/* 04c0 */ 0x00000000L,
+/* 04c4 */ 0x48000000L, /* wait disconnect */
+/* 04c8 */ 0x00000000L,
+/* 04cc */ 0xc0000004L, /* move memory 4, state, scratcha */
+/* 04d0 */ 0x00000640L,
+/* 04d4 */ 0x00000034L,
+/* 04d8 */ 0x78340300L, /* move STATE_DISCONNECTED to scratcha0 */
+/* 04dc */ 0x00000000L,
+/* 04e0 */ 0xc0000004L, /* move memory 4, scratcha, state */
+/* 04e4 */ 0x00000034L,
+/* 04e8 */ 0x00000640L,
+/* 04ec */ 0x88880000L, /* call save_state */
+/* 04f0 */ 0x00000238L,
+/* 04f4 */ 0x74020100L, /* move scntl2&0x01 to sfbr */
+/* 04f8 */ 0x00000000L,
+/* 04fc */ 0x98040000L, /* int SIR_NOTIFY_WSR, if not 0 */
+/* 0500 */ 0x00000073L,
+/* 0504 */ 0x80880000L, /* jump issue_check */
+/* 0508 */ 0x00000248L,
+/* 050c */ 0x98080000L, /* int SIR_NOTIFY_RESELECTED_ON_SELECT */
+/* 0510 */ 0x00000075L,
+/* 0514 */ 0x80880000L, /* jump reselected */
+/* 0518 */ 0x00000008L,
+/* 051c */ 0x54000000L, /* wait reselect sigp_set */
+/* 0520 */ 0x00000228L,
+/* 0524 */ 0x60000200L, /* clear target */
+/* 0528 */ 0x00000000L,
+/* 052c */ 0x9f030000L, /* int SIR_ERROR_NOT_MSG_IN_AFTER_RESELECT, when not msg_in */
+/* 0530 */ 0x00000006L,
+/* 0534 */ 0x0f000001L, /* move 1, scratchb, when msg_in */
+/* 0538 */ 0x0000005cL,
+/* 053c */ 0x98041f80L, /* int error_not_identify_after_reselect, if not MSG_IDENTIFY and mask 0x1f */
+/* 0540 */ 0x00000007L,
+/* 0544 */ 0xc0000004L, /* move memory 4, dsa_head, dsa */
+/* 0548 */ 0x00000008L,
+/* 054c */ 0x00000010L,
+/* 0550 */ 0x88880000L, /* call load_state */
+/* 0554 */ 0x00000100L,
+/* 0558 */ 0xc0000004L, /* move memory 4, state, scratcha */
+/* 055c */ 0x00000640L,
+/* 0560 */ 0x00000034L,
+/* 0564 */ 0x72340000L, /* move scratcha0 to sfbr */
+/* 0568 */ 0x00000000L,
+/* 056c */ 0x80840003L, /* jump find_dsa_next, if not STATE_DISCONNECTED */
+/* 0570 */ 0x00000040L,
+/* 0574 */ 0x980c0005L, /* int error_reselected, if STATE_END */
+/* 0578 */ 0x00000003L,
+/* 057c */ 0x740a0900L, /* move ssid & ssid_mask to sfbr */
+/* 0580 */ 0x00000000L,
+/* 0584 */ 0xc0000001L, /* move memory 1, targ, find_dsa_smc1 */
+/* 0588 */ 0x00000648L,
+/* 058c */ 0x00000590L,
+/* 0590 */ 0x808400ffL, /* jump find_dsa_next, if not 255 */
+/* 0594 */ 0x0000001cL,
+/* 0598 */ 0xc0000001L, /* move memory 1, lun, find_dsa_smc2 */
+/* 059c */ 0x0000064cL,
+/* 05a0 */ 0x000005acL,
+/* 05a4 */ 0x725c0000L, /* move scratchb0 to sfbr */
+/* 05a8 */ 0x00000000L,
+/* 05ac */ 0x808cf8ffL, /* jump reload_sync, if 255 and mask ~7 */
+/* 05b0 */ 0x00000034L,
+/* 05b4 */ 0xc0000004L, /* move memory 4, next, dsa */
+/* 05b8 */ 0x00000654L,
+/* 05bc */ 0x00000010L,
+/* 05c0 */ 0x80880000L, /* jump find_dsa_loop */
+/* 05c4 */ 0x00ffff88L,
+/* 05c8 */ 0x60000008L, /* clear atn */
+/* 05cc */ 0x00000000L,
+/* 05d0 */ 0x878b0000L, /* jump msg_in_phase, when msg_in */
+/* 05d4 */ 0x00fffc2cL,
+/* 05d8 */ 0x98080000L, /* int SIR_MSG_REJECT */
+/* 05dc */ 0x0000000aL,
+/* 05e0 */ 0x80880000L, /* jump to_decisions */
+/* 05e4 */ 0x00000010L,
+/* 05e8 */ 0x88880000L, /* call load_sync */
+/* 05ec */ 0x000001b0L,
+/* 05f0 */ 0x60000040L, /* clear ack */
+/* 05f4 */ 0x00000000L,
+/* 05f8 */ 0x818b0000L, /* jump data_in_phase, when data_in */
+/* 05fc */ 0x00fffa58L,
+/* 0600 */ 0x828a0000L, /* jump cmd_phase, if cmd */
+/* 0604 */ 0x00fffa38L,
+/* 0608 */ 0x808a0000L, /* jump data_out_phase, if data_out */
+/* 060c */ 0x00fffb24L,
+/* 0610 */ 0x838a0000L, /* jump status_phase, if status */
+/* 0614 */ 0x00fffbdcL,
+/* 0618 */ 0x878a0000L, /* jump msg_in_phase, if msg_in */
+/* 061c */ 0x00fffbe4L,
+/* 0620 */ 0x98080000L, /* int error_unexpected_phase */
+/* 0624 */ 0x00000004L,
+/* 0628 */ 0x838b0000L, /* jump status_phase, when status */
+/* 062c */ 0x00fffbc4L,
+/* 0630 */ 0x878a0000L, /* jump msg_in_phase, if msg_in */
+/* 0634 */ 0x00fffbccL,
+/* 0638 */ 0x98080000L, /* int error_unexpected_phase */
+/* 063c */ 0x00000004L,
+/* 0640 */ 0x00000000L, /* state: defw 0 */
+/* 0644 */ 0x00000000L, /* dmaaddr: defw 0 */
+/* 0648 */ 0x00000000L, /* targ: defw 0 */
+/* 064c */ 0x00000000L, /* lun: defw 0 */
+/* 0650 */ 0x00000000L, /* sync: defw 0 */
+/* 0654 */ 0x00000000L, /* next: defw 0 */
+ /* dsa_load_len = dsa_load_end - dsa_copy */
+ /* dsa_save_len = dsa_save_end - dsa_copy */
+/* 0658 */ 0x80880000L, /* jump load_state_okay */
+/* 065c */ 0x000000acL,
+/* 0660 */ 0x72100000L, /* move dsa0 to sfbr */
+/* 0664 */ 0x00000000L,
+/* 0668 */ 0x80840000L, /* jump load_state_okay, if not 0 */
+/* 066c */ 0x0000009cL,
+/* 0670 */ 0x72110000L, /* move dsa1 to sfbr */
+/* 0674 */ 0x00000000L,
+/* 0678 */ 0x80840000L, /* jump load_state_okay, if not 0 */
+/* 067c */ 0x0000008cL,
+/* 0680 */ 0x72120000L, /* move dsa2 to sfbr */
+/* 0684 */ 0x00000000L,
+/* 0688 */ 0x80840000L, /* jump load_state_okay, if not 0 */
+/* 068c */ 0x0000007cL,
+/* 0690 */ 0x72130000L, /* move dsa3 to sfbr */
+/* 0694 */ 0x00000000L,
+/* 0698 */ 0x80840000L, /* jump load_state_okay, if not 0 */
+/* 069c */ 0x0000006cL,
+/* 06a0 */ 0xc0000004L, /* move memory 4, dsa, dmaaddr */
+/* 06a4 */ 0x00000010L,
+/* 06a8 */ 0x00000644L,
+/* 06ac */ 0xc0000004L, /* move memory 4, dsa, targ */
+/* 06b0 */ 0x00000010L,
+/* 06b4 */ 0x00000648L,
+/* 06b8 */ 0xc0000004L, /* move memory 4, dsa, lun */
+/* 06bc */ 0x00000010L,
+/* 06c0 */ 0x0000064cL,
+/* 06c4 */ 0xc0000004L, /* move memory 4, dsa, sync */
+/* 06c8 */ 0x00000010L,
+/* 06cc */ 0x00000650L,
+/* 06d0 */ 0xc0000004L, /* move memory 4, dsa, next */
+/* 06d4 */ 0x00000010L,
+/* 06d8 */ 0x00000654L,
+/* 06dc */ 0xc0000004L, /* move memory 4, dsa, scratcha */
+/* 06e0 */ 0x00000010L,
+/* 06e4 */ 0x00000034L,
+/* 06e8 */ 0x68080500L, /* move STATE_END to sfbr */
+/* 06ec */ 0x00000000L,
+/* 06f0 */ 0x6a340000L, /* move sfbr to scratcha0 */
+/* 06f4 */ 0x00000000L,
+/* 06f8 */ 0xc0000004L, /* move memory 4, scratcha, state */
+/* 06fc */ 0x00000034L,
+/* 0700 */ 0x00000640L,
+/* 0704 */ 0x90080000L, /* return */
+/* 0708 */ 0x00000000L,
+/* 070c */ 0xc0000004L, /* move memory 4, dsa, load_state_smc0 + 4 */
+/* 0710 */ 0x00000010L,
+/* 0714 */ 0x0000071cL,
+/* 0718 */ 0xc0000018L, /* move memory dsa_load_len, 0, dsa_copy */
+/* 071c */ 0x00000000L,
+/* 0720 */ 0x00000640L,
+/* 0724 */ 0x90080000L, /* return */
+/* 0728 */ 0x00000000L,
+/* 072c */ 0xc0000004L, /* move memory 4, dsa, save_state_smc0 + 8 */
+/* 0730 */ 0x00000010L,
+/* 0734 */ 0x00000740L,
+/* 0738 */ 0xc0000008L, /* move memory dsa_save_len, dsa_copy, 0 */
+/* 073c */ 0x00000640L,
+/* 0740 */ 0x00000000L,
+/* 0744 */ 0x90080000L, /* return */
+/* 0748 */ 0x00000000L,
+/* 074c */ 0x721a0000L, /* move ctest2 to sfbr */
+/* 0750 */ 0x00000000L,
+/* 0754 */ 0xc0000004L, /* move memory 4, dsa_head, dsa */
+/* 0758 */ 0x00000008L,
+/* 075c */ 0x00000010L,
+/* 0760 */ 0x88880000L, /* call load_state */
+/* 0764 */ 0x00fffef0L,
+/* 0768 */ 0xc0000004L, /* move memory 4, state, scratcha */
+/* 076c */ 0x00000640L,
+/* 0770 */ 0x00000034L,
+/* 0774 */ 0x72340000L, /* move scratcha0 to sfbr */
+/* 0778 */ 0x00000000L,
+/* 077c */ 0x808c0002L, /* jump start, if STATE_ISSUE */
+/* 0780 */ 0x00fff884L,
+/* 0784 */ 0x808c0005L, /* jump wait_for_reselection, if STATE_END */
+/* 0788 */ 0x00fffd90L,
+/* 078c */ 0xc0000004L, /* move memory 4, next, dsa */
+/* 0790 */ 0x00000654L,
+/* 0794 */ 0x00000010L,
+/* 0798 */ 0x80880000L, /* jump issue_check_loop */
+/* 079c */ 0x00ffffc0L,
+/* 07a0 */ 0xc0000004L, /* move memory 4, sync, scratcha */
+/* 07a4 */ 0x00000650L,
+/* 07a8 */ 0x00000034L,
+/* 07ac */ 0x72340000L, /* move scratcha0 to sfbr */
+/* 07b0 */ 0x00000000L,
+/* 07b4 */ 0x6a030000L, /* move sfbr to scntl3 */
+/* 07b8 */ 0x00000000L,
+/* 07bc */ 0x72350000L, /* move scratcha1 to sfbr */
+/* 07c0 */ 0x00000000L,
+/* 07c4 */ 0x6a050000L, /* move sfbr to sxfer */
+/* 07c8 */ 0x00000000L,
+/* 07cc */ 0x90080000L, /* return */
+/* 07d0 */ 0x00000000L,
+};
+
+#define NA_SCRIPT_SIZE 501
+
+struct na_patch na_patches[] = {
+ { 0x0006, 5 }, /* 00000018 */
+ { 0x000b, 4 }, /* 0000002c */
+ { 0x0013, 4 }, /* 0000004c */
+ { 0x0017, 1 }, /* 0000005c */
+ { 0x0018, 2 }, /* 00000060 */
+ { 0x001a, 1 }, /* 00000068 */
+ { 0x001b, 2 }, /* 0000006c */
+ { 0x0021, 1 }, /* 00000084 */
+ { 0x002b, 2 }, /* 000000ac */
+ { 0x002c, 1 }, /* 000000b0 */
+ { 0x0030, 2 }, /* 000000c0 */
+ { 0x0031, 1 }, /* 000000c4 */
+ { 0x0037, 2 }, /* 000000dc */
+ { 0x0038, 1 }, /* 000000e0 */
+ { 0x003a, 2 }, /* 000000e8 */
+ { 0x003b, 1 }, /* 000000ec */
+ { 0x0043, 4 }, /* 0000010c */
+ { 0x0047, 2 }, /* 0000011c */
+ { 0x0048, 1 }, /* 00000120 */
+ { 0x004e, 1 }, /* 00000138 */
+ { 0x004f, 2 }, /* 0000013c */
+ { 0x0051, 1 }, /* 00000144 */
+ { 0x0052, 2 }, /* 00000148 */
+ { 0x0058, 1 }, /* 00000160 */
+ { 0x0059, 2 }, /* 00000164 */
+ { 0x005b, 1 }, /* 0000016c */
+ { 0x0065, 2 }, /* 00000194 */
+ { 0x0066, 1 }, /* 00000198 */
+ { 0x006a, 2 }, /* 000001a8 */
+ { 0x006b, 1 }, /* 000001ac */
+ { 0x0073, 4 }, /* 000001cc */
+ { 0x0077, 2 }, /* 000001dc */
+ { 0x0078, 1 }, /* 000001e0 */
+ { 0x007e, 4 }, /* 000001f8 */
+ { 0x0082, 2 }, /* 00000208 */
+ { 0x0098, 1 }, /* 00000260 */
+ { 0x0099, 2 }, /* 00000264 */
+ { 0x009f, 2 }, /* 0000027c */
+ { 0x00a0, 1 }, /* 00000280 */
+ { 0x00b6, 2 }, /* 000002d8 */
+ { 0x00c2, 2 }, /* 00000308 */
+ { 0x00ca, 2 }, /* 00000328 */
+ { 0x00d0, 2 }, /* 00000340 */
+ { 0x00d6, 2 }, /* 00000358 */
+ { 0x00e6, 2 }, /* 00000398 */
+ { 0x00ec, 2 }, /* 000003b0 */
+ { 0x0102, 2 }, /* 00000408 */
+ { 0x010e, 2 }, /* 00000438 */
+ { 0x011c, 4 }, /* 00000470 */
+ { 0x0126, 2 }, /* 00000498 */
+ { 0x0134, 1 }, /* 000004d0 */
+ { 0x0135, 2 }, /* 000004d4 */
+ { 0x0139, 2 }, /* 000004e4 */
+ { 0x013a, 1 }, /* 000004e8 */
+ { 0x014e, 2 }, /* 00000538 */
+ { 0x0152, 4 }, /* 00000548 */
+ { 0x0153, 2 }, /* 0000054c */
+ { 0x0157, 1 }, /* 0000055c */
+ { 0x0158, 2 }, /* 00000560 */
+ { 0x015f, 3 }, /* 0000057c */
+ { 0x0162, 1 }, /* 00000588 */
+ { 0x0163, 1 }, /* 0000058c */
+ { 0x0167, 1 }, /* 0000059c */
+ { 0x0168, 1 }, /* 000005a0 */
+ { 0x016e, 1 }, /* 000005b8 */
+ { 0x016f, 2 }, /* 000005bc */
+ { 0x01a9, 2 }, /* 000006a4 */
+ { 0x01aa, 1 }, /* 000006a8 */
+ { 0x01ac, 2 }, /* 000006b0 */
+ { 0x01ad, 1 }, /* 000006b4 */
+ { 0x01af, 2 }, /* 000006bc */
+ { 0x01b0, 1 }, /* 000006c0 */
+ { 0x01b2, 2 }, /* 000006c8 */
+ { 0x01b3, 1 }, /* 000006cc */
+ { 0x01b5, 2 }, /* 000006d4 */
+ { 0x01b6, 1 }, /* 000006d8 */
+ { 0x01b8, 2 }, /* 000006e0 */
+ { 0x01b9, 2 }, /* 000006e4 */
+ { 0x01bf, 2 }, /* 000006fc */
+ { 0x01c0, 1 }, /* 00000700 */
+ { 0x01c4, 2 }, /* 00000710 */
+ { 0x01c5, 1 }, /* 00000714 */
+ { 0x01c8, 1 }, /* 00000720 */
+ { 0x01cc, 2 }, /* 00000730 */
+ { 0x01cd, 1 }, /* 00000734 */
+ { 0x01cf, 1 }, /* 0000073c */
+ { 0x01d6, 4 }, /* 00000758 */
+ { 0x01d7, 2 }, /* 0000075c */
+ { 0x01db, 1 }, /* 0000076c */
+ { 0x01dc, 2 }, /* 00000770 */
+ { 0x01e4, 1 }, /* 00000790 */
+ { 0x01e5, 2 }, /* 00000794 */
+ { 0x01e9, 1 }, /* 000007a4 */
+ { 0x01ea, 2 }, /* 000007a8 */
+};
+#define NA_PATCHES 94
+
+enum na_external {
+ X_scsi_id_buf,
+ X_msg_out_buf,
+ X_cmd_buf,
+ X_data_buf,
+ X_status_buf,
+ X_msgin_buf,
+ X_dsa_0,
+ X_dsa_1,
+ X_dsa_head,
+ X_ssid_mask,
+};
+
+enum {
+ E_issue_check_loop = 1888,
+ E_save_state_smc0 = 1848,
+ E_load_state_smc0 = 1816,
+ E_load_state_okay = 1804,
+ E_dsa_load_end = 1624,
+ E_sync = 1616,
+ E_dsa_save_end = 1608,
+ E_dsa_copy = 1600,
+ E_id_out_mismatch_recover = 1480,
+ E_next = 1620,
+ E_reload_sync = 1512,
+ E_find_dsa_smc2 = 1452,
+ E_lun = 1612,
+ E_find_dsa_smc1 = 1424,
+ E_targ = 1608,
+ E_find_dsa_next = 1460,
+ E_load_state = 1624,
+ E_find_dsa_loop = 1360,
+ E_find_dsa = 1348,
+ E_sigp_set = 1868,
+ E_reselected = 1316,
+ E_wsr_check = 1268,
+ E_response_msg_in = 1172,
+ E_response_repeat = 1132,
+ E_response = 1108,
+ E_reject = 988,
+ E_wdtr = 964,
+ E_sdtr = 876,
+ E_ext_done = 988,
+ E_ext_1 = 756,
+ E_ext_2 = 900,
+ E_ext_3 = 788,
+ E_issue_check = 1876,
+ E_extended = 708,
+ E_ignore_wide = 1060,
+ E_msg_in_skip = 692,
+ E_disconnected = 1204,
+ E_msg_in_not_reject = 532,
+ E_rejected = 668,
+ E_msg_in_phase = 516,
+ E_status_phase = 500,
+ E_data_out_mismatch = 464,
+ E_data_out_block_mismatch = 368,
+ E_data_out_normal = 440,
+ E_data_out_block_loop = 332,
+ E_data_out_phase = 308,
+ E_post_data_to_decisions = 1576,
+ E_data_in_mismatch = 272,
+ E_data_mismatch_recover = 228,
+ E_data_block_mismatch_recover = 216,
+ E_save_state = 1836,
+ E_data_in_block_mismatch = 136,
+ E_data_in_normal = 248,
+ E_data_in_block_loop = 112,
+ E_dmaaddr = 1604,
+ E_state = 1600,
+ E_data_in_phase = 88,
+ E_cmd_out_mismatch = 80,
+ E_cmd_phase = 64,
+ E_to_decisions = 1528,
+ E_id_out_mismatch = 48,
+ E_start1 = 40,
+ E_reselected_on_select = 1292,
+ E_load_sync = 1952,
+ E_start = 8,
+ E_wait_for_reselection = 1308,
+};
+#define A_dsa_save_len 8
+#define A_dsa_load_len 24
+#define A_BSIZE 512
+#define A_MSG_REJECT 7
+#define A_X_MSG_WDTR 3
+#define A_X_MSG_SDTR 1
+#define A_X_MSG 1
+#define A_MSG_IGNORE_WIDE_RESIDUE 35
+#define A_MSG_RESTORE_POINTERS 3
+#define A_MSG_SAVE_DATA_POINTER 2
+#define A_MSG_DISCONNECT 4
+#define A_MSG_IDENTIFY 128
+#define A_RESULT_OK 0
+#define A_STATE_END 5
+#define A_STATE_DONE 4
+#define A_STATE_DISCONNECTED 3
+#define A_STATE_ISSUE 2
+#define A_STATE_ALLOCATED 1
+#define A_STATE_FREE 0
+#define A_SIR_NOTIFY_LOAD_STATE 118
+#define A_SIR_NOTIFY_RESELECTED_ON_SELECT 117
+#define A_SIR_NOTIFY_LOAD_SYNC 116
+#define A_SIR_NOTIFY_WSR 115
+#define A_SIR_NOTIFY_BLOCK_DATA_IN 114
+#define A_SIR_NOTIFY_DATA_OUT 113
+#define A_SIR_NOTIFY_DATA_IN 112
+#define A_SIR_NOTIFY_COMMAND 111
+#define A_SIR_NOTIFY_DUMP_NEXT_CODE 110
+#define A_SIR_NOTIFY_ISSUE_CHECK 109
+#define A_SIR_NOTIFY_WAIT_RESELECT 108
+#define A_SIR_NOTIFY_ISSUE 107
+#define A_SIR_NOTIFY_SIGP 106
+#define A_SIR_NOTIFY_DUMP2 105
+#define A_SIR_NOTIFY_DUMP 104
+#define A_SIR_NOTIFY_STATUS 103
+#define A_SIR_NOTIFY_MSG_IN 102
+#define A_SIR_NOTIFY_RESELECT 101
+#define A_SIR_NOTIFY_DISC 100
+#define A_SIR_MSG_IGNORE_WIDE_RESIDUE 16
+#define A_SIR_MSG_WDTR 15
+#define A_SIR_EV_PHASE_SWITCH_AFTER_ID 14
+#define A_error_sigp_set 13
+#define A_SIR_EV_RESPONSE_OK 12
+#define A_SIR_MSG_SDTR 11
+#define A_SIR_MSG_REJECT 10
+#define A_error_too_little_data 9
+#define A_error_too_much_data 8
+#define A_error_not_identify_after_reselect 7
+#define A_SIR_ERROR_NOT_MSG_IN_AFTER_RESELECT 6
+#define A_error_weird_message 5
+#define A_error_unexpected_phase 4
+#define A_error_reselected 3
+#define A_error_disconnected 2
+#define A_error_not_cmd_complete 1
+#define A_SIR_MSG_IO_COMPLETE 0
diff --git a/sys/src/9/alphapc/sio.c b/sys/src/9/alphapc/sio.c
new file mode 100755
index 000000000..1b75fabad
--- /dev/null
+++ b/sys/src/9/alphapc/sio.c
@@ -0,0 +1,18 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+/*
+ * 82378ZB Saturn-I/O (SIO) PCI-to-ISA Bus Bridge.
+ */
+static Pcidev* siodev;
+
+void
+siodump(void)
+{
+ if(siodev == nil && (siodev = pcimatch(nil, 0x8086, 0x0484)) == nil)
+ return;
+}
diff --git a/sys/src/9/alphapc/trap.c b/sys/src/9/alphapc/trap.c
new file mode 100755
index 000000000..4767c802a
--- /dev/null
+++ b/sys/src/9/alphapc/trap.c
@@ -0,0 +1,916 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "ureg.h"
+#include "io.h"
+#include "../port/error.h"
+
+void noted(Ureg*, Ureg**, ulong);
+void rfnote(Ureg**);
+void kernfault(Ureg*, int);
+void illegal(Ureg *);
+void fen(Ureg *);
+
+char *regname[]={
+ "type", "a0", "a1",
+ "a2", "R0", "R1",
+ "R2", "R3", "R4",
+ "R5", "R6", "R7",
+ "R8", "R9", "R10",
+ "R11", "R12", "R13",
+ "R14", "R15", "R19",
+ "R20", "R21", "R22",
+ "R23", "R24", "R25",
+ "R26", "R27", "R28",
+ "R30", "status", "PC",
+ "R29", "R16", "R17",
+ "R18",
+};
+
+static Lock vctllock;
+static Vctl *vctl[256];
+
+void
+intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
+{
+ int vno;
+ Vctl *v;
+
+ if(f == nil){
+ print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
+ irq, tbdf, name);
+ return;
+ }
+
+ v = xalloc(sizeof(Vctl));
+ v->isintr = 1;
+ v->irq = irq;
+ v->tbdf = tbdf;
+ v->f = f;
+ v->a = a;
+ strncpy(v->name, name, KNAMELEN-1);
+ v->name[KNAMELEN-1] = 0;
+
+ ilock(&vctllock);
+ vno = arch->intrenable(v);
+ if(vno == -1){
+ iunlock(&vctllock);
+ print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
+ irq, tbdf, v->name);
+ xfree(v);
+ return;
+ }
+ if(vctl[vno]){
+ if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
+ panic("intrenable: handler: %s %s %#p %#p %#p %#p",
+ vctl[vno]->name, v->name,
+ vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
+ v->next = vctl[vno];
+ }
+ vctl[vno] = v;
+ iunlock(&vctllock);
+}
+
+int
+intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
+{
+ Vctl **pv, *v;
+ int vno;
+
+ /*
+ * For now, none of this will work with the APIC code,
+ * there is no mapping between irq and vector as the IRQ
+ * is pretty meaningless.
+ */
+ if(arch->intrvecno == nil)
+ return -1;
+ vno = arch->intrvecno(irq);
+ ilock(&vctllock);
+ for(pv = &vctl[vno]; *pv != nil; pv = &((*pv)->next)){
+ if((*pv)->irq != irq)
+ continue;
+ if((*pv)->tbdf != tbdf)
+ continue;
+ if((*pv)->f != f)
+ continue;
+ if((*pv)->a != a)
+ continue;
+ if(strcmp((*pv)->name, name) != 0)
+ continue;
+ break;
+ }
+ assert(*pv != nil);
+
+ v = *pv;
+ *pv = (*pv)->next; /* Link out the entry */
+
+ if (vctl[vno] == nil && arch->intrdisable != nil)
+ arch->intrdisable(irq);
+ iunlock(&vctllock);
+ xfree(v);
+ return 0;
+}
+
+int
+irqallocread(char *buf, long n, vlong offset)
+{
+ int vno;
+ Vctl *v;
+ long oldn;
+ char str[11+1+KNAMELEN+1], *p;
+ int m;
+
+ if(n < 0 || offset < 0)
+ error(Ebadarg);
+
+ oldn = n;
+ for(vno=0; vno<nelem(vctl); vno++){
+ for(v=vctl[vno]; v; v=v->next){
+ m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name);
+ if(m <= offset) /* if do not want this, skip entry */
+ offset -= m;
+ else{
+ /* skip offset bytes */
+ m -= offset;
+ p = str+offset;
+ offset = 0;
+
+ /* write at most max(n,m) bytes */
+ if(m > n)
+ m = n;
+ memmove(buf, p, m);
+ n -= m;
+ buf += m;
+
+ if(n == 0)
+ return oldn;
+ }
+ }
+ }
+ return oldn - n;
+}
+
+typedef struct Mcheck Mcheck;
+struct Mcheck
+{
+ ulong len;
+ ulong inprogress;
+ ulong procoff;
+ ulong sysoff;
+ ulong code;
+};
+
+static char *
+smcheck(ulong code)
+{
+ switch (code) {
+ case 0x80: return "tag parity error";
+ case 0x82: return "tag control parity error";
+ case 0x84: return "generic hard error";
+ case 0x86: return "correctable ECC error";
+ case 0x88: return "uncorrectable ECC error";
+ case 0x8a: return "OS-specific PAL bugcheck";
+ case 0x90: return "callsys in kernel mode";
+ case 0x96: return "i-cache read retryable error";
+ case 0x98: return "processor detected hard error";
+
+ case 0x203: return "system detected uncorrectable ECC error";
+ case 0x205: return "parity error detected by CIA";
+ case 0x207: return "non-existent memory error";
+ case 0x209: return "PCI SERR detected";
+ case 0x20b: return "PCI data parity error detected";
+ case 0x20d: return "PCI address parity error detected";
+ case 0x20f: return "PCI master abort error";
+ case 0x211: return "PCI target abort error";
+ case 0x213: return "scatter/gather PTE invalid error";
+ case 0x215: return "flash ROM write error";
+ case 0x217: return "IOA timeout detected";
+ case 0x219: return "IOCHK#, EISA add-in board parity or other catastrophic error";
+ case 0x21b: return "EISA fail-safe timer timeout";
+ case 0x21d: return "EISA bus time-out";
+ case 0x21f: return "EISA software generated NMI";
+ case 0x221: return "unexpected ev5 IRQ[3] interrupt";
+ default: return "unknown mcheck";
+ }
+}
+
+void
+mcheck(Ureg *ur, void *x)
+{
+ Mcheck *m;
+ uvlong *data;
+ int i, col;
+
+ m = x;
+ data = x;
+ iprint("panic: Machine Check @%#p: %s (%lux) len %lud\n",
+ m, smcheck(m->code), m->code, m->len);
+ iprint("proc offset %lux sys offset %lux\n", m->procoff, m->sysoff);
+ for (i = 0, col = 0; i < m->len/8; i++) {
+ iprint("%.3x: %.16llux%s", 8*i, data[i], (col == 2) ? "\n" : " ");
+ if (col++ == 2)
+ col = 0;
+ }
+ if(col != 2)
+ print("\n");
+ print("\n");
+ dumpregs(ur);
+ prflush();
+ firmware();
+}
+
+void
+intr(Ureg *ur)
+{
+ int i, vno;
+ Vctl *ctl, *v;
+ Mach *mach;
+
+ vno = (ulong)ur->a1>>4;
+ vno -= 0x80;
+ if(vno < nelem(vctl) && (ctl = vctl[vno])){
+ if(ctl->isintr){
+ m->intr++;
+ if(vno >= VectorPIC && vno <= MaxVectorPIC)
+ m->lastintr = vno-VectorPIC;
+ }
+
+ if(ctl->isr)
+ ctl->isr(vno);
+ for(v = ctl; v != nil; v = v->next) {
+ if(v->f)
+ v->f(ur, v->a);
+ }
+
+ if(ctl->eoi)
+ ctl->eoi(vno);
+
+ if(ctl->isintr && up)
+ preempted();
+ }
+ else if(vno >= VectorPIC && vno <= MaxVectorPIC){
+ /*
+ * An unknown interrupt.
+ * Check for a default IRQ7. This can happen when
+ * the IRQ input goes away before the acknowledge.
+ * In this case, a 'default IRQ7' is generated, but
+ * the corresponding bit in the ISR isn't set.
+ * In fact, just ignore all such interrupts.
+ */
+ iprint("cpu%d: spurious interrupt %d, last %d",
+ m->machno, vno-VectorPIC, m->lastintr);
+ for(i = 0; i < 32; i++){
+ if(!(active.machs & (1<<i)))
+ continue;
+ mach = MACHP(i);
+ if(m->machno == mach->machno)
+ continue;
+ iprint(": cpu%d: last %d", mach->machno, mach->lastintr);
+ }
+ iprint("\n");
+ m->spuriousintr++;
+ return;
+ }
+ else{
+ dumpregs(ur);
+ print("unknown intr: %d\n", vno); /* */
+ }
+}
+
+void
+trap(Ureg *ur)
+{
+ char buf[ERRMAX];
+ int clockintr, user, x;
+
+ user = ur->status&UMODE;
+
+ if(user){
+ up = m->proc;
+ up->dbgreg = ur;
+ }
+ clockintr = 0;
+ switch ((int)ur->type) {
+ case 1: /* arith */
+ fptrap(ur);
+ break;
+ case 2: /* bad instr or FEN */
+ illegal(ur);
+ break;
+
+ case 3: /* intr */
+ m->intr++;
+ switch ((int)ur->a0) {
+ case 0: /* interprocessor */
+ panic("interprocessor intr");
+ break;
+ case 1: /* clock */
+ clockintr = 1;
+ clock(ur);
+ break;
+ case 2: /* machine check */
+ mcheck(ur, (void*)(KZERO|(ulong)ur->a2));
+ break;
+ case 3: /* device */
+ intr(ur);
+ break;
+ case 4: /* perf counter */
+ panic("perf count");
+ break;
+ default:
+ panic("bad intr");
+ break;
+ }
+ break;
+
+ case 4: /* memory fault */
+ if(up == 0)
+ kernfault(ur, (ulong)ur->a1);
+
+ x = up->insyscall;
+ up->insyscall = 1;
+ spllo();
+ faultalpha(ur);
+ up->insyscall = x;
+ break;
+ case 6: /* alignment fault */
+ ur->pc -= 4;
+ sprint(buf, "trap: unaligned addr 0x%lux", (ulong)ur->a0);
+ fataltrap(ur, buf);
+ break;
+ default: /* cannot happen */
+ panic("bad trap type %d", (int)ur->type);
+ break;
+ }
+
+ splhi();
+
+ /* delaysched set because we held a lock or because our quantum ended */
+ if(up && up->delaysched && clockintr){
+ sched();
+ splhi();
+ }
+
+ if(user){
+ if(up->procctl || up->nnote)
+ notify(ur);
+ kexit(ur);
+ }
+}
+
+void
+trapinit(void)
+{
+ splhi();
+ wrent(0, intr0);
+ wrent(1, arith);
+ wrent(2, fault0);
+ wrent(3, illegal0);
+ wrent(4, unaligned);
+ wrent(5, syscall0);
+}
+
+void
+fataltrap(Ureg *ur, char *reason)
+{
+ char buf[ERRMAX];
+
+ if(ur->status&UMODE) {
+ spllo();
+ sprint(buf, "sys: %s", reason);
+ postnote(up, 1, buf, NDebug);
+ return;
+ }
+ print("kernel %s pc=%lux\n", reason, (ulong)ur->pc);
+ dumpregs(ur);
+ dumpstack();
+ if(m->machno == 0)
+ spllo();
+ exit(1);
+}
+
+void
+kernfault(Ureg *ur, int code)
+{
+ Label l;
+ char *s;
+
+ splhi();
+ if (code == 0)
+ s = "read";
+ else if (code == 1)
+ s = "write";
+ else
+ s = "ifetch";
+ print("panic: kfault %s VA=0x%lux\n", s, (ulong)ur->a0);
+ print("u=%#p status=0x%lux pc=0x%lux sp=0x%lux\n",
+ up, (ulong)ur->status, (ulong)ur->pc, (ulong)ur->sp);
+ dumpregs(ur);
+ l.sp = ur->sp;
+ l.pc = ur->pc;
+ dumpstack();
+ exit(1);
+}
+
+void
+dumpregs(Ureg *ur)
+{
+ int i, col;
+ uvlong *l;
+
+ if(up)
+ print("registers for %s %ld\n", up->text, up->pid);
+ else
+ print("registers for kernel\n");
+
+ l = &ur->type;
+ col = 0;
+ for (i = 0; i < sizeof regname/sizeof(char*); i++, l++) {
+ print("%-7s%.16llux%s", regname[i], *l, col == 2 ? "\n" : " ");
+ if (col++ == 2)
+ col = 0;
+ }
+ print("\n");
+}
+
+
+/*
+ * Fill in enough of Ureg to get a stack trace, and call a function.
+ * Used by debugging interface rdb.
+ */
+static void
+getpcsp(ulong *pc, ulong *sp)
+{
+ *pc = getcallerpc(&pc);
+ *sp = (ulong)&pc-8;
+}
+
+void
+callwithureg(void (*fn)(Ureg*))
+{
+ Ureg ureg;
+
+ getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
+ ureg.r26 = getcallerpc(&fn);
+ fn(&ureg);
+}
+
+void
+_dumpstack(Ureg *ureg)
+{
+ ulong l, sl, el, v, i, instr, op;
+ extern ulong etext;
+
+ l=(ulong)&l;
+ if(l&4)
+ l += 4;
+ if(up == 0){
+ el = (ulong)m+BY2PG;
+ sl = el-KSTACK;
+ }
+ else{
+ sl = (ulong)up->kstack;
+ el = sl + KSTACK;
+ }
+ if(l > el || l < sl){
+ el = (ulong)m+BY2PG;
+ sl = el-KSTACK;
+ }
+ if(l > el || l < sl)
+ return;
+ print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", (ulong)ureg->pc, (ulong)ureg->sp, (ulong)ureg->r26);
+
+ i = 0;
+ for(; l<el; l+=8){
+ v = *(ulong*)l - 4;
+ if(KTZERO < v && v < (ulong)&etext && (v&3) == 0){
+ /*
+ * Check for JSR/BSR
+ */
+ instr = *(ulong*)v;
+ op = (instr>>26);
+ if(op == 26 || op == 52){
+ print("%lux=%lux ", l, v);
+ i++;
+ }
+ }
+ if(i == 4){
+ i = 0;
+ print("\n");
+ }
+ }
+ if(i)
+ print("\n");
+}
+
+void
+dumpstack(void)
+{
+ callwithureg(_dumpstack);
+}
+
+int
+notify(Ureg *ur)
+{
+ int l;
+ ulong sp;
+ Note *n;
+
+ if(up->procctl)
+ procctl(up);
+ if(up->nnote == 0)
+ return 0;
+
+ spllo();
+ qlock(&up->debug);
+ up->notepending = 0;
+
+ if(up->fpstate == FPactive){
+ savefpregs(&up->fpsave);
+ up->fpstate = FPinactive;
+ }
+ up->fpstate |= FPillegal;
+
+ n = &up->note[0];
+ if(strncmp(n->msg, "sys:", 4) == 0) {
+ l = strlen(n->msg);
+ if(l > ERRMAX-15) /* " pc=0x12345678\0" */
+ l = ERRMAX-15;
+
+ sprint(n->msg+l, " pc=0x%lux", (ulong)ur->pc);
+ }
+
+ if(n->flag != NUser && (up->notified || up->notify==0)) {
+ if(n->flag == NDebug)
+ pprint("suicide: %s\n", n->msg);
+ qunlock(&up->debug);
+ pexit(n->msg, n->flag!=NDebug);
+ }
+
+ if(up->notified) {
+ qunlock(&up->debug);
+ splhi();
+ return 0;
+ }
+
+ if(!up->notify) {
+ qunlock(&up->debug);
+ pexit(n->msg, n->flag!=NDebug);
+ }
+ sp = ur->usp & ~(BY2V-1);
+ sp -= sizeof(Ureg);
+
+ if(!okaddr((ulong)up->notify, BY2WD, 0)
+ || !okaddr(sp-ERRMAX-6*BY2WD, sizeof(Ureg)+ERRMAX-6*BY2WD, 1)) {
+ pprint("suicide: bad address or sp in notify\n");
+print("suicide: bad address or sp in notify\n");
+ qunlock(&up->debug);
+ pexit("Suicide", 0);
+ }
+
+ memmove((Ureg*)sp, ur, sizeof(Ureg));
+ *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
+ up->ureg = (void*)sp;
+ sp -= 2*BY2WD+ERRMAX;
+ memmove((char*)sp, up->note[0].msg, ERRMAX);
+ sp -= 4*BY2WD;
+ *(ulong*)(sp+3*BY2WD) = sp+4*BY2WD; /* arg 2 is string */
+ ur->r0 = (ulong)up->ureg; /* arg 1 (R0) is ureg* */
+ *(ulong*)(sp+2*BY2WD) = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */
+ *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */
+ ur->usp = sp;
+ ur->pc = (ulong)up->notify;
+ up->notified = 1;
+ up->nnote--;
+ memmove(&up->lastnote, &up->note[0], sizeof(Note));
+ memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
+
+ qunlock(&up->debug);
+ splhi();
+ return 1;
+}
+
+/*
+ * Check that status is OK to return from note.
+ */
+int
+validstatus(ulong kstatus, ulong ustatus)
+{
+ if((kstatus & 7) != (ustatus & 7))
+ return 0;
+ if((ustatus&UMODE) != UMODE)
+ return 0;
+ return 1;
+}
+
+/*
+ * Return user to state before notify()
+ */
+void
+noted(Ureg *kur, Ureg **urp, ulong arg0)
+{
+ Ureg *nur;
+ ulong oureg, sp;
+
+ qlock(&up->debug);
+ if(arg0!=NRSTR && !up->notified) {
+ qunlock(&up->debug);
+ pprint("call to noted() when not notified\n");
+print("call to noted() when not notified\n");
+ pexit("Suicide", 0);
+ }
+ up->notified = 0;
+
+ up->fpstate &= ~FPillegal;
+
+ nur = up->ureg;
+
+ oureg = (ulong)nur;
+ if((oureg & (BY2V-1))
+ || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
+ pprint("bad ureg in noted or call to noted() when not notified\n");
+print("bad ureg in noted or call to noted() when not notified\n");
+ qunlock(&up->debug);
+ pexit("Suicide", 0);
+ }
+
+ if(!validstatus(kur->status, nur->status)) {
+ qunlock(&up->debug);
+ pprint("bad noted ureg status %lux\n", (ulong)nur->status);
+print("bad noted ureg status %lux\n", (ulong)nur->status);
+ pexit("Suicide", 0);
+ }
+
+ memmove(*urp, up->ureg, sizeof(Ureg));
+ switch(arg0) {
+ case NCONT:
+ case NRSTR:
+ if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
+ pprint("suicide: trap in noted\n");
+print("suicide: trap in noted\n");
+ qunlock(&up->debug);
+ pexit("Suicide", 0);
+ }
+ up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
+ qunlock(&up->debug);
+ splhi();
+ rfnote(urp);
+ break;
+
+ case NSAVE:
+ if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
+ pprint("suicide: trap in noted\n");
+print("suicide: trap in noted\n");
+ qunlock(&up->debug);
+ pexit("Suicide", 0);
+ }
+ qunlock(&up->debug);
+ sp = oureg-4*BY2WD-ERRMAX;
+ splhi();
+ (*urp)->sp = sp;
+ ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
+ ((ulong*)sp)[0] = 0; /* arg 0 is pc */
+ (*urp)->r0 = oureg; /* arg 1 is ureg* */
+ rfnote(urp);
+ break;
+
+ default:
+ pprint("unknown noted arg 0x%lux\n", arg0);
+print("unknown noted arg 0x%lux\n", arg0);
+ up->lastnote.flag = NDebug;
+ /* fall through */
+
+ case NDFLT:
+ if(up->lastnote.flag == NDebug)
+ pprint("suicide: %s\n", up->lastnote.msg);
+ qunlock(&up->debug);
+ pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
+ }
+}
+
+#include "../port/systab.h"
+
+long
+syscall(Ureg *aur)
+{
+ int i;
+ char *e;
+ long ret;
+ ulong sp;
+ Ureg *ur;
+ ulong scallnr;
+
+ m->syscall++;
+ up = m->proc;
+ up->insyscall = 1;
+ ur = aur;
+ up->pc = ur->pc;
+ up->dbgreg = aur;
+ ur->type = 5; /* for debugging */
+
+ scallnr = ur->r0;
+ up->scallnr = ur->r0;
+
+ if(scallnr == RFORK && up->fpstate == FPactive){
+ savefpregs(&up->fpsave);
+ up->fpstate = FPinactive;
+//print("SR=%lux+", up->fpsave.fpstatus);
+ }
+ spllo();
+
+ sp = ur->sp;
+ up->nerrlab = 0;
+ ret = -1;
+ if(!waserror()) {
+ if(scallnr >= nsyscall || systab[scallnr] == nil){
+ pprint("bad sys call %d pc %lux\n", up->scallnr, (ulong)ur->pc);
+ postnote(up, 1, "sys: bad sys call", NDebug);
+ error(Ebadarg);
+ }
+
+ if(sp & (BY2WD-1)){ /* XXX too weak? */
+ pprint("odd sp in sys call pc %lux sp %lux\n",
+ (ulong)ur->pc, (ulong)ur->sp);
+ postnote(up, 1, "sys: odd stack", NDebug);
+ error(Ebadarg);
+ }
+
+ if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)))
+ validaddr(sp, sizeof(Sargs), 0);
+
+ up->s = *((Sargs*)(sp+2*BY2WD));
+ up->psstate = sysctab[scallnr];
+ ret = systab[scallnr](up->s.args);
+ poperror();
+ }else{
+ /* failure: save the error buffer for errstr */
+ e = up->syserrstr;
+ up->syserrstr = up->errstr;
+ up->errstr = e;
+ }
+ if(up->nerrlab){
+ print("bad errstack [%uld]: %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");
+ }
+
+ up->nerrlab = 0;
+ up->psstate = 0;
+ up->insyscall = 0;
+ if(scallnr == NOTED) /* ugly hack */
+ noted(ur, &aur, *(ulong*)(sp+2*BY2WD)); /* doesn't return */
+
+ if(scallnr!=RFORK && (up->procctl || up->nnote)){
+ ur->r0 = ret; /* load up for noted() */
+ if(notify(ur))
+ return ur->r0;
+ }
+
+ return ret;
+}
+
+void
+forkchild(Proc *p, Ureg *ur)
+{
+ Ureg *cur;
+
+ p->sched.sp = (ulong)p->kstack+KSTACK-(4*BY2WD+sizeof(Ureg));
+ p->sched.pc = (ulong)forkret;
+
+ cur = (Ureg*)(p->sched.sp+4*BY2WD);
+ memmove(cur, ur, sizeof(Ureg));
+
+ /* Things from bottom of syscall we never got to execute */
+ p->psstate = 0;
+ p->insyscall = 0;
+}
+
+static
+void
+linkproc(void)
+{
+ spllo();
+ up->kpfun(up->kparg);
+ pexit("kproc exiting", 0);
+}
+
+void
+kprocchild(Proc *p, void (*func)(void*), void *arg)
+{
+ p->sched.pc = (ulong)linkproc;
+ p->sched.sp = (ulong)p->kstack+KSTACK;
+
+ p->kpfun = func;
+ p->kparg = arg;
+}
+
+long
+execregs(ulong entry, ulong ssize, ulong nargs)
+{
+ Ureg *ur;
+ ulong *sp;
+
+ sp = (ulong*)(USTKTOP - ssize);
+ *--sp = nargs;
+
+ ur = (Ureg*)up->dbgreg;
+ ur->usp = (ulong)sp;
+ ur->pc = entry;
+ return USTKTOP-BY2WD; /* address of user-level clock */
+}
+
+ulong
+userpc(void)
+{
+ Ureg *ur;
+
+ ur = (Ureg*)up->dbgreg;
+ return ur->pc;
+}
+
+/* This routine must save the values of registers the user is not permitted to write
+ * from devproc and then restore the saved values before returning
+ */
+void
+setregisters(Ureg *xp, char *pureg, char *uva, int n)
+{
+ ulong status;
+
+ status = xp->status;
+ memmove(pureg, uva, n);
+ xp->status = status;
+}
+
+/* Give enough context in the ureg to produce a kernel stack for
+ * a sleeping process
+ */
+void
+setkernur(Ureg *xp, Proc *p)
+{
+ xp->pc = p->sched.pc;
+ xp->sp = p->sched.sp;
+ xp->r26 = (ulong)sched;
+}
+
+ulong
+dbgpc(Proc *p)
+{
+ Ureg *ur;
+
+ ur = p->dbgreg;
+ if(ur == 0)
+ return 0;
+
+ return ur->pc;
+}
+
+void
+illegal(Ureg *ur)
+{
+ switch ((int)ur->a0) {
+ case 0: /* breakpoint */
+ ur->pc -= 4;
+ fataltrap(ur, "breakpoint");
+ break;
+ case 1: /* bugchk */
+ fataltrap(ur, "trap: bugchk");
+ break;
+ case 2: /* gentrap */
+ fataltrap(ur, "trap: gentrap");
+ break;
+ case 3: /* FEN */
+ fen(ur);
+ break;
+ case 4: /* opDEC */
+ fataltrap(ur, "trap: illegal instruction");
+ break;
+ default:
+ panic("illegal illegal %d", (int)ur->a0);
+ break;
+ }
+}
+
+void
+fen(Ureg *ur)
+{
+ if(up){
+ switch(up->fpstate){
+ case FPinit:
+ restfpregs(&initfp);
+ up->fpstate = FPactive;
+//print("EI=%lux+", initfp.fpstatus);
+ return;
+
+ case FPinactive:
+ restfpregs(&up->fpsave);
+ up->fpstate = FPactive;
+//print("EIA=%lux+", up->fpsave.fpstatus);
+ return;
+ }
+ }
+ fataltrap(ur, "trap: floating enable"); /* should never happen */
+}