Browse Source

Plan 9 from Bell Labs 2011-10-12

David du Colombier 12 years ago
parent
commit
5f9adff483

+ 5 - 0
sys/src/9/pc/apic.c

@@ -100,12 +100,14 @@ struct
 static ulong
 lapicr(int r)
 {
+	assert(lapicbase != 0);
 	return *(lapicbase+(r/sizeof(*lapicbase)));
 }
 
 static void
 lapicw(int r, ulong data)
 {
+	assert(lapicbase != 0);
 	*(lapicbase+(r/sizeof(*lapicbase))) = data;
 	data = *(lapicbase+(LapicID/sizeof(*lapicbase)));
 	USED(data);
@@ -156,6 +158,7 @@ lapictimerinit(void)
 					lapictimer.hz, hz);
 			lapictimer.hz = hz;
 		}
+		assert(lapictimer.hz != 0);
 		lapictimer.div = hz/lapictimer.hz;
 	}
 }
@@ -372,6 +375,8 @@ lapictimerset(uvlong next)
 	period = lapictimer.max;
 	if(next != 0){
 		period = next - fastticks(nil);
+		if (lapictimer.div == 0)
+			panic("lapictimerset: zero lapictimer.div");
 		period /= lapictimer.div;
 
 		if(period < lapictimer.min)

+ 8 - 1
sys/src/9/pc/devarch.c

@@ -717,7 +717,8 @@ cpuidprint(void)
 	int i;
 	char buf[128];
 
-	i = sprint(buf, "cpu%d: %dMHz ", m->machno, m->cpumhz);
+	i = sprint(buf, "cpu%d: %s%dMHz ", m->machno, m->machno < 10? " ": "",
+		m->cpumhz);
 	if(m->cpuidid[0])
 		i += sprint(buf+i, "%12.12s ", m->cpuidid);
 	seprint(buf+i, buf + sizeof buf - 1,
@@ -1030,6 +1031,12 @@ archinit(void)
 	addarchfile("archctl", 0664, archctlread, archctlwrite);
 }
 
+void
+archrevert(void)
+{
+	arch = &archgeneric;
+}
+
 /*
  *  call either the pcmcia or pccard device setup
  */

+ 1 - 0
sys/src/9/pc/fns.h

@@ -4,6 +4,7 @@ void	aamloop(int);
 void	acpiscan(void (*func)(uchar *));
 Dirtab*	addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,void*,long,vlong));
 void	archinit(void);
+void	archrevert(void);
 int	bios32call(BIOS32ci*, u16int[3]);
 int	bios32ci(BIOS32si*, BIOS32ci*);
 void	bios32close(BIOS32si*);

+ 68 - 22
sys/src/9/pc/mp.c

@@ -9,14 +9,22 @@
 #include "mp.h"
 #include "apbootstrap.h"
 
+#define dprint(...)	if(mpdebug) print(__VA_ARGS__); else USED(mpdebug)
+
+/* from mpacpi.c */
+Apic *bootapic;
+
+int mpdebug;
+void (*mpacpifunc)(void);
+
 static PCMP* mppcmp;
 static Bus* mpbus;
 static Bus* mpbuslast;
 static int mpisabus = -1;
 static int mpeisabus = -1;
 extern int i8259elcr;			/* mask of level-triggered interrupts */
-static Apic mpapic[MaxAPICNO+1];
-static int machno2apicno[MaxAPICNO+1];	/* inverse map: machno -> APIC ID */
+/* static */ Apic mpapic[MaxAPICNO+1];
+/* static */ int machno2apicno[MaxAPICNO+1];	/* inverse map: machno -> APIC ID */
 static Ref mpvnoref;			/* unique vector assignment */
 static int mpmachno = 1;
 static Lock mpphysidlock;
@@ -185,7 +193,7 @@ mkiointr(PCMPintr* p)
 	aintr->intr = p;
 
 	if(0)
-		print("mkiointr: type %d intr type %d flags %#o "
+		dprint("mkiointr: type %d intr type %d flags %#o "
 			"bus %d irq %d apicno %d intin %d\n",
 			p->type, p->intr, p->flags,
 			p->busno, p->irq, p->apicno, p->intin);
@@ -193,7 +201,7 @@ mkiointr(PCMPintr* p)
 	 * Hack for Intel SR1520ML motherboard, which BIOS describes
 	 * the i82575 dual ethernet controllers incorrectly.
 	 */
-	if(memcmp(mppcmp->product, "INTEL   X38MLST     ", 20) == 0){
+	if(mppcmp && memcmp(mppcmp->product, "INTEL   X38MLST     ", 20) == 0){
 		if(p->busno == 1 && p->intin == 16 && p->irq == 1){
 			pcmpintr = malloc(sizeof(PCMPintr));
 			if(pcmpintr == nil)
@@ -207,6 +215,8 @@ mkiointr(PCMPintr* p)
 			aintr->intr = pcmpintr;
 		}
 	}
+	if ((unsigned)p->apicno >= nelem(mpapic))
+		panic("mkiointr: apic %d out of range", p->apicno);
 	aintr->apic = &mpapic[p->apicno];
 	aintr->next = bus->aintr;
 	bus->aintr = aintr;
@@ -320,6 +330,8 @@ mklintr(PCMPintr* p)
 		}
 	}
 	else{
+		if ((unsigned)p->apicno >= nelem(mpapic))
+			panic("mklintr: ioapic %d out of range", p->apicno);
 		apic = &mpapic[p->apicno];
 		if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR)
 			apic->lintr[intin] = v;
@@ -486,21 +498,41 @@ mpstartap(Apic* apic)
 	nvramwrite(0x0F, 0x00);
 }
 
+static void
+trympacpi(void)
+{
+	if (mpacpifunc == nil) {
+		print("mpinit: scanning acpi madt for extra cpus\n");
+		(*mpacpifunc)();
+	}
+}
+
 void
 mpinit(void)
 {
-	int ncpu;
+	int ncpu, cpuson;
 	char *cp;
 	PCMP *pcmp;
 	uchar *e, *p;
 	Apic *apic, *bpapic;
 	void *va;
 
+	mpdebug = getconf("*debugmp") != nil;
 	i8259init();
 	syncclock();
 
-	if(_mp_ == 0)
+	bpapic = nil;
+	cpuson = 0;
+
+	if(_mp_ == 0) {
+		/*
+		 * We can easily get processor info from ACPI, but
+		 * interrupt routing, etc. would require interpreting AML.
+		 */
+		print("mpinit: no mp table found, assuming uniprocessor\n");
+		archrevert();
 		return;
+	}
 	pcmp = KADDR(_mp_->physaddr);
 
 	/*
@@ -509,9 +541,7 @@ mpinit(void)
 	if((va = vmap(pcmp->lapicbase, 1024)) == nil)
 		return;
 	mppcmp = pcmp;
-	print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va);
-
-	bpapic = nil;
+	print("LAPIC: %#lux %#lux\n", pcmp->lapicbase, (ulong)va);
 
 	/*
 	 * Run through the table saving information needed for starting
@@ -544,6 +574,7 @@ mpinit(void)
 			apic->paddr = pcmp->lapicbase;
 			if(apic->flags & PcmpBP)
 				bpapic = apic;
+			cpuson++;
 		}
 		p += sizeof(PCMPprocessor);
 		continue;
@@ -570,6 +601,14 @@ mpinit(void)
 		continue;
 	}
 
+	dprint("mpinit: mp table describes %d cpus\n", cpuson);
+
+	/* For now, always scan ACPI's MADT for processors that MP missed. */
+	trympacpi();
+
+	if (bpapic == nil)
+		bpapic = bootapic;
+
 	/*
 	 * No bootstrap processor, no need to go further.
 	 */
@@ -648,6 +687,14 @@ mpintrcpu(void)
 	 * to more than one thread in a core, or to use a "noise" core.
 	 * But, as usual, Intel make that an onerous task. 
 	 */
+
+	/*
+	 * temporary workaround for many-core intel (non-amd) systems:
+	 * always use cpu 0.
+	 */
+	if(strncmp(m->cpuidid, "AuthenticAMD", 12) != 0 && conf.nmach > 8)
+		return 0;
+
 	lock(&mpphysidlock);
 	for(;;){
 		i = mpphysid++;
@@ -669,6 +716,7 @@ mpintrenablex(Vctl* v, int tbdf)
 	Apic *apic;
 	Pcidev *pcidev;
 	int bno, dno, hi, irq, lo, n, type, vno;
+	char *typenm;
 
 	/*
 	 * Find the bus.
@@ -678,6 +726,7 @@ mpintrenablex(Vctl* v, int tbdf)
 	dno = BUSDNO(tbdf);
 	if(type == BusISA)
 		bno = mpisabus;
+	vno = -1;
 	for(bus = mpbus; bus != nil; bus = bus->next){
 		if(bus->type != type)
 			continue;
@@ -685,7 +734,9 @@ mpintrenablex(Vctl* v, int tbdf)
 			break;
 	}
 	if(bus == nil){
-		print("ioapicirq: can't find bus type %d\n", type);
+		typenm = type < 0 || type >= nelem(buses)? "": buses[type];
+		panic("mpintrenablex: can't find bus type %d (%s) for "
+			"irq %d %s busno %d", type, typenm, v->irq, v->name, bno);
 		return -1;
 	}
 
@@ -701,7 +752,7 @@ mpintrenablex(Vctl* v, int tbdf)
 			irq = (dno<<2)|(n-1);
 		else
 			irq = -1;
-		//print("pcidev %uX: irq %uX v->irq %uX\n", tbdf, irq, v->irq);
+		//print("pcidev %#uX: irq %#uX v->irq %#uX\n", tbdf, irq, v->irq);
 	}
 	else
 		irq = v->irq;
@@ -742,11 +793,7 @@ mpintrenablex(Vctl* v, int tbdf)
 					v->irq, tbdf, lo, n);
 				return -1;
 			}
-
-			v->isr = lapicisr;
-			v->eoi = lapiceoi;
-
-			return vno;
+			break;
 		}
 
 		/*
@@ -769,6 +816,7 @@ mpintrenablex(Vctl* v, int tbdf)
 				vno, v->irq, tbdf);
 			return -1;
 		}
+
 		hi = mpintrcpu()<<24;
 		lo = mpintrinit(bus, aintr->intr, vno, v->irq);
 		//print("lo 0x%uX: busno %d intr %d vno %d irq %d elcr 0x%uX\n",
@@ -776,7 +824,6 @@ mpintrenablex(Vctl* v, int tbdf)
 		//	v->irq, i8259elcr);
 		if(lo & ApicIMASK)
 			return -1;
-
 		lo |= ApicPHYSICAL;			/* no-op */
 
 		if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC)
@@ -784,14 +831,13 @@ mpintrenablex(Vctl* v, int tbdf)
 		//else
 		//	print("lo not enabled 0x%uX %d\n",
 		//		apic->flags, apic->type);
-
+		break;
+	}
+	if (aintr) {
 		v->isr = lapicisr;
 		v->eoi = lapiceoi;
-
-		return vno;
 	}
-
-	return -1;
+	return vno;
 }
 
 int

+ 287 - 0
sys/src/9/pc/mpacpi.c

@@ -0,0 +1,287 @@
+/*
+ * minimal acpi support for multiprocessors.
+ *
+ * avoids AML but that's only enough to discover
+ * the processors, not the interrupt routing details.
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "mp.h"
+#include "mpacpi.h"
+
+/* 8c says: out of fixed registers */
+#define L64GET(p)	((uvlong)L32GET((p)+4) << 32 | L32GET(p))
+
+enum {
+	/* apic types */
+	Apiclproc,
+	Apicio,
+	Apicintrsrcoverride,
+	Apicnmisrc,
+	Apiclnmi,
+	Apicladdroverride,
+	Apicios,
+	Apicls,
+	Apicintrsrc,
+	Apiclx2,
+	Apiclx2nmi,
+
+	PcmpUsed = 1ul<<31,		/* Apic->flags addition */
+
+	Lapicbase = 0x1b,		/* msr */
+
+	Lapicae	= 1<<11,		/* apic enable in Lapicbase */
+};
+
+#define dprint(...)	if(mpdebug) print(__VA_ARGS__); else USED(mpdebug)
+
+/* from mp.c */
+int	mpdebug;
+int	mpmachno;
+Apic	mpapic[MaxAPICNO+1];
+int	machno2apicno[MaxAPICNO+1];	/* inverse map: machno -> APIC ID */
+
+Apic	*bootapic;
+
+static int nprocid;
+
+static uvlong
+l64get(uchar *p)
+{
+	return L64GET(p);
+}
+
+int
+apicset(Apic *apic, int type, int apicno, int f)
+{
+	if(apicno > MaxAPICNO)
+		return -1;
+	apic->type = type;
+	apic->apicno = apicno;
+	apic->flags = f | PcmpEN | PcmpUsed;
+	return 0;
+}
+
+int
+mpnewproc(Apic *apic, int apicno, int f)
+{
+	if(apic->flags & PcmpUsed) {
+		print("mpnewproc: apic already enabled\n");
+		return -1;
+	}
+	if (apicset(apic, PcmpPROCESSOR, apicno, f) < 0)
+		return -1;
+	apic->lintr[1] = apic->lintr[0] = ApicIMASK;
+	/* botch! just enumerate */
+	if(apic->flags & PcmpBP)
+		apic->machno = 0;
+	else
+		apic->machno = ++mpmachno;
+	machno2apicno[apic->machno] = apicno;
+	return 0;
+}
+
+static int
+mpacpiproc(uchar *p, ulong laddr)
+{
+	int id, f;
+	ulong *vladdr;
+	vlong base;
+	char *already;
+	Apic *apic;
+
+	/* p bytes: type (0), len (8), cpuid, cpu_lapic id, flags[4] */
+	id = p[3];
+	/* cpu unusable flag or id out of range? */
+	if((L32GET(p+4) & 1) == 0 || id > MaxAPICNO)
+		return -1;
+
+	vladdr = nil;
+	already = "";
+	f = 0;
+	apic = &mpapic[id];
+	apic->paddr = laddr;
+	if (nprocid++ == 0) {
+		f = PcmpBP;
+		vladdr = vmap(apic->paddr, 1024);
+		if(apic->addr == nil){
+			print("proc apic %d: failed to map %#p\n", id,
+				apic->paddr);
+			already = "(fail)";
+		}
+		bootapic = apic;
+	}
+	apic->addr = vladdr;
+
+	if(apic->flags & PcmpUsed)
+		already = "(on)";
+	else
+		mpnewproc(apic, id, f);
+
+	if (0)
+		dprint("\tapic proc %d/%d apicid %d flags%s%s %s\n", nprocid-1,
+			apic->machno, id, f & PcmpBP? " boot": "",
+			f & PcmpEN? " enabled": "", already);
+	USED(already);
+
+	rdmsr(Lapicbase, &base);
+	if (!(base & Lapicae)) {
+		dprint("mpacpiproc: enabling lapic\n");
+		wrmsr(Lapicbase, base | Lapicae);
+	}
+	return 0;
+}
+
+static void
+mpacpicpus(Madt *madt)
+{
+	int i, n;
+	ulong laddr;
+	uchar *p;
+
+	laddr = L32GET(madt->addr);
+	dprint("APIC mpacpicpus lapic addr %#lux, flags %#ux\n",
+		laddr, L32GET(madt->flags));
+
+	n = L32GET(&madt->sdthdr[4]);
+	p = madt->structures;
+	/* byte 0 is assumed to be type, 1 is assumed to be length */
+	for(i = offsetof(Madt, structures[0]); i < n; i += p[1], p += p[1])
+		switch(p[0]){
+		case Apiclproc:
+			mpacpiproc(p, laddr);
+			break;
+		}
+}
+
+/* returns nil iff checksum is bad */
+static void *
+mpacpirsdchecksum(void* addr, int length)
+{
+	uchar *p, sum;
+
+	sum = 0;
+	for(p = addr; length-- > 0; p++)
+		sum += *p;
+	return sum == 0? addr: nil;
+}
+
+static void *
+mpacpirsdscan(uchar* addr, int len, char* signature)
+{
+	int sl;
+	uchar *e, *p;
+
+	sl = strlen(signature);
+	e = addr + len - sl;
+	for(p = addr; p < e; p += 16)
+		if(memcmp(p, signature, sl) == 0)
+			return p;
+	return nil;
+}
+
+static void *
+mpacpirsdsearch(char* signature)
+{
+	uintptr p;
+	uchar *bda;
+	Rsd *rsd;
+
+	/*
+	 * Search for the data structure signature:
+	 * 1) in the first KB of the EBDA;
+	 * 2) in the BIOS ROM between 0xE0000 and 0xFFFFF.
+	 */
+	if(strncmp((char*)KADDR(0xFFFD9), "EISA", 4) == 0){
+		bda = BIOSSEG(0x40);
+		p = bda[0x0F]<<8 | bda[0x0E];
+		if(p != 0 &&
+		    (rsd = mpacpirsdscan(KADDR(p), 1024, signature)) != nil)
+			return rsd;
+	}
+	return mpacpirsdscan(BIOSSEG(0xE000), 0x20000, signature);
+}
+
+/* call func for each acpi table found */
+static void
+mpacpiscan(void (*func)(uchar *))
+{
+	int asize, i, tbllen, sdtlen;
+	uintptr dhpa, sdtpa;
+	uchar *tbl, *sdt;
+	Rsd *rsd;
+
+	dprint("ACPI...");
+	if((rsd = mpacpirsdsearch("RSD PTR ")) == nil) {
+		dprint("none\n");
+		return;
+	}
+
+	dprint("rsd %#p physaddr %#ux length %ud %#llux rev %d oem %.6s\n",
+		rsd, L32GET(rsd->raddr), L32GET(rsd->length),
+		l64get(rsd->xaddr), rsd->revision, (char*)rsd->oemid);
+
+	if(rsd->revision == 2){
+		if(mpacpirsdchecksum(rsd, 36) == nil)
+			return;
+		asize = 8;
+		sdtpa = l64get(rsd->xaddr);
+	} else {
+		if(mpacpirsdchecksum(rsd, 20) == nil)
+			return;
+		asize = 4;
+		sdtpa = L32GET(rsd->raddr);
+	}
+
+	if((sdt = vmap(sdtpa, 8)) == nil)
+		return;
+	if((sdt[0] != 'R' && sdt[0] != 'X') || memcmp(sdt+1, "SDT", 3) != 0){
+		vunmap(sdt, 8);
+		return;
+	}
+	sdtlen = L32GET(sdt + 4);
+	vunmap(sdt, 8);
+
+	if((sdt = vmap(sdtpa, sdtlen)) == nil)
+		return;
+	if(mpacpirsdchecksum(sdt, sdtlen) != nil)
+		for(i = 36; i < sdtlen; i += asize){
+			if(asize == 8)
+				dhpa = l64get(sdt+i);
+			else
+				dhpa = L32GET(sdt+i);
+	
+			if((tbl = vmap(dhpa, 8)) == nil)
+				continue;
+			tbllen = L32GET(tbl + 4);
+			vunmap(tbl, 8);
+	
+			if((tbl = vmap(dhpa, tbllen)) == nil)
+				continue;
+			if(mpacpirsdchecksum(tbl, tbllen) != nil)
+				(*func)(tbl);
+			vunmap(tbl, tbllen);
+		}
+	vunmap(sdt, sdtlen);
+}
+
+static void
+mpacpitbl(uchar *p)
+{
+	/* for now, just activate any idle cpus */
+	if (memcmp(p, "APIC", 4) == 0)
+		mpacpicpus((Madt *)p);
+}
+
+static void
+mpacpi(void)
+{
+	mpdebug = getconf("*debugmp") != nil;
+	mpacpiscan(mpacpitbl);
+}
+
+void	(*mpacpifunc)(void) = mpacpi;

+ 62 - 0
sys/src/9/pc/mpacpi.h

@@ -0,0 +1,62 @@
+/*
+ * ACPI definitions
+ *
+ * A System Descriptor Table starts with a header of 4 bytes of signature
+ * followed by 4 bytes of total table length then 28 bytes of ID information
+ * (including the table checksum).
+ */
+typedef struct Dsdt Dsdt;
+typedef struct Facp Facp;
+typedef struct Hpet Hpet;
+typedef struct Madt Madt;
+typedef struct Mcfg Mcfg;
+typedef struct Mcfgd Mcfgd;
+typedef struct Rsd Rsd;
+
+struct Dsdt {				/* Differentiated System DT */
+	uchar	sdthdr[36];		/* "DSDT" + length[4] + [28] */
+	uchar	db[];			/* Definition Block */
+};
+struct Facp {				/* Fixed ACPI DT */
+	uchar	sdthdr[36];		/* "FACP" + length[4] + [28] */
+	uchar	faddr[4];		/* Firmware Control Address */
+	uchar	dsdt[4];		/* DSDT Address */
+	uchar	pad[200];		/* total table is 244 */
+};
+struct Hpet {				/* High-Precision Event Timer DT */
+	uchar	sdthdr[36];		/* "HPET" + length[4] + [28] */
+	uchar	id[4];			/* Event Timer Block ID */
+	uchar	addr[12];		/* ACPI Format Address */
+	uchar	seqno;			/* Sequence Number */
+	uchar	minticks[2];		/* Minimum Clock Tick */
+	uchar	attr;			/* Page Protection */
+};
+struct Madt {				/* Multiple APIC DT */
+	uchar	sdthdr[36];		/* "MADT" + length[4] + [28] */
+	uchar	addr[4];		/* Local APIC Address */
+	uchar	flags[4];
+	uchar	structures[];
+};
+typedef struct Mcfg {			/* PCI Memory Mapped Config */
+	uchar	sdthdr[36];		/* "MCFG" + length[4] + [28] */
+	uchar	pad[8];			/* reserved */
+	Mcfgd	mcfgd[];		/* descriptors */
+} Mcfg;
+struct Mcfgd {				/* MCFG Descriptor */
+	uchar	addr[8];		/* base address */
+	uchar	segno[2];		/* segment group number */
+	uchar	sbno;			/* start bus number */
+	uchar	ebno;			/* end bus number */
+	uchar	pad[4];			/* reserved */
+};
+struct Rsd {				/* Root System Description * */
+	uchar	signature[8];		/* "RSD PTR " */
+	uchar	rchecksum;
+	uchar	oemid[6];
+	uchar	revision;
+	uchar	raddr[4];		/* RSDT */
+	uchar	length[4];
+	uchar	xaddr[8];		/* XSDT */
+	uchar	xchecksum;		/* XSDT */
+	uchar	pad[3];			/* reserved */
+};

+ 1 - 1
sys/src/9/pc/pccpu

@@ -61,7 +61,7 @@ link
 	usbehci		usbehcipc
 
 misc
-	archmp		mp apic
+	archmp		mp apic mpacpi
 	mtrr
 
 	uarti8250

+ 1 - 1
sys/src/9/pc/sdiahci.c

@@ -1409,7 +1409,7 @@ iainterrupt(Ureg*, void *a)
 	cause = c->hba->isr;
 	if (cause == 0) {
 		isctlrjabbering(c, cause);
-		iprint("sdiahci: interrupt for no drive\n");
+		// iprint("sdiahci: interrupt for no drive\n");
 		iunlock(c);
 		return;
 	}

+ 1 - 1
sys/src/cmd/nntpfs.c

@@ -213,7 +213,7 @@ nntpconnect(Netbuf *n)
 	n->currentgroup = nil;
 	close(n->fd);
 	if((n->fd = dial(n->addr, nil, nil, nil)) < 0){	
-		snprint(n->response, sizeof n->response, "dial: %r");
+		snprint(n->response, sizeof n->response, "dial %s: %r", n->addr);
 		return -1;
 	}
 	Binit(&n->br, n->fd, OREAD);