From e730a2625ae2ad2616b5736919f6afd6e1b4243f Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 15 Apr 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-04-15 --- alphapc/arch164.c | 389 ++++++++++++++++ alphapc/axp.h | 71 +++ alphapc/cga.c | 113 +++++ alphapc/clock.c | 146 ++++++ alphapc/dat.h | 228 +++++++++ alphapc/devether.c | 436 +++++++++++++++++ alphapc/devfloppy.c | 1057 ++++++++++++++++++++++++++++++++++++++++++ alphapc/devvga.c | 331 +++++++++++++ alphapc/dma.c | 232 +++++++++ alphapc/etherif.h | 33 ++ alphapc/faultalpha.c | 63 +++ alphapc/floppy.h | 173 +++++++ alphapc/fns.h | 108 +++++ alphapc/fptrap.c | 46 ++ alphapc/i8259.c | 151 ++++++ alphapc/io.h | 204 ++++++++ alphapc/kbd.c | 417 +++++++++++++++++ alphapc/l.s | 381 +++++++++++++++ alphapc/main.c | 401 ++++++++++++++++ alphapc/mem.h | 134 ++++++ alphapc/mmu.c | 245 ++++++++++ alphapc/mouse.c | 220 +++++++++ alphapc/ns16552.h | 60 +++ alphapc/pci.c | 351 ++++++++++++++ alphapc/screen.c | 314 +++++++++++++ alphapc/screen.h | 122 +++++ alphapc/segment.h | 9 + alphapc/trap.c | 700 ++++++++++++++++++++++++++++ alphapc/vga.c | 194 ++++++++ alphapc/vgargb524.c | 237 ++++++++++ alphapc/vgas3.c | 305 ++++++++++++ alphapc/vgax.c | 103 ++++ mpc/clock.c | 12 +- mpc/devuart.c | 10 +- mpc/main.c | 18 +- mpc/mem.h | 1 - port/devssl.c | 17 +- 37 files changed, 7998 insertions(+), 34 deletions(-) create mode 100644 alphapc/arch164.c create mode 100644 alphapc/axp.h create mode 100644 alphapc/cga.c create mode 100644 alphapc/clock.c create mode 100644 alphapc/dat.h create mode 100644 alphapc/devether.c create mode 100644 alphapc/devfloppy.c create mode 100644 alphapc/devvga.c create mode 100644 alphapc/dma.c create mode 100644 alphapc/etherif.h create mode 100644 alphapc/faultalpha.c create mode 100644 alphapc/floppy.h create mode 100644 alphapc/fns.h create mode 100644 alphapc/fptrap.c create mode 100644 alphapc/i8259.c create mode 100644 alphapc/io.h create mode 100644 alphapc/kbd.c create mode 100644 alphapc/l.s create mode 100644 alphapc/main.c create mode 100644 alphapc/mem.h create mode 100644 alphapc/mmu.c create mode 100644 alphapc/mouse.c create mode 100644 alphapc/ns16552.h create mode 100644 alphapc/pci.c create mode 100644 alphapc/screen.c create mode 100644 alphapc/screen.h create mode 100644 alphapc/segment.h create mode 100644 alphapc/trap.c create mode 100644 alphapc/vga.c create mode 100644 alphapc/vgargb524.c create mode 100644 alphapc/vgas3.c create mode 100644 alphapc/vgax.c diff --git a/alphapc/arch164.c b/alphapc/arch164.c new file mode 100644 index 0000000000000000000000000000000000000000..f1053d3f5c790ea438d7ccebcd59e05940a3bfe9 --- /dev/null +++ b/alphapc/arch164.c @@ -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<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, +}; diff --git a/alphapc/axp.h b/alphapc/axp.h new file mode 100644 index 0000000000000000000000000000000000000000..8ce9c6f15239238f7e6ae525b5976ea7d55cc840 --- /dev/null +++ b/alphapc/axp.h @@ -0,0 +1,71 @@ +typedef struct Hwrpb Hwrpb; +typedef struct Hwcpu Hwcpu; +typedef struct Hwdsr Hwdsr; + +struct Hwrpb +{ + uvlong phys; + uvlong sign; + uvlong rev; + uvlong size; + uvlong cpu0; + uvlong by2pg; + uvlong pabits; + uvlong maxasn; + char ssn[16]; + uvlong systype; + uvlong sysvar; + uvlong sysrev; + uvlong ifreq; + uvlong cfreq; + uvlong vptb; + uvlong resv; + uvlong tbhint; + uvlong ncpu; + uvlong cpulen; + uvlong cpuoff; + uvlong nctb; + uvlong ctblen; + uvlong ctboff; + uvlong ccrboff; + uvlong memoff; + uvlong confoff; + uvlong fruoff; + uvlong termsaveva; + uvlong termsavex; + uvlong termrestva; + uvlong termrestx; + uvlong termresetva; + uvlong termresetx; + uvlong sysresv; + uvlong hardresv; + uvlong csum; + uvlong rxrdymsk; + uvlong txrdymsk; + uvlong dsroff; /* rev 6 or higher */ +}; + +extern Hwrpb* hwrpb; + +struct Hwcpu +{ + uvlong hwpcb[16]; + uvlong state; + uvlong palmainlen; + uvlong palscratchlen; + uvlong palmainpa; + uvlong palscratchpa; + uvlong palrev; + uvlong cputype; + uvlong cpuvar; + uvlong cpurev; + uvlong serial[2]; + /* more crap ... */ +}; + +struct Hwdsr +{ + vlong smm; + uvlong lurtoff; + uvlong sysnameoff; +}; diff --git a/alphapc/cga.c b/alphapc/cga.c new file mode 100644 index 0000000000000000000000000000000000000000..c216617b7a79e9eb6e669d72ebbd3f3dc946b4c1 --- /dev/null +++ b/alphapc/cga.c @@ -0,0 +1,113 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "io.h" + +enum { + Width = 160, + Height = 25, + + Attr = 0x4f, /* white on blue */ +}; + +static ulong cgabase; +#define CGASCREENBASE ((uchar*)cgabase) + +static int cgapos; +static int screeninitdone; +static Lock cgascreenlock; + +static uchar +cgaregr(int index) +{ + outb(0x3D4, index); + return inb(0x3D4+1) & 0xFF; +} + +static void +cgaregw(int index, int data) +{ + outb(0x3D4, index); + outb(0x3D4+1, data); +} + +static void +movecursor(void) +{ + cgaregw(0x0E, (cgapos/2>>8) & 0xFF); + cgaregw(0x0F, cgapos/2 & 0xFF); + CGASCREENBASE[cgapos+1] = Attr; +} + +static void +cgascreenputc(int c) +{ + int i; + + if(c == '\n'){ + cgapos = cgapos/Width; + cgapos = (cgapos+1)*Width; + } + else if(c == '\t'){ + i = 8 - ((cgapos/2)&7); + while(i-->0) + cgascreenputc(' '); + } + else if(c == '\b'){ + if(cgapos >= 2) + cgapos -= 2; + cgascreenputc(' '); + cgapos -= 2; + } + else{ + CGASCREENBASE[cgapos++] = c; + CGASCREENBASE[cgapos++] = Attr; + } + if(cgapos >= Width*Height){ + memmove(CGASCREENBASE, &CGASCREENBASE[Width], Width*(Height-1)); + for (i = Width*(Height-1); i < Width*Height;) { + CGASCREENBASE[i++] = 0x20; + CGASCREENBASE[i++] = Attr; + } + cgapos = Width*(Height-1); + } + movecursor(); +} + +void +screeninit(void) +{ + cgabase = (ulong)arch->pcimem(0xB8000, 0x8000); + + cgapos = cgaregr(0x0E)<<8; + cgapos |= cgaregr(0x0F); + cgapos *= 2; + screeninitdone = 1; +} + +static void +cgascreenputs(char* s, int n) +{ + if(!screeninitdone) + return; + if(!islo()){ + /* + * Don't deadlock trying to + * print in an interrupt. + */ + if(!canlock(&cgascreenlock)) + return; + } + else + lock(&cgascreenlock); + + while(n-- > 0) + cgascreenputc(*s++); + + unlock(&cgascreenlock); +} + +void (*screenputs)(char*, int) = cgascreenputs; diff --git a/alphapc/clock.c b/alphapc/clock.c new file mode 100644 index 0000000000000000000000000000000000000000..02922f2eed37302a1998f2f5c994dc0be9440494 --- /dev/null +++ b/alphapc/clock.c @@ -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<machno)) == 0) + return; + + if(active.exiting && (active.machs & (1<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; +} diff --git a/alphapc/dat.h b/alphapc/dat.h new file mode 100644 index 0000000000000000000000000000000000000000..be53548d71ed666ead0de691effe1e995d717d9d --- /dev/null +++ b/alphapc/dat.h @@ -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; diff --git a/alphapc/devether.c b/alphapc/devether.c new file mode 100644 index 0000000000000000000000000000000000000000..18c7a33109c2890f52c14c970e96e3340347fc28 --- /dev/null +++ b/alphapc/devether.c @@ -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, +}; diff --git a/alphapc/devfloppy.c b/alphapc/devfloppy.c new file mode 100644 index 0000000000000000000000000000000000000000..4e43269bef13add4a342969302389253762b6e71 --- /dev/null +++ b/alphapc/devfloppy.c @@ -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, +}; diff --git a/alphapc/devvga.c b/alphapc/devvga.c new file mode 100644 index 0000000000000000000000000000000000000000..e6b4aa907e6cd9a3c0fd873a9e22aacf63d1092d --- /dev/null +++ b/alphapc/devvga.c @@ -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 +#include +#include +#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<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, +}; diff --git a/alphapc/dma.c b/alphapc/dma.c new file mode 100644 index 0000000000000000000000000000000000000000..ceea0333c02966191843a70a5c2cf7d035bee654 --- /dev/null +++ b/alphapc/dma.c @@ -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<>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<shift)+1); +} + */ diff --git a/alphapc/etherif.h b/alphapc/etherif.h new file mode 100644 index 0000000000000000000000000000000000000000..271b506b0fca23a14f1e271cad6d0310a7ddc16b --- /dev/null +++ b/alphapc/etherif.h @@ -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)) diff --git a/alphapc/faultalpha.c b/alphapc/faultalpha.c new file mode 100644 index 0000000000000000000000000000000000000000..9e18619a052fbf2e6c6f10dbdb71d75e0858352e --- /dev/null +++ b/alphapc/faultalpha.c @@ -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); + } +} diff --git a/alphapc/floppy.h b/alphapc/floppy.h new file mode 100644 index 0000000000000000000000000000000000000000..8376e59729c34f5de9502d35abc65f029a0cbfb3 --- /dev/null +++ b/alphapc/floppy.h @@ -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; +} diff --git a/alphapc/fns.h b/alphapc/fns.h new file mode 100644 index 0000000000000000000000000000000000000000..7d335cb95274e8b1ed842898e9ba8264bd858fc9 --- /dev/null +++ b/alphapc/fns.h @@ -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)) diff --git a/alphapc/fptrap.c b/alphapc/fptrap.c new file mode 100644 index 0000000000000000000000000000000000000000..0166d3603ed05eb08007510b0e863740b1d2fccb --- /dev/null +++ b/alphapc/fptrap.c @@ -0,0 +1,46 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "ureg.h" +#include "io.h" +#include "../port/error.h" + +char *fpcause[] = +{ + "invalid operation", + "division by zero", + "overflow", + "underflow", + "inexact operation", + "integer overflow", +}; +char *fpexcname(Ureg*, ulong, char*); + +void +fptrap(Ureg *ur) +{ + char buf[ERRLEN]; + int i; + ulong reason; + + ur->pc &= ~2; + reason = (ulong)ur->a0; + for (i = 1; i < 6; i++) + if (reason & (1<= 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<eoi = i8259isr; + else + irqctl->isr = i8259isr; + irqctl->isintr = 1; + + return v; +} diff --git a/alphapc/io.h b/alphapc/io.h new file mode 100644 index 0000000000000000000000000000000000000000..1473d266a32096a8d0e0ed87834faab8830b0c1c --- /dev/null +++ b/alphapc/io.h @@ -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; diff --git a/alphapc/kbd.c b/alphapc/kbd.c new file mode 100644 index 0000000000000000000000000000000000000000..11d612ac3db6dd68da06681e3dc411e1ed96ffab --- /dev/null +++ b/alphapc/kbd.c @@ -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; isplpc */ + 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 diff --git a/alphapc/main.c b/alphapc/main.c new file mode 100644 index 0000000000000000000000000000000000000000..6569202afb1395fb18d010193e4e5d261bc9bb83 --- /dev/null +++ b/alphapc/main.c @@ -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<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; +} diff --git a/alphapc/mem.h b/alphapc/mem.h new file mode 100644 index 0000000000000000000000000000000000000000..07e785063733b64ae7b5b706e312481fc56644d0 --- /dev/null +++ b/alphapc/mem.h @@ -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) diff --git a/alphapc/mmu.c b/alphapc/mmu.c new file mode 100644 index 0000000000000000000000000000000000000000..85985c248e142ff0aca583c43687733b2b58e74e --- /dev/null +++ b/alphapc/mmu.c @@ -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)<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); + + 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)<newtlb = 1; + mmuswitch(up); + splx(s); + +} + +ulong +upamalloc(...) +{ + panic("upamalloc"); +} + +void +upafree(...) +{ + panic("upafree"); +} diff --git a/alphapc/mouse.c b/alphapc/mouse.c new file mode 100644 index 0000000000000000000000000000000000000000..a5aec038466ef7b9b860529a3e96c6488e79778a --- /dev/null +++ b/alphapc/mouse.c @@ -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 +#include +#include +#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); +} diff --git a/alphapc/ns16552.h b/alphapc/ns16552.h new file mode 100644 index 0000000000000000000000000000000000000000..fdf072e8f5d814dc9df7f76e4a5a7e4f7d2c2038 --- /dev/null +++ b/alphapc/ns16552.h @@ -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; +} diff --git a/alphapc/pci.c b/alphapc/pci.c new file mode 100644 index 0000000000000000000000000000000000000000..01e56d6d19e056f2e0e01ca1fb18e9aee6fbe7ca --- /dev/null +++ b/alphapc/pci.c @@ -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); + } +} diff --git a/alphapc/screen.c b/alphapc/screen.c new file mode 100644 index 0000000000000000000000000000000000000000..a634ab32c42e5f59b4800e9825557ae0e8a106ea --- /dev/null +++ b/alphapc/screen.c @@ -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 +#include +#include +#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<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<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); +} diff --git a/alphapc/screen.h b/alphapc/screen.h new file mode 100644 index 0000000000000000000000000000000000000000..ac896752d94c2e630a80b69dca75e39bcbe6c344 --- /dev/null +++ b/alphapc/screen.h @@ -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*); diff --git a/alphapc/segment.h b/alphapc/segment.h new file mode 100644 index 0000000000000000000000000000000000000000..f9c7e43410e8c8c8f2d46e0e558e77507d230db4 --- /dev/null +++ b/alphapc/segment.h @@ -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 }, +}; diff --git a/alphapc/trap.c b/alphapc/trap.c new file mode 100644 index 0000000000000000000000000000000000000000..028d159a6fd0f863379dd4264997bdc564f4473d --- /dev/null +++ b/alphapc/trap.c @@ -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>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 */ +} diff --git a/alphapc/vga.c b/alphapc/vga.c new file mode 100644 index 0000000000000000000000000000000000000000..7ca41d658d1d7f0020fe4a16a9837216f4a5e342 --- /dev/null +++ b/alphapc/vga.c @@ -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 +#include +#include +#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; +} diff --git a/alphapc/vgargb524.c b/alphapc/vgargb524.c new file mode 100644 index 0000000000000000000000000000000000000000..384901fc4228f9c4f642571bc165aa931fe67f4b --- /dev/null +++ b/alphapc/vgargb524.c @@ -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 +#include +#include +#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, +}; diff --git a/alphapc/vgas3.c b/alphapc/vgas3.c new file mode 100644 index 0000000000000000000000000000000000000000..a9d3bb164e64f6ee6b6e3407e5f683f78dc181aa --- /dev/null +++ b/alphapc/vgas3.c @@ -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 +#include +#include +#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, +}; diff --git a/alphapc/vgax.c b/alphapc/vgax.c new file mode 100644 index 0000000000000000000000000000000000000000..757ca171af4d8559ce7a2cd17307f3139bef8905 --- /dev/null +++ b/alphapc/vgax.c @@ -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 +#include +#include +#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; +} diff --git a/mpc/clock.c b/mpc/clock.c index 1fb7e037de8184e793d6b148ac6e41eae5ff22b6..e17723f655adbb51a0d384c92b31be51c70588d9 100644 --- a/mpc/clock.c +++ b/mpc/clock.c @@ -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; diff --git a/mpc/devuart.c b/mpc/devuart.c index 98acfa89e82ee537e791b6872b7da38fdeb5b573..4a1ab092daeb0b243d6b356fc96c94ef5168ca1b 100644 --- a/mpc/devuart.c +++ b/mpc/devuart.c @@ -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; iparam+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"); diff --git a/mpc/main.c b/mpc/main.c index dec9b1e5070c3bb374557526ed141b098b2c4241..1e4cdb5a998e4e50212751c54d152ed6345c0331 100644 --- a/mpc/main.c +++ b/mpc/main.c @@ -17,18 +17,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) { @@ -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; diff --git a/mpc/mem.h b/mpc/mem.h index 0476477ab0633f3972e3ebeb59808faf09155041..7594f07668a1f394b33ede2f44f9abbbef8fd69c 100644 --- a/mpc/mem.h +++ b/mpc/mem.h @@ -176,7 +176,6 @@ * atlas board registers */ #define INTMEM 0x80000000 -#define NIMMEM 0x80100000 #define FLASH0MEM 0x80200000 #define FLASH1MEM 0x80400000 #define SDRAMMEM 0x03000000 diff --git a/port/devssl.c b/port/devssl.c index 80c65ad73b290d735dee05a9595a8b9c7f6532a2..5f4d72899afee4aacec699617a741f09917911e3 100644 --- a/port/devssl.c +++ b/port/devssl.c @@ -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"); }