code: 9ferno

Download patch

ref: 0e0590fe5946c9bb1b9777b18099ee452564d1d1
parent: 37775f47e6b73f64997fcc179e061d943c8721de
author: 9ferno <gophone2015@gmail.com>
date: Fri Oct 15 08: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)
 {