experimental acpi support for apic irq routing
This commit is contained in:
parent
9cb66f310b
commit
a47521a3ed
13 changed files with 2876 additions and 644 deletions
36
sys/include/aml.h
Normal file
36
sys/include/aml.h
Normal 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*);
|
|
@ -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
525
sys/src/9/pc/archacpi.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
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
15
sys/src/libaml/mkfile
Normal 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
|
Loading…
Reference in a new issue