ref: 0e0590fe5946c9bb1b9777b18099ee452564d1d1
parent: 37775f47e6b73f64997fcc179e061d943c8721de
author: 9ferno <[email protected]>
date: Fri Oct 15 01:24:35 EDT 2021
importing 9front irq.c
--- a/os/pc/apic.c
+++ b/os/pc/apic.c
@@ -500,18 +500,16 @@
timerintr(u, 0);
}
-int
-lapicintron(Vctl*)
+void
+lapicintron(void)
{
lapicw(LapicTPR, 0);
- return 0;
}
-int
-lapicintroff(int)
+void
+lapicintroff(void)
{
lapicw(LapicTPR, 0xFF);
- return 0;
}
void
--- a/os/pc/archacpi.c
+++ b/os/pc/archacpi.c
@@ -782,8 +782,8 @@
.intrinit= acpiinit,
.intrassign= mpintrassign,
.intrirqno= i8259irqno,
-.intrenable= lapicintron,
-.intrdisable= lapicintroff,
+.intron= lapicintron,
+.introff= lapicintroff,
.clockinit= i8253init,
.fastclock= i8253read,
.timerset= lapictimerset,
--- a/os/pc/archgeneric.c
+++ b/os/pc/archgeneric.c
@@ -11,8 +11,8 @@
extern int i8259irqno(int, int);
extern void i8259init(void);
extern int i8259isr(int);
-extern int i8259enable(Vctl*);
-extern int i8259disable(int);
+extern void i8259on(void);
+extern void i8259off(void);
extern int i8259vecno(int);
void
@@ -85,8 +85,8 @@
.intrirqno= i8259irqno,
.intrvecno= i8259vecno,
.intrspurious= i8259isr,
-.intrenable= i8259enable,
-.intrdisable= i8259disable,
+.intron= i8259on,
+.introff= i8259off,
.clockinit= i8253init,
.clockenable= i8253enable,
--- a/os/pc/archmp.c
+++ b/os/pc/archmp.c
@@ -376,8 +376,8 @@
.intrinit= pcmpinit,
.intrassign= mpintrassign,
.intrirqno= i8259irqno,
-.intrenable= lapicintron,
-.intrdisable= lapicintroff,
+.intron= lapicintron,
+.introff= lapicintroff,
.fastclock= i8253read,
.timerset= lapictimerset,
};
--- a/os/pc/i8259.c
+++ b/os/pc/i8259.c
@@ -131,23 +131,9 @@
}
int
-i8259enable(Vctl*)
-{
- i8259on();
- return 1; /* TODO fix this */
-}
-
-int
i8259vecno(int irq)
{
return VectorPIC+irq;
-}
-
-int
-i8259disable(int)
-{
- i8259off();
- return 0;
}
static int
--- /dev/null
+++ b/os/pc/irq.c
@@ -1,0 +1,306 @@
+#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 *vclock, *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;
+
+ ctl = vctl[vno];
+ if(ctl != nil){
+ if(vno < VectorPIC){
+ (*ctl->f)(ureg, ctl->a);
+ return 1;
+ }
+
+ 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 || vno == VectorSYSCALL)
+ return 0;
+
+ m->spuriousintr++;
+ if(arch->intrspurious != nil && (*arch->intrspurious)(vno) == 0)
+ return 1; /* false alarm */
+
+ iprint("cpu%d: spurious interrupt %d, last %d\n",
+ m->machno, vno, m->lastintr);
+
+ /* 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);
+ }
+
+ return -1;
+}
+
+void
+trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
+{
+ Vctl *v;
+
+ 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->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] != 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)
+{
+ Vctl **pv, *v;
+
+ if(f == nil){
+ print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
+ irq, tbdf, name);
+ return;
+ }
+
+ if(arch->intrirqno != nil)
+ irq = (*arch->intrirqno)(irq, tbdf);
+
+ if((v = xalloc(sizeof(Vctl))) == nil)
+ panic("intrenable: out of memory");
+
+ 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);
+ 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);
+Unlockandfree:
+ iunlock(&vctllock);
+ if(v != nil)
+ xfree(v);
+ return;
+ }
+ 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;
+ }
+ }
+ iunlock(&vctllock);
+}
+
+void
+intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
+{
+ Vctl **pv, *v;
+ int vno;
+
+ 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;
+ }
+
+ ilock(&vctllock);
+ do {
+ for(pv = &vctl[vno]; (v = *pv) != nil; pv = &v->next){
+ 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){
+ 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;
+ if(v == vclock)
+ vclock = nil;
+ if(conf.nmach > 1)
+ v = delayfree(v);
+ iunlock(&vctllock);
+ if(v != nil)
+ xfree(v);
+ return;
+ }
+ } while(irq == -1 && ++vno < nelem(vctl));
+ iunlock(&vctllock);
+}
+
+static s32
+irqallocread(Chan*, void *a, s32 n, s64 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 != nil; 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
+irqinit(void)
+{
+ addarchfile("irqalloc", 0444, irqallocread, nil);
+}
--- a/os/pc/mp.c
+++ b/os/pc/mp.c
@@ -657,7 +657,7 @@
*/
if(m->machno != 0){
splhi();
- arch->intrdisable(0);
+ arch->introff();
for(;;) idle();
}
delay(1000);
--- a/os/pc64/dat.h
+++ b/os/pc64/dat.h
@@ -259,10 +259,10 @@
void (*intrinit)(void);
s32 (*intrassign)(Vctl*);
s32 (*intrirqno)(s32, s32);
- s32 (*intrspurious)(s32);
- s32 (*intrenable)(Vctl*);
s32 (*intrvecno)(s32);
- s32 (*intrdisable)(s32);
+ s32 (*intrspurious)(s32);
+ void (*introff)(void);
+ void (*intron)(void);
void (*clockinit)(void);
void (*clockenable)(void);
--- a/os/pc64/fns.h
+++ b/os/pc64/fns.h
@@ -76,8 +76,10 @@
void inss(int, void*, int);
ulong inl(int);
void insl(int, void*, int);
-int intrdisable(int, void (*)(Ureg *, void *), void*, int, char*);
+void intrdisable(int, void (*)(Ureg *, void *), void*, int, char*);
void intrenable(int, void (*)(Ureg*, void*), void*, int, char*);
+void introff(void);
+void intron(void);
void invlpg(uintptr);
void iofree(u32);
void ioinit(void);
@@ -116,6 +118,7 @@
void mtrrclock(void);
int mtrrprint(char *, s32);
void mtrrsync(void);
+void nmienable(void);
uchar nvramread(intptr);
void nvramwrite(intptr, uchar);
void outb(int, int);
--- a/os/pc64/mkfile
+++ b/os/pc64/mkfile
@@ -31,6 +31,7 @@
memmap.$O\
memory.$O\
mmu.$O\
+ irq.$O\
trap.$O\
bootargs.$O\
$CONF.root.$O\
--- a/os/pc64/mp.h
+++ b/os/pc64/mp.h
@@ -238,8 +238,8 @@
extern void lapicerror(Ureg*, void*);
extern void lapicicrw(ulong, ulong);
extern void lapicinit(Apic*);
-extern int lapicintroff(int);
-extern int lapicintron(Vctl*);
+extern void lapicintroff(void);
+extern void lapicintron(void);
extern int lapicisr(int);
extern void lapicnmidisable(void);
extern void lapicnmienable(void);
--- a/os/pc64/trap.c
+++ b/os/pc64/trap.c
@@ -7,6 +7,11 @@
#include "ureg.h"
#include "../port/error.h"
+Vctl *vctl[256]; /* defined in pc/irq.c */
+
+extern int irqhandled(Ureg*, int);
+extern void irqinit(void);
+
int (*breakhandler)(Ureg *ur, Proc*);
static void debugbpt(Ureg*, void*);
@@ -15,183 +20,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;
- }
-
- 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 %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);
-}
-
-int
-intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
-{
- Vctl **pv, *v;
- int vno;
-
- /*
- * For now, none of this will work with the APIC code,
- * there is no mapping between irq and vector as the IRQ
- * is pretty meaningless.
- */
- if(arch->intrvecno == nil)
- return -1;
- vno = arch->intrvecno(irq);
- 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 && arch->intrdisable != nil)
- arch->intrdisable(irq);
- iunlock(&vctllock);
- xfree(v);
- return 0;
-}
-
-static s32
-irqallocread(Chan*, void *vbuf, s32 n, s64 offset)
-{
- char *buf, *p, str[2*(11+1)+KNAMELEN+1+1];
- int m, vno;
- long oldn;
- Vctl *v;
-
- if(n < 0 || offset < 0)
- error(Ebadarg);
-
- oldn = n;
- buf = vbuf;
- for(vno=0; vno<nelem(vctl); vno++){
- for(v=vctl[vno]; v; v=v->next){
- m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name);
- if(m <= offset) /* if do not want this, skip entry */
- offset -= m;
- else{
- /* skip offset bytes */
- m -= offset;
- p = str+offset;
- offset = 0;
-
- /* write at most max(n,m) bytes */
- if(m > n)
- m = n;
- memmove(buf, p, m);
- n -= m;
- buf += m;
-
- if(n == 0)
- return oldn;
- }
- }
- }
- return oldn - n;
-}
-
-void
-trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
-{
- Vctl *v;
-
- if(f == nil)
- panic("trapenable: nil handler for %d, for %s\n",
- vno, name);
- if(vno < 0 || vno >= VectorPIC)
- panic("trapenable: vno %d out of range\n", vno);
- if((v = xalloc(sizeof(Vctl))) == nil){
- panic("trapenable: out of memory");
- }
- v->tbdf = BUSUNKNOWN;
- v->f = f;
- v->a = a;
- v->irq = -1;
- v->cpu = -1;
- 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
-nmihandler(Ureg *ureg, void*)
-{
- iprint("cpu%d: nmi PC %#p, status %ux\n",
- m->machno, ureg->pc, inb(0x61));
- while(m->machno != 0)
- ;
-}
-
-static 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, 0x08|x);
- outb(0x61, x);
-}
-
-void
trapinit0(void)
{
u32 d1, v;
@@ -235,19 +64,19 @@
void
trapinit(void)
{
+ irqinit();
+
+ nmienable();
+
/*
* Special traps.
* Syscall() is called directly without going through trap().
*/
+ /* 9front specific trapenable(VectorDE, debugexc, 0, "debugexc"); */
trapenable(VectorBPT, debugbpt, 0, "debugpt");
trapenable(VectorPF, faultamd64, 0, "faultamd64");
trapenable(Vector2F, doublefault, 0, "doublefault");
trapenable(Vector15, unexpected, 0, "unexpected");
-
- nmienable();
-
- /* 9front calls this irqinit() */
- addarchfile("irqalloc", 0444, irqallocread, nil);
}
static char* excname[32] = {
--- a/os/port/portfns.h
+++ b/os/port/portfns.h
@@ -196,6 +196,7 @@
Block* padblock(Block*, int);
void panic(char*, ...);
Cmdbuf* parsecmd(char*, int);
+ulong perfticks(void);
void pexit(char*, int);
void pgrpcpy(Pgrp*, Pgrp*);
#define poperror() up->nerrlab--
@@ -203,6 +204,7 @@
void poolsize(Pool *, u64, int);
int postnote(Proc *, int, char *, int);
int pprint(char*, ...);
+int preempted(void);
int preemption(int);
void printinit(void);
void procctl(Proc*);
--- a/os/port/proc.c
+++ b/os/port/proc.c
@@ -164,7 +164,30 @@
}
return 0;
}
-
+
+/* this is from 9front, above is inferno's */
+/*
+ * here at the end of non-clock interrupts to see if we should preempt the
+ * current process. Returns 1 if preempted, 0 otherwise.
+ */
+int
+preempted(void)
+{
+ if(up != nil && up->state == Running)
+ if(up->preempted == 0)
+ if(anyhigher())
+ if(anyready()){ /* TODO replaced the below 2 lines with this line. Have to test */
+ /* if(!active.exiting){
+ m->readied = nil; */ /* avoid cooperative scheduling */
+ up->preempted = 1;
+ sched();
+ splhi();
+ up->preempted = 0;
+ return 1;
+ }
+ return 0;
+}
+
Proc*
runproc(void)
{