diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/alphapc |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/alphapc')
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 */ +} |