From 6bef100f0dd843cc87308798f1686a0801dc0d77 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 18 Dec 2001 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2001-12-18 --- mtx/clock.c | 36 ++++- mtx/dat.h | 16 ++ mtx/devarch.c | 400 ++++++++++++++++++++++++++++++++++++++++++++++ mtx/fns.h | 33 ++-- mtx/i8259.c | 14 ++ mtx/kbd.c | 435 ++++++++++++++++++++++++++++++++++++++++++++++++++ mtx/main.c | 9 +- mtx/raven.c | 16 +- mtx/trap.c | 257 ++++++++++++++++++----------- port/proc.c | 5 +- 10 files changed, 1092 insertions(+), 129 deletions(-) create mode 100644 mtx/devarch.c create mode 100644 mtx/kbd.c diff --git a/mtx/clock.c b/mtx/clock.c index 4113e9a1e34442732cb23bef4318918c5969bb74..729b00d4900bc0daea97be60e28ce4d76afe83bc 100644 --- a/mtx/clock.c +++ b/mtx/clock.c @@ -6,12 +6,36 @@ #include "io.h" #include "ureg.h" +static ulong clkreload; + +// the following can be 4 or 16 depending on the clock multiplier +// see 15.3.3 in 860 manual +enum { + Timebase = 16, /* system clock cycles per time base cycle */ +}; + +void +clockinit(void) +{ +// delayloopinit(); + +// clkreload = (m->clockgen/Timebase)/HZ-1; + clkreload = (300000000/Timebase)/HZ-1; + putdec(clkreload); +} + void clockintr(Ureg *ureg) { - // this needs to be here for synchronizing mp clocks - // see pc/mp.c's squidboy() - fastticks(nil); + long v; + + v = -getdec(); + if(v > clkreload/2){ + if(v > clkreload) + m->ticks += v/clkreload; + v = 0; + } + putdec(clkreload-v); if(m->flushmmu){ if(up) @@ -20,6 +44,7 @@ clockintr(Ureg *ureg) } portclock(ureg); +if((m->ticks%HZ) == 0) print("tick! %d\n", m->ticks/HZ); } void @@ -47,11 +72,6 @@ microdelay(int l) ; } -void -clockinit(void) -{ -} - vlong fastticks(uvlong *hz) { diff --git a/mtx/dat.h b/mtx/dat.h index 02251b58734daf8f6a435dfb16d90ee3f4c032af..589793e42b75dd2e46e96ba8cb9d342908fd7c2d 100644 --- a/mtx/dat.h +++ b/mtx/dat.h @@ -6,6 +6,7 @@ typedef struct Lock Lock; typedef struct Mach Mach; typedef struct Notsave Notsave; typedef struct Page Page; +typedef struct PCArch PCArch; typedef struct Pcidev Pcidev; typedef struct PMMU PMMU; typedef struct Proc Proc; @@ -164,6 +165,21 @@ struct short ispanic; }active; +/* + * Implementation-dependant functions (outside of PPC architecture proper). + * Called PCArch because that's what mkdevc calls it (for the PC). + */ +struct PCArch +{ + char* id; + int (*ident)(void); /* this should be in the model */ + + void (*intrinit)(void); + int (*intrenable)(Vctl*); + int (*intrvecno)(int); + int (*intrdisable)(int); +}; + /* * a parsed plan9.ini line */ diff --git a/mtx/devarch.c b/mtx/devarch.c new file mode 100644 index 0000000000000000000000000000000000000000..e80d8bc427c16868537e7f0a90deac9eb83f2a09 --- /dev/null +++ b/mtx/devarch.c @@ -0,0 +1,400 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +typedef struct IOMap IOMap; +struct IOMap +{ + IOMap *next; + char tag[13]; + ulong start; + ulong end; +}; + +static struct +{ + Lock; + IOMap *m; + IOMap *free; + IOMap maps[32]; // some initial free maps + + QLock ql; // lock for reading map +} iomap; + +enum { + Qdir = 0, + Qioalloc = 1, + Qiob, + Qiow, + Qiol, + Qbase, + + Qmax = 16, +}; + +typedef long Rdwrfn(Chan*, void*, long, vlong); + +static Rdwrfn *readfn[Qmax]; +static Rdwrfn *writefn[Qmax]; + +static Dirtab archdir[] = { + ".", { Qdir, 0, QTDIR }, 0, 0555, + "ioalloc", { Qioalloc, 0 }, 0, 0444, + "iob", { Qiob, 0 }, 0, 0660, + "iow", { Qiow, 0 }, 0, 0660, + "iol", { Qiol, 0 }, 0, 0660, +}; +Lock archwlock; /* the lock is only for changing archdir */ +int narchdir = Qbase; +int (*_pcmspecial)(char *, ISAConf *); +void (*_pcmspecialclose)(int); + +/* + * Add a file to the #P listing. Once added, you can't delete it. + * You can't add a file with the same name as one already there, + * and you get a pointer to the Dirtab entry so you can do things + * like change the Qid version. Changing the Qid path is disallowed. + */ +Dirtab* +addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn) +{ + int i; + Dirtab d; + Dirtab *dp; + + memset(&d, 0, sizeof d); + strcpy(d.name, name); + d.perm = perm; + + lock(&archwlock); + if(narchdir >= Qmax){ + unlock(&archwlock); + return nil; + } + + for(i=0; inext){ + m = *l; + i = m->start - port; + if(i > size) + break; + if(align > 0) + port = ((port+align-1)/align)*align; + else + port = m->end; + } + if(*l == nil){ + unlock(&iomap); + return -1; + } + } else { + // see if the space clashes with previously allocated ports + for(l = &iomap.m; *l; l = &(*l)->next){ + m = *l; + if(m->end <= port) + continue; + if(m->start >= port+size) + break; + unlock(&iomap); + return -1; + } + } + m = iomap.free; + if(m == nil){ + print("ioalloc: out of maps"); + unlock(&iomap); + return port; + } + iomap.free = m->next; + m->next = *l; + m->start = port; + m->end = port + size; + strncpy(m->tag, tag, sizeof(m->tag)); + m->tag[sizeof(m->tag)-1] = 0; + *l = m; + + archdir[0].qid.vers++; + + unlock(&iomap); + return m->start; +} + +void +iofree(int port) +{ + IOMap *m, **l; + + lock(&iomap); + for(l = &iomap.m; *l; l = &(*l)->next){ + if((*l)->start == port){ + m = *l; + *l = m->next; + m->next = iomap.free; + iomap.free = m; + break; + } + if((*l)->start > port) + break; + } + archdir[0].qid.vers++; + unlock(&iomap); +} + +int +iounused(int start, int end) +{ + IOMap *m; + + for(m = iomap.m; m; m = m->next){ + if(start >= m->start && start < m->end + || start <= m->start && end > m->start) + return 0; + } + return 1; +} + +static void +checkport(int start, int end) +{ + /* standard vga regs are OK */ + if(start >= 0x2b0 && end <= 0x2df+1) + return; + if(start >= 0x3c0 && end <= 0x3da+1) + return; + + if(iounused(start, end)) + return; + error(Eperm); +} + +static Chan* +archattach(char* spec) +{ + return devattach('P', spec); +} + +Walkqid* +archwalk(Chan* c, Chan *nc, char** name, int nname) +{ + return devwalk(c, nc, name, nname, archdir, narchdir, devgen); +} + +static int +archstat(Chan* c, uchar* dp, int n) +{ + return devstat(c, dp, n, archdir, narchdir, devgen); +} + +static Chan* +archopen(Chan* c, int omode) +{ + return devopen(c, omode, archdir, nelem(archdir), devgen); +} + +static void +archclose(Chan*) +{ +} + +enum +{ + Linelen= 31, +}; + +static long +archread(Chan *c, void *a, long n, vlong offset) +{ + char buf[Linelen+1], *p; + int port; + ushort *sp; + ulong *lp; + IOMap *m; + Rdwrfn *fn; + + switch((ulong)c->qid.path){ + + case Qdir: + return devdirread(c, a, n, archdir, nelem(archdir), devgen); + + case Qiob: + port = offset; + checkport(offset, offset+n); + for(p = a; port < offset+n; port++) + *p++ = inb(port); + return n; + + case Qiow: + if((n & 0x01) || (offset & 0x01)) + error(Ebadarg); + checkport(offset, offset+n+1); + n /= 2; + sp = a; + for(port = offset; port < offset+n; port += 2) + *sp++ = ins(port); + return n*2; + + case Qiol: + if((n & 0x03) || (offset & 0x03)) + error(Ebadarg); + checkport(offset, offset+n+3); + n /= 4; + lp = a; + for(port = offset; port < offset+n; port += 4) + *lp++ = inl(port); + return n*4; + + case Qioalloc: + break; + + default: + if(c->qid.path < narchdir && (fn = readfn[c->qid.path])) + return fn(c, a, n, offset); + error(Eperm); + break; + } + + offset = offset/Linelen; + n = n/Linelen; + p = a; + lock(&iomap); + for(m = iomap.m; n > 0 && m != nil; m = m->next){ + if(offset-- > 0) + continue; + if(strcmp(m->tag, "dummy") == 0) + break; + sprint(buf, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag); + memmove(p, buf, Linelen); + p += Linelen; + n--; + } + unlock(&iomap); + + return p - (char*)a; +} + +static long +archwrite(Chan *c, void *a, long n, vlong offset) +{ + char *p; + int port; + ushort *sp; + ulong *lp; + Rdwrfn *fn; + + switch((ulong)c->qid.path){ + + case Qiob: + p = a; + checkport(offset, offset+n); + for(port = offset; port < offset+n; port++) + outb(port, *p++); + return n; + + case Qiow: + if((n & 01) || (offset & 01)) + error(Ebadarg); + checkport(offset, offset+n+1); + n /= 2; + sp = a; + for(port = offset; port < offset+n; port += 2) + outs(port, *sp++); + return n*2; + + case Qiol: + if((n & 0x03) || (offset & 0x03)) + error(Ebadarg); + checkport(offset, offset+n+3); + n /= 4; + lp = a; + for(port = offset; port < offset+n; port += 4) + outl(port, *lp++); + return n*4; + + default: + if(c->qid.path < narchdir && (fn = writefn[c->qid.path])) + return fn(c, a, n, offset); + error(Eperm); + break; + } + return 0; +} + +Dev archdevtab = { + 'P', + "arch", + + devreset, + devinit, + archattach, + archwalk, + archstat, + archopen, + devcreate, + archclose, + archread, + devbread, + archwrite, + devbwrite, + devremove, + devwstat, +}; + +int +pcmspecial(char *idstr, ISAConf *isa) +{ + return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1; +} + +void +pcmspecialclose(int a) +{ + if (_pcmspecialclose != nil) + _pcmspecialclose(a); +} diff --git a/mtx/fns.h b/mtx/fns.h index 4f1aabb554845aba3813395719086618b3df6bbe..b9cec89d3289a35d6d6e6479aaf354ffd257cda8 100644 --- a/mtx/fns.h +++ b/mtx/fns.h @@ -1,9 +1,6 @@ #include "../port/portfns.h" void archinit(void); -int brgalloc(void); -void brgfree(int); -ulong baudgen(int, int); int cistrcmp(char*, char*); int cistrncmp(char*, char*, int); void clockcheck(void); @@ -11,14 +8,10 @@ void clockinit(void); void clockintr(Ureg*); void clrfptrap(void); #define coherence() -void cpminit(void); void cpuidentify(void); void cpuidprint(void); void dcflush(void*, ulong); void delay(int); -ulong draminit(ulong*); -void dtlbmiss(void); -void dtlberror(void); void dumpregs(Ureg*); void delayloopinit(void); void eieio(void); @@ -40,7 +33,13 @@ ulong getpvr(void); ulong gettbl(void); ulong gettbu(void); void gotopc(ulong); +void hwintrinit(void); void i8250console(void); +void i8259init(void); +int i8259intack(void); +int i8259enable(Vctl*); +int i8259vecno(int); +int i8259disable(int); void icflush(void*, ulong); void idle(void); #define idlehands() /* nothing to do in the runproc */ @@ -52,10 +51,9 @@ ulong inl(int); void insl(int, void*, int); void intr(Ureg*); void intrenable(int, void (*)(Ureg*, void*), void*, int, char*); -int intrstats(char*, int); -void intrvec(void); +int ioalloc(int, int, int, char*); +void ioinit(void); int iprint(char*, ...); -void itlbmiss(void); int isaconfig(char*, int, ISAConf*); void kbdinit(void); void kbdreset(void); @@ -65,8 +63,9 @@ void links(void); void mathinit(void); void mmuinit(void); ulong* mmuwalk(ulong*, ulong, int); -void mpicenable(int); -void mpiceoi(void); +void mpicdisable(int); +void mpicenable(int, Vctl*); +int mpiceoi(int); int mpicintack(void); void outb(int, int); void outsb(int, void*, int); @@ -89,11 +88,7 @@ Pcidev* pcimatch(Pcidev*, int, int); Pcidev* pcimatchtbdf(int); void pcireset(void); void pcisetbme(Pcidev*); -int pcmspecial(char*, ISAConf*); -void pcmspecialclose(int); #define procrestore(p) -void powerdownled(void); -void powerupled(void); void procsave(Proc*); void procsetup(Proc*); void putdec(ulong); @@ -101,14 +96,9 @@ void putmsr(ulong); void putcasid(ulong); void raveninit(void); void screeninit(void); -void setpanic(void); int screenprint(char*, ...); /* debugging */ -ulong sdraminit(ulong*); int segflush(void*, ulong); -void spireset(void); -long spioutin(void*, long, void*); int tas(void*); -uchar* tarlookup(uchar *addr, char *file, int *dlen); void touser(void*); void trapinit(void); void trapvec(void); @@ -116,7 +106,6 @@ void tlbflush(ulong); void tlbflushall(void); void uartinstall(void); void uartwait(void); /* debugging */ -int unsac(uchar *dst, uchar *src, int n, int nsrc); #define userureg(ur) (((ur)->status & MSR_PR) != 0) void wbflush(void); diff --git a/mtx/i8259.c b/mtx/i8259.c index 562196b96fe5738eaa11a913ba7dbfdf716a879f..605cd3fc02c5b64c87d7730fe84f468c3bbfb7a1 100644 --- a/mtx/i8259.c +++ b/mtx/i8259.c @@ -165,6 +165,20 @@ i8259enable(Vctl* v) return VectorPIC+irq; } +int +i8259intack(void) +{ + int irq; + + outb(Int0ctl, Ocw3|0x07); /* intr ack on first 8259 */ + irq = inb(Int0ctl) & 7; + if(irq == 2) { /* cascade */ + outb(Int1ctl, Ocw3|0x07); /* intr ack on second 8259 */ + irq = (inb(Int1ctl) & 7) + 8; + } + return irq+VectorPIC; +} + int i8259vecno(int irq) { diff --git a/mtx/kbd.c b/mtx/kbd.c new file mode 100644 index 0000000000000000000000000000000000000000..fe96fc3455a20195f20546940288de3c8e0968b6 --- /dev/null +++ b/mtx/kbd.c @@ -0,0 +1,435 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +enum { + Data= 0x60, /* data port */ + + Status= 0x64, /* status port */ + Inready= 0x01, /* input character ready */ + Outbusy= 0x02, /* output busy */ + Sysflag= 0x04, /* system flag */ + Cmddata= 0x08, /* cmd==0, data==1 */ + Inhibit= 0x10, /* keyboard/mouse inhibited */ + Minready= 0x20, /* mouse character ready */ + Rtimeout= 0x40, /* general timeout */ + Parity= 0x80, + + Cmd= 0x64, /* command port (write only) */ + + Spec= 0x80, + + PF= Spec|0x20, /* num pad function key */ + View= Spec|0x00, /* view (shift window up) */ + KF= 0xF000, /* function key (begin Unicode private space) */ + Shift= Spec|0x60, + Break= Spec|0x61, + Ctrl= Spec|0x62, + Latin= Spec|0x63, + Caps= Spec|0x64, + Num= Spec|0x65, + Middle= Spec|0x66, + No= 0x00, /* peter */ + + Home= KF|13, + Up= KF|14, + Pgup= KF|15, + Print= KF|16, + Left= KF|17, + Right= KF|18, + End= '\r', + Down= View, + Pgdown= KF|19, + Ins= KF|20, + Del= 0x7F, + Scroll= KF|21, +}; + +/* + * The codes at 0x79 and 0x81 are produed by the PFU Happy Hacking keyboard. + * A 'standard' keyboard doesn't produce anything above 0x58. + */ +Rune kbtab[] = +{ +[0x00] No, 0x1b, '1', '2', '3', '4', '5', '6', +[0x08] '7', '8', '9', '0', '-', '=', '\b', '\t', +[0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', +[0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's', +[0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', +[0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v', +[0x30] 'b', 'n', 'm', ',', '.', '/', Shift, '*', +[0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5, +[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7', +[0x48] '8', '9', '-', '4', '5', '6', '+', '1', +[0x50] '2', '3', '0', '.', No, No, No, KF|11, +[0x58] KF|12, No, No, No, No, No, No, No, +[0x60] No, No, No, No, No, No, No, No, +[0x68] No, No, No, No, No, No, No, No, +[0x70] No, No, No, No, No, No, No, No, +[0x78] No, View, No, Up, No, No, No, No, +}; + +Rune kbtabshift[] = +{ +[0x00] No, 0x1b, '!', '@', '#', '$', '%', '^', +[0x08] '&', '*', '(', ')', '_', '+', '\b', '\t', +[0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', +[0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S', +[0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', +[0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V', +[0x30] 'B', 'N', 'M', '<', '>', '?', Shift, '*', +[0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5, +[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7', +[0x48] '8', '9', '-', '4', '5', '6', '+', '1', +[0x50] '2', '3', '0', '.', No, No, No, KF|11, +[0x58] KF|12, No, No, No, No, No, No, No, +[0x60] No, No, No, No, No, No, No, No, +[0x68] No, No, No, No, No, No, No, No, +[0x70] No, No, No, No, No, No, No, No, +[0x78] No, Up, No, Up, No, No, No, No, +}; + +Rune kbtabesc1[] = +{ +[0x00] No, No, No, No, No, No, No, No, +[0x08] No, No, No, No, No, No, No, No, +[0x10] No, No, No, No, No, No, No, No, +[0x18] No, No, No, No, '\n', Ctrl, No, No, +[0x20] No, No, No, No, No, No, No, No, +[0x28] No, No, Shift, No, No, No, No, No, +[0x30] No, No, No, No, No, '/', No, Print, +[0x38] Latin, No, No, No, No, No, No, No, +[0x40] No, No, No, No, No, No, Break, Home, +[0x48] Up, Pgup, No, Left, No, Right, No, End, +[0x50] Down, Pgdown, Ins, Del, No, No, No, No, +[0x58] No, No, No, No, No, No, No, No, +[0x60] No, No, No, No, No, No, No, No, +[0x68] No, No, No, No, No, No, No, No, +[0x70] No, No, No, No, No, No, No, No, +[0x78] No, Up, No, No, No, No, No, No, +}; + +enum +{ + /* controller command byte */ + Cscs1= (1<<6), /* scan code set 1 */ + Cauxdis= (1<<5), /* mouse disable */ + Ckbddis= (1<<4), /* kbd disable */ + Csf= (1<<2), /* system flag */ + Cauxint= (1<<1), /* mouse interrupt enable */ + Ckbdint= (1<<0), /* kbd interrupt enable */ +}; + +static Lock i8042lock; +static uchar ccc; +static void (*auxputc)(int, int); + +/* + * wait for output no longer busy + */ +static int +outready(void) +{ + int tries; + + for(tries = 0; (inb(Status) & Outbusy); tries++){ + if(tries > 500) + return -1; + delay(2); + } + return 0; +} + +/* + * wait for input + */ +static int +inready(void) +{ + int tries; + + for(tries = 0; !(inb(Status) & Inready); tries++){ + if(tries > 500) + return -1; + delay(2); + } + return 0; +} + +/* + * ask 8042 to reset the machine + */ +void +i8042reset(void) +{ + ushort *s = KADDR(0x472); + int i, x; + + *s = 0x1234; /* BIOS warm-boot flag */ + + /* + * newer reset the machine command + */ + outready(); + outb(Cmd, 0xFE); + outready(); + + /* + * Pulse it by hand (old somewhat reliable) + */ + x = 0xDF; + for(i = 0; i < 5; i++){ + x ^= 1; + outready(); + outb(Cmd, 0xD1); + outready(); + outb(Data, x); /* toggle reset */ + delay(100); + } +} + +int +i8042auxcmd(int cmd) +{ + unsigned int c; + int tries; + + c = 0; + tries = 0; + + ilock(&i8042lock); + do{ + if(tries++ > 2) + break; + if(outready() < 0) + break; + outb(Cmd, 0xD4); + if(outready() < 0) + break; + outb(Data, cmd); + if(outready() < 0) + break; + if(inready() < 0) + break; + c = inb(Data); + } while(c == 0xFE || c == 0); + iunlock(&i8042lock); + + if(c != 0xFA){ + print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd); + return -1; + } + return 0; +} + +/* + * keyboard interrupt + */ +static void +i8042intr(Ureg*, void*) +{ + int s, c, i; + static int esc1, esc2; + static int alt, caps, ctl, num, shift; + static int collecting, nk; + static Rune kc[5]; + int keyup; + + /* + * get status + */ + lock(&i8042lock); + s = inb(Status); + if(!(s&Inready)){ + unlock(&i8042lock); + return; + } + + /* + * get the character + */ + c = inb(Data); + unlock(&i8042lock); + + /* + * if it's the aux port... + */ + if(s & Minready){ + if(auxputc != nil) + auxputc(c, shift); + return; + } + + /* + * e0's is the first of a 2 character sequence + */ + if(c == 0xe0){ + esc1 = 1; + return; + } else if(c == 0xe1){ + esc2 = 2; + return; + } + + keyup = c&0x80; + c &= 0x7f; + if(c > sizeof kbtab){ + c |= keyup; + if(c != 0xFF) /* these come fairly often: CAPSLOCK U Y */ + print("unknown key %ux\n", c); + return; + } + + if(esc1){ + c = kbtabesc1[c]; + esc1 = 0; + } else if(esc2){ + esc2--; + return; + } else if(shift) + c = kbtabshift[c]; + else + c = kbtab[c]; + + if(caps && c<='z' && c>='a') + c += 'A' - 'a'; + + /* + * keyup only important for shifts + */ + if(keyup){ + switch(c){ + case Latin: + alt = 0; + break; + case Shift: + shift = 0; + break; + case Ctrl: + ctl = 0; + break; + } + return; + } + + /* + * normal character + */ + if(!(c & (Spec|KF))){ + if(ctl){ + if(alt && c == Del) + exit(0); + c &= 0x1f; + } + if(!collecting){ + kbdputc(kbdq, c); + return; + } + kc[nk++] = c; + c = latin1(kc, nk); + if(c < -1) /* need more keystrokes */ + return; + if(c != -1) /* valid sequence */ + kbdputc(kbdq, c); + else /* dump characters */ + for(i=0; ieoi = mpiceoi; +} + +void +mpicdisable(int vec) +{ + mpic32w(0x10000+0x20*vec, (1<<31)); } int @@ -136,8 +144,10 @@ mpicintack(void) return mpic32r(0x200A0 + (m->machno<<12)); } -void -mpiceoi(void) +int +mpiceoi(int vec) { + USED(vec); mpic32w(0x200B0 + (m->machno<<12), 0); + return 0; } diff --git a/mtx/trap.c b/mtx/trap.c index 76129dad3ccd502268779c9e7c8e9257ff95f02c..e42df7e6449aa8f170ba3f3220370510bccc4e86 100644 --- a/mtx/trap.c +++ b/mtx/trap.c @@ -7,31 +7,141 @@ #include "io.h" #include "../port/error.h" -enum +static Lock vctllock; +static Vctl *vctl[256]; + +void +hwintrinit(void) { - Maxhandler= 32+16, /* max number of interrupt handlers */ -}; + i8259init(); + mpicenable(0, nil); /* 8259 interrupts are routed through MPIC intr 0 */ +} -typedef struct Handler Handler; -struct Handler +static int +hwintrenable(Vctl *v) { - void (*r)(Ureg*, void*); - void *arg; - Handler *next; - int edge; - int nintr; - ulong ticks; - int maxtick; -}; + int vec, irq; + + irq = v->irq; + if(BUSTYPE(v->tbdf) == BusPCI) { /* MPIC? */ + if(irq > 15) { + print("intrenable: pci irq %d out of range\n", v->irq); + return -1; + } + vec = irq; + mpicenable(vec, v); + } + else { + if(irq > MaxIrqPIC) { + print("intrenable: irq %d out of range\n", v->irq); + return -1; + } + vec = irq+VectorPIC; + if(i8259enable(v) == -1) + return -1; + } + return vec; +} + +static int +hwintrdisable(Vctl *v) +{ + int vec, irq; + + irq = v->irq; + if(BUSTYPE(v->tbdf) == BusPCI) { /* MPIC? */ + if(irq > 15) { + print("intrdisable: pci irq %d out of range\n", v->irq); + return -1; + } + vec = irq; + mpicdisable(vec); + } + else { + if(irq > MaxIrqPIC) { + print("intrdisable: irq %d out of range\n", v->irq); + return -1; + } + vec = irq+VectorPIC; + if(i8259disable(irq) == -1) + return -1; + } + return vec; +} -struct +static int +hwvecno(int irq, int tbdf) { - Handler *ivec[MaxVectorPIC+1]; - Handler h[Maxhandler]; - int free; -} halloc; + if(BUSTYPE(tbdf) == BusPCI) /* MPIC? */ + return irq; + else + return irq+VectorPIC; +} -Lock veclock; +void +intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name) +{ + int vno; + Vctl *v; + + if(f == nil){ + print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n", + irq, tbdf, name); + return; + } + + v = xalloc(sizeof(Vctl)); + v->isintr = 1; + v->irq = irq; + v->tbdf = tbdf; + v->f = f; + v->a = a; + strncpy(v->name, name, KNAMELEN-1); + v->name[KNAMELEN-1] = 0; + + ilock(&vctllock); + vno = hwintrenable(v); + if(vno == -1){ + iunlock(&vctllock); + print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n", + irq, tbdf, v->name); + xfree(v); + return; + } + if(vctl[vno]){ + if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi) + panic("intrenable: handler: %s %s %luX %luX %luX %luX\n", + vctl[vno]->name, v->name, + vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi); + v->next = vctl[vno]; + } + vctl[vno] = v; + iunlock(&vctllock); +} + +void +intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name) +{ + Vctl **pv, *v; + int vno; + + vno = hwvecno(irq, tbdf); + ilock(&vctllock); + pv = &vctl[vno]; + while (*pv && + ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a || + strcmp((*pv)->name, name))) + pv = &((*pv)->next); + assert(*pv); + + v = *pv; + *pv = (*pv)->next; /* Link out the entry */ + + if(vctl[vno] == nil) + hwintrdisable(v); + iunlock(&vctllock); + xfree(v); +} void faultpower(Ureg *ur, ulong addr, int read); void syscall(Ureg* ureg); @@ -108,26 +218,20 @@ trap(Ureg *ur) ecode = (ur->cause >> 8) & 0xff; user = (ur->srr1 & MSR_PR) != 0; -if(ur->status & MSR_RI == 0) -print("double fault?: ecode = %d\n", ecode); - switch(ecode){ + if(ur->status & MSR_RI == 0) + print("double fault?: ecode = %d\n", ecode); + + switch(ecode) { case CEI: -print("intr\n"); intr(ur); break; - case CDEC: -print("clock\n"); clockintr(ur); break; - case CSYSCALL: -print("syscall\n"); syscall(ur); break; - case CPROG: -print("program\n"); if(ur->status & (1<<19)) s = "floating point exception"; else if(ur->status & (1<<18)) @@ -145,9 +249,7 @@ print("program\n"); dumpregs(ur); panic(s); break; - default: -print("trap: default\n"); if(ecode <= nelem(excname) && user){ spllo(); sprint(buf, "sys: trap: %s", excname[ecode]); @@ -173,7 +275,6 @@ faultpower(Ureg *ureg, ulong addr, int read) char buf[ERRMAX]; user = (ureg->srr1 & MSR_PR) != 0; -if(0)print("fault: pid=%ld pc = %lux, addr = %lux read = %d user = %d stack=%ulx\n", up->pid, ureg->pc, addr, read, user, &ureg); insyscall = up->insyscall; up->insyscall = 1; spllo(); @@ -183,23 +284,12 @@ if(0)print("fault: pid=%ld pc = %lux, addr = %lux read = %d user = %d stack=%ulx dumpregs(ureg); panic("fault: 0x%lux\n", addr); } -print("fault: pid=%ld pc = %lux, addr = %lux read = %d user = %d stack=%ulx\n", up->pid, ureg->pc, addr, read, user, &ureg); -dumpregs(ureg); sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr); postnote(up, 1, buf, NDebug); } up->insyscall = insyscall; } -void -spurious(Ureg *ur, void *a) -{ - USED(a); - print("SPURIOUS interrupt pc=0x%lux cause=0x%lux\n", - ur->pc, ur->cause); - panic("bad interrupt"); -} - void sethvec(int v, void (*r)(void)) { @@ -237,58 +327,47 @@ trapinit(void) } void -intrenable(int v, void (*r)(Ureg*, void*), void *arg, int, char *name) +intr(Ureg *ureg) { - Handler *h; - - if(halloc.free >= Maxhandler) - panic("out of interrupt handlers"); - if(v < 0 || v >= nelem(halloc.ivec)) - panic("intrenable(%d)", v); - ilock(&veclock); - h = &halloc.h[halloc.free++]; - h->next = halloc.ivec[v]; - halloc.ivec[v] = h; - h->r = r; - h->arg = arg; - - eieio(); - eieio(); - iunlock(&veclock); -} + int vno; + Vctl *ctl, *v; -void -intr(Ureg *ur) -{ - int b, v; - Handler *h; + vno = mpicintack(); + if(vno == 0) { /* 8259, wired through MPIC vec 0 */ + vno = i8259intack(); + mpiceoi(0); + } - v = mpicintack(); - if(v == 0) { /* 8259 */ + if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) { + panic("spurious intr %d", vno); + return; } - /* - * call the interrupt handlers + if(ctl->isr) + ctl->isr(vno); + for(v = ctl; v != nil; v = v->next){ + if(v->f) + v->f(ureg, v->a); + } + if(ctl->eoi) + ctl->eoi(vno); + + /* + * preemptive scheduling. to limit stack depth, + * make sure process has a chance to return from + * the current interrupt before being preempted a + * second time. */ -/* do { - h->nintr++; - (*h->r)(ur, h->arg); - h = h->next; - } while(h != nil); -*/ -} - -int -intrstats(char *buf, int bsize) -{ - Handler *h; - int i, n; - - n = 0; - for(i=0; inintr) - n += snprint(buf+n, bsize-n, "%3d %ud %uld %ud\n", i, h->nintr, h->ticks, h->maxtick); - return n; + if(up && up->state == Running) + if(anyhigher()) + if(up->preempted == 0) + if(!active.exiting){ + up->preempted = 1; + sched(); + splhi(); + up->preempted = 0; + return; + } } char* diff --git a/port/proc.c b/port/proc.c index c8c6bd24f4dc4fb9ad6eb30d054f5b71617a02df..044e4d4c11019a67ef0fad33e99b0bab5958c32f 100644 --- a/port/proc.c +++ b/port/proc.c @@ -480,10 +480,7 @@ sleep(Rendez *r, int (*f)(void*), void *arg) if(up->notepending) { up->notepending = 0; splx(s); - if(up->kp) - print("attempt to interrupt %ld %s\n", up->pid, up->text); - else - error(Eintr); + error(Eintr); } splx(s);