summaryrefslogtreecommitdiff
path: root/sys/src/9/xen
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2020-11-29 17:43:22 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2020-11-29 17:43:22 +0100
commit1d93a5628adc0f08463fe4272dc88fb0f61e631d (patch)
treeb96cb74f50ab891af2fc72ebaf0d8ac6309ae385 /sys/src/9/xen
parent32a5ff9658cfa2d0d15cecf3b2a27be6b0742227 (diff)
pc, pc64, xen: rewrite interrupt handling code
This implements proper intrdisable() support for all interrupt controllers. For enable, (*arch->intrassign)(Vctl*) fills in the Vctl.enable and Vctl.disable pointers with the appropriate routines and returns the assigned vector number. Once the Vctl struct has been linked to its vector chain, Vctl.enable(Vctl*, shared) gets called with a flag if the vector has been already enabled (shared). This order is important here as enabling the interrupt on the controller before we have linked the chain can cause spurious interrupts, expecially on mp system where the interrupt can target a different cpu than the caller of intrenable(). The intrdisable() case is the other way around. We first disable the interrupt on the controller and after that unlink the Vctl from the chain. On a multiprocessor, the xfree() of the Vctl struct is delayed to avoid freeing it while it is still in use by another cpu. The xen port now also uses pc/irq.c which has been made generic enougth to handle xen's irq scheme. Also, archgeneric is now a separate file to avoid pulling in dependencies from the 8259 interrupt controller code.
Diffstat (limited to 'sys/src/9/xen')
-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
6 files changed, 57 insertions, 316 deletions
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