summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/src/9/pc/archacpi.c5
-rw-r--r--sys/src/9/pc/archgeneric.c59
-rw-r--r--sys/src/9/pc/archmp.c5
-rw-r--r--sys/src/9/pc/dat.h7
-rw-r--r--sys/src/9/pc/devarch.c89
-rw-r--r--sys/src/9/pc/fns.h8
-rw-r--r--sys/src/9/pc/i8259.c80
-rw-r--r--sys/src/9/pc/io.h14
-rw-r--r--sys/src/9/pc/irq.c307
-rw-r--r--sys/src/9/pc/mp.c171
-rw-r--r--sys/src/9/pc/mp.h3
-rw-r--r--sys/src/9/pc/pc1
-rw-r--r--sys/src/9/pc/trap.c2
-rw-r--r--sys/src/9/pc64/dat.h7
-rw-r--r--sys/src/9/pc64/fns.h8
-rw-r--r--sys/src/9/pc64/pc641
-rw-r--r--sys/src/9/pc64/trap.c2
-rw-r--r--sys/src/9/xen/archxen.c24
-rw-r--r--sys/src/9/xen/fns.h7
-rw-r--r--sys/src/9/xen/mkfile1
-rw-r--r--sys/src/9/xen/trap.c298
-rw-r--r--sys/src/9/xen/xensystem.c41
-rw-r--r--sys/src/9/xen/xentimer.c2
23 files changed, 483 insertions, 659 deletions
diff --git a/sys/src/9/pc/archacpi.c b/sys/src/9/pc/archacpi.c
index e19c70166..560dc93a9 100644
--- a/sys/src/9/pc/archacpi.c
+++ b/sys/src/9/pc/archacpi.c
@@ -256,6 +256,7 @@ Foundbus:
ai->intr = pi;
ai->apic = a;
ai->next = bus->aintr;
+ ai->bus = bus;
bus->aintr = ai;
}
@@ -733,13 +734,15 @@ acpireset(void)
}
static int identify(void);
+extern int i8259irqno(int, int);
PCArch archacpi = {
.id= "ACPI",
.ident= identify,
.reset= acpireset,
.intrinit= acpiinit,
-.intrenable= mpintrenable,
+.intrassign= mpintrassign,
+.intrirqno= i8259irqno,
.intron= lapicintron,
.introff= lapicintroff,
.fastclock= i8253read,
diff --git a/sys/src/9/pc/archgeneric.c b/sys/src/9/pc/archgeneric.c
new file mode 100644
index 000000000..e51bf7ad7
--- /dev/null
+++ b/sys/src/9/pc/archgeneric.c
@@ -0,0 +1,59 @@
+#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"
+
+extern int i8259assign(Vctl*);
+extern int i8259irqno(int, int);
+extern void i8259init(void);
+extern int i8259isr(int);
+extern void i8259on(void);
+extern void i8259off(void);
+extern int i8259vecno(int);
+
+void
+archreset(void)
+{
+ i8042reset();
+
+ /*
+ * Often the BIOS hangs during restart if a conventional 8042
+ * warm-boot sequence is tried. The following is Intel specific and
+ * seems to perform a cold-boot, but at least it comes back.
+ * And sometimes there is no keyboard...
+ *
+ * The reset register (0xcf9) is usually in one of the bridge
+ * chips. The actual location and sequence could be extracted from
+ * ACPI but why bother, this is the end of the line anyway.
+ */
+ print("Takes a licking and keeps on ticking...\n");
+ *(ushort*)KADDR(0x472) = 0x1234; /* BIOS warm-boot flag */
+ outb(0xcf9, 0x02);
+ outb(0xcf9, 0x06);
+
+ print("can't reset\n");
+ for(;;)
+ idle();
+}
+
+PCArch archgeneric = {
+.id= "generic",
+.ident= 0,
+.reset= archreset,
+
+.intrinit= i8259init,
+.intrassign= i8259assign,
+.intrirqno= i8259irqno,
+.intrvecno= i8259vecno,
+.intrspurious= i8259isr,
+.intron= i8259on,
+.introff= i8259off,
+
+.clockenable= i8253enable,
+.fastclock= i8253read,
+.timerset= i8253timerset,
+};
diff --git a/sys/src/9/pc/archmp.c b/sys/src/9/pc/archmp.c
index 5d613dd0d..67a522a36 100644
--- a/sys/src/9/pc/archmp.c
+++ b/sys/src/9/pc/archmp.c
@@ -194,6 +194,7 @@ mkiointr(PCMPintr* p)
}
aintr->apic = mpioapic[p->apicno];
aintr->next = bus->aintr;
+ aintr->bus = bus;
bus->aintr = aintr;
return aintr;
@@ -366,13 +367,15 @@ mpreset(void)
}
static int identify(void);
+extern int i8259irqno(int, int);
PCArch archmp = {
.id= "_MP_",
.ident= identify,
.reset= mpreset,
.intrinit= pcmpinit,
-.intrenable= mpintrenable,
+.intrassign= mpintrassign,
+.intrirqno= i8259irqno,
.intron= lapicintron,
.introff= lapicintroff,
.fastclock= i8253read,
diff --git a/sys/src/9/pc/dat.h b/sys/src/9/pc/dat.h
index 278f70893..644fab2a8 100644
--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -280,13 +280,12 @@ struct PCArch
char* id;
int (*ident)(void); /* this should be in the model */
void (*reset)(void); /* this should be in the model */
- int (*serialpower)(int); /* 1 == on, 0 == off */
- int (*modempower)(int); /* 1 == on, 0 == off */
void (*intrinit)(void);
- int (*intrenable)(Vctl*);
+ int (*intrassign)(Vctl*);
+ int (*intrirqno)(int, int);
+ int (*intrspurious)(int);
int (*intrvecno)(int);
- int (*intrdisable)(int);
void (*introff)(void);
void (*intron)(void);
diff --git a/sys/src/9/pc/devarch.c b/sys/src/9/pc/devarch.c
index cc14b394b..6617d3e7b 100644
--- a/sys/src/9/pc/devarch.c
+++ b/sys/src/9/pc/devarch.c
@@ -324,31 +324,6 @@ nop(void)
{
}
-void
-archreset(void)
-{
- i8042reset();
-
- /*
- * Often the BIOS hangs during restart if a conventional 8042
- * warm-boot sequence is tried. The following is Intel specific and
- * seems to perform a cold-boot, but at least it comes back.
- * And sometimes there is no keyboard...
- *
- * The reset register (0xcf9) is usually in one of the bridge
- * chips. The actual location and sequence could be extracted from
- * ACPI but why bother, this is the end of the line anyway.
- */
- print("Takes a licking and keeps on ticking...\n");
- *(ushort*)KADDR(0x472) = 0x1234; /* BIOS warm-boot flag */
- outb(0xcf9, 0x02);
- outb(0xcf9, 0x06);
-
- print("can't reset\n");
- for(;;)
- idle();
-}
-
/*
* 386 has no compare-and-swap instruction.
* Run it with interrupts turned off instead.
@@ -380,25 +355,6 @@ int (*cmpswap)(long*, long, long) = cmpswap386;
PCArch* arch;
extern PCArch* knownarch[];
-PCArch archgeneric = {
-.id= "generic",
-.ident= 0,
-.reset= archreset,
-.serialpower= unimplemented,
-.modempower= unimplemented,
-
-.intrinit= i8259init,
-.intrenable= i8259enable,
-.intrvecno= i8259vecno,
-.intrdisable= i8259disable,
-.intron= i8259on,
-.introff= i8259off,
-
-.clockenable= i8253enable,
-.fastclock= i8253read,
-.timerset= i8253timerset,
-};
-
typedef struct X86type X86type;
struct X86type {
int family;
@@ -912,26 +868,22 @@ archinit(void)
{
PCArch **p;
- arch = &archgeneric;
+ arch = knownarch[0];
for(p = knownarch; *p != nil; p++){
if((*p)->ident != nil && (*p)->ident() == 0){
arch = *p;
break;
}
}
- if(arch != &archgeneric){
+ if(arch != knownarch[0]){
if(arch->id == nil)
- arch->id = archgeneric.id;
+ arch->id = knownarch[0]->id;
if(arch->reset == nil)
- arch->reset = archgeneric.reset;
- if(arch->serialpower == nil)
- arch->serialpower = archgeneric.serialpower;
- if(arch->modempower == nil)
- arch->modempower = archgeneric.modempower;
+ arch->reset = knownarch[0]->reset;
if(arch->intrinit == nil)
- arch->intrinit = archgeneric.intrinit;
- if(arch->intrenable == nil)
- arch->intrenable = archgeneric.intrenable;
+ arch->intrinit = knownarch[0]->intrinit;
+ if(arch->intrassign == nil)
+ arch->intrassign = knownarch[0]->intrassign;
}
/*
@@ -1100,6 +1052,33 @@ dumpmcregs(void)
}
}
+static void
+nmihandler(Ureg *ureg, void*)
+{
+ iprint("cpu%d: nmi PC %#p, status %ux\n",
+ m->machno, ureg->pc, inb(0x61));
+ while(m->machno != 0)
+ ;
+}
+
+void
+nmienable(void)
+{
+ int x;
+
+ trapenable(VectorNMI, nmihandler, nil, "nmi");
+
+ /*
+ * Hack: should be locked with NVRAM access.
+ */
+ outb(0x70, 0x80); /* NMI latch clear */
+ outb(0x70, 0);
+
+ x = inb(0x61) & 0x07; /* Enable NMI */
+ outb(0x61, 0x0C|x);
+ outb(0x61, x);
+}
+
void
setupwatchpts(Proc *pr, Watchpt *wp, int nwp)
{
diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h
index 669f02ee9..a16c0cf74 100644
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -65,13 +65,6 @@ void i8253init(void);
void i8253reset(void);
uvlong i8253read(uvlong*);
void i8253timerset(uvlong);
-int i8259disable(int);
-int i8259enable(Vctl*);
-void i8259init(void);
-int i8259isr(int);
-void i8259on(void);
-void i8259off(void);
-int i8259vecno(int);
void idle(void);
void idlehands(void);
int inb(int);
@@ -111,6 +104,7 @@ char* mtrr(uvlong, uvlong, char *);
void mtrrclock(void);
int mtrrprint(char *, long);
void mtrrsync(void);
+void nmienable(void);
uchar nvramread(int);
void nvramwrite(int, uchar);
void outb(int, int);
diff --git a/sys/src/9/pc/i8259.c b/sys/src/9/pc/i8259.c
index cfe1a5a42..0eed0954f 100644
--- a/sys/src/9/pc/i8259.c
+++ b/sys/src/9/pc/i8259.c
@@ -127,8 +127,38 @@ i8259isr(int vno)
return isr & (1<<irq);
}
+static int
+irqenable(Vctl *v, int shared)
+{
+ if(shared)
+ return 0;
+ ilock(&i8259lock);
+ i8259mask &= ~(1<<v->irq);
+ if(v->irq < 8)
+ outb(Int0aux, i8259mask & 0xFF);
+ else
+ outb(Int1aux, (i8259mask>>8) & 0xFF);
+ iunlock(&i8259lock);
+ return 0;
+}
+
+static int
+irqdisable(Vctl *v, int shared)
+{
+ if(shared)
+ return 0;
+ ilock(&i8259lock);
+ i8259mask |= 1<<v->irq;
+ if(v->irq < 8)
+ outb(Int0aux, i8259mask & 0xFF);
+ else
+ outb(Int1aux, (i8259mask>>8) & 0xFF);
+ iunlock(&i8259lock);
+ return 0;
+}
+
int
-i8259enable(Vctl* v)
+i8259assign(Vctl *v)
{
int irq, irqbit;
@@ -150,52 +180,40 @@ i8259enable(Vctl* v)
iunlock(&i8259lock);
return -1;
}
- i8259mask &= ~irqbit;
- if(irq < 8)
- outb(Int0aux, i8259mask & 0xFF);
- else
- outb(Int1aux, (i8259mask>>8) & 0xFF);
+ iunlock(&i8259lock);
if(i8259elcr & irqbit)
v->eoi = i8259isr;
else
v->isr = i8259isr;
- iunlock(&i8259lock);
- return VectorPIC+irq;
-}
+ v->enable = irqenable;
+ v->disable = irqdisable;
-int
-i8259vecno(int irq)
-{
return VectorPIC+irq;
}
int
-i8259disable(int irq)
+i8259irqno(int irq, int tbdf)
{
- int irqbit;
+ if(tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0))
+ return -1;
/*
- * Given an IRQ, disable the corresponding interrupt
- * in the 8259.
+ * 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(irq < 0 || irq > MaxIrqPIC){
- print("i8259disable: irq %d out of range\n", irq);
- return -1;
- }
- irqbit = 1<<irq;
+ if(irq == 2)
+ irq = 9;
- ilock(&i8259lock);
- if(!(i8259mask & irqbit)){
- i8259mask |= irqbit;
- if(irq < 8)
- outb(Int0aux, i8259mask & 0xFF);
- else
- outb(Int1aux, (i8259mask>>8) & 0xFF);
- }
- iunlock(&i8259lock);
- return 0;
+ return irq;
+}
+
+int
+i8259vecno(int irq)
+{
+ return VectorPIC+irq;
}
void
diff --git a/sys/src/9/pc/io.h b/sys/src/9/pc/io.h
index d0113af69..cbb03086f 100644
--- a/sys/src/9/pc/io.h
+++ b/sys/src/9/pc/io.h
@@ -46,19 +46,23 @@ enum {
};
typedef struct Vctl {
- Vctl* next; /* handlers on this vector */
+ Vctl *next; /* handlers on this vector */
void (*f)(Ureg*, void*); /* handler to call */
- void* a; /* argument to call it with */
-
- int isintr; /* interrupt or fault/trap */
+ void *a; /* argument to call it with */
int (*isr)(int); /* get isr bit for this irq */
int (*eoi)(int); /* eoi */
- void (*disable)(Vctl*);
+ int (*enable)(Vctl*, int);
+ int (*disable)(Vctl*, int);
+ void *aux;
+
int irq;
int tbdf;
+ int vno;
+ int cpu;
+ int local;
char name[KNAMELEN]; /* of driver */
} Vctl;
diff --git a/sys/src/9/pc/irq.c b/sys/src/9/pc/irq.c
index 3ad717849..7bfee87a4 100644
--- a/sys/src/9/pc/irq.c
+++ b/sys/src/9/pc/irq.c
@@ -9,7 +9,7 @@
#include "../port/error.h"
static Lock vctllock;
-static Vctl *vctl[256];
+static Vctl *vclock, *vctl[256];
enum
{
@@ -46,86 +46,55 @@ irqhandled(Ureg *ureg, int vno)
Vctl *ctl, *v;
int i;
- if(ctl = vctl[vno]){
- if(ctl->isintr){
- m->perf.intrts = perfticks();
- m->intr++;
- if(vno >= VectorPIC)
- m->lastintr = ctl->irq;
+ ctl = vctl[vno];
+ if(ctl != nil){
+ if(vno < VectorPIC){
+ (*ctl->f)(ureg, ctl->a);
+ return 1;
}
- 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);
-
- if(ctl->isintr){
- intrtime(m, vno);
-
- if(up){
- if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER){
- /* delaysched set because we held a lock or because our quantum ended */
- if(up->delaysched)
- sched();
- } else {
- preempted();
- }
+
+ m->perf.intrts = perfticks();
+ m->intr++;
+ m->lastintr = ctl->irq;
+ if(ctl->isr != nil)
+ (*ctl->isr)(vno);
+ for(v = ctl; v != nil; v = v->next)
+ (*v->f)(ureg, v->a);
+ if(ctl->eoi != nil)
+ (*ctl->eoi)(vno);
+ intrtime(m, vno);
+
+ if(up != nil){
+ if(ctl == vclock){
+ /* delaysched set because we held a lock or because our quantum ended */
+ if(up->delaysched)
+ sched();
+ } else {
+ preempted();
}
}
return 1;
}
- if(vno < VectorPIC)
+ if(vno < VectorPIC || vno == VectorSYSCALL)
return 0;
- /*
- * 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.
- */
-
- /* call all interrupt routines, just in case */
- for(i = VectorPIC; i <= MaxIrqLAPIC; i++){
- ctl = vctl[i];
- if(ctl == nil)
- continue;
- if(!ctl->isintr)
- continue;
- for(v = ctl; v != nil; v = v->next){
- if(v->f)
- v->f(ureg, v->a);
- }
- /* should we do this? */
- if(ctl->eoi)
- ctl->eoi(i);
- }
-
- /* clear the interrupt */
- i8259isr(vno);
+ m->spuriousintr++;
+ if(arch->intrspurious != nil && (*arch->intrspurious)(vno) == 0)
+ return 1; /* false alarm */
- if(0)print("cpu%d: spurious interrupt %d, last %d\n",
+ iprint("cpu%d: spurious interrupt %d, last %d\n",
m->machno, vno, m->lastintr);
- if(0)if(conf.nmach > 1){
- for(i = 0; i < MAXMACH; i++){
- Mach *mach;
- if(active.machs[i] == 0)
- continue;
- mach = MACHP(i);
- if(m->machno == mach->machno)
- continue;
- print(" cpu%d: last %d",
- mach->machno, mach->lastintr);
- }
- print("\n");
+ /* call all non-local interrupt routines, just in case */
+ for(i = VectorPIC; i < nelem(vctl); i++){
+ ctl = vctl[i];
+ if(ctl == nil || ctl == vclock || ctl->local)
+ continue;
+ for(v = ctl; v != nil; v = v->next)
+ (*v->f)(ureg, v->a);
}
- m->spuriousintr++;
+
return -1;
}
@@ -134,28 +103,59 @@ trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
{
Vctl *v;
- if(vno < 0 || vno >= VectorPIC)
- panic("trapenable: vno %d", vno);
+ if(f == nil){
+ print("trapenable: nil handler for %d, for %s\n",
+ vno, name);
+ return;
+ }
+
+ if(vno < 0 || vno >= VectorPIC){
+ print("trapenable: vno %d out of range", vno);
+ return;
+ }
+
if((v = xalloc(sizeof(Vctl))) == nil)
panic("trapenable: out of memory");
- v->tbdf = BUSUNKNOWN;
+
v->f = f;
v->a = a;
+
+ v->tbdf = BUSUNKNOWN;
+ v->irq = -1;
+ v->vno = vno;
+ v->cpu = -1;
+
strncpy(v->name, name, KNAMELEN-1);
v->name[KNAMELEN-1] = 0;
ilock(&vctllock);
- if(vctl[vno])
- v->next = vctl[vno]->next;
+ if(vctl[vno] != nil){
+ print("trapenable: vno %d assigned twice: %s %s\n",
+ vno, vctl[vno]->name, v->name);
+ iunlock(&vctllock);
+ xfree(v);
+ return;
+ }
vctl[vno] = v;
iunlock(&vctllock);
}
+static Vctl*
+delayfree(Vctl *v)
+{
+ static Vctl *q[4];
+ static uint x;
+ Vctl *r;
+
+ r = q[x], q[x] = v;
+ x = (x+1) % nelem(q);
+ return r;
+}
+
void
intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
{
- int vno;
- Vctl *v;
+ Vctl **pv, *v;
if(f == nil){
print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
@@ -163,45 +163,63 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
return;
}
- if(tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0))
- irq = -1;
-
-
- /*
- * 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(irq == 2)
- irq = 9;
+ if(arch->intrirqno != nil)
+ irq = (*arch->intrirqno)(irq, tbdf);
if((v = xalloc(sizeof(Vctl))) == nil)
panic("intrenable: out of memory");
- v->isintr = 1;
- v->irq = irq;
- v->tbdf = tbdf;
+
v->f = f;
v->a = a;
+
+ v->tbdf = tbdf;
+ v->irq = irq;
+ v->vno = -1;
+ v->cpu = -1;
+
strncpy(v->name, name, KNAMELEN-1);
v->name[KNAMELEN-1] = 0;
ilock(&vctllock);
- vno = arch->intrenable(v);
- if(vno == -1){
- iunlock(&vctllock);
- print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
+ v->vno = (*arch->intrassign)(v);
+ if(v->vno < VectorPIC || v->vno >= nelem(vctl)){
+ print("intrenable: couldn't assign irq %d, tbdf 0x%uX for %s\n",
irq, tbdf, v->name);
- xfree(v);
+Unlockandfree:
+ iunlock(&vctllock);
+ if(v != nil)
+ xfree(v);
return;
}
- if(vctl[vno]){
- if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
- panic("intrenable: handler: %s %s %#p %#p %#p %#p",
- vctl[vno]->name, v->name,
- vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
- v->next = vctl[vno];
+ pv = &vctl[v->vno];
+ if(*pv != nil){
+ if((*pv)->isr != v->isr || (*pv)->eoi != v->eoi){
+ print("intrenable: incompatible handler: %s %s %#p %#p %#p %#p\n",
+ (*pv)->name, v->name,
+ (*pv)->isr, v->isr,
+ (*pv)->eoi, v->eoi);
+ goto Unlockandfree;
+ }
+ if(*pv == vclock)
+ pv = &vclock->next;
+ v->next = *pv;
+ }
+ if(strcmp(name, "clock") == 0)
+ vclock = v;
+ *pv = v;
+ if(v->enable != nil){
+ coherence();
+ if((*v->enable)(v, pv != &vctl[v->vno] || v->next != nil) < 0){
+ print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
+ irq, tbdf, v->name);
+ *pv = v->next;
+ if(v == vclock)
+ vclock = nil;
+ if(conf.nmach > 1)
+ v = delayfree(v);
+ goto Unlockandfree;
+ }
}
- vctl[vno] = v;
iunlock(&vctllock);
}
@@ -211,40 +229,47 @@ intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
Vctl **pv, *v;
int vno;
- if(irq == 2)
- irq = 9;
- if(arch->intrvecno == nil || (tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0))){
- /*
- * on APIC machine, irq is pretty meaningless
- * and disabling a the vector is not implemented.
- * however, we still want to remove the matching
- * Vctl entry to prevent calling Vctl.f() with a
- * stale Vctl.a pointer.
- */
+ if(arch->intrirqno != nil)
+ irq = (*arch->intrirqno)(irq, tbdf);
+
+ if(irq != -1 && arch->intrvecno != nil) {
+ vno = (*arch->intrvecno)(irq);
+ if(vno < VectorPIC || vno >= nelem(vctl)){
+ irq = -1;
+ vno = VectorPIC;
+ }
+ } else {
irq = -1;
vno = VectorPIC;
- } else {
- vno = arch->intrvecno(irq);
}
+
ilock(&vctllock);
do {
for(pv = &vctl[vno]; (v = *pv) != nil; pv = &v->next){
- if(v->isintr && (v->irq == irq || irq == -1)
+ if((v->irq == irq || irq == -1)
&& v->tbdf == tbdf && v->f == f && v->a == a
&& strcmp(v->name, name) == 0)
break;
}
if(v != nil){
- if(v->disable != nil)
- (*v->disable)(v);
+ if(v->disable != nil){
+ if((*v->disable)(v, pv != &vctl[vno] || v->next != nil) < 0){
+ print("intrdisable: couldn't disable irq %d, tbdf 0x%uX for %s\n",
+ irq, tbdf, name);
+ }
+ coherence();
+ }
*pv = v->next;
- xfree(v);
-
- if(irq != -1 && vctl[vno] == nil && arch->intrdisable != nil)
- arch->intrdisable(irq);
- break;
+ if(v == vclock)
+ vclock = nil;
+ if(conf.nmach > 1)
+ v = delayfree(v);
+ iunlock(&vctllock);
+ if(v != nil)
+ xfree(v);
+ return;
}
- } while(irq == -1 && ++vno <= MaxVectorAPIC);
+ } while(irq == -1 && ++vno < nelem(vctl));
iunlock(&vctllock);
}
@@ -258,8 +283,8 @@ irqallocread(Chan*, void *a, long n, vlong offset)
if(n < 0 || offset < 0)
error(Ebadarg);
- for(vno=0; vno<nelem(vctl); vno++){
- for(v=vctl[vno]; v; v=v->next){
+ for(vno = 0; vno < nelem(vctl); vno++){
+ for(v = vctl[vno]; v != nil; v = v->next){
m = snprint(buf, sizeof(buf), "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name);
offset -= m;
if(offset >= 0)
@@ -274,40 +299,8 @@ irqallocread(Chan*, void *a, long n, vlong offset)
return 0;
}
-static void
-nmienable(void)
-{
- int x;
-
- /*
- * Hack: should be locked with NVRAM access.
- */
- outb(0x70, 0x80); /* NMI latch clear */
- outb(0x70, 0);
-
- x = inb(0x61) & 0x07; /* Enable NMI */
- outb(0x61, 0x0C|x);
- outb(0x61, x);
-}
-
-static void
-nmihandler(Ureg *ureg, void*)
-{
- /*
- * Don't re-enable, it confuses the crash dumps.
- nmienable();
- */
- iprint("cpu%d: nmi PC %#p, status %ux\n",
- m->machno, ureg->pc, inb(0x61));
- while(m->machno != 0)
- ;
-}
-
void
irqinit(void)
{
addarchfile("irqalloc", 0444, irqallocread, nil);
-
- trapenable(VectorNMI, nmihandler, nil, "nmi");
- nmienable();
}
diff --git a/sys/src/9/pc/mp.c b/sys/src/9/pc/mp.c
index 591fc6735..abb3e010e 100644
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -10,6 +10,8 @@
#include "mp.h"
#include "apbootstrap.i"
+extern void i8259init(void);
+
/* filled in by pcmpinit or acpiinit */
Bus* mpbus;
Bus* mpbuslast;
@@ -291,23 +293,51 @@ allocvector(void)
}
static int
-mpintrenablex(Vctl* v, int tbdf)
+ioapicirqenable(Vctl *v, int shared)
+{
+ Aintr *aintr = v->aux;
+ int lo, hi;
+
+ if(shared)
+ return 0;
+ hi = v->cpu<<24;
+ lo = mpintrinit(aintr->bus, aintr->intr, v->vno, v->irq);
+ lo |= ApicPHYSICAL; /* no-op */
+ ioapicrdtw(aintr->apic, aintr->intr->intin, hi, lo);
+ return 0;
+}
+
+static int
+ioapicirqdisable(Vctl *v, int shared)
+{
+ Aintr *aintr = v->aux;
+ int lo, hi;
+
+ if(shared)
+ return 0;
+ hi = 0;
+ lo = ApicIMASK;
+ ioapicrdtw(aintr->apic, aintr->intr->intin, hi, lo);
+ return 0;
+}
+
+static int
+mpintrassignx(Vctl* v, int tbdf)
{
Bus *bus;
+ Pcidev *pci;
Aintr *aintr;
- Apic *apic;
- Pcidev *pcidev;
- int bno, dno, pin, hi, irq, lo, n, type, vno;
+ int bno, dno, pin, irq, type, lo, hi, n;
type = BUSTYPE(tbdf);
bno = BUSBNO(tbdf);
dno = BUSDNO(tbdf);
pin = 0;
- pcidev = nil;
+ pci = nil;
if(type == BusPCI){
- if(pcidev = pcimatchtbdf(tbdf))
- pin = pcicfgr8(pcidev, PciINTP);
+ if((pci = pcimatchtbdf(tbdf)) != nil)
+ pin = pcicfgr8(pci, PciINTP);
} else if(type == BusISA)
bno = mpisabus;
@@ -325,14 +355,14 @@ Findbus:
* by the MP or ACPI tables then walk up the bus translating interrupt
* pin to parent bus.
*/
- if(pcidev && pcidev->parent && pin > 0){
+ if(pci != nil && pci->parent != nil && pin > 0){
pin = ((dno+(pin-1))%4)+1;
- pcidev = pcidev->parent;
- bno = BUSBNO(pcidev->tbdf);
- dno = BUSDNO(pcidev->tbdf);
+ pci = pci->parent;
+ bno = BUSBNO(pci->tbdf);
+ dno = BUSDNO(pci->tbdf);
goto Findbus;
}
- print("mpintrenable: can't find bus type %d, number %d\n", type, bno);
+ print("mpintrassign: can't find bus type %d, number %d\n", type, bno);
return -1;
}
@@ -346,65 +376,56 @@ Findbus:
irq = (dno<<2)|(pin-1);
else
irq = -1;
- }
- else
+ } else
irq = v->irq;
/*
* Find a matching interrupt entry from the list of interrupts
* attached to this bus.
*/
- for(aintr = bus->aintr; aintr; aintr = aintr->next){
+ for(aintr = bus->aintr; aintr != nil; aintr = aintr->next){
if(aintr->intr->irq != irq)
continue;
- if(0){
- PCMPintr* p = aintr->intr;
- print("mpintrenablex: bus %d intin %d irq %d\n",
- p->busno, p->intin, p->irq);
- }
+
/*
* Check if already enabled. Multifunction devices may share
* INT[A-D]# so, if already enabled, check the polarity matches
* and the trigger is level.
- *
- * Should check the devices differ only in the function number,
- * but that can wait for the planned enable/disable rewrite.
- * The RDT read here is safe for now as currently interrupts
- * are never disabled once enabled.
*/
- apic = aintr->apic;
- ioapicrdtr(apic, aintr->intr->intin, 0, &lo);
- if(!(lo & ApicIMASK)){
- vno = lo & 0xFF;
- if(0) print("%s vector %d (!imask)\n", v->name, vno);
- n = mpintrinit(bus, aintr->intr, vno, v->irq);
- n |= ApicPHYSICAL; /* no-op */
+ ioapicrdtr(aintr->apic, aintr->intr->intin, &hi, &lo);
+ if(lo & ApicIMASK){
+ v->vno = allocvector();
+ v->cpu = mpintrcpu();
+ lo = mpintrinit(aintr->bus, aintr->intr, v->vno, v->irq);
+ lo |= ApicPHYSICAL; /* no-op */
+ if(lo & ApicIMASK){
+ print("mpintrassign: disabled irq %d, tbdf %uX, lo %8.8uX, hi %8.8uX\n",
+ v->irq, v->tbdf, lo, hi);
+ break;
+ }
+ } else {
+ v->vno = lo & 0xFF;
+ v->cpu = hi >> 24;
lo &= ~(ApicRemoteIRR|ApicDELIVS);
- if(n != lo){
- print("mpintrenable: multiple botch irq %d, tbdf %uX, lo %8.8uX, n %8.8uX\n",
- v->irq, tbdf, lo, n);
- return -1;
+ n = mpintrinit(aintr->bus, aintr->intr, v->vno, v->irq);
+ n |= ApicPHYSICAL; /* no-op */
+ if(lo != n){
+ print("mpintrassign: multiple botch irq %d, tbdf %uX, lo %8.8uX, n %8.8uX\n",
+ v->irq, v->tbdf, lo, n);
+ break;
}
- v->isr = lapicisr;
- v->eoi = lapiceoi;
- return vno;
- }
-
- vno = allocvector();
- hi = mpintrcpu()<<24;
- lo = mpintrinit(bus, aintr->intr, vno, v->irq);
- lo |= ApicPHYSICAL; /* no-op */
- if(lo & ApicIMASK){
- print("mpintrenable: disabled irq %d, tbdf %uX, lo %8.8uX, hi %8.8uX\n",
- v->irq, tbdf, lo, hi);
- return -1;
}
- if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC)
- ioapicrdtw(apic, aintr->intr->intin, hi, lo);
v->isr = lapicisr;
v->eoi = lapiceoi;
- return vno;
+
+ if((aintr->apic->flags & PcmpEN) && aintr->apic->type == PcmpIOAPIC){
+ v->aux = aintr;
+ v->enable = ioapicirqenable;
+ v->disable = ioapicirqdisable;
+ }
+
+ return v->vno;
}
return -1;
@@ -469,23 +490,29 @@ htmsienable(Pcidev *pdev)
return -1;
}
-static void
-msiintrdisable(Vctl *v)
+static int
+msiirqenable(Vctl *v, int)
{
- Pcidev *pci;
+ Pcidev *pci = v->aux;
+ return pcimsienable(pci, 0xFEE00000ULL | (v->cpu << 12), v->vno | (1<<14));
+}
- if((pci = pcimatchtbdf(v->tbdf)) != nil)
- pcimsidisable(pci);
+static int
+msiirqdisable(Vctl *v, int)
+{
+ Pcidev *pci = v->aux;
+ return pcimsidisable(pci);
}
static int
msiintrenable(Vctl *v)
{
- int tbdf, vno, cpu;
Pcidev *pci;
+ int tbdf;
if(getconf("*nomsi") != nil)
return -1;
+
tbdf = v->tbdf;
if(tbdf == BUSUNKNOWN || BUSTYPE(tbdf) != BusPCI)
return -1;
@@ -498,18 +525,21 @@ msiintrenable(Vctl *v)
return -1;
if(pcimsidisable(pci) < 0)
return -1;
- vno = allocvector();
- cpu = mpintrcpu();
- if(pcimsienable(pci, 0xFEE00000ULL | (cpu << 12), vno | (1<<14)) < 0)
- return -1;
- v->disable = msiintrdisable;
+
+ v->vno = allocvector();
+ v->cpu = mpintrcpu();
v->isr = lapicisr;
v->eoi = lapiceoi;
- return vno;
+
+ v->aux = pci;
+ v->enable = msiirqenable;
+ v->disable = msiirqdisable;
+
+ return v->vno;
}
int
-mpintrenable(Vctl* v)
+mpintrassign(Vctl* v)
{
int irq, tbdf, vno;
@@ -524,17 +554,18 @@ mpintrenable(Vctl* v)
* breakpoint and page-fault).
*/
tbdf = v->tbdf;
- if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1)
+ if(tbdf != BUSUNKNOWN && (vno = mpintrassignx(v, tbdf)) != -1)
return vno;
irq = v->irq;
if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){
+ v->local = 1;
if(irq != IrqSPURIOUS)
v->isr = lapiceoi;
return VectorPIC+irq;
}
if(irq < 0 || irq > MaxIrqPIC){
- print("mpintrenable: irq %d out of range\n", irq);
+ print("mpintrassign: irq %d out of range\n", irq);
return -1;
}
@@ -550,16 +581,16 @@ mpintrenable(Vctl* v)
* be compatible with ISA.
*/
if(mpeisabus != -1){
- vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0));
+ vno = mpintrassignx(v, MKBUS(BusEISA, 0, 0, 0));
if(vno != -1)
return vno;
}
if(mpisabus != -1){
- vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0));
+ vno = mpintrassignx(v, MKBUS(BusISA, 0, 0, 0));
if(vno != -1)
return vno;
}
- print("mpintrenable: out of choices eisa %d isa %d tbdf %uX irq %d\n",
+ print("mpintrassign: out of choices eisa %d isa %d tbdf %uX irq %d\n",
mpeisabus, mpisabus, v->tbdf, v->irq);
return -1;
}
diff --git a/sys/src/9/pc/mp.h b/sys/src/9/pc/mp.h
index 4090f343e..802766cf6 100644
--- a/sys/src/9/pc/mp.h
+++ b/sys/src/9/pc/mp.h
@@ -168,6 +168,7 @@ typedef struct Bus {
typedef struct Aintr {
PCMPintr* intr;
Apic* apic;
+ Bus* bus;
Aintr* next;
};
@@ -249,7 +250,7 @@ extern void lapictimerset(uvlong);
extern int mpintrinit(Bus*, PCMPintr*, int, int);
extern void mpinit(void);
-extern int mpintrenable(Vctl*);
+extern int mpintrassign(Vctl*);
extern void mpshutdown(void);
extern void mpstartap(Apic*);
diff --git a/sys/src/9/pc/pc b/sys/src/9/pc/pc
index 3f7816d6e..1b45434b1 100644
--- a/sys/src/9/pc/pc
+++ b/sys/src/9/pc/pc
@@ -96,6 +96,7 @@ link
misc
pci pcipc
+ archgeneric devkbd i8259 i8253
archacpi mp apic squidboy ec
archmp mp apic squidboy
mtrr
diff --git a/sys/src/9/pc/trap.c b/sys/src/9/pc/trap.c
index 2d5d7cce9..c7dec7c13 100644
--- a/sys/src/9/pc/trap.c
+++ b/sys/src/9/pc/trap.c
@@ -66,6 +66,8 @@ trapinit(void)
{
irqinit();
+ nmienable();
+
/*
* Special traps.
* Syscall() is called directly without going through trap().
diff --git a/sys/src/9/pc64/dat.h b/sys/src/9/pc64/dat.h
index 6cb1cc9ed..84efe9a2c 100644
--- a/sys/src/9/pc64/dat.h
+++ b/sys/src/9/pc64/dat.h
@@ -254,13 +254,12 @@ struct PCArch
char* id;
int (*ident)(void); /* this should be in the model */
void (*reset)(void); /* this should be in the model */
- int (*serialpower)(int); /* 1 == on, 0 == off */
- int (*modempower)(int); /* 1 == on, 0 == off */
void (*intrinit)(void);
- int (*intrenable)(Vctl*);
+ int (*intrassign)(Vctl*);
+ int (*intrirqno)(int, int);
int (*intrvecno)(int);
- int (*intrdisable)(int);
+ int (*intrspurious)(int);
void (*introff)(void);
void (*intron)(void);
diff --git a/sys/src/9/pc64/fns.h b/sys/src/9/pc64/fns.h
index b3408badb..5afd1c0b1 100644
--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -63,13 +63,6 @@ void i8253init(void);
void i8253reset(void);
uvlong i8253read(uvlong*);
void i8253timerset(uvlong);
-int i8259disable(int);
-int i8259enable(Vctl*);
-void i8259init(void);
-int i8259isr(int);
-void i8259on(void);
-void i8259off(void);
-int i8259vecno(int);
void idle(void);
void idlehands(void);
int inb(int);
@@ -109,6 +102,7 @@ char* mtrr(uvlong, uvlong, char *);
void mtrrclock(void);
int mtrrprint(char *, long);
void mtrrsync(void);
+void nmienable(void);
void noteret(void);
uchar nvramread(int);
void nvramwrite(int, uchar);
diff --git a/sys/src/9/pc64/pc64 b/sys/src/9/pc64/pc64
index c5ef1fbbe..b4891a04b 100644
--- a/sys/src/9/pc64/pc64
+++ b/sys/src/9/pc64/pc64
@@ -93,6 +93,7 @@ link
misc
pci pcipc
+ archgeneric devkbd i8259 i8253
archacpi mp apic squidboy ec
archmp mp apic squidboy
mtrr
diff --git a/sys/src/9/pc64/trap.c b/sys/src/9/pc64/trap.c
index c79bc4ec5..252462096 100644
--- a/sys/src/9/pc64/trap.c
+++ b/sys/src/9/pc64/trap.c
@@ -67,6 +67,8 @@ trapinit(void)
{
irqinit();
+ nmienable();
+
/*
* Special traps.
* Syscall() is called directly without going through trap().
diff --git a/sys/src/9/xen/archxen.c b/sys/src/9/xen/archxen.c
index 50bf70f19..c4f1b5607 100644
--- a/sys/src/9/xen/archxen.c
+++ b/sys/src/9/xen/archxen.c
@@ -52,9 +52,7 @@ shutdown(void)
HYPERVISOR_shutdown(1);
}
-int xenintrenable(Vctl *v);
-int xenintrvecno(int irq);
-int xenintrdisable(int irq);
+int xenintrassign(Vctl *v);
void xentimerenable(void);
uvlong xentimerread(uvlong*);
void xentimerset(uvlong);
@@ -64,16 +62,14 @@ PCArch archxen = {
.ident= identify,
.reset= shutdown,
.intrinit= intrinit,
-.intrenable= xenintrenable,
-.intrvecno= xenintrvecno,
-.intrdisable= xenintrdisable,
+.intrassign= xenintrassign,
.clockenable= xentimerenable,
.fastclock= xentimerread,
.timerset= xentimerset,
};
/*
- * Placeholders to satisfy external references in generic devarch.c
+ * Placeholders to satisfy external references in devarch.c
*/
ulong getcr4(void) { return 0; }
void putcr4(ulong) {}
@@ -83,19 +79,7 @@ ulong inl(int) { return 0; }
void outb(int, int) {}
void outs(int, ushort) {}
void outl(int, ulong) {}
-void i8042reset(void) {}
-void i8253enable(void) {}
-void i8253init(void) {}
-void i8253link(void) {}
-uvlong i8253read(uvlong*) { return 0; }
-void i8253timerset(uvlong) {}
-int i8259disable(int) { return 0; }
-int i8259enable(Vctl*) { return 0; }
-void i8259init(void) {}
-int i8259isr(int) { return 0; }
-void i8259on(void) {}
-void i8259off(void) {}
-int i8259vecno(int) { return 0; }
+
int mtrrprint(char*, long) { return 0; }
char* mtrr(uvlong, uvlong, char *) { return nil; }
void mtrrsync(void) {}
diff --git a/sys/src/9/xen/fns.h b/sys/src/9/xen/fns.h
index 7289bd570..9dd3d239e 100644
--- a/sys/src/9/xen/fns.h
+++ b/sys/src/9/xen/fns.h
@@ -39,13 +39,6 @@ void i8253init(void);
void i8253link(void);
uvlong i8253read(uvlong*);
void i8253timerset(uvlong);
-int i8259disable(int);
-int i8259enable(Vctl*);
-void i8259init(void);
-int i8259isr(int);
-void i8259on(void);
-void i8259off(void);
-int i8259vecno(int);
void idle(void);
void idlehands(void);
int inb(int);
diff --git a/sys/src/9/xen/mkfile b/sys/src/9/xen/mkfile
index 3a3ecc87b..e97857c01 100644
--- a/sys/src/9/xen/mkfile
+++ b/sys/src/9/xen/mkfile
@@ -71,6 +71,7 @@ OBJ=\
mmu.$O\
random.$O\
rdb.$O\
+ irq.$O\
trap.$O\
$CONF.root.$O\
$CONF.rootc.$O\
diff --git a/sys/src/9/xen/trap.c b/sys/src/9/xen/trap.c
index 8d77b8c43..0ed66fbd4 100644
--- a/sys/src/9/xen/trap.c
+++ b/sys/src/9/xen/trap.c
@@ -28,6 +28,9 @@ enum {
void noted(Ureg*, ulong);
+extern void irqinit(void);
+extern int irqhandled(Ureg*, int);
+
static void debugbpt(Ureg*, void*);
static void fault386(Ureg*, void*);
static void safe_fault386(Ureg*, void*);
@@ -35,148 +38,6 @@ static void doublefault(Ureg*, void*);
static void unexpected(Ureg*, void*);
static void _dumpstack(Ureg*);
-static Lock vctllock;
-static Vctl *vctl[256];
-
-enum
-{
- Ntimevec = 20 /* number of time buckets for each intr */
-};
-ulong intrtimes[256][Ntimevec];
-
-void
-intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
-{
- int vno;
- Vctl *v;
-
-/**/
- SETUPLOG(dprint("intrenable: irq %d, f %p, a %p, tbdf 0x%x, name %s\n",
- irq, f, a, tbdf, name);)
-/**/
- if(f == nil){
- print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
- irq, tbdf, name);
- return;
- }
-
- v = xalloc(sizeof(Vctl));
- v->isintr = 1;
- v->irq = irq;
- v->tbdf = tbdf;
- v->f = f;
- v->a = a;
- strncpy(v->name, name, KNAMELEN-1);
- v->name[KNAMELEN-1] = 0;
-
- ilock(&vctllock);
- vno = arch->intrenable(v);
- if(vno == -1){
- iunlock(&vctllock);
- print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
- irq, tbdf, v->name);
- xfree(v);
- return;
- }
- if(vctl[vno]){
- if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
- panic("intrenable: handler: %s %s %p %p %p %p\n",
- vctl[vno]->name, v->name,
- vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
- v->next = vctl[vno];
- }
- vctl[vno] = v;
- SETUPLOG(dprint("INTRENABLE: vctl[%d] is %p\n", vno, vctl[vno]);)
- iunlock(&vctllock);
-}
-
-void
-intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
-{
- Vctl **pv, *v;
- int vno;
-
- vno = arch->intrvecno(irq);
- ilock(&vctllock);
- for(pv = &vctl[vno]; (v = *pv) != nil; pv = &v->next){
- if(v->isintr && v->irq == irq
- && v->tbdf == tbdf && v->f == f && v->a == a
- && strcmp(v->name, name) == 0){
- *pv = v->next;
- xfree(v);
-
- if(vctl[vno] == nil && arch->intrdisable != nil)
- arch->intrdisable(irq);
- break;
- }
- }
- iunlock(&vctllock);
-}
-
-static long
-irqallocread(Chan*, void *a, long n, vlong offset)
-{
- char buf[2*(11+1)+KNAMELEN+1+1];
- int vno, m;
- Vctl *v;
-
- if(n < 0 || offset < 0)
- error(Ebadarg);
-
- for(vno=0; vno<nelem(vctl); vno++){
- for(v=vctl[vno]; v; v=v->next){
- m = snprint(buf, sizeof(buf), "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name);
- offset -= m;
- if(offset >= 0)
- continue;
- if(n > -offset)
- n = -offset;
- offset += m;
- memmove(a, buf+offset, n);
- return n;
- }
- }
- return 0;
-}
-
-void
-trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
-{
- Vctl *v;
-
- if(vno < 0 || vno >= VectorPIC)
- panic("trapenable: vno %d\n", vno);
- v = xalloc(sizeof(Vctl));
- v->tbdf = BUSUNKNOWN;
- v->f = f;
- v->a = a;
- strncpy(v->name, name, KNAMELEN);
- v->name[KNAMELEN-1] = 0;
-
- lock(&vctllock);
- if(vctl[vno])
- v->next = vctl[vno]->next;
- vctl[vno] = v;
- unlock(&vctllock);
-}
-
-static void
-nmienable(void)
-{
- /* leave this here in case plan 9 ever makes it to dom0 */
-#ifdef NOWAY
- /*
- * Hack: should be locked with NVRAM access.
- */
- outb(0x70, 0x80); /* NMI latch clear */
- outb(0x70, 0);
-
- x = inb(0x61) & 0x07; /* Enable NMI */
- outb(0x61, 0x08|x);
- outb(0x61, x);
-#endif
-}
-
/* we started out doing the 'giant bulk init' for all traps.
* we're going to do them one-by-one since error analysis is
* so much easier that way.
@@ -212,6 +73,8 @@ trapinit(void)
vaddr += 6;
}
+ irqinit();
+
/*
* Special traps.
* Syscall() is called directly without going through trap().
@@ -220,9 +83,6 @@ trapinit(void)
trapenable(VectorPF, fault386, 0, "fault386");
trapenable(Vector2F, doublefault, 0, "doublefault");
trapenable(Vector15, unexpected, 0, "unexpected");
-
- nmienable();
- addarchfile("irqalloc", 0444, irqallocread, nil);
}
static char* excname[32] = {
@@ -260,27 +120,18 @@ static char* excname[32] = {
"31 (reserved)",
};
-/*
- * keep histogram of interrupt service times
- */
-void
-intrtime(Mach*, int vno)
+static int
+usertrap(int vno)
{
- ulong diff;
- ulong x;
-
- x = perfticks();
- diff = x - m->perf.intrts;
- m->perf.intrts = x;
-
- m->perf.inintr += diff;
- if(up == nil && m->perf.inidle > diff)
- m->perf.inidle -= diff;
+ char buf[ERRMAX];
- diff /= m->cpumhz*100; // quantum = 100µsec
- if(diff >= Ntimevec)
- diff = Ntimevec-1;
- intrtimes[vno][diff]++;
+ if(vno < nelem(excname)){
+ spllo();
+ sprint(buf, "sys: trap: %s", excname[vno]);
+ postnote(up, 1, buf, NDebug);
+ return 1;
+ }
+ return 0;
}
/* go to user space */
@@ -304,120 +155,27 @@ kexit(Ureg*)
* rather than directly vectoring the handler. However, this avoids a
* lot of code duplication and possible bugs. The only exception is
* VectorSYSCALL.
- * Trap is called with interrupts (and events) disabled via interrupt-gates.
+ * Trap is called with interrupts disabled via interrupt-gates.
*/
void
trap(Ureg* ureg)
{
- int clockintr, i, vno, user;
- char buf[ERRMAX];
- Vctl *ctl, *v;
- Mach *mach;
+ int vno, user;
- TRAPLOG(dprint("trap ureg %lux %lux\n", (ulong*)ureg, ureg->trap);)
- m->perf.intrts = perfticks();
- user = (ureg->cs & 0xFFFF) == UESEL;
+ user = userureg(ureg);
if(user){
up->dbgreg = ureg;
cycles(&up->kentry);
}
- clockintr = 0;
-
vno = ureg->trap;
- if(vno < 0 || vno >= 256)
- panic("bad interrupt number %d\n", vno);
- TRAPLOG(dprint("trap: vno is 0x%x, vctl[%d] is %p\n", vno, vno, vctl[vno]);)
- if(ctl = vctl[vno]){
- INTRLOG(dprint("ctl is %p, isintr is %d\n", ctl, ctl->isintr);)
- if(ctl->isintr){
- m->intr++;
- if(vno >= VectorPIC && vno != VectorSYSCALL)
- m->lastintr = ctl->irq;
- }
-
- INTRLOG(dprint("ctl %p, isr %p\n", ctl, ctl->isr);)
- if(ctl->isr)
- ctl->isr(vno);
- for(v = ctl; v != nil; v = v->next){
- INTRLOG(dprint("ctl %p, f is %p\n", v, v->f);)
- if(v->f)
- v->f(ureg, v->a);
- }
- INTRLOG(dprint("ctl %p, eoi %p\n", ctl, ctl->eoi);)
- if(ctl->eoi)
- ctl->eoi(vno);
-
- if(ctl->isintr){
- intrtime(m, vno);
-
- //if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER)
- if (ctl->tbdf != BUSUNKNOWN && ctl->irq == VIRQ_TIMER)
- clockintr = 1;
-
- if(up && !clockintr)
- preempted();
- }
- }
- else if(vno <= nelem(excname) && user){
- spllo();
- sprint(buf, "sys: trap: %s", excname[vno]);
- postnote(up, 1, buf, NDebug);
- }
- else if(vno >= VectorPIC && vno != VectorSYSCALL){
- /*
- * 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.
- */
-
- /* call all interrupt routines, just in case */
- for(i = VectorPIC; i <= MaxIrqLAPIC; i++){
- ctl = vctl[i];
- if(ctl == nil)
- continue;
- if(!ctl->isintr)
- continue;
- for(v = ctl; v != nil; v = v->next){
- if(v->f)
- v->f(ureg, v->a);
- }
- /* should we do this? */
- if(ctl->eoi)
- ctl->eoi(i);
+ if(!irqhandled(ureg, vno) && (!user || !usertrap(vno))){
+ if(!user){
+ /* early fault before trapinit() */
+ if(vno == VectorPF)
+ fault386(ureg, 0);
}
- iprint("cpu%d: spurious interrupt %d, last %d\n",
- m->machno, vno, m->lastintr);
- if(0)if(conf.nmach > 1){
- for(i = 0; i < MAXMACH; i++){
- if(active.machs[i] == 0)
- continue;
- mach = MACHP(i);
- if(m->machno == mach->machno)
- continue;
- print(" cpu%d: last %d",
- mach->machno, mach->lastintr);
- }
- print("\n");
- }
- m->spuriousintr++;
- if(user)
- kexit(ureg);
- return;
- }
- else{
- if(vno == VectorNMI){
- nmienable();
- if(m->machno != 0){
- print("cpu%d: PC %8.8luX\n",
- m->machno, ureg->pc);
- for(;;);
- }
- }
dumpregs(ureg);
if(!user){
ureg->sp = (ulong)&ureg->sp;
@@ -425,18 +183,10 @@ trap(Ureg* ureg)
}
if(vno < nelem(excname))
panic("%s", excname[vno]);
- panic("unknown trap/intr: %d\n", vno);
+ panic("unknown trap/intr: %d", vno);
}
splhi();
- /* delaysched set because we held a lock or because our quantum ended */
- if(up && up->delaysched && clockintr){
- INTRLOG(dprint("calling sched in trap? \n");)
- sched();
- INTRLOG(dprint("Back from calling sched in trap?\n");)
- splhi();
- }
-
if(user){
if(up->procctl || up->nnote)
notify(ureg);
diff --git a/sys/src/9/xen/xensystem.c b/sys/src/9/xen/xensystem.c
index bff81afb3..82196d9ad 100644
--- a/sys/src/9/xen/xensystem.c
+++ b/sys/src/9/xen/xensystem.c
@@ -389,6 +389,26 @@ xenupcall(Ureg *ureg)
}
+static int
+xenirqenable(Vctl *v, int shared)
+{
+ if(!shared){
+ uint port = v->vno-100;
+ HYPERVISOR_shared_info->evtchn_mask[port/32] &= ~(1<<(port%32));
+ }
+ return 0;
+}
+
+static int
+xenirqdisable(Vctl *v, int shared)
+{
+ if(!shared){
+ uint port = v->vno-100;
+ HYPERVISOR_shared_info->evtchn_mask[port/32] |= (1<<(port%32));
+ }
+ return 0;
+}
+
/*
* tbdf field is abused to distinguish virqs from channels:
*
@@ -396,37 +416,30 @@ xenupcall(Ureg *ureg)
* tbdf=0 -> irq is a channel number
*/
int
-xenintrenable(Vctl *v)
+xenintrassign(Vctl *v)
{
evtchn_op_t op;
uint port;
- /* XXX locking? */
if (v->tbdf != BUSUNKNOWN) {
op.cmd = EVTCHNOP_bind_virq;
op.u.bind_virq.virq = v->irq;
op.u.bind_virq.vcpu = m->machno;
- if(HYPERVISOR_event_channel_op(&op) != 0)
- panic("xenintrenable: bind %d failed", v->irq);
+ if(HYPERVISOR_event_channel_op(&op) != 0){
+ print("xenintrenable: bind %d failed", v->irq);
+ return -1;
+ }
port = op.u.bind_virq.port;
} else
port = v->irq;
if (port > 155)
return -1;
- HYPERVISOR_shared_info->evtchn_mask[port/32] &= ~(1<<(port%32));
- if(0)print("xenintrenable %s: irq %d port %d mask[%d] = %#lux\n", v->name, v->irq, port, port/32, HYPERVISOR_shared_info->evtchn_mask[port/32]);
+ v->enable = xenirqenable;
+ v->disable = xenirqdisable;
return 100+port;
}
int
-xenintrdisable(int irq)
-{
- USED(irq);
- panic("xenintrdisable notyet\n");
- return 0;
-}
-
-int
xenintrvecno(int irq)
{
return irq;
diff --git a/sys/src/9/xen/xentimer.c b/sys/src/9/xen/xentimer.c
index 2a57cc5b9..4e6a2715e 100644
--- a/sys/src/9/xen/xentimer.c
+++ b/sys/src/9/xen/xentimer.c
@@ -68,7 +68,7 @@ xentimerclock(Ureg* ureg, void*)
void
xentimerenable(void)
{
- intrenable(VIRQ_TIMER, xentimerclock, nil, 0, "Xen Timer");
+ intrenable(VIRQ_TIMER, xentimerclock, nil, 0, "clock");
}
uvlong