experimental acpi support for apic irq routing

front
cinap_lenrek 2012-06-17 23:12:19 +02:00
parent 9cb66f310b
commit a47521a3ed
13 changed files with 2876 additions and 644 deletions

36
sys/include/aml.h Normal file
View File

@ -0,0 +1,36 @@
#pragma lib "libaml.a"
#pragma src "/sys/src/libaml"
/*
* b uchar* buffer amllen() returns number of bytes
* s char* string amllen() is strlen()
* i uvlong* integer
* p void** package amllen() is # of elements
* r void* region
* f void* field
* u void* bufferfield
* N void* name
* R void* reference
*/
int amltag(void *);
void* amlval(void *);
uvlong amlint(void *);
int amllen(void *);
void amlinit(void);
void amlexit(void);
int amlload(uchar *data, int len);
void* amlwalk(void *dot, char *name);
int amleval(void *dot, char *fmt, ...);
void amlenum(void *dot, char *seg, int (*proc)(void *, void *), void *arg);
void* amlroot;
int amldebug;
#pragma varargck type "V" void*
#pragma varargck type "N" void*
/* to be provided by operating system */
extern void* amlalloc(int);
extern void amlfree(void*);

View File

@ -1,219 +0,0 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
typedef struct Rsd Rsd;
typedef struct Tbl Tbl;
struct Rsd {
uchar sig[8];
uchar csum;
uchar oemid[6];
uchar rev;
uchar raddr[4];
uchar len[4];
uchar xaddr[8];
uchar xcsum;
uchar reserved[3];
};
struct Tbl {
uchar sig[4];
uchar len[4];
uchar rev;
uchar csum;
uchar oemid[6];
uchar oemtid[8];
uchar oemrev[4];
uchar cid[4];
uchar crev[4];
uchar data[];
};
static int ntbltab;
static Tbl *tbltab[64];
static ushort
get16(uchar *p){
return p[1]<<8 | p[0];
}
static uint
get32(uchar *p){
return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
}
static uvlong
get64(uchar *p){
uvlong u;
u = get32(p+4);
return u<<32 | get32(p);
}
static int
checksum(void *v, int n)
{
uchar *p, s;
s = 0;
p = v;
while(n-- > 0)
s += *p++;
return s;
}
static void*
rsdscan(uchar* addr, int len, char* sig)
{
int sl;
uchar *e, *p;
e = addr+len;
sl = strlen(sig);
for(p = addr; p+sl < e; p += 16){
if(memcmp(p, sig, sl))
continue;
return p;
}
return nil;
}
static void*
rsdsearch(char* sig)
{
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 = KADDR(0x400);
if((p = (bda[0x0F]<<8)|bda[0x0E]))
if(rsd = rsdscan(KADDR(p), 1024, sig))
return rsd;
}
return rsdscan(KADDR(0xE0000), 0x20000, sig);
}
static void
maptable(uvlong xpa)
{
uchar *p, *e;
Tbl *t, *a;
uintptr pa;
u32int l;
int i;
pa = xpa;
if((uvlong)pa != xpa || pa == 0)
return;
if(ntbltab >= nelem(tbltab))
return;
if((t = vmap(pa, 8)) == nil)
return;
l = get32(t->len);
if(l < sizeof(Tbl) || t->sig[0] == 0){
vunmap(t, 8);
return;
}
for(i=0; i<ntbltab; i++){
if(memcmp(tbltab[i]->sig, t->sig, sizeof(t->sig)) == 0)
break;
}
vunmap(t, 8);
if(i < ntbltab)
return;
if((a = malloc(l)) == nil)
return;
if((t = vmap(pa, l)) == nil){
free(a);
return;
}
if(checksum(t, l)){
vunmap(t, l);
free(a);
return;
}
memmove(a, t, l);
vunmap(t, l);
tbltab[ntbltab++] = t = a;
if(0) print("acpi: %llux %.4s %d\n", xpa, (char*)t->sig, l);
p = (uchar*)t;
e = p + l;
if(memcmp("RSDT", t->sig, 4) == 0){
for(p = t->data; p+3 < e; p += 4)
maptable(get32(p));
return;
}
if(memcmp("XSDT", t->sig, 4) == 0){
for(p = t->data; p+7 < e; p += 8)
maptable(get64(p));
return;
}
if(memcmp("FACP", t->sig, 4) == 0){
if(l < 44)
return;
maptable(get32(p + 40));
if(l < 148)
return;
maptable(get64(p + 140));
return;
}
}
static long
readtbls(Chan*, void *v, long n, vlong o)
{
int i, l, m;
uchar *p;
Tbl *t;
p = v;
for(i=0; n > 0 && i < ntbltab; i++){
t = tbltab[i];
l = get32(t->len);
if(o >= l){
o -= l;
continue;
}
m = l - o;
if(m > n)
m = n;
memmove(p, (uchar*)t + o, m);
p += m;
n -= m;
o = 0;
}
return p - (uchar*)v;
}
void
acpilink(void)
{
Rsd *r;
/*
* this is a debug driver to dump the acpi tables.
* do nothing unless *acpi gets explicitly enabled.
*/
if(getconf("*acpi") == nil)
return;
if((r = rsdsearch("RSD PTR ")) == nil)
return;
if(checksum(r, 20) == 0)
maptable(get32(r->raddr));
if(r->rev >= 2)
if(checksum(r, 36) == 0)
maptable(get64(r->xaddr));
addarchfile("acpitbls", 0444, readtbls, nil);
}

525
sys/src/9/pc/archacpi.c Normal file
View File

@ -0,0 +1,525 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "mp.h"
#include <aml.h>
typedef struct Rsd Rsd;
typedef struct Tbl Tbl;
struct Rsd {
uchar sig[8];
uchar csum;
uchar oemid[6];
uchar rev;
uchar raddr[4];
uchar len[4];
uchar xaddr[8];
uchar xcsum;
uchar reserved[3];
};
struct Tbl {
uchar sig[4];
uchar len[4];
uchar rev;
uchar csum;
uchar oemid[6];
uchar oemtid[8];
uchar oemrev[4];
uchar cid[4];
uchar crev[4];
uchar data[];
};
static Rsd *rsd;
static int ntbltab;
static Tbl *tbltab[64];
void*
amlalloc(int n){
void *p;
if((p = malloc(n)) == nil)
panic("amlalloc: no memory");
memset(p, 0, n);
return p;
}
void
amlfree(void *p){
free(p);
}
static ushort
get16(uchar *p){
return p[1]<<8 | p[0];
}
static uint
get32(uchar *p){
return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
}
static uvlong
get64(uchar *p){
uvlong u;
u = get32(p+4);
return u<<32 | get32(p);
}
static uint
tbldlen(Tbl *t){
return get32(t->len) - sizeof(Tbl);
}
static int
checksum(void *v, int n)
{
uchar *p, s;
s = 0;
p = v;
while(n-- > 0)
s += *p++;
return s;
}
static void*
rsdscan(uchar* addr, int len, char* sig)
{
int sl;
uchar *e, *p;
e = addr+len;
sl = strlen(sig);
for(p = addr; p+sl < e; p += 16){
if(memcmp(p, sig, sl))
continue;
return p;
}
return nil;
}
static void*
rsdsearch(char* sig)
{
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 = KADDR(0x400);
if((p = (bda[0x0F]<<8)|bda[0x0E]))
if(rsd = rsdscan(KADDR(p), 1024, sig))
return rsd;
}
return rsdscan(KADDR(0xE0000), 0x20000, sig);
}
static Tbl*
findtable(void *sig){
int i;
for(i=0; i<ntbltab; i++)
if(memcmp(tbltab[i]->sig, sig, 4) == 0)
return tbltab[i];
return nil;
}
static void
maptable(uvlong xpa)
{
uchar *p, *e;
uintptr pa;
u32int l;
Tbl *t;
pa = xpa;
if((uvlong)pa != xpa || pa == 0)
return;
if(ntbltab >= nelem(tbltab))
return;
if((t = vmap(pa, 8)) == nil)
return;
l = get32(t->len);
if(l < sizeof(Tbl) || findtable(t->sig)){
vunmap(t, 8);
return;
}
vunmap(t, 8);
if((t = vmap(pa, l)) == nil)
return;
if(checksum(t, l)){
vunmap(t, l);
return;
}
tbltab[ntbltab++] = t;
p = (uchar*)t;
e = p + l;
if(memcmp("RSDT", t->sig, 4) == 0){
for(p = t->data; p+3 < e; p += 4)
maptable(get32(p));
return;
}
if(memcmp("XSDT", t->sig, 4) == 0){
for(p = t->data; p+7 < e; p += 8)
maptable(get64(p));
return;
}
if(memcmp("FACP", t->sig, 4) == 0){
if(l < 44)
return;
maptable(get32(p + 40));
if(l < 148)
return;
maptable(get64(p + 140));
return;
}
}
static void
maptables(void)
{
if(rsd == nil || ntbltab > 0)
return;
if(!checksum(rsd, 20))
maptable(get32(rsd->raddr));
if(rsd->rev >= 2)
if(!checksum(rsd, 36))
maptable(get64(rsd->xaddr));
}
static Apic*
findapic(int gsi, int *pintin)
{
Apic *a;
int i;
for(i=0; i<=MaxAPICNO; i++){
if((a = mpioapic[i]) == nil)
continue;
if((a->flags & PcmpEN) == 0)
continue;
if(gsi >= a->gsibase && gsi < a->gsibase+a->mre){
if(pintin)
*pintin = gsi - a->gsibase;
return a;
}
}
print("findapic: no ioapic found for gsi %d\n", gsi);
return nil;
}
static void
addirq(int gsi, int type, int busno, int irq, int flags)
{
Apic *a;
Bus *bus;
Aintr *ai;
PCMPintr *pi;
int intin;
if((a = findapic(gsi, &intin)) == nil)
return;
for(bus = mpbus; bus; bus = bus->next)
if(bus->type == type && bus->busno == busno)
goto Foundbus;
if((bus = xalloc(sizeof(Bus))) == nil)
panic("addirq: no memory for Bus");
bus->busno = busno;
bus->type = type;
if(type == BusISA){
bus->po = PcmpHIGH;
bus->el = PcmpEDGE;
if(mpisabus == -1)
mpisabus = busno;
} else {
bus->po = PcmpLOW;
bus->el = PcmpLEVEL;
}
if(mpbus)
mpbuslast->next = bus;
else
mpbus = bus;
mpbuslast = bus;
Foundbus:
for(ai = bus->aintr; ai; ai = ai->next)
if(ai->intr->irq == irq)
return;
if((pi = xalloc(sizeof(PCMPintr))) == nil)
panic("addirq: no memory for PCMPintr");
pi->type = PcmpIOINTR;
pi->intr = PcmpINT;
pi->flags = flags & (PcmpPOMASK|PcmpELMASK);
pi->busno = busno;
pi->irq = irq;
pi->apicno = a->apicno;
pi->intin = intin;
if((ai = xalloc(sizeof(Aintr))) == nil)
panic("addirq: no memory for Aintr");
ai->intr = pi;
ai->apic = a;
ai->next = bus->aintr;
bus->aintr = ai;
}
static int
pcibusno(void *dot)
{
int bno, adr, tbdf;
Pcidev *pdev;
void *p, *x;
p = nil;
if(x = amlwalk(dot, "^_BBN")){
if(amleval(x, "", &p) < 0)
return -1;
return amlint(p);
}
if((x = amlwalk(dot, "^_ADR")) == nil)
return -1;
if(amleval(x, "", &p) < 0)
return -1;
adr = amlint(p);
x = amlwalk(dot, "^");
if(x == nil || x == dot)
return -1;
if((bno = pcibusno(x)) < 0)
return -1;
tbdf = MKBUS(BusPCI, bno, adr>>16, adr&0xFFFF);
pdev = pcimatchtbdf(tbdf);
if(pdev == nil || pdev->bridge == nil){
print("pcibusno: bridge tbdf %luX not found\n", (ulong)tbdf);
return -1;
}
return BUSBNO(pdev->bridge->tbdf);
}
static int
enumprt(void *dot, void *)
{
void *p, **a, **b;
int bno, dno, pin;
int n, i;
bno = pcibusno(dot);
if(bno < 0){
print("enumprt: cannot get pci bus number for %V\n", dot);
return 1;
}
/* evalulate _PRT method */
p = nil;
if(amleval(dot, "", &p) < 0)
return 1;
if(amltag(p) != 'p')
return 1;
n = amllen(p);
a = amlval(p);
for(i=0; i<n; i++){
if(amltag(a[i]) != 'p')
continue;
if(amllen(a[i]) != 4)
continue;
b = amlval(a[i]);
dno = amlint(b[0])>>16;
pin = amlint(b[1]);
if(amltag(b[2]) == 'N' || amlint(b[2])){
print("enumprt: interrupt link not handled %V\n", b[2]);
continue;
}
addirq(amlint(b[3]), BusPCI, bno, (dno<<2)|pin, 0);
}
return 1;
}
static void
acpiinit(void)
{
Tbl *t;
Apic *a;
void *va;
uchar *p, *e;
ulong lapicbase;
int machno, i, c;
maptables();
amlinit();
if(t = findtable("DSDT"))
amlload(t->data, tbldlen(t));
if(t = findtable("SSDT"))
amlload(t->data, tbldlen(t));
/* set APIC mode */
amleval(amlwalk(amlroot, "_PIC"), "i", 1, nil);
if((t = findtable("APIC")) == nil)
panic("acpiinit: no APIC table found");
p = t->data;
e = p + tbldlen(t);
lapicbase = get32(p); p += 8;
va = vmap(lapicbase, 1024);
print("LAPIC: %.8lux %.8lux\n", lapicbase, (ulong)va);
if(va == nil)
panic("acpiinit: cannot map lapic %.8lux", lapicbase);
machno = 0;
for(; p < e; p += c){
c = p[1];
if(c < 2 || (p+c) > e)
break;
switch(*p){
case 0x00: /* Processor Local APIC */
if(p[3] > MaxAPICNO)
break;
if((a = xalloc(sizeof(Apic))) == nil)
panic("acpiinit: no memory for Apic");
a->type = PcmpPROCESSOR;
a->apicno = p[3];
a->paddr = lapicbase;
a->addr = va;
a->lintr[0] = ApicIMASK;
a->lintr[1] = ApicIMASK;
a->flags = (p[4] & PcmpEN);
if(a->flags & PcmpEN){
a->machno = machno++;
/*
* how do we know if this is the
* bootstrap processors apic?
*/
if(a->machno == 0)
a->flags |= PcmpBP;
}
mpapic[a->apicno] = a;
break;
case 0x01: /* I/O APIC */
if(p[2] > MaxAPICNO)
break;
if((a = xalloc(sizeof(Apic))) == nil)
panic("acpiinit: no memory for io Apic");
a->type = PcmpIOAPIC;
a->apicno = p[2];
a->paddr = get32(p+4);
if((a->addr = vmap(a->paddr, 1024)) == nil)
panic("acpiinit: cannot map ioapic %.8lux", a->paddr);
a->gsibase = get32(p+8);
a->flags = PcmpEN;
mpioapic[a->apicno] = a;
ioapicinit(a, a->apicno);
break;
case 0x02: /* Interrupt Source Override */
addirq(get32(p+4), BusISA, 0, p[3], get16(p+8));
break;
case 0x03: /* NMI Source */
case 0x04: /* Local APIC NMI */
case 0x05: /* Local APIC Address Override */
case 0x06: /* I/O SAPIC */
case 0x07: /* Local SAPIC */
case 0x08: /* Platform Interrupt Sources */
case 0x09: /* Processor Local x2APIC */
case 0x0A: /* x2APIC NMI */
case 0x0B: /* GIC */
case 0x0C: /* GICD */
break;
}
}
/* look for PCI interrupt mappings */
amlenum(amlroot, "_PRT", enumprt, nil);
/* add identity mapped legacy isa interrupts */
for(i=0; i<16; i++)
addirq(i, BusISA, 0, i, 0);
/* free the AML interpreter */
amlexit();
/*
* Ininitalize local APIC and start application processors.
*/
mpinit();
}
static int identify(void);
PCArch archacpi = {
.id= "ACPI",
.ident= identify,
.reset= mpshutdown,
.intrinit= acpiinit,
.intrenable= mpintrenable,
.intron= lapicintron,
.introff= lapicintroff,
.fastclock= i8253read,
.timerset= lapictimerset,
};
static long
readtbls(Chan*, void *v, long n, vlong o)
{
int i, l, m;
uchar *p;
Tbl *t;
maptables();
p = v;
for(i=0; n > 0 && i < ntbltab; i++){
t = tbltab[i];
l = get32(t->len);
if(o >= l){
o -= l;
continue;
}
m = l - o;
if(m > n)
m = n;
memmove(p, (uchar*)t + o, m);
p += m;
n -= m;
o = 0;
}
return p - (uchar*)v;
}
static int
identify(void)
{
char *cp;
if((cp = getconf("*acpi")) == nil)
return 1;
if((rsd = rsdsearch("RSD PTR ")) == nil)
return 1;
addarchfile("acpitbls", 0444, readtbls, nil);
if(strcmp(cp, "0") == 0)
return 1;
if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
return 1;
if(cpuserver && m->havetsc)
archacpi.fastclock = tscticks;
return 0;
}

View File

@ -7,7 +7,352 @@
#include "mp.h"
_MP_ *_mp_;
static PCMP *pcmp;
static char* buses[] = {
"CBUSI ",
"CBUSII",
"EISA ",
"FUTURE",
"INTERN",
"ISA ",
"MBI ",
"MBII ",
"MCA ",
"MPI ",
"MPSA ",
"NUBUS ",
"PCI ",
"PCMCIA",
"TC ",
"VL ",
"VME ",
"XPRESS",
0,
};
static Bus*
mpgetbus(int busno)
{
Bus *bus;
for(bus = mpbus; bus; bus = bus->next)
if(bus->busno == busno)
return bus;
print("mpgetbus: can't find bus %d\n", busno);
return 0;
}
static Apic*
mkprocessor(PCMPprocessor* p)
{
static int machno = 1;
int apicno;
Apic *apic;
apicno = p->apicno;
if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpapic[apicno] != nil)
return 0;
if((apic = xalloc(sizeof(Apic))) == nil)
panic("mkprocessor: no memory for Apic");
apic->type = PcmpPROCESSOR;
apic->apicno = apicno;
apic->flags = p->flags;
apic->lintr[0] = ApicIMASK;
apic->lintr[1] = ApicIMASK;
if(p->flags & PcmpBP)
apic->machno = 0;
else
apic->machno = machno++;
mpapic[apicno] = apic;
return apic;
}
static Bus*
mkbus(PCMPbus* p)
{
Bus *bus;
int i;
for(i = 0; buses[i]; i++)
if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
break;
if(buses[i] == 0)
return 0;
if((bus = xalloc(sizeof(Bus))) == nil)
panic("mkbus: no memory for Bus");
if(mpbus)
mpbuslast->next = bus;
else
mpbus = bus;
mpbuslast = bus;
bus->type = i;
bus->busno = p->busno;
if(bus->type == BusEISA){
bus->po = PcmpLOW;
bus->el = PcmpLEVEL;
if(mpeisabus != -1)
print("mkbus: more than one EISA bus\n");
mpeisabus = bus->busno;
}
else if(bus->type == BusPCI){
bus->po = PcmpLOW;
bus->el = PcmpLEVEL;
}
else if(bus->type == BusISA){
bus->po = PcmpHIGH;
bus->el = PcmpEDGE;
if(mpisabus != -1)
print("mkbus: more than one ISA bus\n");
mpisabus = bus->busno;
}
else{
bus->po = PcmpHIGH;
bus->el = PcmpEDGE;
}
return bus;
}
static Apic*
mkioapic(PCMPioapic* p)
{
void *va;
int apicno;
Apic *apic;
apicno = p->apicno;
if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpioapic[apicno] != nil)
return 0;
/*
* Map the I/O APIC.
*/
if((va = vmap(p->addr, 1024)) == nil)
return 0;
if((apic = xalloc(sizeof(Apic))) == nil)
panic("mkioapic: no memory for Apic");
apic->type = PcmpIOAPIC;
apic->apicno = apicno;
apic->addr = va;
apic->paddr = p->addr;
apic->flags = p->flags;
mpioapic[apicno] = apic;
return apic;
}
static Aintr*
mkiointr(PCMPintr* p)
{
Bus *bus;
Aintr *aintr;
PCMPintr* pcmpintr;
/*
* According to the MultiProcessor Specification, a destination
* I/O APIC of 0xFF means the signal is routed to all I/O APICs.
* It's unclear how that can possibly be correct so treat it as
* an error for now.
*/
if(p->apicno > MaxAPICNO || mpioapic[p->apicno] == nil)
return 0;
if((bus = mpgetbus(p->busno)) == 0)
return 0;
if((aintr = xalloc(sizeof(Aintr))) == nil)
panic("mkiointr: no memory for Aintr");
aintr->intr = p;
if(0)
print("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);
/*
* Hack for Intel SR1520ML motherboard, which BIOS describes
* the i82575 dual ethernet controllers incorrectly.
*/
if(memcmp(pcmp->product, "INTEL X38MLST ", 20) == 0){
if(p->busno == 1 && p->intin == 16 && p->irq == 1){
if((pcmpintr = xalloc(sizeof(PCMPintr))) == nil)
panic("iointr: no memory for PCMPintr");
memmove(pcmpintr, p, sizeof(PCMPintr));
print("mkiointr: %20.20s bus %d intin %d irq %d\n",
(char*)pcmp->product,
pcmpintr->busno, pcmpintr->intin,
pcmpintr->irq);
pcmpintr->intin = 17;
aintr->intr = pcmpintr;
}
}
aintr->apic = mpioapic[p->apicno];
aintr->next = bus->aintr;
bus->aintr = aintr;
return aintr;
}
static int
mklintr(PCMPintr* p)
{
Apic *apic;
Bus *bus;
int i, intin, v;
/*
* The offsets of vectors for LINT[01] are known to be
* 0 and 1 from the local APIC vector space at VectorLAPIC.
*/
if((bus = mpgetbus(p->busno)) == 0)
return 0;
intin = p->intin;
/*
* Pentium Pros have problems if LINT[01] are set to ExtINT
* so just bag it, SMP mode shouldn't need ExtINT anyway.
*/
if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
v = ApicIMASK;
else
v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
if(p->apicno == 0xFF){
for(i=0; i<=MaxAPICNO; i++){
if((apic = mpapic[i]) == nil)
continue;
if(apic->flags & PcmpEN)
apic->lintr[intin] = v;
}
}
else{
if(apic = mpapic[p->apicno])
if(apic->flags & PcmpEN)
apic->lintr[intin] = v;
}
return v;
}
static void
dumpmp(uchar *p, uchar *e)
{
int i;
for(i = 0; p < e; p++) {
if((i % 16) == 0) print("*mp%d=", i/16);
print("%.2x ", *p);
if((++i % 16) == 0) print("\n");
}
if((i % 16) != 0) print("\n");
}
static void
mpoverride(uchar** newp, uchar** e)
{
int size, i, j;
char buf[20];
uchar* p;
char* s;
size = atoi(getconf("*mp"));
if(size == 0) panic("mpoverride: invalid size in *mp");
*newp = p = xalloc(size);
if(p == nil) panic("mpoverride: can't allocate memory");
*e = p + size;
for(i = 0; ; i++){
snprint(buf, sizeof buf, "*mp%d", i);
s = getconf(buf);
if(s == nil) break;
while(*s){
j = strtol(s, &s, 16);
if(*s && *s != ' ' || j < 0 || j > 0xff) panic("mpoverride: invalid entry in %s", buf);
if(p >= *e) panic("mpoverride: overflow in %s", buf);
*p++ = j;
}
}
if(p != *e) panic("mpoverride: size doesn't match");
}
static void
pcmpinit(void)
{
uchar *p, *e;
Apic *apic;
void *va;
/*
* Map the local APIC.
*/
va = vmap(pcmp->lapicbase, 1024);
print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va);
if(va == nil)
panic("pcmpinit: cannot map lapic %.8lux", pcmp->lapicbase);
p = ((uchar*)pcmp)+sizeof(PCMP);
e = ((uchar*)pcmp)+pcmp->length;
if(getconf("*dumpmp") != nil)
dumpmp(p, e);
if(getconf("*mp") != nil)
mpoverride(&p, &e);
/*
* Run through the table saving information needed for starting
* application processors and initialising any I/O APICs. The table
* is guaranteed to be in order such that only one pass is necessary.
*/
while(p < e) switch(*p){
default:
print("pcmpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",
*p, e-p);
while(p < e){
print("%uX ", *p);
p++;
}
break;
case PcmpPROCESSOR:
if(apic = mkprocessor((PCMPprocessor*)p)){
apic->addr = va;
apic->paddr = pcmp->lapicbase;
}
p += sizeof(PCMPprocessor);
continue;
case PcmpBUS:
mkbus((PCMPbus*)p);
p += sizeof(PCMPbus);
continue;
case PcmpIOAPIC:
if(apic = mkioapic((PCMPioapic*)p))
ioapicinit(apic, apic->apicno);
p += sizeof(PCMPioapic);
continue;
case PcmpIOINTR:
mkiointr((PCMPintr*)p);
p += sizeof(PCMPintr);
continue;
case PcmpLINTR:
mklintr((PCMPintr*)p);
p += sizeof(PCMPintr);
continue;
}
/*
* Ininitalize local APIC and start application processors.
*/
mpinit();
}
static _MP_*
mpscan(uchar *addr, int len)
@ -60,7 +405,7 @@ PCArch archmp = {
.id= "_MP_",
.ident= identify,
.reset= mpshutdown,
.intrinit= mpinit,
.intrinit= pcmpinit,
.intrenable= mpintrenable,
.intron= lapicintron,
.introff= lapicintroff,
@ -72,7 +417,7 @@ static int
identify(void)
{
char *cp;
PCMP *pcmp;
_MP_ *_mp_;
uchar *p, sum;
ulong length;
@ -90,50 +435,23 @@ identify(void)
return 1;
pcmp = KADDR(_mp_->physaddr);
if(memcmp(pcmp, "PCMP", 4))
if(memcmp(pcmp, "PCMP", 4)){
pcmp = nil;
return 1;
}
length = pcmp->length;
sum = 0;
for(p = (uchar*)pcmp; length; length--)
sum += *p++;
if(sum || (pcmp->version != 1 && pcmp->version != 4))
if(sum || (pcmp->version != 1 && pcmp->version != 4)){
pcmp = nil;
return 1;
}
if(cpuserver && m->havetsc)
archmp.fastclock = tscticks;
return 0;
}
Lock mpsynclock;
void
syncclock(void)
{
uvlong x;
if(arch->fastclock != tscticks)
return;
if(m->machno == 0){
wrmsr(0x10, 0);
m->tscticks = 0;
} else {
x = MACHP(0)->tscticks;
while(x == MACHP(0)->tscticks)
;
wrmsr(0x10, MACHP(0)->tscticks);
cycles(&m->tscticks);
}
}
uvlong
tscticks(uvlong *hz)
{
if(hz != nil)
*hz = m->cpuhz;
cycles(&m->tscticks); /* Uses the rdtsc instruction */
return m->tscticks;
}

View File

@ -271,6 +271,7 @@ struct Pcidev
Pcidev* list;
Pcidev* link; /* next device on this bno */
Pcidev* parent; /* up a bus */
Pcidev* bridge; /* down a bus */
struct {
ulong bar;

View File

@ -68,6 +68,7 @@ LIB=\
/$objtype/lib/libsec.a\
/$objtype/lib/libmp.a\
/$objtype/lib/libfis.a\
/$objtype/lib/libaml.a\
ETHER=`{echo devether.c ether*.c | sed 's/\.c/.'$O'/g'}
VGA=`{echo devvga.c screen.c vga*.c | sed 's/\.c/.'$O'/g'}

View File

@ -9,209 +9,15 @@
#include "mp.h"
#include "apbootstrap.h"
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 *mpioapic[MaxAPICNO+1];
static Apic *mpapic[MaxAPICNO+1];
static int mpmachno = 1;
static Lock mpphysidlock;
static int mpphysid;
/* filled in by pcmpinit or acpiinit */
Bus* mpbus;
Bus* mpbuslast;
int mpisabus = -1;
int mpeisabus = -1;
Apic *mpioapic[MaxAPICNO+1];
Apic *mpapic[MaxAPICNO+1];
static char* buses[] = {
"CBUSI ",
"CBUSII",
"EISA ",
"FUTURE",
"INTERN",
"ISA ",
"MBI ",
"MBII ",
"MCA ",
"MPI ",
"MPSA ",
"NUBUS ",
"PCI ",
"PCMCIA",
"TC ",
"VL ",
"VME ",
"XPRESS",
0,
};
static Apic*
mkprocessor(PCMPprocessor* p)
{
int apicno;
Apic *apic;
apicno = p->apicno;
if(!(p->flags & PcmpEN) || apicno >= nelem(mpapic) || mpapic[apicno] != nil)
return 0;
if((apic = xalloc(sizeof(Apic))) == nil)
panic("mkprocessor: no memory for Apic");
apic->type = PcmpPROCESSOR;
apic->apicno = apicno;
apic->flags = p->flags;
apic->lintr[0] = ApicIMASK;
apic->lintr[1] = ApicIMASK;
if(p->flags & PcmpBP)
apic->machno = 0;
else
apic->machno = mpmachno++;
mpapic[apicno] = apic;
return apic;
}
static Bus*
mkbus(PCMPbus* p)
{
Bus *bus;
int i;
for(i = 0; buses[i]; i++){
if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
break;
}
if(buses[i] == 0)
return 0;
if((bus = xalloc(sizeof(Bus))) == nil)
panic("mkbus: no memory for Bus");
if(mpbus)
mpbuslast->next = bus;
else
mpbus = bus;
mpbuslast = bus;
bus->type = i;
bus->busno = p->busno;
if(bus->type == BusEISA){
bus->po = PcmpLOW;
bus->el = PcmpLEVEL;
if(mpeisabus != -1)
print("mkbus: more than one EISA bus\n");
mpeisabus = bus->busno;
}
else if(bus->type == BusPCI){
bus->po = PcmpLOW;
bus->el = PcmpLEVEL;
}
else if(bus->type == BusISA){
bus->po = PcmpHIGH;
bus->el = PcmpEDGE;
if(mpisabus != -1)
print("mkbus: more than one ISA bus\n");
mpisabus = bus->busno;
}
else{
bus->po = PcmpHIGH;
bus->el = PcmpEDGE;
}
return bus;
}
static Bus*
mpgetbus(int busno)
{
Bus *bus;
for(bus = mpbus; bus; bus = bus->next){
if(bus->busno == busno)
return bus;
}
print("mpgetbus: can't find bus %d\n", busno);
return 0;
}
static Apic*
mkioapic(PCMPioapic* p)
{
void *va;
int apicno;
Apic *apic;
apicno = p->apicno;
if(!(p->flags & PcmpEN) || apicno >= nelem(mpioapic) || mpioapic[apicno] != nil)
return 0;
/*
* Map the I/O APIC.
*/
if((va = vmap(p->addr, 1024)) == nil)
return 0;
if((apic = xalloc(sizeof(Apic))) == nil)
panic("mkioapic: no memory for Apic");
apic->type = PcmpIOAPIC;
apic->apicno = apicno;
apic->addr = va;
apic->paddr = p->addr;
apic->flags = p->flags;
mpioapic[apicno] = apic;
return apic;
}
static Aintr*
mkiointr(PCMPintr* p)
{
Bus *bus;
Aintr *aintr;
PCMPintr* pcmpintr;
/*
* According to the MultiProcessor Specification, a destination
* I/O APIC of 0xFF means the signal is routed to all I/O APICs.
* It's unclear how that can possibly be correct so treat it as
* an error for now.
*/
if(p->apicno >= nelem(mpioapic) || mpioapic[p->apicno] == nil)
return 0;
if((bus = mpgetbus(p->busno)) == 0)
return 0;
if((aintr = xalloc(sizeof(Aintr))) == nil)
panic("iointr: no memory for Aintr");
aintr->intr = p;
if(0)
print("iointr: 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);
/*
* Hack for Intel SR1520ML motherboard, which BIOS describes
* the i82575 dual ethernet controllers incorrectly.
*/
if(memcmp(mppcmp->product, "INTEL X38MLST ", 20) == 0){
if(p->busno == 1 && p->intin == 16 && p->irq == 1){
if((pcmpintr = xalloc(sizeof(PCMPintr))) == nil)
panic("iointr: no memory for PCMPintr");
memmove(pcmpintr, p, sizeof(PCMPintr));
print("mkiointr: %20.20s bus %d intin %d irq %d\n",
(char*)mppcmp->product,
pcmpintr->busno, pcmpintr->intin,
pcmpintr->irq);
pcmpintr->intin = 17;
aintr->intr = pcmpintr;
}
}
aintr->apic = mpioapic[p->apicno];
aintr->next = bus->aintr;
bus->aintr = aintr;
return aintr;
}
static int
int
mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
{
int el, po, v;
@ -284,47 +90,6 @@ mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
return v;
}
static int
mklintr(PCMPintr* p)
{
Apic *apic;
Bus *bus;
int i, intin, v;
/*
* The offsets of vectors for LINT[01] are known to be
* 0 and 1 from the local APIC vector space at VectorLAPIC.
*/
if((bus = mpgetbus(p->busno)) == 0)
return 0;
intin = p->intin;
/*
* Pentium Pros have problems if LINT[01] are set to ExtINT
* so just bag it, SMP mode shouldn't need ExtINT anyway.
*/
if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
v = ApicIMASK;
else
v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
if(p->apicno == 0xFF){
for(i=0; i<nelem(mpapic); i++){
if((apic = mpapic[i]) == nil)
continue;
if(apic->flags & PcmpEN)
apic->lintr[intin] = v;
}
}
else{
if(apic = mpapic[p->apicno])
if(apic->flags & PcmpEN)
apic->lintr[intin] = v;
}
return v;
}
static void
checkmtrr(void)
{
@ -377,6 +142,36 @@ checkmtrr(void)
}
}
uvlong
tscticks(uvlong *hz)
{
if(hz != nil)
*hz = m->cpuhz;
cycles(&m->tscticks); /* Uses the rdtsc instruction */
return m->tscticks;
}
void
syncclock(void)
{
uvlong x;
if(arch->fastclock != tscticks)
return;
if(m->machno == 0){
wrmsr(0x10, 0);
m->tscticks = 0;
} else {
x = MACHP(0)->tscticks;
while(x == MACHP(0)->tscticks)
;
wrmsr(0x10, MACHP(0)->tscticks);
cycles(&m->tscticks);
}
}
static void
squidboy(Apic* apic)
{
@ -483,141 +278,56 @@ mpstartap(Apic* apic)
nvramwrite(0x0F, 0x00);
}
static void
dumpmp(uchar *p, uchar *e)
{
int i;
for(i = 0; p < e; p++) {
if((i % 16) == 0) print("*mp%d=", i/16);
print("%.2x ", *p);
if((++i % 16) == 0) print("\n");
}
if((i % 16) != 0) print("\n");
}
static void
mpoverride(uchar** newp, uchar** e)
{
int size, i, j;
char buf[20];
uchar* p;
char* s;
size = atoi(getconf("*mp"));
if(size == 0) panic("mpoverride: invalid size in *mp");
*newp = p = xalloc(size);
if(p == nil) panic("mpoverride: can't allocate memory");
*e = p + size;
for(i = 0; ; i++){
snprint(buf, sizeof buf, "*mp%d", i);
s = getconf(buf);
if(s == nil) break;
while(*s){
j = strtol(s, &s, 16);
if(*s && *s != ' ' || j < 0 || j > 0xff) panic("mpoverride: invalid entry in %s", buf);
if(p >= *e) panic("mpoverride: overflow in %s", buf);
*p++ = j;
}
}
if(p != *e) panic("mpoverride: size doesn't match");
}
void
mpinit(void)
{
int ncpu, i;
Apic *apic;
char *cp;
PCMP *pcmp;
uchar *e, *p;
Apic *apic, *bpapic;
void *va;
i8259init();
syncclock();
if(_mp_ == 0)
return;
pcmp = KADDR(_mp_->physaddr);
if(getconf("*apicdebug")){
Bus *b;
Aintr *ai;
PCMPintr *pi;
/*
* Map the local APIC.
*/
if((va = vmap(pcmp->lapicbase, 1024)) == nil)
return;
mppcmp = pcmp;
print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va);
bpapic = nil;
/*
* Run through the table saving information needed for starting
* application processors and initialising any I/O APICs. The table
* is guaranteed to be in order such that only one pass is necessary.
*/
p = ((uchar*)pcmp)+sizeof(PCMP);
e = ((uchar*)pcmp)+pcmp->length;
if(getconf("*dumpmp") != nil)
dumpmp(p, e);
if(getconf("*mp") != nil)
mpoverride(&p, &e);
while(p < e) switch(*p){
default:
print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",
*p, e-p);
while(p < e){
print("%uX ", *p);
p++;
for(i=0; i<=MaxAPICNO; i++){
if(apic = mpapic[i])
print("LAPIC%d: pa=%lux va=%lux flags=%x\n",
i, apic->paddr, (ulong)apic->addr, apic->flags);
if(apic = mpioapic[i])
print("IOAPIC%d: pa=%lux va=%lux flags=%x gsibase=%d mre=%d\n",
i, apic->paddr, (ulong)apic->addr, apic->flags, apic->gsibase, apic->mre);
}
break;
case PcmpPROCESSOR:
if(apic = mkprocessor((PCMPprocessor*)p)){
/*
* Must take a note of bootstrap processor APIC
* now as it will be needed in order to start the
* application processors later and there's no
* guarantee that the bootstrap processor appears
* first in the table before the others.
*/
apic->addr = va;
apic->paddr = pcmp->lapicbase;
if(apic->flags & PcmpBP)
bpapic = apic;
for(b = mpbus; b; b = b->next){
print("BUS%d type=%d flags=%x\n", b->busno, b->type, b->po|b->el);
for(ai = b->aintr; ai; ai = ai->next){
if(pi = ai->intr)
print("\ttype=%d irq=%d (%d [%c]) apic=%d intin=%d flags=%x\n",
pi->type, pi->irq, pi->irq>>2, "ABCD"[pi->irq&3],
pi->apicno, pi->intin, pi->flags);
}
}
p += sizeof(PCMPprocessor);
continue;
case PcmpBUS:
mkbus((PCMPbus*)p);
p += sizeof(PCMPbus);
continue;
case PcmpIOAPIC:
if(apic = mkioapic((PCMPioapic*)p))
ioapicinit(apic, ((PCMPioapic*)p)->apicno);
p += sizeof(PCMPioapic);
continue;
case PcmpIOINTR:
mkiointr((PCMPintr*)p);
p += sizeof(PCMPintr);
continue;
case PcmpLINTR:
mklintr((PCMPintr*)p);
p += sizeof(PCMPintr);
continue;
}
/*
* No bootstrap processor, no need to go further.
*/
if(bpapic == 0)
return;
bpapic->online = 1;
apic = nil;
for(i=0; i<=MaxAPICNO; i++){
if(mpapic[i] == nil)
continue;
if(mpapic[i]->flags & PcmpBP){
apic = mpapic[i];
break;
}
}
lapicinit(bpapic);
if(apic == nil){
panic("mpinit: no bootstrap processor");
return;
}
apic->online = 1;
lapicinit(apic);
/*
* These interrupts are local to the processor
@ -670,6 +380,8 @@ mpinit(void)
static int
mpintrcpu(void)
{
static Lock physidlock;
static int physid;
int i;
/*
@ -689,17 +401,17 @@ 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.
*/
lock(&mpphysidlock);
lock(&physidlock);
for(;;){
i = mpphysid++;
if(mpphysid >= nelem(mpapic))
mpphysid = 0;
i = physid++;
if(physid >= nelem(mpapic))
physid = 0;
if(mpapic[i] == nil)
continue;
if(mpapic[i]->online)
break;
}
unlock(&mpphysidlock);
unlock(&physidlock);
return mpapic[i]->apicno;
}
@ -741,23 +453,41 @@ mpintrenablex(Vctl* v, int tbdf)
Aintr *aintr;
Apic *apic;
Pcidev *pcidev;
int bno, dno, hi, irq, lo, n, type, vno;
int bno, dno, pin, hi, irq, lo, n, type, vno;
/*
* Find the bus.
*/
type = BUSTYPE(tbdf);
bno = BUSBNO(tbdf);
dno = BUSDNO(tbdf);
if(type == BusISA)
pin = 0;
pcidev = nil;
if(type == BusPCI){
if(pcidev = pcimatchtbdf(tbdf))
pin = pcicfgr8(pcidev, PciINTP);
} else if(type == BusISA)
bno = mpisabus;
Findbus:
for(bus = mpbus; bus != nil; bus = bus->next){
if(bus->type != type)
continue;
if(bus->busno == bno)
break;
}
if(bus == nil){
/*
* if the PCI device is behind a PCI-PCI bridge thats not described
* by the MP or ACPI tables then walk up the bus translating interrupt
* pin to parent bus.
*/
if(pcidev && pcidev->parent && pin > 0){
pin = ((dno+(pin-1))%4)+1;
pcidev = pcidev->parent;
bno = BUSBNO(pcidev->tbdf);
dno = BUSDNO(pcidev->tbdf);
goto Findbus;
}
print("mpintrenable: can't find bus type %d, number %d\n", type, bno);
return -1;
}
@ -765,13 +495,11 @@ mpintrenablex(Vctl* v, int tbdf)
/*
* For PCI devices the interrupt pin (INT[ABCD]) and device
* number are encoded into the entry irq field, so create something
* to match on. The interrupt pin used by the device has to be
* obtained from the PCI config space.
* to match on.
*/
if(bus->type == BusPCI){
pcidev = pcimatchtbdf(tbdf);
if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0)
irq = (dno<<2)|(n-1);
if(pin > 0)
irq = (dno<<2)|(pin-1);
else
irq = -1;
}
@ -932,15 +660,16 @@ mpintrenable(Vctl* v)
return -1;
}
static Lock mpshutdownlock;
void
mpshutdown(void)
{
static Lock shutdownlock;
/*
* To be done...
*/
if(!canlock(&mpshutdownlock)){
if(!canlock(&shutdownlock)){
/*
* If this processor received the CTRL-ALT-DEL from
* the keyboard, acknowledge it. Send an INIT to self.

View File

@ -162,6 +162,7 @@ typedef struct Apic {
Lock; /* I/O APIC: register access */
int mre; /* I/O APIC: maximum redirection entry */
int gsibase; /* I/O APIC: global system interrupt base (acpi) */
int lintr[2]; /* Local APIC */
int machno;
@ -228,8 +229,14 @@ extern void lapicspurious(Ureg*, void*);
extern void lapicstartap(Apic*, int);
extern void lapictimerset(uvlong);
extern int mpintrinit(Bus*, PCMPintr*, int, int);
extern void mpinit(void);
extern int mpintrenable(Vctl*);
extern void mpshutdown(void);
extern _MP_ *_mp_;
extern Bus* mpbus;
extern Bus* mpbuslast;
extern int mpisabus;
extern int mpeisabus;
extern Apic *mpioapic[];
extern Apic *mpapic[];

View File

@ -41,7 +41,6 @@ link
devpccard
devi82365
cputemp
acpi
apm apmjump
ether2000 ether8390
ether2114x pci
@ -79,6 +78,7 @@ link
audiohda
misc
archacpi mp apic
archmp mp apic
mtrr

View File

@ -42,7 +42,6 @@ link
devpccard
devi82365
cputemp
acpi
apm apmjump
ether2000 ether8390
ether2114x pci
@ -81,6 +80,7 @@ link
audiohda
misc
archacpi mp apic
archmp mp apic
mtrr

View File

@ -367,7 +367,7 @@ pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
}
static int
pcilscan(int bno, Pcidev** list)
pcilscan(int bno, Pcidev** list, Pcidev *parent)
{
Pcidev *p, *head, *tail;
int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
@ -453,6 +453,7 @@ pcilscan(int bno, Pcidev** list)
break;
}
p->parent = parent;
if(head != nil)
tail->link = p;
else
@ -494,7 +495,7 @@ pcilscan(int bno, Pcidev** list)
l = (MaxUBN<<16)|(sbn<<8)|bno;
pcicfgw32(p, PciPBN, l);
pcicfgw16(p, PciSPSR, 0xFFFF);
maxubn = pcilscan(sbn, &p->bridge);
maxubn = pcilscan(sbn, &p->bridge, p);
l = (maxubn<<16)|(sbn<<8)|bno;
pcicfgw32(p, PciPBN, l);
@ -502,7 +503,7 @@ pcilscan(int bno, Pcidev** list)
else {
if(ubn > maxubn)
maxubn = ubn;
pcilscan(sbn, &p->bridge);
pcilscan(sbn, &p->bridge, p);
}
}
@ -515,7 +516,7 @@ pciscan(int bno, Pcidev **list)
int ubn;
lock(&pcicfginitlock);
ubn = pcilscan(bno, list);
ubn = pcilscan(bno, list, nil);
unlock(&pcicfginitlock);
return ubn;
}
@ -1004,7 +1005,7 @@ pcicfginit(void)
list = &pciroot;
for(bno = 0; bno <= pcimaxbno; bno++) {
int sbno = bno;
bno = pcilscan(bno, list);
bno = pcilscan(bno, list, nil);
while(*list)
list = &(*list)->link;

1818
sys/src/libaml/aml.c Normal file

File diff suppressed because it is too large Load Diff

15
sys/src/libaml/mkfile Normal file
View File

@ -0,0 +1,15 @@
</$objtype/mkfile
LIB=/$objtype/lib/libaml.a
OFILES=\
aml.$O\
HFILES=/sys/include/aml.h
UPDATE=\
mkfile\
$HFILES\
${OFILES:%.$O=%.c}\
${LIB:/$objtype/%=/386/%}\
</sys/src/cmd/mksyslib