ref: a041c90431c5987496ac1d5de4f330f70fd2966f
parent: 97008caa4174cee3dd849d9962c529897717e333
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Nov 22 12:44:21 EST 2020
pc, pc64: move common irq handling code out of trap.c Move the common irq handling code out of trap.c into pc/irq.c so that it can be shared between 386 and amd64 ports.
--- /dev/null
+++ b/sys/src/9/pc/irq.c
@@ -1,0 +1,313 @@
+#include "u.h"
+#include "tos.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../port/error.h"
+
+static Lock vctllock;
+static Vctl *vctl[256];
+
+enum
+{
+ Ntimevec = 20 /* number of time buckets for each intr */
+};
+ulong intrtimes[256][Ntimevec];
+
+/*
+ * keep histogram of interrupt service times
+ */
+static void
+intrtime(Mach*, 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;
+
+ diff /= m->cpumhz*100; /* quantum = 100µsec */
+ if(diff >= Ntimevec)
+ diff = Ntimevec-1;
+ intrtimes[vno][diff]++;
+}
+
+int
+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;
+ }
+ 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();
+ }
+ }
+ }
+ return 1;
+ }
+
+ if(vno < VectorPIC)
+ 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);
+
+ if(0)print("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");
+ }
+ m->spuriousintr++;
+ return -1;
+}
+
+void
+trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
+{
+ Vctl *v;
+
+ if(vno < 0 || vno >= VectorPIC)
+ panic("trapenable: vno %d", vno);
+ if((v = xalloc(sizeof(Vctl))) == nil)
+ panic("trapenable: out of memory");
+ v->tbdf = BUSUNKNOWN;
+ v->f = f;
+ v->a = a;
+ strncpy(v->name, name, KNAMELEN-1);
+ v->name[KNAMELEN-1] = 0;
+
+ ilock(&vctllock);
+ if(vctl[vno])
+ v->next = vctl[vno]->next;
+ vctl[vno] = v;
+ iunlock(&vctllock);
+}
+
+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;
+ }
+
+ 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((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;
+ strncpy(v->name, name, KNAMELEN-1);
+ v->name[KNAMELEN-1] = 0;
+
+ ilock(&vctllock);
+ vno = arch->intrenable(v);
+ if(vno == -1){
+ iunlock(&vctllock);
+ print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
+ irq, tbdf, v->name);
+ xfree(v);
+ return;
+ }
+ if(vctl[vno]){
+ if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
+ panic("intrenable: handler: %s %s %#p %#p %#p %#p",
+ vctl[vno]->name, v->name,
+ vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
+ v->next = vctl[vno];
+ }
+ vctl[vno] = v;
+ iunlock(&vctllock);
+}
+
+void
+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.
+ */
+ 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)
+ && 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);
+ *pv = v->next;
+ xfree(v);
+
+ if(irq != -1 && vctl[vno] == nil && arch->intrdisable != nil)
+ arch->intrdisable(irq);
+ break;
+ }
+ } while(irq == -1 && ++vno <= MaxVectorAPIC);
+ 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;
+}
+
+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();
+}
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -54,6 +54,7 @@
main.$O\
memory.$O\
mmu.$O\
+ irq.$O\
trap.$O\
bootargs.$O\
$CONF.root.$O\
--- a/sys/src/9/pc/trap.c
+++ b/sys/src/9/pc/trap.c
@@ -9,6 +9,9 @@
#include "../port/error.h"
#include <trace.h>
+extern int irqhandled(Ureg*, int);
+extern void irqinit(void);
+
void noted(Ureg*, ulong);
static void debugexc(Ureg*, void*);
@@ -18,173 +21,6 @@
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;
-
- if(f == nil){
- print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
- irq, tbdf, 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((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;
- strncpy(v->name, name, KNAMELEN-1);
- v->name[KNAMELEN-1] = 0;
-
- ilock(&vctllock);
- vno = arch->intrenable(v);
- if(vno == -1){
- iunlock(&vctllock);
- print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
- irq, tbdf, v->name);
- xfree(v);
- return;
- }
- if(vctl[vno]){
- if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
- panic("intrenable: handler: %s %s %#p %#p %#p %#p",
- vctl[vno]->name, v->name,
- vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
- v->next = vctl[vno];
- }
- vctl[vno] = v;
- iunlock(&vctllock);
-}
-
-void
-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.
- * however, we still want to remove the matching
- * Vctl entry to prevent calling Vctl.f() with a
- * stale Vctl.a pointer.
- */
- 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)
- && 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);
- *pv = v->next;
- xfree(v);
-
- if(irq != -1 && vctl[vno] == nil && arch->intrdisable != nil)
- arch->intrdisable(irq);
- break;
- }
- } while(irq == -1 && ++vno <= MaxVectorAPIC);
- 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", vno);
- if((v = xalloc(sizeof(Vctl))) == nil)
- panic("trapenable: out of memory");
- v->tbdf = BUSUNKNOWN;
- v->f = f;
- v->a = a;
- strncpy(v->name, name, KNAMELEN-1);
- v->name[KNAMELEN-1] = 0;
-
- ilock(&vctllock);
- if(vctl[vno])
- v->next = vctl[vno]->next;
- vctl[vno] = v;
- iunlock(&vctllock);
-}
-
-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);
-}
-
/*
* Minimal trap setup. Just enough so that we can panic
* on traps (bugs) during kernel initialization.
@@ -228,6 +64,8 @@
void
trapinit(void)
{
+ irqinit();
+
/*
* Special traps.
* Syscall() is called directly without going through trap().
@@ -237,9 +75,6 @@
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] = {
@@ -277,27 +112,18 @@
"31 (reserved)",
};
-/*
- * keep histogram of interrupt service times
- */
-void
-intrtime(Mach*, int vno)
+static int
+usertrap(int vno)
{
- ulong diff;
- ulong x;
+ char buf[ERRMAX];
- 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;
-
- 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 */
@@ -325,12 +151,8 @@
void
trap(Ureg* ureg)
{
- int clockintr, i, vno, user;
- char buf[ERRMAX];
- Vctl *ctl, *v;
- Mach *mach;
+ int vno, user;
- m->perf.intrts = perfticks();
user = userureg(ureg);
if(user){
up->dbgreg = ureg;
@@ -337,100 +159,8 @@
cycles(&up->kentry);
}
- clockintr = 0;
-
vno = ureg->trap;
- if(ctl = vctl[vno]){
- if(ctl->isintr){
- m->intr++;
- if(vno >= VectorPIC && vno != VectorSYSCALL)
- m->lastintr = ctl->irq;
- }
-
- 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(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER)
- 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);
- }
-
- /* clear the interrupt */
- i8259isr(vno);
-
- if(0)print("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){
- /*
- * Don't re-enable, it confuses the crash dumps.
- nmienable();
- */
- iprint("cpu%d: nmi PC %#8.8lux, status %ux\n",
- m->machno, ureg->pc, inb(0x61));
- while(m->machno != 0)
- ;
- }
-
+ if(!irqhandled(ureg, vno) && (!user || !usertrap(vno))){
if(!user){
void (*pc)(void);
ulong *sp;
@@ -493,12 +223,6 @@
panic("unknown trap/intr: %d", vno);
}
splhi();
-
- /* delaysched set because we held a lock or because our quantum ended */
- if(up && up->delaysched && clockintr){
- sched();
- splhi();
- }
if(user){
if(up->procctl || up->nnote)
--- a/sys/src/9/pc64/mkfile
+++ b/sys/src/9/pc64/mkfile
@@ -52,6 +52,7 @@
main.$O\
memory.$O\
mmu.$O\
+ irq.$O\
trap.$O\
bootargs.$O\
$CONF.root.$O\
--- a/sys/src/9/pc64/trap.c
+++ b/sys/src/9/pc64/trap.c
@@ -9,6 +9,9 @@
#include "../port/error.h"
#include <trace.h>
+extern int irqhandled(Ureg*, int);
+extern void irqinit(void);
+
void noted(Ureg*, ulong);
static void debugexc(Ureg*, void*);
@@ -18,177 +21,7 @@
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;
-
- if(f == nil){
- print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
- irq, tbdf, 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((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;
- strncpy(v->name, name, KNAMELEN-1);
- v->name[KNAMELEN-1] = 0;
-
- ilock(&vctllock);
- vno = arch->intrenable(v);
- if(vno == -1){
- iunlock(&vctllock);
- print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
- irq, tbdf, v->name);
- xfree(v);
- return;
- }
- if(vctl[vno]){
- if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
- panic("intrenable: handler: %s %s %#p %#p %#p %#p",
- vctl[vno]->name, v->name,
- vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
- v->next = vctl[vno];
- }
- vctl[vno] = v;
- iunlock(&vctllock);
-}
-
-void
-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.
- */
- 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)
- && 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);
- *pv = v->next;
- xfree(v);
-
- if(irq != -1 && vctl[vno] == nil && arch->intrdisable != nil)
- arch->intrdisable(irq);
- break;
- }
- } while(irq == -1 && ++vno <= MaxVectorAPIC);
- 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", vno);
- if((v = xalloc(sizeof(Vctl))) == nil)
- panic("trapenable: out of memory");
- v->tbdf = BUSUNKNOWN;
- v->f = f;
- v->a = a;
- strncpy(v->name, name, KNAMELEN-1);
- v->name[KNAMELEN-1] = 0;
-
- ilock(&vctllock);
- if(vctl[vno])
- v->next = vctl[vno]->next;
- vctl[vno] = v;
- iunlock(&vctllock);
-}
-
-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);
-}
-
-void
trapinit0(void)
{
u32int d1, v;
@@ -232,6 +65,8 @@
void
trapinit(void)
{
+ irqinit();
+
/*
* Special traps.
* Syscall() is called directly without going through trap().
@@ -241,8 +76,6 @@
trapenable(VectorPF, faultamd64, 0, "faultamd64");
trapenable(Vector2F, doublefault, 0, "doublefault");
trapenable(Vector15, unexpected, 0, "unexpected");
- nmienable();
- addarchfile("irqalloc", 0444, irqallocread, nil);
}
static char* excname[32] = {
@@ -280,27 +113,18 @@
"31 (reserved)",
};
-/*
- * keep histogram of interrupt service times
- */
-void
-intrtime(Mach*, int vno)
+static int
+usertrap(int vno)
{
- ulong diff;
- ulong x;
+ char buf[ERRMAX];
- 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;
-
- 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 */
@@ -321,12 +145,8 @@
void
trap(Ureg *ureg)
{
- int clockintr, i, vno, user;
- char buf[ERRMAX];
- Vctl *ctl, *v;
- Mach *mach;
+ int vno, user;
- m->perf.intrts = perfticks();
user = userureg(ureg);
if(user){
up->dbgreg = ureg;
@@ -333,100 +153,8 @@
cycles(&up->kentry);
}
- clockintr = 0;
-
vno = ureg->type;
-
- if(ctl = vctl[vno]){
- if(ctl->isintr){
- m->intr++;
- if(vno >= VectorPIC)
- m->lastintr = ctl->irq;
- }
- 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(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER)
- 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){
- /*
- * 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);
-
- if(0)print("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){
- /*
- * 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)
- ;
- }
-
+ if(!irqhandled(ureg, vno) && (!user || !usertrap(vno))){
if(!user){
void (*pc)(void);
@@ -463,12 +191,6 @@
panic("unknown trap/intr: %d", vno);
}
splhi();
-
- /* delaysched set because we held a lock or because our quantum ended */
- if(up && up->delaysched && clockintr){
- sched();
- splhi();
- }
if(user){
if(up->procctl || up->nnote)