A alphapc/arch164.c => alphapc/arch164.c +389 -0
@@ 0,0 1,389 @@
+/*
+ * 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"
+#include "ureg.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 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];
+
+ /* direct map bottom 2G PCI target space to KZERO in window 1 */
+ wind[0x500/4] = KZERO|1;
+ wind[0x540/4] = 0x7ff00000;
+ wind[0x580/4] = 0;
+
+ /* disable other windows */
+ wind[0x400/4] = 0;
+ wind[0x600/4] = 0;
+ wind[0x700/4] = 0;
+
+ /* clear error state */
+ core[0x8200/4] = 0x7ff;
+
+ /* set config: byte/word enable, no monster window, etc. */
+ core[0x140/4] = 1;
+
+ /* 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 */
+}
+
+static void
+corehello(void)
+{
+ print("cpu%d: CIA revision %d; 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);
+}
+
+/*
+ * interrupts -- adapted from PC, needs work.
+ */
+
+static Lock irqctllock;
+static Irqctl *irqctl[256];
+static char irqmask[3];
+
+static void
+intr164(Ureg *ur)
+{
+ int i, v;
+ Irqctl *ctl;
+ Irq *irq;
+ Mach *mach;
+
+ v = (ulong)ur->a1>>4;
+ if (v < 0x80) {
+ iprint("unknown device intr v %d\n", v);
+ return;
+ }
+ v -= 0x80;
+ if(v < 256 && (ctl = irqctl[v])){
+ if(ctl->isintr){
+ m->intr++;
+ if(ctl->isr)
+ ctl->isr(v);
+/* if(v >= VectorPIC && v <= MaxVectorPIC)
+ m->lastintr = v-VectorPIC; */
+ }
+
+ for(irq = ctl->irq; irq; irq = irq->next)
+ irq->f(ur, irq->a);
+
+ if(ctl->eoi)
+ ctl->eoi(v);
+ }
+ else if(v >= VectorPIC && v <= 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, v-VectorPIC, 0 /*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, 0 /*mach->lastintr*/);
+ }
+ iprint("\n");
+/* m->spuriousintr++; */
+ return;
+ }
+ else{
+ dumpregs(ur);
+ panic("unknown intr: %d\n", v); /* */
+ }
+}
+
+static int
+intrenable164(int v, void (*f)(Ureg*, void*), void*a, int tbdf)
+{
+ Irq * irq;
+ Irqctl *ctl;
+
+ lock(&irqctllock);
+ if(irqctl[v] == 0){
+ ctl = xalloc(sizeof(Irqctl));
+/* this is all wrong; FIXME! */
+ if(BUSTYPE(tbdf) == BusPCI)
+ cserve(52, v-VectorPCI);
+ else if(v >= VectorPIC && i8259enable(v, tbdf, ctl) == -1){
+ unlock(&irqctllock);
+ iprint("intrenable: didn't find v %d, tbdf 0x%uX\n", v, tbdf);
+ xfree(ctl);
+ return -1;
+ }
+ irqctl[v] = ctl;
+ }
+ ctl = irqctl[v];
+ irq = xalloc(sizeof(Irq));
+ irq->f = f;
+ irq->a = a;
+ irq->next = ctl->irq;
+ ctl->irq = irq;
+ unlock(&irqctllock);
+ return 0;
+}
+
+/*
+ * 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;
+}
+
+void
+outs2117x(int port, ushort val)
+{
+ mb();
+ *(ushort*)(iobase(port)) = val;
+}
+
+void
+outl2117x(int port, ulong val)
+{
+ mb();
+ *(ulong*)(iobase(port)) = val;
+}
+
+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,
+ intr164,
+ intrenable164,
+
+ inb2117x,
+ ins2117x,
+ inl2117x,
+ outb2117x,
+ outs2117x,
+ outl2117x,
+ insb2117x,
+ inss2117x,
+ insl2117x,
+ outsb2117x,
+ outss2117x,
+ outsl2117x,
+};
A alphapc/axp.h => alphapc/axp.h +71 -0
@@ 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;
+};
A alphapc/cga.c => alphapc/cga.c +113 -0
@@ 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;
A alphapc/clock.c => alphapc/clock.c +146 -0
@@ 0,0 1,146 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "ureg.h"
+
+void (*kproftimer)(ulong);
+
+typedef struct Clock0link Clock0link;
+typedef struct Clock0link {
+ void (*clock)(void);
+ Clock0link* link;
+} Clock0link;
+
+static Clock0link *clock0link;
+static Lock clock0lock;
+
+void
+addclock0link(void (*clock)(void))
+{
+ Clock0link *lp;
+
+ if((lp = malloc(sizeof(Clock0link))) == 0){
+ print("addclock0link: too many links\n");
+ return;
+ }
+ ilock(&clock0lock);
+ lp->clock = clock;
+ lp->link = clock0link;
+ clock0link = lp;
+ iunlock(&clock0lock);
+}
+
+
+/*
+ * delay for l milliseconds more or less. delayloop is set by
+ * clockinit() to match the actual CPU speed.
+ */
+void
+delay(int l)
+{
+ ulong i, j;
+
+ j = m->delayloop;
+ while(l-- > 0)
+ for(i=0; i < j; i++)
+ ;
+}
+
+void
+microdelay(int l)
+{
+ ulong i, j;
+
+// j = m->delayloop/1000;
+j = 10000;
+ while(l-- > 0)
+ for(i=0; i < j; i++)
+ ;
+}
+
+void
+clockinit(void)
+{
+m->delayloop = 250*1000; /* BUG */
+#ifdef NOTYET
+ long x;
+
+ m->delayloop = m->speed*100;
+ do {
+ x = rdcount();
+ delay(10);
+ x = rdcount() - x;
+ } while(x < 0);
+
+ /*
+ * fix count
+ */
+ m->delayloop = (m->delayloop*m->speed*1000*10)/x;
+ if(m->delayloop == 0)
+ m->delayloop = 1;
+
+/* wrcompare(rdcount()+(m->speed*1000000)/HZ); */
+#endif
+}
+
+void
+clock(Ureg *ur)
+{
+ Clock0link *lp;
+ static int count;
+
+ /* HZ == 100, timer == 1024Hz. error < 1ms */
+ count += 100;
+ if (count < 1024)
+ return;
+ count -= 1024;
+
+ m->ticks++;
+ if(m->proc)
+ m->proc->pc = ur->pc;
+
+ accounttime();
+
+ if(kproftimer != nil)
+ kproftimer(ur->pc);
+
+ if((active.machs&(1<<m->machno)) == 0)
+ return;
+
+ if(active.exiting && (active.machs & (1<<m->machno))) {
+ print("someone's exiting\n");
+ exit(0);
+ }
+
+ checkalarms();
+ if(m->machno == 0){
+ lock(&clock0lock);
+ for(lp = clock0link; lp; lp = lp->link)
+ lp->clock();
+ unlock(&clock0lock);
+ }
+
+ if(up == 0 || up->state != Running)
+ return;
+
+ if(anyready())
+ sched();
+
+ /* user profiling clock */
+ if(ur->status & UMODE) {
+ (*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1);
+ segclock(ur->pc);
+ }
+}
+
+vlong
+fastticks(uvlong *hz)
+{
+ if (hz)
+ *hz = 100;
+ return m->ticks;
+}
A alphapc/dat.h => alphapc/dat.h +228 -0
@@ 0,0 1,228 @@
+typedef struct Conf Conf;
+typedef struct FPsave FPsave;
+typedef struct Irq Irq;
+typedef struct Irqctl Irqctl;
+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 Sys Sys;
+typedef struct Ureg Ureg;
+typedef struct Proc Proc;
+
+/*
+ * 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;
+ ulong pid;
+ ushort isilock;
+};
+
+struct Label
+{
+ ulong sp;
+ ulong pc;
+};
+
+/*
+ * FPsave.fpstatus
+ */
+enum
+{
+ FPinit,
+ FPactive,
+ FPinactive,
+};
+
+struct FPsave
+{
+ long fpreg[2*32];
+ long dummy; /* lower bits of FPCR, useless */
+ long fpstatus;
+};
+
+struct Conf
+{
+ ulong nmach; /* processors */
+ ulong nproc; /* processes */
+ ulong npage0; /* total physical pages of memory */
+ ulong npage1; /* total physical pages of memory */
+ ulong npage; /* total physical pages of memory */
+ ulong base0; /* base of bank 0 */
+ ulong base1; /* base of bank 1 */
+ ulong upages; /* user page pool */
+ ulong nimage; /* number of page cache image headers */
+ ulong nswap; /* number of swap pages */
+ int nswppo; /* max # of pageouts per segment pass */
+ ulong copymode; /* 0 is copy on write, 1 is copy on reference */
+ ulong ptebase;
+ ulong mbytes;
+ 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 */
+ int tlbfault; /* only used by devproc; no access to tlb */
+ int tlbpurge; /* ... */
+ 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 */
+ Page *ufreeme; /* address of upage of exited process */
+ int speed; /* cpu speed */
+ ulong delayloop; /* for the delay() routine */
+ int nrdy;
+ ulong fairness; /* for runproc */
+
+ int pfault;
+ int cs;
+ int syscall;
+ int load;
+ int intr;
+ int nettime;
+ int flushmmu; /* make current proc flush it's mmu state */
+
+ 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 */
+ void (*intr)(Ureg*);
+ int (*intrenable)(int, void (*)(Ureg*, void*), void*, 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 ISAOPTLEN 16
+#define NISAOPT 8
+
+struct ISAConf {
+ char type[NAMELEN];
+ ulong port;
+ ulong irq;
+ ulong dma;
+ ulong mem;
+ ulong size;
+ ulong freq;
+
+ int nopt;
+ char opt[NISAOPT][ISAOPTLEN];
+};
+
+extern PCArch *arch;
+
+#define MACHP(n) ((Mach *)((int)&mach0+n*BY2PG))
+extern Mach mach0;
+
+extern register Mach *m;
+extern register Proc *up;
A alphapc/devether.c => alphapc/devether.c +436 -0
@@ 0,0 1,436 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+
+#include "etherif.h"
+
+static Ether *etherxx[MaxEther];
+
+Chan*
+etherattach(char* spec)
+{
+ ulong ctlrno;
+ char *p;
+ Chan *chan;
+
+ ctlrno = 0;
+ if(spec && *spec){
+ ctlrno = strtoul(spec, &p, 0);
+ if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
+ error(Ebadarg);
+ }
+ if(etherxx[ctlrno] == 0)
+ error(Enodev);
+
+ chan = devattach('l', spec);
+ chan->dev = ctlrno;
+ if(etherxx[ctlrno]->attach)
+ etherxx[ctlrno]->attach(etherxx[ctlrno]);
+ return chan;
+}
+
+static int
+etherwalk(Chan* chan, char* name)
+{
+ return netifwalk(etherxx[chan->dev], chan, name);
+}
+
+static void
+etherstat(Chan* chan, char* dp)
+{
+ netifstat(etherxx[chan->dev], chan, dp);
+}
+
+static Chan*
+etheropen(Chan* chan, int omode)
+{
+ return netifopen(etherxx[chan->dev], chan, omode);
+}
+
+static void
+ethercreate(Chan*, char*, int, ulong)
+{
+}
+
+static void
+etherclose(Chan* chan)
+{
+ netifclose(etherxx[chan->dev], chan);
+}
+
+static long
+etherread(Chan* chan, void* buf, long n, vlong off)
+{
+ Ether *ether;
+ ulong offset = off;
+
+ ether = etherxx[chan->dev];
+ if((chan->qid.path & CHDIR) == 0 && ether->ifstat){
+ /*
+ * With some controllers it is necessary to reach
+ * into the chip to extract statistics.
+ */
+ if(NETTYPE(chan->qid.path) == Nifstatqid)
+ return ether->ifstat(ether, buf, n, offset);
+ else if(NETTYPE(chan->qid.path) == Nstatqid)
+ ether->ifstat(ether, buf, 0, offset);
+ }
+
+ return netifread(ether, chan, buf, n, offset);
+}
+
+static Block*
+etherbread(Chan* chan, long n, ulong offset)
+{
+ return netifbread(etherxx[chan->dev], chan, n, offset);
+}
+
+static void
+etherremove(Chan*)
+{
+}
+
+static void
+etherwstat(Chan* chan, char* dp)
+{
+ netifwstat(etherxx[chan->dev], chan, dp);
+}
+
+static void
+etherrtrace(Netfile* f, Etherpkt* pkt, int len)
+{
+ int i, n;
+ Block *bp;
+
+ if(qwindow(f->in) <= 0)
+ return;
+ if(len > 64)
+ n = 64;
+ else
+ n = len;
+ bp = iallocb(n);
+ if(bp == 0)
+ return;
+ memmove(bp->wp, pkt->d, n);
+ i = TK2MS(MACHP(0)->ticks);
+ bp->wp[58] = len>>8;
+ bp->wp[59] = len;
+ bp->wp[60] = i>>24;
+ bp->wp[61] = i>>16;
+ bp->wp[62] = i>>8;
+ bp->wp[63] = i;
+ bp->wp += 64;
+ qpass(f->in, bp);
+}
+
+Block*
+etheriq(Ether* ether, Block* bp, int freebp)
+{
+ Etherpkt *pkt;
+ ushort type;
+ int len;
+ Netfile **ep, *f, **fp, *fx;
+ Block *xbp;
+
+ ether->inpackets++;
+
+ pkt = (Etherpkt*)bp->rp;
+ len = BLEN(bp);
+ type = (pkt->type[0]<<8)|pkt->type[1];
+ fx = 0;
+ ep = ðer->f[Ntypes];
+
+ /* check for valid multcast addresses */
+ if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
+ if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
+ if(freebp){
+ freeb(bp);
+ bp = 0;
+ }
+ return bp;
+ }
+ }
+
+ /*
+ * Multiplex the packet to all the connections which want it.
+ * If the packet is not to be used subsequently (freebp != 0),
+ * attempt to simply pass it into one of the connections, thereby
+ * saving a copy of the data (usual case hopefully).
+ */
+ for(fp = ether->f; fp < ep; fp++){
+ if((f = *fp) && (f->type == type || f->type < 0)){
+ if(f->type > -2){
+ if(freebp && fx == 0)
+ fx = f;
+ else if(xbp = iallocb(len)){
+ memmove(xbp->wp, pkt, len);
+ xbp->wp += len;
+ qpass(f->in, xbp);
+ }
+ else
+ ether->soverflows++;
+ }
+ else
+ etherrtrace(f, pkt, len);
+ }
+ }
+
+ if(fx){
+ qpass(fx->in, bp);
+ return 0;
+ }
+ if(freebp){
+ freeb(bp);
+ return 0;
+ }
+
+ return bp;
+}
+
+static int
+etheroq(Ether* ether, Block* bp)
+{
+ int len, loopback, s;
+ Etherpkt *pkt;
+
+ ether->outpackets++;
+
+ /*
+ * Check if the packet has to be placed back onto the input queue,
+ * i.e. if it's a loopback or broadcast packet or the interface is
+ * in promiscuous mode.
+ * If it's a loopback packet indicate to etheriq that the data isn't
+ * needed and return, etheriq will pass-on or free the block.
+ */
+ pkt = (Etherpkt*)bp->rp;
+ len = BLEN(bp);
+ loopback = (memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0);
+ if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
+ s = splhi();
+ etheriq(ether, bp, loopback);
+ splx(s);
+ }
+
+ if(!loopback){
+ qbwrite(ether->oq, bp);
+ ether->transmit(ether);
+ }
+
+ return len;
+}
+
+static long
+etherwrite(Chan* chan, void* buf, long n, vlong)
+{
+ Ether *ether;
+ Block *bp;
+
+ ether = etherxx[chan->dev];
+ if(NETTYPE(chan->qid.path) != Ndataqid)
+ return netifwrite(ether, chan, buf, n);
+
+ if(n > ETHERMAXTU)
+ error(Etoobig);
+ if(n < ETHERMINTU)
+ error(Etoosmall);
+
+ bp = allocb(n);
+ if(waserror()){
+ freeb(bp);
+ nexterror();
+ }
+ memmove(bp->rp, buf, n);
+ memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
+ poperror();
+ bp->wp += n;
+
+ return etheroq(ether, bp);
+}
+
+static long
+etherbwrite(Chan* chan, Block* bp, ulong)
+{
+ Ether *ether;
+ long n;
+
+ n = BLEN(bp);
+ ether = etherxx[chan->dev];
+ if(NETTYPE(chan->qid.path) != Ndataqid){
+ n = netifwrite(ether, chan, bp->rp, n);
+ freeb(bp);
+ return n;
+ }
+
+ if(n > ETHERMAXTU){
+ freeb(bp);
+ error(Ebadarg);
+ }
+ if(n < ETHERMINTU){
+ freeb(bp);
+ error(Etoosmall);
+ }
+
+ return etheroq(ether, bp);
+}
+
+static struct {
+ char* type;
+ int (*reset)(Ether*);
+} cards[MaxEther+1];
+
+void
+addethercard(char* t, int (*r)(Ether*))
+{
+ static int ncard;
+
+ if(ncard == MaxEther)
+ panic("too many ether cards");
+ cards[ncard].type = t;
+ cards[ncard].reset = r;
+ ncard++;
+}
+
+int
+parseether(uchar *to, char *from)
+{
+ char nip[4];
+ char *p;
+ int i;
+
+ p = from;
+ for(i = 0; i < 6; i++){
+ if(*p == 0)
+ return -1;
+ nip[0] = *p++;
+ if(*p == 0)
+ return -1;
+ nip[1] = *p++;
+ nip[2] = 0;
+ to[i] = strtoul(nip, 0, 16);
+ if(*p == ':')
+ p++;
+ }
+ return 0;
+}
+
+static void
+etherreset(void)
+{
+ Ether *ether;
+ int i, n, ctlrno;
+ char name[NAMELEN], buf[128];
+
+ for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
+ if(ether == 0)
+ ether = malloc(sizeof(Ether));
+ memset(ether, 0, sizeof(Ether));
+ ether->ctlrno = ctlrno;
+ ether->tbdf = BUSUNKNOWN;
+ ether->mbps = 10;
+ if(isaconfig("ether", ctlrno, ether) == 0)
+ continue;
+ for(n = 0; cards[n].type; n++){
+ if(cistrcmp(cards[n].type, ether->type))
+ continue;
+ for(i = 0; i < ether->nopt; i++){
+ if(strncmp(ether->opt[i], "ea=", 3))
+ continue;
+ if(parseether(ether->ea, ðer->opt[i][3]) == -1)
+ memset(ether->ea, 0, Eaddrlen);
+ }
+ if(cards[n].reset(ether))
+ break;
+
+ /*
+ * IRQ2 doesn't really exist, it's used to gang the interrupt
+ * controllers together. A device set to IRQ2 will appear on
+ * the second interrupt controller as IRQ9.
+ */
+ if(ether->irq == 2)
+ ether->irq = 9;
+ intrenable(VectorPCI+ether->irq, ether->interrupt, ether, ether->tbdf);
+
+ i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
+ ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
+ if(ether->mem)
+ i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
+ if(ether->size)
+ i += sprint(buf+i, " size 0x%luX", ether->size);
+ i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX",
+ ether->ea[0], ether->ea[1], ether->ea[2],
+ ether->ea[3], ether->ea[4], ether->ea[5]);
+ sprint(buf+i, "\n");
+ print(buf);
+
+ snprint(name, sizeof(name), "ether%d", ctlrno);
+ if(ether->mbps == 100){
+ netifinit(ether, name, Ntypes, 256*1024);
+ if(ether->oq == 0)
+ ether->oq = qopen(256*1024, 1, 0, 0);
+ }
+ else{
+ netifinit(ether, name, Ntypes, 65*1024);
+ if(ether->oq == 0)
+ ether->oq = qopen(65*1024, 1, 0, 0);
+ }
+ if(ether->oq == 0)
+ panic("etherreset %s", name);
+ ether->alen = Eaddrlen;
+ memmove(ether->addr, ether->ea, Eaddrlen);
+ memset(ether->bcast, 0xFF, Eaddrlen);
+
+ etherxx[ctlrno] = ether;
+ ether = 0;
+ break;
+ }
+ }
+ if(ether)
+ free(ether);
+}
+
+#define POLY 0xedb88320
+
+/* really slow 32 bit crc for ethers */
+ulong
+ethercrc(uchar *p, int len)
+{
+ int i, j;
+ ulong crc, b;
+
+ crc = 0xffffffff;
+ for(i = 0; i < len; i++){
+ b = *p++;
+ for(j = 0; j < 8; j++){
+ crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
+ b >>= 1;
+ }
+ }
+ return crc;
+}
+
+Dev etherdevtab = {
+ 'l',
+ "ether",
+
+ etherreset,
+ devinit,
+ etherattach,
+ devclone,
+ etherwalk,
+ etherstat,
+ etheropen,
+ ethercreate,
+ etherclose,
+ etherread,
+ etherbread,
+ etherwrite,
+ etherbwrite,
+ etherremove,
+ etherwstat,
+};
A alphapc/devfloppy.c => alphapc/devfloppy.c +1057 -0
@@ 0,0 1,1057 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#include "floppy.h"
+
+/* Intel 82077A (8272A compatible) floppy controller */
+
+/* This module expects the following functions to be defined
+ * elsewhere:
+ *
+ * inb()
+ * outb()
+ * floppyexec()
+ * floppyeject()
+ * floppysetup0()
+ * floppysetup1()
+ * dmainit()
+ * dmasetup()
+ * dmaend()
+ *
+ * On DMA systems, floppyexec() should be an empty function;
+ * on non-DMA systems, dmaend() should be an empty function;
+ * dmasetup() may enforce maximum transfer sizes.
+ */
+
+enum {
+ /* file types */
+ Qdir= 0,
+ Qdata= (1<<2),
+ Qctl= (2<<2),
+ Qmask= (3<<2),
+
+ DMAchan= 2, /* floppy dma channel */
+};
+
+#define DPRINT if(floppydebug)print
+int floppydebug = 0;
+
+/*
+ * types of drive (from PC equipment byte)
+ */
+enum
+{
+ Tnone= 0,
+ T360kb= 1,
+ T1200kb= 2,
+ T720kb= 3,
+ T1440kb= 4,
+};
+
+FType floppytype[] =
+{
+ { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
+ { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
+ { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
+ { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
+ { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, },
+ { "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, },
+ { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
+};
+
+/*
+ * bytes per sector encoding for the controller.
+ * - index for b2c is is (bytes per sector/128).
+ * - index for c2b is code from b2c
+ */
+static int b2c[] =
+{
+[1] 0,
+[2] 1,
+[4] 2,
+[8] 3,
+};
+static int c2b[] =
+{
+ 128,
+ 256,
+ 512,
+ 1024,
+};
+
+FController fl;
+
+#define MOTORBIT(i) (1<<((i)+4))
+
+/*
+ * predeclared
+ */
+static int cmddone(void*);
+static void floppyformat(FDrive*, char*);
+static void floppykproc(void*);
+static void floppypos(FDrive*,long);
+static int floppyrecal(FDrive*);
+static int floppyresult(void);
+static void floppyrevive(void);
+static long floppyseek(FDrive*, long);
+static int floppysense(void);
+static void floppywait(void);
+static long floppyxfer(FDrive*, int, void*, long, long);
+
+Dirtab floppydir[]={
+ "fd0disk", {Qdata + 0}, 0, 0660,
+ "fd0ctl", {Qctl + 0}, 0, 0660,
+ "fd1disk", {Qdata + 1}, 0, 0660,
+ "fd1ctl", {Qctl + 1}, 0, 0660,
+ "fd2disk", {Qdata + 2}, 0, 0660,
+ "fd2ctl", {Qctl + 2}, 0, 0660,
+ "fd3disk", {Qdata + 3}, 0, 0660,
+ "fd3ctl", {Qctl + 3}, 0, 0660,
+};
+#define NFDIR 2 /* directory entries/drive */
+
+static void
+fldump(void)
+{
+mb();
+ DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb),
+ inb(Pdor), inb(Pmsr), inb(Pdir));
+mb();
+}
+
+/*
+ * set floppy drive to its default type
+ */
+static void
+floppysetdef(FDrive *dp)
+{
+ FType *t;
+
+ for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++)
+ if(dp->dt == t->dt){
+ dp->t = t;
+ floppydir[NFDIR*dp->dev].length = dp->t->cap;
+ break;
+ }
+}
+
+static void
+floppyreset(void)
+{
+ FDrive *dp;
+ FType *t;
+ ulong maxtsize;
+
+ dmainit(DMAchan);
+
+ floppysetup0(&fl);
+
+ /*
+ * init dependent parameters
+ */
+ maxtsize = 0;
+ for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
+ t->cap = t->bytes * t->heads * t->sectors * t->tracks;
+ t->bcode = b2c[t->bytes/128];
+ t->tsize = t->bytes * t->sectors;
+ if(maxtsize < t->tsize)
+ maxtsize = t->tsize;
+ }
+
+ /*
+ * allocate the drive storage
+ */
+ fl.d = xalloc(fl.ndrive*sizeof(FDrive));
+ fl.selected = fl.d;
+
+ /*
+ * stop the motors
+ */
+ fl.motor = 0;
+ delay(10);
+mb();
+ outb(Pdor, fl.motor | Fintena | Fena);
+mb();
+ delay(10);
+
+ /*
+ * init drives
+ */
+ for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
+ dp->dev = dp - fl.d;
+ dp->dt = T1440kb;
+ floppysetdef(dp);
+ dp->cyl = -1; /* because we don't know */
+ dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024);
+ dp->ccyl = -1;
+ dp->vers = 0;
+ }
+
+ /*
+ * first operation will recalibrate
+ */
+ fl.confused = 1;
+
+ floppysetup1(&fl);
+}
+
+static Chan*
+floppyattach(char *spec)
+{
+ static int kstarted;
+
+ if(kstarted == 0){
+ /*
+ * watchdog to turn off the motors
+ */
+ kstarted = 1;
+ kproc("floppy", floppykproc, 0);
+ }
+ return devattach('f', spec);
+}
+
+static int
+floppywalk(Chan *c, char *name)
+{
+ return devwalk(c, name, floppydir, fl.ndrive*NFDIR, devgen);
+}
+
+static void
+floppystat(Chan *c, char *dp)
+{
+ devstat(c, dp, floppydir, fl.ndrive*NFDIR, devgen);
+}
+
+static Chan*
+floppyopen(Chan *c, int omode)
+{
+ return devopen(c, omode, floppydir, fl.ndrive*NFDIR, devgen);
+}
+
+static void
+floppyclose(Chan *)
+{
+}
+
+static void
+islegal(ulong offset, long n, FDrive *dp)
+{
+ if(offset % dp->t->bytes)
+ error(Ebadarg);
+ if(n % dp->t->bytes)
+ error(Ebadarg);
+}
+
+/*
+ * check if the floppy has been replaced under foot. cause
+ * an error if it has.
+ *
+ * a seek and a read clears the condition. this was determined
+ * experimentally, there has to be a better way.
+ *
+ * if the read fails, cycle through the possible floppy
+ * density till one works or we've cycled through all
+ * possibilities for this drive.
+ */
+static void
+changed(Chan *c, FDrive *dp)
+{
+ ulong old;
+ FType *start;
+
+ /*
+ * if floppy has changed or first time through
+ */
+mb();
+ if((inb(Pdir)&Fchange) || dp->vers == 0){
+mb();
+ DPRINT("changed\n");
+ fldump();
+ dp->vers++;
+ floppysetdef(dp);
+ start = dp->t;
+ dp->confused = 1; /* make floppyon recal */
+DPRINT("b4 floppyon:\n");
+fldump();
+ floppyon(dp);
+DPRINT("after floppyon:\n");
+fldump();
+ floppyseek(dp, dp->t->heads*dp->t->tsize);
+DPRINT("after floppyseek:\n");
+fldump();
+ while(waserror()){
+ while(++dp->t){
+ if(dp->t == &floppytype[nelem(floppytype)])
+ dp->t = floppytype;
+ if(dp->dt == dp->t->dt)
+ break;
+ }
+ floppydir[NFDIR*dp->dev].length = dp->t->cap;
+ floppyon(dp);
+ DPRINT("changed: trying %s\n", dp->t->name);
+ fldump();
+ if(dp->t == start)
+ nexterror();
+ }
+ floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize);
+ poperror();
+ }
+
+ old = c->qid.vers;
+ c->qid.vers = dp->vers;
+ if(old && old != dp->vers)
+ error(Eio);
+}
+
+static int
+readtrack(FDrive *dp, int cyl, int head)
+{
+ int i, nn, sofar;
+ ulong pos;
+
+ nn = dp->t->tsize;
+ if(dp->ccyl==cyl && dp->chead==head)
+ return nn;
+ pos = (cyl*dp->t->heads+head) * nn;
+ for(sofar = 0; sofar < nn; sofar += i){
+ dp->ccyl = -1;
+ i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar);
+ if(i <= 0)
+ return -1;
+ }
+ dp->ccyl = cyl;
+ dp->chead = head;
+ return nn;
+}
+
+static long
+floppyread(Chan *c, void *a, long n, vlong off)
+{
+ FDrive *dp;
+ long rv;
+ int sec, head, cyl;
+ long len;
+ uchar *aa;
+ ulong offset = off;
+
+ if(c->qid.path == CHDIR)
+ return devdirread(c, a, n, floppydir, fl.ndrive*NFDIR, devgen);
+
+ rv = 0;
+ dp = &fl.d[c->qid.path & ~Qmask];
+ switch ((int)(c->qid.path & Qmask)) {
+ case Qdata:
+ islegal(offset, n, dp);
+ aa = a;
+
+ qlock(&fl);
+ if(waserror()){
+ qunlock(&fl);
+ nexterror();
+ }
+ floppyon(dp);
+ changed(c, dp);
+ for(rv = 0; rv < n; rv += len){
+ /*
+ * all xfers come out of the track cache
+ */
+ dp->len = n - rv;
+ floppypos(dp, offset+rv);
+ cyl = dp->tcyl;
+ head = dp->thead;
+ len = dp->len;
+ sec = dp->tsec;
+ if(readtrack(dp, cyl, head) < 0)
+ break;
+ memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len);
+ }
+ qunlock(&fl);
+ poperror();
+
+ break;
+ case Qctl:
+ return readstr(offset, a, n, dp->t->name);
+ default:
+ panic("floppyread: bad qid");
+ }
+
+ return rv;
+}
+
+#define SNCMP(a, b) strncmp(a, b, sizeof(b)-1)
+static long
+floppywrite(Chan *c, void *a, long n, vlong off)
+{
+ FDrive *dp;
+ long rv, i;
+ char *aa = a;
+ char ctlmsg[64];
+ ulong offset = off;
+
+ rv = 0;
+ dp = &fl.d[c->qid.path & ~Qmask];
+ switch ((int)(c->qid.path & Qmask)) {
+ case Qdata:
+ islegal(offset, n, dp);
+ qlock(&fl);
+ if(waserror()){
+ qunlock(&fl);
+ nexterror();
+ }
+ floppyon(dp);
+ changed(c, dp);
+ for(rv = 0; rv < n; rv += i){
+ floppypos(dp, offset+rv);
+ if(dp->tcyl == dp->ccyl)
+ dp->ccyl = -1;
+ i = floppyxfer(dp, Fwrite, aa+rv, offset+rv, n-rv);
+ if(i < 0)
+ break;
+ if(i == 0)
+ error(Eio);
+ }
+ qunlock(&fl);
+ poperror();
+ break;
+ case Qctl:
+ rv = n;
+ qlock(&fl);
+ if(waserror()){
+ qunlock(&fl);
+ nexterror();
+ }
+ if(n >= sizeof(ctlmsg))
+ n = sizeof(ctlmsg) - 1;
+ memmove(ctlmsg, aa, n);
+ ctlmsg[n] = 0;
+ if(SNCMP(ctlmsg, "eject") == 0){
+ floppyeject(dp);
+ } else if(SNCMP(ctlmsg, "reset") == 0){
+ fl.confused = 1;
+ floppyon(dp);
+ } else if(SNCMP(ctlmsg, "format") == 0){
+ floppyformat(dp, ctlmsg);
+ } else if(SNCMP(ctlmsg, "debug") == 0){
+ floppydebug = 1;
+ } else
+ error(Ebadctl);
+ poperror();
+ qunlock(&fl);
+ break;
+ default:
+ panic("floppywrite: bad qid");
+ }
+
+ return rv;
+}
+
+static void
+floppykproc(void *)
+{
+ FDrive *dp;
+
+ while(waserror())
+ ;
+ for(;;){
+ for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
+ if((fl.motor&MOTORBIT(dp->dev))
+ && TK2SEC(m->ticks - dp->lasttouched) > 5
+ && canqlock(&fl)){
+ if(TK2SEC(m->ticks - dp->lasttouched) > 5)
+ floppyoff(dp);
+ qunlock(&fl);
+ }
+ }
+ tsleep(&fl.kr, return0, 0, 1000);
+ }
+}
+
+/*
+ * start a floppy drive's motor.
+ */
+static void
+floppyon(FDrive *dp)
+{
+ int alreadyon;
+ int tries;
+
+ if(fl.confused)
+ floppyrevive();
+
+ /* start motor and select drive */
+ alreadyon = fl.motor & MOTORBIT(dp->dev);
+ fl.motor |= MOTORBIT(dp->dev);
+mb();
+ outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
+mb();
+ if(!alreadyon){
+ /* wait for drive to spin up */
+ tsleep(&dp->r, return0, 0, 750);
+
+ /* clear any pending interrupts */
+ floppysense();
+ }
+
+ /* set transfer rate */
+ if(fl.rate != dp->t->rate){
+ fl.rate = dp->t->rate;
+mb();
+ outb(Pdsr, fl.rate);
+mb();
+ }
+
+ /* get drive to a known cylinder */
+ if(dp->confused)
+ for(tries = 0; tries < 4; tries++)
+ if(floppyrecal(dp) >= 0)
+ break;
+ dp->lasttouched = m->ticks;
+ fl.selected = dp;
+}
+
+/*
+ * stop the floppy if it hasn't been used in 5 seconds
+ */
+static void
+floppyoff(FDrive *dp)
+{
+ fl.motor &= ~MOTORBIT(dp->dev);
+mb();
+ outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
+mb();
+}
+
+/*
+ * send a command to the floppy
+ */
+static int
+floppycmd(void)
+{
+ int i;
+ int tries;
+
+ fl.nstat = 0;
+ for(i = 0; i < fl.ncmd; i++){
+ for(tries = 0; ; tries++){
+mb();
+ if((inb(Pmsr)&(Ffrom|Fready)) == Fready)
+ break;
+mb();
+ if(tries > 1000){
+ DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i);
+ fldump();
+
+ /* empty fifo, might have been a bad command */
+ floppyresult();
+ return -1;
+ }
+ microdelay(8); /* for machine independence */
+ }
+mb();
+ outb(Pfdata, fl.cmd[i]);
+mb();
+ }
+ return 0;
+}
+
+/*
+ * get a command result from the floppy
+ *
+ * when the controller goes ready waiting for a command
+ * (instead of sending results), we're done
+ *
+ */
+static int
+floppyresult(void)
+{
+ int i, s;
+ int tries;
+
+ /* get the result of the operation */
+ for(i = 0; i < sizeof(fl.stat); i++){
+ /* wait for status byte */
+ for(tries = 0; ; tries++){
+mb();
+ s = inb(Pmsr)&(Ffrom|Fready);
+mb();
+ if(s == Fready){
+ fl.nstat = i;
+ return fl.nstat;
+ }
+ if(s == (Ffrom|Fready))
+ break;
+ if(tries > 1000){
+ DPRINT("floppyresult: %d stats\n", i);
+ fldump();
+ fl.confused = 1;
+ return -1;
+ }
+ microdelay(8); /* for machine independence */
+ }
+mb();
+ fl.stat[i] = inb(Pfdata);
+mb();
+// print("stat[%d]: %.2ux\n", i, fl.stat[i]);
+ }
+ fl.nstat = sizeof(fl.stat);
+ return fl.nstat;
+}
+
+/*
+ * calculate physical address of a logical byte offset into the disk
+ *
+ * truncate dp->length if it crosses a track boundary
+ */
+static void
+floppypos(FDrive *dp, long off)
+{
+ int lsec;
+ int ltrack;
+ int end;
+
+ lsec = off/dp->t->bytes;
+ ltrack = lsec/dp->t->sectors;
+ dp->tcyl = ltrack/dp->t->heads;
+ dp->tsec = (lsec % dp->t->sectors) + 1;
+ dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
+
+ /*
+ * can't read across track boundaries.
+ * if so, decrement the bytes to be read.
+ */
+ end = (ltrack+1)*dp->t->sectors*dp->t->bytes;
+ if(off+dp->len > end)
+ dp->len = end - off;
+}
+
+/*
+ * get the interrupt cause from the floppy.
+ */
+static int
+floppysense(void)
+{
+ fl.ncmd = 0;
+ fl.cmd[fl.ncmd++] = Fsense;
+ if(floppycmd() < 0)
+ return -1;
+ if(floppyresult() < 2){
+ DPRINT("can't read sense response\n");
+ fldump();
+ fl.confused = 1;
+ return -1;
+ }
+ return 0;
+}
+
+static int
+cmddone(void *)
+{
+ return fl.ncmd == 0;
+}
+
+/*
+ * Wait for a floppy interrupt. If none occurs in 5 seconds, we
+ * may have missed one. This only happens on some portables which
+ * do power management behind our backs. Call the interrupt
+ * routine to try to clear any conditions.
+ */
+static void
+floppywait(void)
+{
+ tsleep(&fl.r, cmddone, 0, 5000);
+ if(!cmddone(0)){
+ floppyintr(0);
+ fl.confused = 1;
+ }
+}
+
+/*
+ * we've lost the floppy position, go to cylinder 0.
+ */
+static int
+floppyrecal(FDrive *dp)
+{
+ dp->ccyl = -1;
+ dp->cyl = -1;
+
+ fl.ncmd = 0;
+ fl.cmd[fl.ncmd++] = Frecal;
+ fl.cmd[fl.ncmd++] = dp->dev;
+ if(floppycmd() < 0)
+ return -1;
+ floppywait();
+ if(fl.nstat < 2){
+mb();
+ DPRINT("recalibrate: confused %ux\n", inb(Pmsr));
+mb();
+ fl.confused = 1;
+ return -1;
+ }
+ if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
+ DPRINT("recalibrate: failed\n");
+ dp->confused = 1;
+ return -1;
+ }
+ dp->cyl = fl.stat[1];
+ if(dp->cyl != 0){
+ DPRINT("recalibrate: wrong cylinder %d\n", dp->cyl);
+ dp->cyl = -1;
+ dp->confused = 1;
+ return -1;
+ }
+
+ dp->confused = 0;
+ return 0;
+}
+
+/*
+ * if the controller or a specific drive is in a confused state,
+ * reset it and get back to a kown state
+ */
+static void
+floppyrevive(void)
+{
+ FDrive *dp;
+
+ /*
+ * reset the controller if it's confused
+ */
+ if(fl.confused){
+ DPRINT("floppyrevive in\n");
+ fldump();
+
+ /* reset controller and turn all motors off */
+ splhi();
+ fl.ncmd = 1;
+ fl.cmd[0] = 0;
+mb();
+ outb(Pdor, 0);
+mb();
+ delay(10);
+mb();
+ outb(Pdor, Fintena|Fena);
+mb();
+ delay(10);
+ spllo();
+ fl.motor = 0;
+ fl.confused = 0;
+ floppywait();
+
+ /* mark all drives in an unknown state */
+ for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++)
+ dp->confused = 1;
+
+ /* set rate to a known value */
+mb();
+ outb(Pdsr, 0);
+mb();
+ fl.rate = 0;
+
+ DPRINT("floppyrevive out\n");
+ fldump();
+ }
+}
+
+/*
+ * seek to the target cylinder
+ *
+ * interrupt, no results
+ */
+static long
+floppyseek(FDrive *dp, long off)
+{
+ floppypos(dp, off);
+ if(dp->cyl == dp->tcyl)
+ return dp->tcyl;
+ dp->cyl = -1;
+
+ fl.ncmd = 0;
+ fl.cmd[fl.ncmd++] = Fseek;
+ fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
+ fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps;
+ if(floppycmd() < 0)
+ return -1;
+ floppywait();
+ if(fl.nstat < 2){
+ DPRINT("seek: confused\n");
+ fl.confused = 1;
+ return -1;
+ }
+ if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
+ DPRINT("seek: failed\n");
+ dp->confused = 1;
+ return -1;
+ }
+
+ dp->cyl = dp->tcyl;
+ return dp->tcyl;
+}
+
+/*
+ * read or write to floppy. try up to three times.
+ */
+static long
+floppyxfer(FDrive *dp, int cmd, void *a, long off, long n)
+{
+ long offset;
+ int tries;
+
+ if(off >= dp->t->cap)
+ return 0;
+ if(off + n > dp->t->cap)
+ n = dp->t->cap - off;
+
+ /* retry on error (until it gets ridiculous) */
+ tries = 0;
+ while(waserror()){
+ if(tries++ > 20)
+ nexterror();
+ DPRINT("floppyxfer: retrying\n");
+ /*floppyon(dp);*/
+ }
+
+ dp->len = n;
+ if(floppyseek(dp, off) < 0){
+ DPRINT("xfer: seek failed\n");
+ dp->confused = 1;
+ error(Eio);
+ }
+
+ /*
+ * set up the dma (dp->len may be trimmed)
+ */
+ if(waserror()){
+ dmaend(DMAchan);
+ nexterror();
+ }
+ dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread);
+ if(dp->len < 0)
+ error(Eio);
+
+ /*
+ * start operation
+ */
+ fl.ncmd = 0;
+ fl.cmd[fl.ncmd++] = cmd | (dp->t->heads > 1 ? Fmulti : 0);
+ fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
+ fl.cmd[fl.ncmd++] = dp->tcyl;
+ fl.cmd[fl.ncmd++] = dp->thead;
+ fl.cmd[fl.ncmd++] = dp->tsec;
+ fl.cmd[fl.ncmd++] = dp->t->bcode;
+ fl.cmd[fl.ncmd++] = dp->t->sectors;
+ fl.cmd[fl.ncmd++] = dp->t->gpl;
+ fl.cmd[fl.ncmd++] = 0xFF;
+ if(floppycmd() < 0)
+ error(Eio);
+
+ /* Poll ready bits and transfer data */
+ floppyexec((char*)a, dp->len, cmd==Fread);
+
+ /*
+ * give bus to DMA, floppyintr() will read result
+ */
+ floppywait();
+ dmaend(DMAchan);
+ poperror();
+
+ /*
+ * check for errors
+ */
+ if(fl.nstat < 7){
+ DPRINT("xfer: confused\n");
+ fl.confused = 1;
+ error(Eio);
+ }
+ if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){
+ DPRINT("xfer: failed %ux %ux %ux\n", fl.stat[0],
+ fl.stat[1], fl.stat[2]);
+ DPRINT("offset %lud len %ld\n", off, dp->len);
+ if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun){
+ DPRINT("DMA overrun: retry\n");
+ } else
+ dp->confused = 1;
+ error(Eio);
+ }
+
+ /*
+ * check for correct cylinder
+ */
+ offset = fl.stat[3] * dp->t->heads + fl.stat[4];
+ offset = offset*dp->t->sectors + fl.stat[5] - 1;
+ offset = offset * c2b[fl.stat[6]];
+ if(offset != off+dp->len){
+ DPRINT("xfer: ends on wrong cyl\n");
+ dp->confused = 1;
+ error(Eio);
+ }
+ poperror();
+
+ dp->lasttouched = m->ticks;
+ return dp->len;
+}
+
+/*
+ * format a track
+ */
+static void
+floppyformat(FDrive *dp, char *params)
+{
+ int cyl, h, sec;
+ ulong track;
+ uchar *buf, *bp;
+ FType *t;
+ char *f[3];
+
+ /*
+ * set the type
+ */
+ if(parsefields(params, f, 3, " ") > 1){
+ for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
+ if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){
+ dp->t = t;
+ floppydir[NFDIR*dp->dev].length = dp->t->cap;
+ break;
+ }
+ }
+ if(t >= &floppytype[nelem(floppytype)])
+ error(Ebadarg);
+ } else {
+ floppysetdef(dp);
+ t = dp->t;
+ }
+
+ /*
+ * buffer for per track info
+ */
+ buf = smalloc(t->sectors*4);
+ if(waserror()){
+ free(buf);
+ nexterror();
+ }
+
+ /* force a recalibrate to cylinder 0 */
+ dp->confused = 1;
+ if(!waserror()){
+ floppyon(dp);
+ poperror();
+ }
+
+ /*
+ * format a track at time
+ */
+ for(track = 0; track < t->tracks*t->heads; track++){
+ cyl = track/t->heads;
+ h = track % t->heads;
+
+ /*
+ * seek to track, ignore errors
+ */
+ floppyseek(dp, track*t->tsize);
+ dp->cyl = cyl;
+ dp->confused = 0;
+
+ /*
+ * set up the dma (dp->len may be trimmed)
+ */
+ bp = buf;
+ for(sec = 1; sec <= t->sectors; sec++){
+ *bp++ = cyl;
+ *bp++ = h;
+ *bp++ = sec;
+ *bp++ = t->bcode;
+ }
+ if(waserror()){
+ dmaend(DMAchan);
+ nexterror();
+ }
+ if(dmasetup(DMAchan, buf, bp-buf, 0) < 0)
+ error(Eio);
+
+ /*
+ * start operation
+ */
+ fl.ncmd = 0;
+ fl.cmd[fl.ncmd++] = Fformat;
+ fl.cmd[fl.ncmd++] = (h<<2) | dp->dev;
+ fl.cmd[fl.ncmd++] = t->bcode;
+ fl.cmd[fl.ncmd++] = t->sectors;
+ fl.cmd[fl.ncmd++] = t->fgpl;
+ fl.cmd[fl.ncmd++] = 0x5a;
+ if(floppycmd() < 0)
+ error(Eio);
+
+ /* Poll ready bits and transfer data */
+ floppyexec((char *)buf, bp-buf, 0);
+
+ /*
+ * give bus to DMA, floppyintr() will read result
+ */
+ floppywait();
+ dmaend(DMAchan);
+ poperror();
+
+ /*
+ * check for errors
+ */
+ if(fl.nstat < 7){
+ DPRINT("format: confused\n");
+ fl.confused = 1;
+ error(Eio);
+ }
+ if((fl.stat[0]&Codemask)!=0 || fl.stat[1]|| fl.stat[2]){
+ DPRINT("format: failed %ux %ux %ux\n",
+ fl.stat[0], fl.stat[1], fl.stat[2]);
+ dp->confused = 1;
+ error(Eio);
+ }
+ }
+ free(buf);
+ dp->confused = 1;
+ poperror();
+}
+
+static void
+floppyintr(Ureg *)
+{
+ switch(fl.cmd[0]&~Fmulti){
+ case Fread:
+ case Fwrite:
+ case Fformat:
+ case Fdumpreg:
+ floppyresult();
+ break;
+ case Fseek:
+ case Frecal:
+ default:
+ floppysense(); /* to clear interrupt */
+ break;
+ }
+ fl.ncmd = 0;
+ wakeup(&fl.r);
+}
+
+Dev floppydevtab = {
+ 'f',
+ "floppy",
+
+ floppyreset,
+ devinit,
+ floppyattach,
+ devclone,
+ floppywalk,
+ floppystat,
+ floppyopen,
+ devcreate,
+ floppyclose,
+ floppyread,
+ devbread,
+ floppywrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
A alphapc/devvga.c => alphapc/devvga.c +331 -0
@@ 0,0 1,331 @@
+/*
+ */
+#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"
+
+enum {
+ Qdir,
+ Qvgaiob,
+ Qvgaiow,
+ Qvgaiol,
+ Qvgactl,
+};
+
+static Dirtab vgadir[] = {
+ "vgaiob", { Qvgaiob, 0 }, 0, 0660,
+ "vgaiow", { Qvgaiow, 0 }, 0, 0660,
+ "vgaiol", { Qvgaiol, 0 }, 0, 0660,
+ "vgactl", { Qvgactl, 0 }, 0, 0660,
+};
+
+static void
+vgareset(void)
+{
+ conf.monitor = 1;
+}
+
+static Chan*
+vgaattach(char* spec)
+{
+ if(*spec && strcmp(spec, "0"))
+ error(Eio);
+ return devattach('v', spec);
+}
+
+int
+vgawalk(Chan* c, char* name)
+{
+ return devwalk(c, name, vgadir, nelem(vgadir), devgen);
+}
+
+static void
+vgastat(Chan* c, char* dp)
+{
+ devstat(c, dp, vgadir, nelem(vgadir), devgen);
+}
+
+static Chan*
+vgaopen(Chan* c, int omode)
+{
+ return devopen(c, omode, vgadir, nelem(vgadir), devgen);
+}
+
+static void
+vgaclose(Chan*)
+{
+}
+
+static long
+vgaread(Chan* c, void* a, long n, vlong off)
+{
+ int len, port;
+ char *p, *s;
+ ushort *sp;
+ ulong *lp;
+ VGAscr *scr;
+ ulong offset = off;
+
+ switch(c->qid.path & ~CHDIR){
+
+ case Qdir:
+ return devdirread(c, a, n, vgadir, nelem(vgadir), devgen);
+
+ case Qvgactl:
+ scr = &vgascreen[0];
+
+ p = malloc(READSTR);
+ if(waserror()){
+ free(p);
+ nexterror();
+ }
+ if(scr->dev)
+ s = scr->dev->name;
+ else
+ s = "cga";
+ len = snprint(p, READSTR, "type: %s\n", s);
+ if(scr->gscreen)
+ len += snprint(p+len, READSTR-len, "size: %dx%dx%d\n",
+ scr->gscreen->r.max.x, scr->gscreen->r.max.y,
+ 1<<scr->gscreen->ldepth);
+ if(scr->cur)
+ s = scr->cur->name;
+ else
+ s = "off";
+ len += snprint(p+len, READSTR-len, "hwgc: %s\n", s);
+ snprint(p+len, READSTR-len, "addr: 0x%lux\n", scr->aperture);
+
+ n = readstr(offset, a, n, p);
+ poperror();
+ free(p);
+
+ return n;
+
+ case Qvgaiob:
+ port = offset;
+ for(p = a; port < offset+n; port++)
+ *p++ = inb(port);
+ return n;
+
+ case Qvgaiow:
+ if((n & 0x01) || (offset & 0x01))
+ error(Ebadarg);
+ n /= 2;
+ sp = a;
+ for(port = offset; port < offset+n; port += 2)
+ *sp++ = ins(port);
+ return n*2;
+
+ case Qvgaiol:
+ if((n & 0x03) || (offset & 0x03))
+ error(Ebadarg);
+ n /= 4;
+ lp = a;
+ for(port = offset; port < offset+n; port += 4)
+ *lp++ = inl(port);
+ return n*4;
+
+ default:
+ error(Egreg);
+ break;
+ }
+
+ return 0;
+}
+
+static void
+vgactl(char* a)
+{
+ int align, i, n, size, x, y, z;
+ char *field[4], *p;
+ VGAscr *scr;
+ extern VGAdev *vgadev[];
+ extern VGAcur *vgacur[];
+
+ n = parsefields(a, field, 4, " ");
+ if(n < 2)
+ 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 < 2)
+ error(Ebadarg);
+ 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++;
+
+ switch(strtoul(p, &p, 0)){
+ case 8:
+ z = 3;
+ break;
+
+ default:
+ z = 0;
+ error(Ebadarg);
+ }
+
+ cursoroff(1);
+ if(screensize(x, y, z))
+ error(Egreg);
+ vgascreenwin(scr);
+ cursoron(1);
+ 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;
+ }
+
+ error(Ebadarg);
+}
+
+static long
+vgawrite(Chan* c, void* a, long n, vlong off)
+{
+ int port;
+ char *p;
+ ushort *sp;
+ ulong *lp;
+ ulong offset = off;
+
+ switch(c->qid.path & ~CHDIR){
+
+ 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;
+
+ case Qvgaiob:
+ p = a;
+ for(port = offset; port < offset+n; port++)
+ outb(port, *p++);
+ return n;
+
+ case Qvgaiow:
+ if((n & 01) || (offset & 01))
+ error(Ebadarg);
+ n /= 2;
+ sp = a;
+ for(port = offset; port < offset+n; port += 2)
+ outs(port, *sp++);
+ return n*2;
+
+ case Qvgaiol:
+ if((n & 0x03) || (offset & 0x03))
+ error(Ebadarg);
+ n /= 4;
+ lp = a;
+ for(port = offset; port < offset+n; port += 4)
+ outl(port, *lp++);
+ return n*4;
+
+ default:
+ error(Egreg);
+ break;
+ }
+
+ return 0;
+}
+
+Dev vgadevtab = {
+ 'v',
+ "vga",
+
+ vgareset,
+ devinit,
+ vgaattach,
+ devclone,
+ vgawalk,
+ vgastat,
+ vgaopen,
+ devcreate,
+ vgaclose,
+ vgaread,
+ devbread,
+ vgawrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
A alphapc/dma.c => alphapc/dma.c +232 -0
@@ 0,0 1,232 @@
+#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;
+
+enum
+{
+ /*
+ * the byte registers for DMA0 are all one byte apart
+ */
+ Dma0= 0x00,
+ Dma0status= Dma0+0x8, /* status port */
+ Dma0reset= Dma0+0xD, /* reset port */
+
+ /*
+ * the byte registers for DMA1 are all two bytes apart (why?)
+ */
+ Dma1= 0xC0,
+ Dma1status= Dma1+2*0x8, /* status port */
+ Dma1reset= Dma1+2*0xD, /* reset port */
+};
+
+/*
+ * state of a dma transfer
+ */
+struct DMAxfer
+{
+ ulong bpa; /* bounce buffer physical address */
+ void* bva; /* bounce buffer virtual address */
+ 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 },
+};
+
+/*
+ * 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
+dmainit(int chan)
+{
+ DMA *dp;
+ DMAxfer *xp;
+ ulong v;
+
+ dp = &dma[(chan>>2)&1];
+ chan = chan & 3;
+ xp = &dp->x[chan];
+ if(xp->bva != nil)
+ return;
+
+ v = (ulong)xalloc(BY2PG+BY2PG);
+ if(v == 0 || PADDR(v) >= 16*MB){
+ print("dmainit: chan %d: 0x%luX out of range\n", chan, v);
+ xfree((void*)v);
+ v = 0;
+ }
+ xp->bva = (void*)ROUND(v, BY2PG);
+ xp->bpa = PADDR(xp->bva);
+ xp->len = 0;
+ xp->isread = 0;
+}
+
+/*
+ * 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];
+
+ /*
+ * if this isn't kernel memory or crossing 64k boundary or above 16 meg
+ * use the allocated low memory page.
+ */
+ pa = PADDR(va);
+ if((((ulong)va)&0xF0000000) != KZERO
+ || (pa&0xFFFF0000) != ((pa+len)&0xFFFF0000)
+ || pa >= 16*MB) {
+ if(xp->bva == nil)
+ return -1;
+ if(len > BY2PG)
+ len = BY2PG;
+ if(!isread)
+ memmove(xp->bva, va, len);
+ xp->va = va;
+ xp->len = len;
+ xp->isread = isread;
+ pa = xp->bpa;
+ }
+ else
+ xp->len = 0;
+
+ /*
+ * this setup must be atomic
+ */
+ ilock(dp);
+ mode = (isread ? 0x44 : 0x48) | chan;
+ outb(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */
+ outb(dp->page[chan], pa>>16);
+ outb(dp->cbp, 0); /* set count & address to their first byte */
+ outb(dp->addr[chan], pa>>dp->shift); /* set address */
+ outb(dp->addr[chan], pa>>(8+dp->shift));
+ 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);
+
+ 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;
+
+ /*
+ * 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);
+}
+ */
A alphapc/etherif.h => alphapc/etherif.h +33 -0
@@ 0,0 1,33 @@
+enum {
+ MaxEther = 24,
+ Ntypes = 8,
+};
+
+typedef struct Ether Ether;
+struct Ether {
+ ISAConf; /* hardware info */
+
+ int ctlrno;
+ int tbdf; /* type+busno+devno+funcno */
+ int mbps; /* Mbps */
+ uchar ea[Eaddrlen];
+
+ void (*attach)(Ether*); /* filled in by reset routine */
+ void (*transmit)(Ether*);
+ void (*interrupt)(Ureg*, void*);
+ long (*ifstat)(Ether*, void*, long, ulong);
+ void *ctlr;
+
+ Queue* oq;
+
+ Netif;
+};
+
+extern Block* etheriq(Ether*, Block*, int);
+extern void addethercard(char*, int(*)(Ether*));
+extern ulong ethercrc(uchar*, int);
+
+#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))
A alphapc/faultalpha.c => alphapc/faultalpha.c +63 -0
@@ 0,0 1,63 @@
+#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[ERRLEN];
+ 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);
+iprint("ptbr %lux up %lux\n", (ulong)m->ptbr, up);
+if(up) iprint("top %lux lvl2 %lux\n", up->mmutop->va, up->mmulvl2->va);
+if(up) iprint("top[N-1] %lux\n", ((uvlong *)up->mmutop->va)[PTE2PG-1]);
+ iprint("st=0x%lux pc=0x%lux sp=0x%lux\n", (ulong)ur->status, (ulong)ur->pc, (ulong)ur->sp);
+ dumpregs(ur);
+ panic("fault");
+}
+
+/*
+ * called in sysfile.c
+ */
+void
+evenaddr(ulong addr)
+{
+ if(addr & 3){
+ postnote(up, 1, "sys: odd address", NDebug);
+ error(Ebadarg);
+ }
+}
A alphapc/floppy.h => alphapc/floppy.h +173 -0
@@ 0,0 1,173 @@
+typedef struct FController FController;
+typedef struct FDrive FDrive;
+typedef struct FType FType;
+
+static void floppyintr(Ureg*);
+static void 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 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 = 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(VectorPIC+IrqFLOPPY, pcfloppyintr, fl, BUSUNKNOWN);
+}
+
+/*
+ * 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;
+}
A alphapc/fns.h => alphapc/fns.h +108 -0
@@ 0,0 1,108 @@
+#include "../port/portfns.h"
+
+void addclock0link(void (*)(void));
+void archinit(void);
+void arginit(void);
+void arith(void);
+void clearmmucache(void);
+void clock(Ureg*);
+void clockinit(void);
+#define coherence mb
+int cistrcmp(char*, char*);
+int cistrncmp(char*, char*, int);
+void cpuidprint(void);
+void cserve(ulong, ulong);
+int dmacount(int);
+int dmadone(int);
+void dmaend(int);
+void dmainit(int);
+long dmasetup(int, void*, long, int);
+void evenaddr(ulong);
+void fataltrap(Ureg *, char *);
+void fault0(void);
+void faultalpha(Ureg*);
+ulong fcr31(void);
+void firmware(void);
+#define flushpage(s) icflush()
+void fpenab(int);
+void fptrap(Ureg*);
+ulong getcallerpc(void*);
+char *getconf(char*);
+ulong getfcr(void);
+ulong getstatus(void);
+void gotopc(ulong);
+int i8042auxcmd(int);
+void i8042auxenable(void (*)(int, int));
+void i8042reset(void);
+void i8259init(void);
+int i8259enable(int, int, Irqctl*);
+#define idlehands() /* nothing to do in the runproc */
+void icflush(void);
+void illegal0(void);
+void intr(Ureg*);
+void intr0(void);
+void intrenable(int, void (*)(Ureg*, void*), void*, int);
+int iprint(char*, ...);
+int isaconfig(char*, int, ISAConf*);
+void kbdinit(void);
+void *kmapv(uvlong, int);
+int kprint(char*, ...);
+void launchinit(void);
+void launch(int);
+void links(void);
+void mb(void);
+ulong meminit(void);
+void mmuinit(void);
+#define mmunewpage(x)
+void mntdump(void);
+void ns16552special(int, int, Queue**, Queue**, int (*)(Queue*, int));
+void ns16552setup(ulong, ulong, char*);
+void ns16552install(void);
+void ns16552intr(int);
+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 pcihinv(Pcidev*);
+Pcidev* pcimatch(Pcidev*, int, int);
+void pcireset(void);
+void prflush(void);
+void printinit(void);
+#define procrestore(p)
+#define procsave(p)
+#define procsetup(p) ((p)->fpstate = FPinit)
+void restfpregs(FPsave*);
+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);
+void wrent(int, void*);
+void wrvptptr(uvlong);
+
+#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
+#define kmapperm(x) kmap(x)
+#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))
A alphapc/fptrap.c => alphapc/fptrap.c +46 -0
@@ 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[ERRLEN];
+ 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;
+}
A alphapc/i8259.c => alphapc/i8259.c +151 -0
@@ 0,0 1,151 @@
+#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;
+
+ 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, Irqctl* irqctl)
+{
+ if(v < VectorPIC || v > MaxVectorPIC){
+ iprint("i8259enable: vector %d out of range\n", v);
+ return -1;
+ }
+ v -= VectorPIC;
+
+ /*
+ * 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))
+ irqctl->eoi = i8259isr;
+ else
+ irqctl->isr = i8259isr;
+ irqctl->isintr = 1;
+
+ return v;
+}
A alphapc/io.h => alphapc/io.h +204 -0
@@ 0,0 1,204 @@
+enum {
+ Uart0 = 0x3F8,
+ Uart1 = 0x2F8,
+ UartFREQ = 1843200,
+};
+
+enum {
+/* VectorPIC = 32, /* external i8259 interrupts */
+ 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,
+ MaxIrqPIC = 15,
+
+/* deprecated: */
+ VectorPIC = 128, /* external [A]PIC interrupts */
+ VectorCLOCK = VectorPIC+0,
+ VectorKBD = VectorPIC+1,
+ VectorUART1 = VectorPIC+3,
+ VectorUART0 = VectorPIC+4,
+ VectorPCMCIA = VectorPIC+5,
+ VectorFLOPPY = VectorPIC+6,
+ VectorLPT = VectorPIC+7,
+ VectorIRQ7 = VectorPIC+7,
+ VectorAUX = VectorPIC+12, /* PS/2 port */
+ VectorIRQ13 = VectorPIC+13, /* corocessor on x386 */
+ VectorATA0 = VectorPIC+14,
+ MaxVectorPIC = VectorPIC+15,
+ VectorPCI = 16, /* PCI bus (PLD) */
+};
+
+typedef struct Irq {
+ void (*f)(Ureg*, void*); /* handler to call */
+ void* a; /* argument to call it with */
+
+ Irq* next; /* link to next handler */
+} Irq;
+
+typedef struct Irqctl {
+ int (*isr)(int); /* get isr bit for this irq */
+ int (*eoi)(int); /* eoi */
+ int isintr;
+
+ Irq* irq; /* handlers on this IRQ */
+} Irqctl;
+
+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,
+
+ PciINTL = 0x3C, /* interrupt line */
+ PciINTP = 0x3D, /* interrupt pin */
+};
+
+enum { /* type 0 pre-defined header */
+ PciBAR2 = 0x18,
+ PciBAR3 = 0x1C,
+ PciBAR4 = 0x20,
+ PciBAR5 = 0x24,
+ 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 */
+
+ struct {
+ ulong bar; /* base address */
+ int size;
+ } mem[3];
+
+ uchar intl; /* interrupt line */
+ ushort ccru;
+
+
+ Pcidev* list;
+ Pcidev* bridge; /* down a bus */
+ Pcidev* link; /* next device on this bno */
+};
+
+/*
+ * 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;
+};
+
+/*
+ * SCSI bus
+ */
+enum {
+ MaxScsi = 8,
+ NTarget = 8, /* should be 16... */
+};
+struct Target {
+ int ctlrno;
+ int target;
+ uchar* inq;
+ uchar* scratch;
+
+ Rendez rendez;
+
+ int ok;
+};
+
+typedef int (*Scsiio)(Target*, int, uchar*, int, void*, int*);
+
+typedef struct SCSIdev {
+ char* type;
+ Scsiio (*reset)(int, ISAConf*);
+} SCSIdev;
A alphapc/kbd.c => alphapc/kbd.c +417 -0
@@ 0,0 1,417 @@
+#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= Spec|0x40, /* function key */
+ 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= View,
+ Right= View,
+ End= '\r',
+ Down= View,
+ Pgdown= View,
+ Ins= KF|20,
+ Del= 0x7F,
+};
+
+uchar 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, KF|12, '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,
+};
+
+uchar 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, KF|12, '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,
+};
+
+uchar 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,
+};
+
+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 uchar 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)){
+ 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(VectorAUX, i8042intr, 0, BUSUNKNOWN);
+ iunlock(&i8042lock);
+}
+
+void
+kbdinit(void)
+{
+ int c, x;
+
+ kbdq = qopen(4*1024, 0, 0, 0);
+ if(kbdq == nil)
+ panic("kbdinit");
+ qnoblock(kbdq, 1);
+
+ intrenable(VectorKBD, i8042intr, 0, BUSUNKNOWN);
+
+ /* wait for a quiescent controller */
+ while((c = inb(Status)) & (Outbusy | Inready))
+ if(c & Inready) {
+ x = inb(Data);
+ USED(x);
+ }
+
+ /* 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();
+}
A alphapc/l.s => alphapc/l.s +381 -0
@@ 0,0 1,381 @@
+#include "mem.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 $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 */
+
+ TRAPB
+ MOVQ $1, R1
+ SLLQ $59, R1 /* normal rounding mode */
+ MOVQ R1, (R30)
+ MOVT (R30), F1
+ MOVT F1, FPCR
+ TRAPB
+
+ MOVT $0.5, F28
+ ADDT F28, F28, F29
+ ADDT F29, F29, F30
+
+ 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 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 $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 getcallerpc(SB), $-8
+ MOVL 0(SP), R0
+ RET
+
+TEXT fpenab(SB), $-8
+ MOVQ R0, R16
+ CALL_PAL $PALwrfen
+ 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)
+ RET
+
+TEXT restfpregs(SB), $-8
+ 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
A alphapc/main.c => alphapc/main.c +401 -0
@@ 0,0 1,401 @@
+#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;
+
+void
+main(void)
+{
+ hwrpb = (Hwrpb*)0x10000000;
+ hwrpb = (Hwrpb*)(KZERO|hwrpb->phys);
+ arginit();
+ machinit();
+ clockinit();
+ confinit();
+ archinit();
+ savefpregs(&initfp);
+ mmuinit();
+ xinit();
+ printinit();
+ if (arch->coreinit)
+ arch->coreinit();
+ trapinit();
+
+ /* console */
+ screeninit();
+ ns16552install();
+ ns16552special(0, 9600, 0, &printq, kbdcr2nl);
+ kbdinit();
+
+ cpuidprint();
+ if (arch->corehello)
+ arch->corehello();
+
+#ifdef NEVER
+ percpu = hwrpb + (hwrpb[40]>>2);
+// percpu[32] |= 2; /* restart capable */
+ percpu[32] &= ~1; /* boot in progress - not */
+// percpu[32] |= (3<<16); /* warm boot requested */
+// percpu[32] |= (2<<16); /* cold boot requested */
+// percpu[32] |= (4<<16); /* stay halted */
+ percpu[32] |= (0<<16); /* default action */
+#endif
+
+ pageinit();
+ procinit0();
+ initseg();
+ links();
+ chandevreset();
+ swapinit();
+ userinit();
+ schedinit();
+}
+
+/*
+ * initialize a processor's mach structure. each processor does this
+ * for itself.
+ */
+void
+machinit(void)
+{
+ int n;
+
+ icflush();
+ n = m->machno;
+ memset(m, 0, sizeof(Mach));
+ m->machno = n;
+
+ active.exiting = 0;
+ active.machs = 1;
+}
+
+void
+init0(void)
+{
+ char buf[2*NAMELEN];
+
+ 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);
+ up->dot = cclone(up->slash, 0);
+
+ chandevinit();
+
+ if(!waserror()){
+ ksetenv("cputype", "alpha");
+ sprint(buf, "alpha %s axp", conffile);
+ ksetenv("terminal", buf);
+ ksetenv("sysname", sysname);
+ 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;
+
+ strcpy(p->text, "*init*");
+ strcpy(p->user, eve);
+
+ p->fpstate = FPinit;
+ p->fpsave.fpstatus = initfp.fpstatus;
+ fpenab(0);
+
+ /*
+ * Kernel Stack
+ */
+ p->sched.pc = (ulong)init0;
+ p->sched.sp = (ulong)p->kstack+KSTACK-(1+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
+exit(int)
+{
+ 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 (arch->coredetach)
+ arch->coredetach();
+ firmware();
+}
+
+void
+confinit(void)
+{
+ long mbytes;
+ int mul;
+ ulong ktop;
+
+ mbytes = 50; /* BUG FIXME */
+
+ /*
+ * This split of memory into 2 banks fools the allocator into
+ * allocating low memory pages from bank 0 for the ethernet since
+ * it has only a 24bit address counter.
+ * Note that the rom monitor has the bottom 2 megs
+ */
+ conf.npage0 = (8*1024*1024)/BY2PG;
+ conf.base0 = 0;
+
+ conf.npage1 = (mbytes-8)*1024/8;
+ conf.base1 = 8*1024*1024;
+
+ conf.npage = conf.npage0+conf.npage1;
+ conf.upages = (conf.npage*70)/100;
+
+ ktop = PGROUND((ulong)end);
+ conf.ptebase = ktop;
+ ktop = PADDR(ktop);
+ ktop += ((mbytes+7)/8 + 2)*BY2PG; /* space for kernel ptes */
+ conf.npage0 -= ktop/BY2PG;
+ conf.base0 += ktop;
+ conf.mbytes = mbytes;
+ conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
+
+ mul = (mbytes+11)/12;
+ if(mul > 2)
+ mul = 2;
+ conf.nmach = 1;
+ conf.nproc = 20 + 50*mul;
+ conf.nswap = conf.nproc*80;
+ conf.nimage = 50;
+ conf.copymode = 0; /* copy on write */
+
+ if(cpuserver)
+ conf.nproc = 500;
+/* else
+ conf.monitor = 1; /* BUG */
+}
+
+void
+lights(int l)
+{
+ USED(l);
+}
+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;
+}
+
+/*
+ * Q&D fake-out of plan9.ini until we resolve the booting issues
+ */
+char *confname[] =
+{
+ "ether0",
+ "scsi0",
+
+};
+
+char *confval[] =
+{
+ "type=21140",
+ "type=aic7xxx",
+};
+
+int nconf = nelem(confname);
+
+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[NAMELEN], *p, *q, *r;
+ int n;
+
+ sprint(cc, "%s%d", class, ctlrno);
+ for(n = 0; n < nconf; n++){
+ if(cistrncmp(confname[n], cc, NAMELEN))
+ continue;
+ isa->nopt = 0;
+ p = confval[n];
+ while(*p){
+ while(*p == ' ' || *p == '\t')
+ p++;
+ if(*p == '\0')
+ break;
+ if(cistrncmp(p, "type=", 5) == 0){
+ p += 5;
+ for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){
+ if(*p == '\0' || *p == ' ' || *p == '\t')
+ break;
+ *q = *p++;
+ }
+ *q = '\0';
+ }
+ 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);
+ else if(isa->nopt < NISAOPT){
+ r = isa->opt[isa->nopt];
+ while(*p && *p != ' ' && *p != '\t'){
+ *r++ = *p++;
+ if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1)
+ break;
+ }
+ *r = '\0';
+ isa->nopt++;
+ }
+ while(*p && *p != ' ' && *p != '\t')
+ p++;
+ }
+ 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;
+}
A alphapc/mem.h => alphapc/mem.h +134 -0
@@ 0,0 1,134 @@
+/*
+ * 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 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 */
+#define TK2MS(t) ((t)*MS2HZ) /* ticks to milliseconds */
+#define MS2TK(t) ((t)/MS2HZ) /* milliseconds to ticks */
+
+/*
+ * 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 */
+
+/*
+ * Palcode instructions a la OSF/1
+ */
+#define PALbpt 0x80
+#define PALbugchk 0x81
+#define PALcallsys 0x83
+#define PALimb 0x86
+#define PALgentrap 0xaa
+#define PALrdunique 0x9e
+#define PALwrunique 0x9f
+
+#define PALhalt 0x00
+#define PALdraina 0x02
+#define PALcserve 0x09
+#define PALrdps 0x36
+#define PALrdusp 0x3a
+#define PALrdval 0x32
+#define PALretsys 0x3d
+#define PALrti 0x3f
+#define PALswpctx 0x30
+#define PALswpipl 0x35
+#define PALtbi 0x33
+#define PALwhami 0x3c
+#define PALwrent 0x34
+#define PALwrfen 0x2b
+#define PALwrkgp 0x37
+#define PALwrusp 0x38
+#define PALwrval 0x31
+#define PALwrvptptr 0x2d
+
+/*
+ * Plus some useful VMS ones (needed at early boot time)
+ */
+#define PALmfpr_pcbb 0x12
+#define PALmfpr_ptbr 0x15
+#define PALmfpr_vptb 0x29
+#define PALldqp 0x03
+#define PALstqp 0x04
+#define PALswppal 0x0a
+
+/*
+ * Processor Status (as returned by rdps)
+ */
+#define UMODE 0x8
+#define IPL 0x7
+
+
+#define isphys(x) (((ulong)x&KZERO)!=0)
A alphapc/mmu.c => alphapc/mmu.c +245 -0
@@ 0,0 1,245 @@
+#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);
+}
+
+/*
+ * Called splhi, not in Running state
+ */
+void
+mmuswitch(Proc *p)
+{
+ Page *pg;
+ uvlong *lvl2;
+
+ if(p->newtlb){
+ /*
+ * newtlb set means that they are inconsistent
+ * with the segment.c data structures.
+ *
+ * bin the current 3rd level page tables and
+ * the pointers to them in the 2nd level page.
+ * pg->daddr is used by putmmu to save the offset into
+ * the 2nd level page.
+ */
+ if(p->mmutop && p->mmuused){
+ lvl2 = (uvlong*)p->mmulvl2->va;
+ for(pg = p->mmuused; pg->next; pg = pg->next)
+ lvl2[pg->daddr] = 0;
+ lvl2[pg->daddr] = 0;
+ pg->next = p->mmufree;
+ p->mmufree = p->mmuused;
+ p->mmuused = 0;
+ }
+ p->newtlb = 0;
+ }
+
+ /* tell processor about new page table and flush cached entries */
+ if(p->mmutop == 0)
+ setptb(origlvl1);
+ else
+ setptb(p->mmutop->pa);
+ tlbflush(-1, 0);
+ icflush();
+}
+
+/*
+ * give all page table pages back to the free pool. This is called in sched()
+ * with palloc locked.
+ */
+void
+mmurelease(Proc *p)
+{
+ Page *pg;
+ Page *next;
+
+ if(canlock(&palloc))
+ panic("mmurelease");
+
+ /* point to protoype page map */
+ setptb(origlvl1);
+ icflush();
+
+ /* give away page table pages */
+ for(pg = p->mmuused; pg; pg = next){
+ next = pg->next;
+ pg->next = p->mmufree;
+ p->mmufree = pg;
+ }
+ p->mmuused = 0;
+ if(p->mmutop) {
+ p->mmutop->next = p->mmufree;
+ p->mmufree = p->mmutop;
+ p->mmutop = 0;
+ }
+ if(p->mmulvl2) {
+ p->mmulvl2->next = p->mmufree;
+ p->mmufree = p->mmulvl2;
+ p->mmulvl2 = 0;
+ }
+ for(pg = p->mmufree; pg; pg = next){
+ next = pg->next;
+ if(--pg->ref)
+ panic("mmurelease: pg->ref %d\n", pg->ref);
+ pagechainhead(pg);
+ }
+ if(p->mmufree && palloc.r.p)
+ wakeup(&palloc.r);
+ p->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);
+
+}
+
+ulong
+upamalloc(...)
+{
+ panic("upamalloc");
+}
+
+void
+upafree(...)
+{
+ panic("upafree");
+}
A alphapc/mouse.c => alphapc/mouse.c +220 -0
@@ 0,0 1,220 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "io.h"
+
+#define Image IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+
+/*
+ * mouse types
+ */
+enum
+{
+ Mouseother= 0,
+ Mouseserial= 1,
+ MousePS2= 2,
+};
+static int mousetype;
+
+/*
+ * setup a serial mouse
+ */
+static void
+serialmouse(int port, char *type, int setspeed)
+{
+ if(mousetype == Mouseserial)
+ error(Emouseset);
+
+ if(port >= 3 || port < 0)
+ error(Ebadarg);
+
+ /* set up /dev/eia? as the mouse */
+ if(setspeed)
+ setspeed = 1200;
+ if(type && *type == 'M')
+ ns16552special(port, setspeed, 0, 0, m3mouseputc);
+ else
+ ns16552special(port, setspeed, 0, 0, mouseputc);
+ mousetype = Mouseserial;
+}
+
+/*
+ * ps/2 mouse message is three bytes
+ *
+ * byte 0 - 0 0 SDY SDX 1 M R L
+ * byte 1 - DX
+ * byte 2 - DY
+ *
+ * shift & left button is the same as middle button
+ */
+static void
+ps2mouseputc(int c, int shift)
+{
+ static short msg[3];
+ static int nb;
+ static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 };
+ int buttons, dx, dy;
+
+ /*
+ * check byte 0 for consistency
+ */
+ if(nb==0 && (c&0xc8)!=0x08)
+ return;
+
+ msg[nb] = c;
+ if(++nb == 3){
+ nb = 0;
+ if(msg[0] & 0x10)
+ msg[1] |= 0xFF00;
+ if(msg[0] & 0x20)
+ msg[2] |= 0xFF00;
+
+ buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
+ dx = msg[1];
+ dy = -msg[2];
+ mousetrack(buttons, dx, dy);
+ }
+ return;
+}
+
+/*
+ * set up a ps2 mouse
+ */
+static void
+ps2mouse(void)
+{
+ if(mousetype == MousePS2)
+ return;
+
+ i8042auxenable(ps2mouseputc);
+ /* make mouse streaming, enabled */
+ i8042auxcmd(0xEA);
+ i8042auxcmd(0xF4);
+
+ mousetype = MousePS2;
+}
+
+static int intellimouse;
+static int resolution;
+static int accelerated;
+
+static void
+setaccelerated(int x)
+{
+ accelerated = x;
+ switch(mousetype){
+ case MousePS2:
+ i8042auxcmd(0xE7);
+ break;
+ default:
+ mouseaccelerate(x);
+ break;
+ }
+}
+
+static void
+setlinear(void)
+{
+ accelerated = 0;
+ switch(mousetype){
+ case MousePS2:
+ i8042auxcmd(0xE6);
+ break;
+ default:
+ mouseaccelerate(0);
+ break;
+ }
+}
+
+static void
+setres(int n)
+{
+ resolution = n;
+ switch(mousetype){
+ case MousePS2:
+ i8042auxcmd(0xE8);
+ i8042auxcmd(n);
+ break;
+ }
+}
+
+static void
+setintellimouse(void)
+{
+ intellimouse = 1;
+ switch(mousetype){
+ case MousePS2:
+ i8042auxcmd(0xF3); /* set sample */
+ i8042auxcmd(0xC8);
+ i8042auxcmd(0xF3); /* set sample */
+ i8042auxcmd(0x64);
+ i8042auxcmd(0xF3); /* set sample */
+ i8042auxcmd(0x50);
+ break;
+ }
+}
+
+static void
+resetmouse(void)
+{
+ switch(mousetype){
+ case MousePS2:
+ i8042auxcmd(0xF6);
+ i8042auxcmd(0xEA); /* streaming */
+ i8042auxcmd(0xE8); /* set resolution */
+ i8042auxcmd(3);
+ i8042auxcmd(0xF4); /* enabled */
+ break;
+ }
+}
+
+void
+mousectl(char* field[], int n)
+{
+ if(strncmp(field[0], "serial", 6) == 0){
+ switch(n){
+ case 1:
+ serialmouse(atoi(field[0]+6), 0, 1);
+ break;
+ case 2:
+ serialmouse(atoi(field[1]), 0, 0);
+ break;
+ case 3:
+ default:
+ serialmouse(atoi(field[1]), field[2], 0);
+ break;
+ }
+ } else if(strcmp(field[0], "ps2") == 0){
+ ps2mouse();
+ } else if(strcmp(field[0], "ps2intellimouse") == 0){
+ ps2mouse();
+ setintellimouse();
+ } else if(strcmp(field[0], "accelerated") == 0){
+ setaccelerated(n == 1 ? 1 : atoi(field[1]));
+ } else if(strcmp(field[0], "linear") == 0){
+ setlinear();
+ } else if(strcmp(field[0], "res") == 0){
+ if(n >= 2)
+ n = atoi(field[1]);
+ setres(n);
+ } else if(strcmp(field[0], "reset") == 0){
+ resetmouse();
+ if(accelerated)
+ setaccelerated(accelerated);
+ if(resolution)
+ setres(resolution);
+ if(intellimouse)
+ setintellimouse();
+ } else if(strcmp(field[0], "intellimouse") == 0){
+ setintellimouse();
+ }
+ else
+ error(Ebadctl);
+}
A alphapc/ns16552.h => alphapc/ns16552.h +60 -0
@@ 0,0 1,60 @@
+#define uartwrreg(u,r,v) outb((u)->port + (r), (u)->sticky[r] | (v))
+#define uartrdreg(u,r) inb((u)->port + (r))
+
+#define uartpower(x, y)
+
+/*
+ * handle an interrupt to a single uart
+ */
+static void
+ns16552intrx(Ureg*, void* arg)
+{
+ ns16552intr((ulong)arg);
+}
+
+void
+ns16552install(void)
+{
+ static int already;
+
+ if(already)
+ return;
+ already = 1;
+
+ ns16552setup(Uart0, UartFREQ, "eia0");
+ intrenable(VectorUART0, ns16552intrx, (void*)0, BUSUNKNOWN);
+ ns16552setup(Uart1, UartFREQ, "eia1");
+ intrenable(VectorUART1, ns16552intrx, (void*)0, BUSUNKNOWN);
+}
+
+#define RD(r) inb(Uart0+(r))
+static void
+ns16552iputc(char c)
+{
+ mb();
+ while((RD(5) & (1<<5)) == 0)
+ mb();
+ outb(Uart0, c);
+ mb();
+ while((RD(5) & (1<<5)) == 0)
+ mb();
+}
+
+int
+iprint(char *fmt, ...)
+{
+ int n, i, s;
+ char buf[512];
+ va_list arg;
+
+ va_start(arg, fmt);
+ n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf;
+ va_end(arg);
+
+ s = splhi();
+ for(i = 0; i < n; i++)
+ ns16552iputc(buf[i]);
+ splx(s);
+
+ return n;
+}
A alphapc/pci.c => alphapc/pci.c +351 -0
@@ 0,0 1,351 @@
+/*
+ * 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,
+};
+
+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);
+
+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->intl = pcicfgr8(p, PciINTL);
+ p->ccru = pcicfgr16(p, PciCCRu);
+
+ /*
+ * 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->ccru>>8){
+
+ case 0x01: /* mass storage controller */
+ case 0x02: /* network controller */
+ case 0x03: /* display 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->ccru != ((0x06<<8)|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;
+/* if(p = getconf("*pcimaxdno"))
+ pcimaxdno = strtoul(p, 0, 0); */
+pcimaxdno = 15 /* was 20; what is correct value??? */;
+
+ 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;
+}
+
+void
+pcihinv(Pcidev* p)
+{
+ int i;
+ Pcidev *t;
+
+ 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 %.4ux %.4ux %.4ux %2d ",
+ BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
+ t->ccru, 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);
+ }
+}
A alphapc/screen.c => alphapc/screen.c +314 -0
@@ 0,0 1,314 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../port/error.h"
+
+#define Image IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+
+static ulong onesbits = ~0;
+static Memdata onesdata = {
+ nil,
+ &onesbits,
+};
+static Memimage xones = {
+ { 0, 0, 1, 1 },
+ { -100000, -100000, 100000, 100000 },
+ 3,
+ 1,
+ &onesdata,
+ 0,
+ 1
+};
+Memimage *memones = &xones;
+
+Point ZP = {0, 0};
+
+Memdata gscreendata;
+Memimage gscreen;
+
+VGAscr vgascreen[1];
+
+Cursor arrow = {
+ { -1, -1 },
+ { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
+ 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
+ 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
+ 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
+ },
+ { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
+ 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
+ 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
+ 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
+ },
+};
+
+int
+screensize(int x, int y, int z)
+{
+ VGAscr *scr;
+
+ scr = &vgascreen[0];
+
+ /*
+ * BUG: need to check if any xalloc'ed memory needs to
+ * be given back if aperture is set.
+ */
+ if(scr->aperture == 0){
+ int width = (x*(1<<z))/BI2WD;
+
+ gscreendata.data = xalloc(width*BY2WD*y);
+ if(gscreendata.data == 0)
+ error("screensize: vga soft memory");
+ memset(gscreendata.data, Backgnd, width*BY2WD*y);
+ scr->useflush = 1;
+
+ scr->aperture = (ulong)arch->pcimem(0xA0000, 1<<16);
+ scr->apsize = 1<<16;
+ }
+ else
+ gscreendata.data = KADDR(scr->aperture);
+
+ gscreen.data = &gscreendata;
+ gscreen.ldepth = z;
+ gscreen.width = (x*(1<<gscreen.ldepth)+31)/32;
+ gscreen.r.min = ZP;
+ gscreen.r.max = Pt(x, y);
+ gscreen.clipr = gscreen.r;
+ gscreen.repl = 0;
+
+ scr->gscreendata = gscreen.data;
+ scr->memdefont = getmemdefont();
+ scr->gscreen = &gscreen;
+
+// memset(gscreen.data->data, Backgnd, scr->apsize);
+
+ drawcmap(0);
+
+ return 0;
+}
+
+int
+screenaperture(int size, int align)
+{
+ VGAscr *scr;
+ ulong aperture;
+
+ scr = &vgascreen[0];
+
+ if(size == 0){
+ if(scr->aperture && scr->isupamem)
+ upafree(scr->aperture, scr->apsize);
+ scr->aperture = 0;
+ scr->isupamem = 0;
+ return 0;
+ }
+ if(scr->dev && scr->dev->linear){
+ aperture = scr->dev->linear(scr, &size, &align);
+ if(aperture == 0)
+ return 1;
+ }
+ else{
+ aperture = upamalloc(0, size, align);
+ if(aperture == 0)
+ return 1;
+
+ if(scr->aperture && scr->isupamem)
+ upafree(scr->aperture, scr->apsize);
+ scr->isupamem = 1;
+ }
+
+ scr->aperture = aperture;
+ scr->apsize = size;
+
+ return 0;
+}
+
+ulong*
+attachscreen(Rectangle* r, int* ld, int* width, int *softscreen)
+{
+ VGAscr *scr;
+
+ scr = &vgascreen[0];
+ if(scr->gscreen == nil || scr->gscreendata == nil)
+ return nil;
+
+ *r = scr->gscreen->r;
+ *ld = scr->gscreen->ldepth;
+ *width = scr->gscreen->width;
+ *softscreen = scr->useflush;
+
+ return scr->gscreendata->data;
+}
+
+void
+flushmemscreen(Rectangle r)
+{
+ VGAscr *scr;
+ uchar *sp, *disp, *sdisp, *edisp;
+ int y, len, incs, off, page;
+
+ scr = &vgascreen[0];
+ if(scr->gscreen == nil || scr->useflush == 0)
+ return;
+ if(scr->dev == nil || scr->dev->page == nil)
+ return;
+
+ if(rectclip(&r, scr->gscreen->r) == 0)
+ return;
+
+ incs = scr->gscreen->width * BY2WD;
+
+ switch(scr->gscreen->ldepth){
+ default:
+ len = 0;
+ panic("flushmemscreen: ldepth\n");
+ break;
+ case 3:
+ len = Dx(r);
+ break;
+ }
+ if(len < 1)
+ return;
+
+ off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x>>(3-scr->gscreen->ldepth));
+ page = off/scr->apsize;
+ off %= scr->apsize;
+ disp = KADDR(scr->aperture);
+ sdisp = disp+off;
+ edisp = disp+scr->apsize;
+
+ off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x>>(3-scr->gscreen->ldepth));
+ sp = ((uchar*)scr->gscreendata->data) + off;
+
+ scr->dev->page(scr, page);
+ for(y = r.min.y; y < r.max.y; y++) {
+ if(sdisp + incs < edisp) {
+ memmove(sdisp, sp, len);
+ sp += incs;
+ sdisp += incs;
+ }
+ else {
+ off = edisp - sdisp;
+ page++;
+ if(off <= len){
+ if(off > 0)
+ memmove(sdisp, sp, off);
+ scr->dev->page(scr, page);
+ if(len - off > 0)
+ memmove(disp, sp+off, len - off);
+ }
+ else {
+ memmove(sdisp, sp, len);
+ scr->dev->page(scr, page);
+ }
+ sp += incs;
+ sdisp += incs - scr->apsize;
+ }
+ }
+}
+
+void
+getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
+{
+ VGAscr *scr;
+ ulong x;
+
+ scr = &vgascreen[0];
+ if(scr->gscreen == nil)
+ return;
+
+ switch(scr->gscreen->ldepth){
+ default:
+ x = 0x0F;
+ break;
+ case 3:
+ x = 0xFF;
+ break;
+ }
+ p &= x;
+ p ^= x;
+
+ lock(&cursor);
+ *pr = scr->colormap[p][0];
+ *pg = scr->colormap[p][1];
+ *pb = scr->colormap[p][2];
+ unlock(&cursor);
+}
+
+int
+setcolor(ulong p, ulong r, ulong g, ulong b)
+{
+ VGAscr *scr;
+ ulong x;
+
+ scr = &vgascreen[0];
+ if(scr->gscreen == nil)
+ return 0;
+
+ switch(scr->gscreen->ldepth){
+ default:
+ x = 0x0F;
+ break;
+ case 3:
+ x = 0xFF;
+ break;
+ }
+ p &= x;
+ p ^= x;
+
+ lock(&cursor);
+ scr->colormap[p][0] = r;
+ scr->colormap[p][1] = g;
+ scr->colormap[p][2] = b;
+ vgao(PaddrW, p);
+ vgao(Pdata, r>>(32-6));
+ vgao(Pdata, g>>(32-6));
+ vgao(Pdata, b>>(32-6));
+ unlock(&cursor);
+
+ return ~0;
+}
+
+int
+cursoron(int dolock)
+{
+ VGAscr *scr;
+ int v;
+
+ scr = &vgascreen[0];
+ if(scr->cur == nil || scr->cur->move == nil)
+ return 0;
+
+ if(dolock)
+ lock(&cursor);
+ v = scr->cur->move(scr, mousexy());
+ if(dolock)
+ unlock(&cursor);
+
+ return v;
+}
+
+void
+cursoroff(int)
+{
+}
+
+void
+setcursor(Cursor* curs)
+{
+ VGAscr *scr;
+
+ scr = &vgascreen[0];
+ if(scr->cur == nil || scr->cur->load == nil)
+ return;
+
+ scr->cur->load(scr, curs);
+}
A alphapc/screen.h => alphapc/screen.h +122 -0
@@ 0,0 1,122 @@
+typedef struct Cursor Cursor;
+typedef struct Cursorinfo Cursorinfo;
+struct Cursorinfo {
+ Cursor;
+ Lock;
+};
+
+/* devmouse.c */
+extern void mousetrack(int, int, int);
+extern Point mousexy(void);
+
+extern void mouseaccelerate(int);
+extern int m3mouseputc(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 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);
+ ulong (*linear)(VGAscr*, int*, int*);
+};
+
+struct VGAcur {
+ char* name;
+
+ void (*enable)(VGAscr*);
+ void (*disable)(VGAscr*);
+ void (*load)(VGAscr*, Cursor*);
+ int (*move)(VGAscr*, Point);
+};
+
+/*
+ */
+struct VGAscr {
+ Lock devlock;
+ VGAdev* dev;
+
+ VGAcur* cur;
+ ulong storage;
+ Cursor;
+
+ int useflush;
+
+ ulong aperture; /* physical address */
+ int isupamem;
+ int apsize;
+
+ ulong io; /* device specific registers */
+
+ ulong colormap[Pcolours][3];
+
+ Memimage* gscreen;
+ Memdata* gscreendata;
+ Memsubfont* memdefont;
+};
+extern VGAscr vgascreen[];
+
+enum {
+ Backgnd = Pwhite,
+};
+
+/* mouse.c */
+extern void mousectl(char*[], int);
+
+/* screen.c */
+extern void flushmemscreen(Rectangle);
+extern int cursoron(int);
+extern void cursoroff(int);
+extern void setcursor(Cursor*);
+extern int screensize(int, int, int);
+extern int screenaperture(int, int);
+
+/* vga.c */
+extern void vgascreenwin(VGAscr*);
A alphapc/segment.h => alphapc/segment.h +9 -0
@@ 0,0 1,9 @@
+/*
+ * Attach segment types
+ */
+
+Physseg physseg[] = {
+ { SG_SHARED, "shared", 0, SEGMAXSIZE, 0, 0 },
+ { SG_BSS, "memory", 0, SEGMAXSIZE, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 },
+};
A alphapc/trap.c => alphapc/trap.c +700 -0
@@ 0,0 1,700 @@
+#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",
+};
+
+void
+intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf)
+{
+ arch->intrenable(irq, f, a, tbdf);
+}
+
+void
+trap(Ureg *ur)
+{
+ char buf[ERRLEN];
+ int user, x;
+
+ user = ur->status&UMODE;
+
+ if(user){
+ up = m->proc;
+ up->dbgreg = ur;
+ if(up && up->fpstate == FPactive) {
+ up->fpstate = FPinactive;
+ savefpregs(&up->fpsave);
+ fpenab(0);
+ }
+ }
+ switch ((int)ur->type) {
+ case 1: /* arith */
+ fptrap(ur);
+ break;
+ case 2: /* bad instr or FEN */
+ illegal(ur);
+ break;
+ case 3: /* intr */
+ intr(ur);
+ 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();
+ if(!user)
+ return;
+
+ notify(ur);
+ if(up->fpstate == FPinactive) {
+ fpenab(1);
+ restfpregs(&up->fpsave);
+ up->fpstate = FPactive;
+ }
+}
+
+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(void *x)
+{
+ Mcheck *m;
+ uvlong *data;
+ int i, col;
+
+ m = x;
+ data = x;
+ iprint("panic: Machine Check @%lux: %s (%lux) len %d\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("%.3lux: %.16llux%s", 8*i, data[i], (col == 2) ? "\n" : " ");
+ if (col++ == 2)
+ col = 0;
+ }
+ firmware();
+}
+
+void
+intr(Ureg *ur)
+{
+ m->intr++;
+ switch ((int)ur->a0) {
+ case 0: /* interprocessor */
+ panic("interprocessor intr");
+ break;
+ case 1: /* clock */
+ clock(ur);
+ break;
+ case 2: /* machine check */
+ mcheck((void*)(KZERO|(ulong)ur->a2));
+ break;
+ case 3: /* device */
+ arch->intr(ur);
+ break;
+ case 4: /* perf counter */
+ panic("perf count");
+ break;
+ default:
+ panic("bad intr");
+ break;
+ }
+
+ /* preemptive scheduling */
+ if(up && up->state == Running && anyhigher())
+ sched();
+}
+
+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[ERRLEN];
+
+ 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=0x%lux 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
+dumpstack(void)
+{
+ 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;
+ }
+ iprint("dumpstack: l %lux sl %lux el %lux m %lux\n", l, sl, el, m);
+ if(l > el || l < sl){
+ return;
+ }
+
+ 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){
+ iprint("%lux ", v);
+ i++;
+ }
+ }
+ if(i == 8){
+ i = 0;
+ iprint("\n");
+ }
+ }
+}
+
+void
+dumpregs(Ureg *ur)
+{
+ int i, col;
+ uvlong *l;
+
+ spllo();
+ prflush();
+ if(up)
+ iprint("registers for %s %d\n", up->text, up->pid);
+ else
+ iprint("registers for kernel\n");
+
+ l = &ur->type;
+ col = 0;
+ for (i = 0; i < sizeof regname/sizeof(char*); i++, l++) {
+ iprint("%-7s%.16llux%s", regname[i], *l, col == 2 ? "\n" : " ");
+ if (col++ == 2)
+ col = 0;
+ }
+ iprint("\n");
+// prflush();
+}
+
+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;
+ n = &up->note[0];
+ if(strncmp(n->msg, "sys:", 4) == 0) {
+ l = strlen(n->msg);
+ if(l > ERRLEN-15) /* " pc=0x12345678\0" */
+ l = ERRLEN-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-ERRLEN-6*BY2WD, sizeof(Ureg)+ERRLEN-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+ERRLEN;
+ memmove((char*)sp, up->note[0].msg, ERRLEN);
+ 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;
+
+ 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-ERRLEN;
+ 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)
+{
+ long ret;
+ ulong sp;
+ Ureg *ur;
+
+ m->syscall++;
+ up = m->proc;
+ up->insyscall = 1;
+ ur = aur;
+ up->pc = ur->pc;
+ up->dbgreg = aur;
+ ur->type = 5; /* for debugging */
+
+ if(up->fpstate == FPactive) {
+ up->fpsave.fpstatus = getfcr();
+ up->fpstate = FPinit;
+ fpenab(0);
+ }
+ spllo();
+
+ if(up->procctl)
+ procctl(up);
+
+ up->scallnr = ur->r0;
+ up->nerrlab = 0;
+ sp = ur->sp;
+ ret = -1;
+ if(waserror())
+ goto error;
+
+ if(up->scallnr >= nsyscall){
+ pprint("bad sys call %d pc %lux\n", up->scallnr, (ulong)ur->pc);
+print("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[up->scallnr];
+
+ ret = (*systab[up->scallnr])(up->s.args);
+ poperror();
+
+error:
+ up->nerrlab = 0;
+ up->psstate = 0;
+ up->insyscall = 0;
+ if(up->scallnr == NOTED) /* ugly hack */
+ noted(ur, &aur, *(ulong*)(sp+2*BY2WD)); /* doesn't return */
+
+ splhi();
+ if(up->scallnr!=RFORK && (up->procctl || up->nnote)){
+ ur->r0 = ret; /* load up for noted() */
+ if(notify(ur))
+ return ur->r0;
+ }
+
+ if(up->fpstate == FPinactive) /* due to race with intr */
+ up->fpstate = FPinit;
+
+ 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);
+}
+
+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;
+ up->fpsave.fpstatus = initfp.fpstatus;
+ 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)
+{
+ ulong fpcr;
+
+ if ((ur->status&UMODE) && up) {
+ if(up->fpstate == FPinit) {
+ up->fpstate = FPactive;
+ fpcr = up->fpsave.fpstatus;
+ up->fpsave = initfp;
+ up->fpsave.fpstatus = fpcr;
+ fpenab(1);
+ restfpregs(&up->fpsave);
+ return;
+ }
+ }
+ fataltrap(ur, "trap: floating enable"); /* should never happen */
+}
A alphapc/vga.c => alphapc/vga.c +194 -0
@@ 0,0 1,194 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#define Image IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+
+static ulong backbits = (Backgnd<<24)|(Backgnd<<16)|(Backgnd<<8)|Backgnd;
+static Memdata backdata = {
+ nil,
+ &backbits
+};
+static Memimage xback = {
+ { 0, 0, 1, 1 },
+ { -100000, -100000, 100000, 100000 },
+ 3,
+ 1,
+ &backdata,
+ 0,
+ 1
+};
+static Memimage* back = &xback;
+
+static ulong consbits = 0;
+static Memdata consdata = {
+ nil,
+ &consbits
+};
+static Memimage conscol = {
+ { 0, 0, 1, 1 },
+ { -100000, -100000, 100000, 100000 },
+ 3,
+ 1,
+ &consdata,
+ 0,
+ 1
+};
+
+static Point curpos;
+static Rectangle window;
+static int *xp;
+static int xbuf[256];
+static Lock vgascreenlock;
+
+static void
+vgascroll(VGAscr* scr)
+{
+ int h, o;
+ Point p;
+ Rectangle r;
+
+ h = scr->memdefont->height;
+ o = 8*h;
+ r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
+ p = Pt(window.min.x, window.min.y+o);
+ memimagedraw(scr->gscreen, r, scr->gscreen, p, memones, p);
+ r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
+ memimagedraw(scr->gscreen, r, back, ZP, memones, ZP);
+
+ curpos.y -= o;
+}
+
+static void
+vgascreenputc(VGAscr* scr, char* buf, Rectangle *flushr)
+{
+ Point p;
+ int h, w, pos;
+ Rectangle r;
+
+ if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
+ xp = xbuf;
+
+ h = scr->memdefont->height;
+ switch(buf[0]){
+
+ case '\n':
+ if(curpos.y+h >= window.max.y){
+ vgascroll(scr);
+ *flushr = window;
+ }
+ curpos.y += h;
+ vgascreenputc(scr, "\r", flushr);
+ break;
+
+ case '\r':
+ xp = xbuf;
+ curpos.x = window.min.x;
+ break;
+
+ case '\t':
+ p = memsubfontwidth(scr->memdefont, " ");
+ w = p.x;
+ *xp++ = curpos.x;
+ pos = (curpos.x-window.min.x)/w;
+ pos = 4-(pos%4);
+ r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y+h);
+ memimagedraw(scr->gscreen, r, back, back->r.min, memones, back->r.min);
+ bbox(flushr, r);
+ curpos.x += pos*w;
+ break;
+
+ case '\b':
+ if(xp <= xbuf)
+ break;
+ xp--;
+ r = Rect(*xp, curpos.y, curpos.x, curpos.y+h);
+ memimagedraw(scr->gscreen, r, back, back->r.min, memones, back->r.min);
+ bbox(flushr, r);
+ curpos.x = *xp;
+ break;
+
+ default:
+ p = memsubfontwidth(scr->memdefont, buf);
+ w = p.x;
+
+ if(curpos.x >= window.max.x-w)
+ vgascreenputc(scr, "\n", flushr);
+
+ *xp++ = curpos.x;
+ r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y+h);
+ memimagedraw(scr->gscreen, r, back, back->r.min, memones, back->r.min);
+ memimagestring(scr->gscreen, curpos, &conscol, scr->memdefont, buf);
+ bbox(flushr, r);
+ curpos.x += w;
+ }
+}
+
+static void
+vgascreenputs(char* s, int n)
+{
+ int i;
+ Rune r;
+ char buf[4];
+ VGAscr *scr;
+ Rectangle flushr;
+
+ scr = &vgascreen[0];
+
+ if(!islo()){
+ /*
+ * Don't deadlock trying to
+ * print in an interrupt.
+ */
+ if(!canlock(&vgascreenlock))
+ return;
+ }
+ else
+ lock(&vgascreenlock);
+
+ flushr = Rect(10000, 10000, -10000, -10000);
+
+ while(n > 0){
+ i = chartorune(&r, s);
+ if(i == 0){
+ s++;
+ --n;
+ continue;
+ }
+ memmove(buf, s, i);
+ buf[i] = 0;
+ n -= i;
+ s += i;
+ vgascreenputc(scr, buf, &flushr);
+ }
+ flushmemscreen(flushr);
+
+ unlock(&vgascreenlock);
+}
+
+void
+vgascreenwin(VGAscr* scr)
+{
+ int h, w;
+
+ h = scr->memdefont->height;
+ w = scr->memdefont->info[' '].width;
+
+ window.min = Pt(48, 48);
+ window.max = addpt(window.min, Pt(10+w*80, 10+h*50));
+ if(window.max.y >= scr->gscreen->r.max.y)
+ window.max.y = scr->gscreen->r.max.y-1;
+ if(window.max.x >= scr->gscreen->r.max.x)
+ window.max.x = scr->gscreen->r.max.x-1;
+ window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
+ curpos = window.min;
+
+ screenputs = vgascreenputs;
+}
A alphapc/vgargb524.c => alphapc/vgargb524.c +237 -0
@@ 0,0 1,237 @@
+#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"
+
+/*
+ * IBM RGB524.
+ * 170/220MHz High Performance Palette DAC.
+ *
+ * Assumes hooked up to an S3 Vision96[48].
+ */
+enum {
+ IndexLo = 0x00,
+ IndexHi = 0x01,
+ Data = 0x02,
+ IndexCtl = 0x03,
+};
+
+enum { /* index registers */
+ CursorCtl = 0x30,
+ CursorXLo = 0x31,
+ CursorXHi = 0x32,
+ CursorYLo = 0x33,
+ CursorYHi = 0x34,
+ CursorHotX = 0x35,
+ CursorHotY = 0x36,
+
+ CursorR1 = 0x40,
+ CursorG1 = 0x41,
+ CursorB1 = 0x42,
+ CursorR2 = 0x43,
+ CursorG2 = 0x44,
+ CursorB2 = 0x45,
+ CursorR3 = 0x46,
+ CursorG3 = 0x47,
+ CursorB3 = 0x48,
+
+ CursorArray = 0x100,
+};
+
+/*
+ * Lower 2-bits of indirect DAC register
+ * addressing.
+ */
+static ushort dacxreg[4] = {
+ PaddrW, Pdata, Pixmask, PaddrR
+};
+
+static uchar
+rgb524setrs2(void)
+{
+ uchar rs2;
+
+ rs2 = vgaxi(Crtx, 0x55);
+ vgaxo(Crtx, 0x55, (rs2 & 0xFC)|0x01);
+
+ return rs2;
+}
+
+static void
+rgb524xo(int index, uchar data)
+{
+ vgao(dacxreg[IndexLo], index & 0xFF);
+ vgao(dacxreg[IndexHi], (index>>8) & 0xFF);
+ vgao(dacxreg[Data], data);
+}
+
+static void
+rgb524disable(VGAscr*)
+{
+ uchar rs2;
+
+ rs2 = rgb524setrs2();
+ rgb524xo(CursorCtl, 0x00);
+ vgaxo(Crtx, 0x55, rs2);
+}
+
+static void
+rgb524enable(VGAscr*)
+{
+ uchar rs2;
+
+ rs2 = rgb524setrs2();
+
+ /*
+ * Make sure cursor is off by initialising the cursor
+ * control to defaults.
+ */
+ rgb524xo(CursorCtl, 0x00);
+
+ /*
+ * Cursor colour 1 (white),
+ * cursor colour 2 (black).
+ */
+ rgb524xo(CursorR1, Pwhite); rgb524xo(CursorG1, Pwhite); rgb524xo(CursorB1, Pwhite);
+ rgb524xo(CursorR2, Pblack); rgb524xo(CursorG2, Pblack); rgb524xo(CursorB2, Pblack);
+
+ /*
+ * Enable the cursor, 32x32, mode 2.
+ */
+ rgb524xo(CursorCtl, 0x23);
+
+ vgaxo(Crtx, 0x55, rs2);
+}
+
+static void
+rgb524load(VGAscr*, Cursor* curs)
+{
+ uchar p, p0, p1, rs2;
+ int x, y;
+
+ rs2 = rgb524setrs2();
+
+ /*
+ * Make sure cursor is off by initialising the cursor
+ * control to defaults.
+ */
+ rgb524xo(CursorCtl, 0x00);
+
+ /*
+ * Set auto-increment mode for index-register addressing
+ * and initialise the cursor array index.
+ */
+ vgao(dacxreg[IndexCtl], 0x01);
+ vgao(dacxreg[IndexLo], CursorArray & 0xFF);
+ vgao(dacxreg[IndexHi], (CursorArray>>8) & 0xFF);
+
+ /*
+ * Initialise the 32x32 cursor RAM array. There are 2 planes,
+ * p0 and p1. Data is written 4 pixels per byte, with p1 the
+ * MS bit of each pixel.
+ * The cursor is set in X-Windows mode which gives the following
+ * truth table:
+ * p1 p0 colour
+ * 0 0 underlying pixel colour
+ * 0 1 underlying pixel colour
+ * 1 0 cursor colour 1
+ * 1 1 cursor colour 2
+ * Put the cursor into the top-left of the 32x32 array.
+ */
+ for(y = 0; y < 32; y++){
+ for(x = 0; x < 32/8; x++){
+ if(x < 16/8 && y < 16){
+ p0 = curs->clr[x+y*2];
+ p1 = curs->set[x+y*2];
+
+ p = 0x00;
+ if(p1 & 0x80)
+ p |= 0xC0;
+ else if(p0 & 0x80)
+ p |= 0x80;
+ if(p1 & 0x40)
+ p |= 0x30;
+ else if(p0 & 0x40)
+ p |= 0x20;
+ if(p1 & 0x20)
+ p |= 0x0C;
+ else if(p0 & 0x20)
+ p |= 0x08;
+ if(p1 & 0x10)
+ p |= 0x03;
+ else if(p0 & 0x10)
+ p |= 0x02;
+ vgao(dacxreg[Data], p);
+
+ p = 0x00;
+ if(p1 & 0x08)
+ p |= 0xC0;
+ else if(p0 & 0x08)
+ p |= 0x80;
+ if(p1 & 0x04)
+ p |= 0x30;
+ else if(p0 & 0x04)
+ p |= 0x20;
+ if(p1 & 0x02)
+ p |= 0x0C;
+ else if(p0 & 0x02)
+ p |= 0x08;
+ if(p1 & 0x01)
+ p |= 0x03;
+ else if(p0 & 0x01)
+ p |= 0x02;
+ vgao(dacxreg[Data], p);
+ }
+ else{
+ vgao(dacxreg[Data], 0x00);
+ vgao(dacxreg[Data], 0x00);
+ }
+ }
+ }
+
+ /*
+ * Initialise the cursor hotpoint,
+ * enable the cursor and restore state.
+ */
+ rgb524xo(CursorHotX, -curs->offset.x);
+ rgb524xo(CursorHotY, -curs->offset.y);
+
+ rgb524xo(CursorCtl, 0x23);
+
+ vgaxo(Crtx, 0x55, rs2);
+}
+
+static int
+rgb524move(VGAscr*, Point p)
+{
+ uchar rs2;
+
+ rs2 = rgb524setrs2();
+
+ rgb524xo(CursorXLo, p.x & 0xFF);
+ rgb524xo(CursorXHi, (p.x>>8) & 0x0F);
+ rgb524xo(CursorYLo, p.y & 0xFF);
+ rgb524xo(CursorYHi, (p.y>>8) & 0x0F);
+
+ vgaxo(Crtx, 0x55, rs2);
+
+ return 0;
+}
+
+VGAcur vgargb524cur = {
+ "rgb524hwgc",
+
+ rgb524enable,
+ rgb524disable,
+ rgb524load,
+ rgb524move,
+};
A alphapc/vgas3.c => alphapc/vgas3.c +305 -0
@@ 0,0 1,305 @@
+#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"
+
+static int
+s3pageset(VGAscr* scr, int page)
+{
+ uchar crt35, crt51;
+ int opage;
+
+ crt35 = vgaxi(Crtx, 0x35);
+ if(scr->gscreen->ldepth == 3){
+ /*
+ * The S3 registers need to be unlocked for this.
+ * Let's hope they are already:
+ * vgaxo(Crtx, 0x38, 0x48);
+ * vgaxo(Crtx, 0x39, 0xA0);
+ *
+ * The page is 6 bits, the lower 4 bits in Crt35<3:0>,
+ * the upper 2 in Crt51<3:2>.
+ */
+ vgaxo(Crtx, 0x35, page & 0x0F);
+ crt51 = vgaxi(Crtx, 0x51);
+ vgaxo(Crtx, 0x51, (crt51 & ~0x0C)|((page & 0x30)>>2));
+ opage = ((crt51 & 0x0C)<<2)|(crt35 & 0x0F);
+ }
+ else{
+ vgaxo(Crtx, 0x35, (page<<2) & 0x0C);
+ opage = (crt35>>2) & 0x03;
+ }
+
+ return opage;
+}
+
+static void
+s3page(VGAscr* scr, int page)
+{
+ int id;
+
+ id = (vgaxi(Crtx, 0x30)<<8)|vgaxi(Crtx, 0x2E);
+ switch(id){
+
+ case 0xE110: /* ViRGE/GX2 */
+ break;
+
+ default:
+ lock(&scr->devlock);
+ s3pageset(scr, page);
+ unlock(&scr->devlock);
+ break;
+ }
+}
+
+static ulong
+s3linear(VGAscr* scr, int* size, int* align)
+{
+ ulong aperture, oaperture;
+ int oapsize, wasupamem;
+ Pcidev *p;
+
+ oaperture = scr->aperture;
+ oapsize = scr->apsize;
+ wasupamem = scr->isupamem;
+ if(wasupamem)
+ upafree(oaperture, oapsize);
+ scr->isupamem = 0;
+
+ if(p = pcimatch(nil, 0x5333, 0)){
+ aperture = p->mem[0].bar & ~0x0F;
+ *size = p->mem[0].size;
+ }
+ else
+ aperture = 0;
+
+ aperture = upamalloc(aperture, *size, *align);
+ if(aperture == 0){
+ if(wasupamem && upamalloc(oaperture, oapsize, 0))
+ scr->isupamem = 1;
+ }
+ else
+ scr->isupamem = 1;
+
+ return aperture;
+}
+
+static void
+s3vsyncactive(void)
+{
+ /*
+ * Hardware cursor information is fetched from display memory
+ * during the horizontal blank active time. The 80x chips may hang
+ * if the cursor is turned on or off during this period.
+ */
+ while((vgai(Status1) & 0x08) == 0)
+ ;
+}
+
+static void
+s3disable(VGAscr*)
+{
+ uchar crt45;
+
+ /*
+ * Turn cursor off.
+ */
+ crt45 = vgaxi(Crtx, 0x45) & 0xFE;
+ s3vsyncactive();
+ vgaxo(Crtx, 0x45, crt45);
+}
+
+static void
+s3enable(VGAscr* scr)
+{
+ int i, id;
+ ulong storage;
+
+ s3disable(scr);
+
+ /*
+ * Cursor colours. Set both the CR0[EF] and the colour
+ * stack in case we are using a 16-bit RAMDAC.
+ * This stuff is just a mystery for the ViRGE/GX2.
+ */
+ vgaxo(Crtx, 0x0E, Pwhite);
+ vgaxo(Crtx, 0x0F, Pblack);
+ vgaxi(Crtx, 0x45);
+ id = (vgaxi(Crtx, 0x30)<<8)|vgaxi(Crtx, 0x2E);
+ switch(id){
+
+ case 0xE110: /* ViRGE/GX2 */
+ for(i = 0; i < 3; i++)
+ vgaxo(Crtx, 0x4A, Pblack);
+ vgaxi(Crtx, 0x45);
+ for(i = 0; i < 3; i++)
+ vgaxo(Crtx, 0x4B, Pwhite);
+ break;
+
+ default:
+ for(i = 0; i < 3; i++)
+ vgaxo(Crtx, 0x4A, Pwhite);
+ vgaxi(Crtx, 0x45);
+ for(i = 0; i < 3; i++)
+ vgaxo(Crtx, 0x4B, Pblack);
+ break;
+ }
+
+ /*
+ * Find a place for the cursor data in display memory.
+ * Must be on a 1024-byte boundary.
+ */
+ storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+1023)/1024;
+ vgaxo(Crtx, 0x4C, (storage>>8) & 0x0F);
+ vgaxo(Crtx, 0x4D, storage & 0xFF);
+ storage *= 1024;
+ scr->storage = storage;
+
+ /*
+ * Enable the cursor in Microsoft Windows format.
+ */
+ vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55) & ~0x10);
+ s3vsyncactive();
+ vgaxo(Crtx, 0x45, 0x01);
+}
+
+static void
+s3load(VGAscr* scr, Cursor* curs)
+{
+ uchar *p;
+ int id, opage, x, y;
+
+ /*
+ * Disable the cursor and
+ * set the pointer to the two planes.
+ */
+ s3disable(scr);
+
+ opage = 0;
+ p = KADDR(scr->aperture);
+ id = (vgaxi(Crtx, 0x30)<<8)|vgaxi(Crtx, 0x2E);
+ switch(id){
+
+ case 0xE110: /* ViRGE/GX2 */
+ p += scr->storage;
+ break;
+
+ default:
+ lock(&scr->devlock);
+ opage = s3pageset(scr, scr->storage>>16);
+ p += (scr->storage & 0xFFFF);
+ break;
+ }
+
+ /*
+ * The cursor is set in Microsoft Windows format (the ViRGE/GX2 no
+ * longer supports the X11 format) which gives the following truth table:
+ * and xor colour
+ * 0 0 background colour
+ * 0 1 foreground colour
+ * 1 0 current screen pixel
+ * 1 1 NOT current screen pixel
+ * Put the cursor into the top-left of the 64x64 array.
+ *
+ * The cursor pattern in memory is interleaved words of
+ * AND and XOR patterns.
+ */
+ for(y = 0; y < 64; y++){
+ for(x = 0; x < 64/8; x += 2){
+ if(x < 16/8 && y < 16){
+ *p++ = ~(curs->clr[2*y + x]|curs->set[2*y + x]);
+ *p++ = ~(curs->clr[2*y + x+1]|curs->set[2*y + x+1]);
+ *p++ = curs->set[2*y + x];
+ *p++ = curs->set[2*y + x+1];
+ }
+ else {
+ *p++ = 0xFF;
+ *p++ = 0xFF;
+ *p++ = 0x00;
+ *p++ = 0x00;
+ }
+ }
+ }
+
+ switch(id){
+
+ case 0xE110: /* ViRGE/GX2 */
+ break;
+
+ default:
+ s3pageset(scr, opage);
+ unlock(&scr->devlock);
+ break;
+ }
+
+ /*
+ * Save the cursor hotpoint and enable the cursor.
+ */
+ scr->offset = curs->offset;
+ s3vsyncactive();
+ vgaxo(Crtx, 0x45, 0x01);
+}
+
+static int
+s3move(VGAscr* scr, Point p)
+{
+ int x, xo, y, yo;
+
+ /*
+ * Mustn't position the cursor offscreen even partially,
+ * or it disappears. Therefore, if x or y is -ve, adjust the
+ * cursor offset instead.
+ * There seems to be a bug in that if the offset is 1, the
+ * cursor doesn't disappear off the left edge properly, so
+ * round it up to be even.
+ */
+ if((x = p.x+scr->offset.x) < 0){
+ xo = -x;
+ xo = ((xo+1)/2)*2;
+ x = 0;
+ }
+ else
+ xo = 0;
+ if((y = p.y+scr->offset.y) < 0){
+ yo = -y;
+ y = 0;
+ }
+ else
+ yo = 0;
+
+ vgaxo(Crtx, 0x46, (x>>8) & 0x07);
+ vgaxo(Crtx, 0x47, x & 0xFF);
+ vgaxo(Crtx, 0x49, y & 0xFF);
+ vgaxo(Crtx, 0x4E, xo);
+ vgaxo(Crtx, 0x4F, yo);
+ vgaxo(Crtx, 0x48, (y>>8) & 0x07);
+
+ return 0;
+}
+
+VGAdev vgas3dev = {
+ "s3",
+
+ 0,
+ 0,
+ s3page,
+ s3linear,
+};
+
+VGAcur vgas3cur = {
+ "s3hwgc",
+
+ s3enable,
+ s3disable,
+ s3load,
+ s3move,
+};
A alphapc/vgax.c => alphapc/vgax.c +103 -0
@@ 0,0 1,103 @@
+#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"
+
+static Lock vgaxlock; /* access to index registers */
+
+int
+vgaxi(long port, uchar index)
+{
+ uchar data;
+
+ ilock(&vgaxlock);
+ switch(port){
+
+ case Seqx:
+ case Crtx:
+ case Grx:
+ outb(port, index);
+ data = inb(port+1);
+ break;
+
+ case Attrx:
+ /*
+ * Allow processor access to the colour
+ * palette registers. Writes to Attrx must
+ * be preceded by a read from Status1 to
+ * initialise the register to point to the
+ * index register and not the data register.
+ * Processor access is allowed by turning
+ * off bit 0x20.
+ */
+ inb(Status1);
+ if(index < 0x10){
+ outb(Attrx, index);
+ data = inb(Attrx+1);
+ inb(Status1);
+ outb(Attrx, 0x20|index);
+ }
+ else{
+ outb(Attrx, 0x20|index);
+ data = inb(Attrx+1);
+ }
+ break;
+
+ default:
+ iunlock(&vgaxlock);
+ return -1;
+ }
+ iunlock(&vgaxlock);
+
+ return data & 0xFF;
+}
+
+int
+vgaxo(long port, uchar index, uchar data)
+{
+ ilock(&vgaxlock);
+ switch(port){
+
+ case Seqx:
+ case Crtx:
+ case Grx:
+ /*
+ * We could use an outport here, but some chips
+ * (e.g. 86C928) have trouble with that for some
+ * registers.
+ */
+ outb(port, index);
+ outb(port+1, data);
+ break;
+
+ case Attrx:
+ inb(Status1);
+ if(index < 0x10){
+ outb(Attrx, index);
+ outb(Attrx, data);
+ inb(Status1);
+ outb(Attrx, 0x20|index);
+ }
+ else{
+ outb(Attrx, 0x20|index);
+ outb(Attrx, data);
+ }
+ break;
+
+ default:
+ iunlock(&vgaxlock);
+ return -1;
+ }
+ iunlock(&vgaxlock);
+
+ return 0;
+}
M mpc/clock.c => mpc/clock.c +6 -6
@@ 59,8 59,10 @@ microdelay(int l)
;
}
+// the following can be 4 or 16 depending on the clock multiplier
+// see 15.3.3 in 860 manual
enum {
- Timebase = 4, /* system clock cycles per time base cycle */
+ Timebase = 16, /* system clock cycles per time base cycle */
};
static ulong clkreload;
@@ 70,18 72,18 @@ clockinit(void)
{
long x, est;
- est = m->clockgen/1000; /* initial estimate */
+ est = m->cpuhz/1000; /* initial estimate */
m->delayloop = est;
do {
x = gettbl();
- delay(10);
+ delay(1);
x = gettbl() - x;
} while(x < 0);
/*
* fix count
*/
- m->delayloop = (m->delayloop*10*est)/(x*Timebase);
+ m->delayloop = (m->delayloop*est/Timebase)/(x);
if(m->delayloop == 0)
m->delayloop = 1;
@@ 110,8 112,6 @@ clockintr(Ureg *ur)
m->iomem->swsr = 0xaa39;
m->ticks++;
- if(m->ticks%MS2TK(1000) == 0)
- *(uchar*)(NIMMEM+0x2200) = (m->ticks/MS2TK(1000))&2;
if(up)
up->pc = ur->pc;
M mpc/devuart.c => mpc/devuart.c +5 -5
@@ 462,7 462,7 @@ sccsetup(Uart *up)
if(0){
print("gsmrl=%8.8lux gsmrh=%8.8lux dsr=%4.4ux irmode=%4.4ux\n", scc->gsmrl, scc->gsmrh, scc->dsr, scc->irmode);
for(i=0; i<sizeof(Uartscc); i+=4)
- print("%2.2lux %8.8lux\n", i, *(ulong*)((uchar*)up->param+i));
+ print("%2.2ux %8.8lux\n", i, *(ulong*)((uchar*)up->param+i));
}
}
@@ 763,7 763,7 @@ static void
txstart(Uart *p)
{
Block *b;
- int n, flags, s;
+ int n, flags;
if(!p->cts || p->blocked || p->txb->status & BDReady)
@@ 1080,8 1080,6 @@ setlength(int i)
void
uartinstall(void)
{
- int port;
- char *p, *q;
static int already;
if(already)
@@ 1089,6 1087,8 @@ uartinstall(void)
already = 1;
uartsetup(1, SMC1ID, "eia0");
/*
+ int port;
+ char *p, *q;
if((p = getconf("console")) || (p = "0")){
if(USESMC2)
port = strtol(p, &q, 0);
@@ 1098,7 1098,7 @@ uartinstall(void)
uartspecial(port, 9600, &kbdq, &printq, kbdcr2nl);
}
*/
- uartspecial(0, 19200, &kbdq, &printq, kbdcr2nl);
+ uartspecial(0, 9600, &kbdq, &printq, kbdcr2nl);
// if(USESMC2)
// uartsetup(2, SMC2ID, "eia1");
M mpc/main.c => mpc/main.c +3 -15
@@ 18,18 18,6 @@ int predawn = 1;
Conf conf;
void
-flash(void)
-{
- int i;
- *(uchar*)(NIMMEM+0x2200) = 0;
- for(i=0; i<1000000; i++)
- ;
- *(uchar*)(NIMMEM+0x2200) = 0x2;
- for(i=0; i<1000000; i++)
- ;
-}
-
-void
main(void)
{
machinit();
@@ 72,7 60,7 @@ machinit(void)
m->iomem = KADDR(INTMEM);
io = m->iomem;
- osc = 5;
+ osc = 50;
mf = io->plprcr >> 20;
m->oscclk = osc;
m->speed = osc*(mf+1);
@@ 259,8 247,8 @@ confinit(void)
conf.nproc = 200; /* processes */
// hard wire for now
- pa = 0xff200000; // leave 2 Meg for kernel
- nbytes = 10*1024*1024; // leave room at the top as well
+ pa = 0xffd00000; // leave 1 Meg for kernel
+ nbytes = 2*1024*1024; // leave room at the top as well
conf.npage0 = nbytes/BY2PG;
conf.base0 = pa;
M mpc/mem.h => mpc/mem.h +0 -1
@@ 176,7 176,6 @@
* atlas board registers
*/
#define INTMEM 0x80000000
-#define NIMMEM 0x80100000
#define FLASH0MEM 0x80200000
#define FLASH1MEM 0x80400000
#define SDRAMMEM 0x03000000
M port/devssl.c => port/devssl.c +10 -7
@@ 737,23 737,26 @@ initDESkey(OneWay *w)
static void
initDESkey_40(OneWay *w)
{
+ uchar key[8];
+
if(w->state){
free(w->state);
w->state = 0;
}
- if(w->slen >= 8) {
- w->secret[0] &= 0x0f;
- w->secret[2] &= 0x0f;
- w->secret[4] &= 0x0f;
- w->secret[6] &= 0x0f;
+ if(w->slen >= 8){
+ memmove(key, w->secret, 8);
+ key[0] &= 0x0f;
+ key[2] &= 0x0f;
+ key[4] &= 0x0f;
+ key[6] &= 0x0f;
}
w->state = malloc(sizeof(DESstate));
if(w->slen >= 16)
- setupDESstate(w->state, w->secret, w->secret+8);
+ setupDESstate(w->state, key, w->secret+8);
else if(w->slen >= 8)
- setupDESstate(w->state, w->secret, 0);
+ setupDESstate(w->state, key, 0);
else
error("secret too short");
}