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"
|
#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_*
|
static _MP_*
|
||||||
mpscan(uchar *addr, int len)
|
mpscan(uchar *addr, int len)
|
||||||
|
@ -60,7 +405,7 @@ PCArch archmp = {
|
||||||
.id= "_MP_",
|
.id= "_MP_",
|
||||||
.ident= identify,
|
.ident= identify,
|
||||||
.reset= mpshutdown,
|
.reset= mpshutdown,
|
||||||
.intrinit= mpinit,
|
.intrinit= pcmpinit,
|
||||||
.intrenable= mpintrenable,
|
.intrenable= mpintrenable,
|
||||||
.intron= lapicintron,
|
.intron= lapicintron,
|
||||||
.introff= lapicintroff,
|
.introff= lapicintroff,
|
||||||
|
@ -72,7 +417,7 @@ static int
|
||||||
identify(void)
|
identify(void)
|
||||||
{
|
{
|
||||||
char *cp;
|
char *cp;
|
||||||
PCMP *pcmp;
|
_MP_ *_mp_;
|
||||||
uchar *p, sum;
|
uchar *p, sum;
|
||||||
ulong length;
|
ulong length;
|
||||||
|
|
||||||
|
@ -90,50 +435,23 @@ identify(void)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
pcmp = KADDR(_mp_->physaddr);
|
pcmp = KADDR(_mp_->physaddr);
|
||||||
if(memcmp(pcmp, "PCMP", 4))
|
if(memcmp(pcmp, "PCMP", 4)){
|
||||||
|
pcmp = nil;
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
length = pcmp->length;
|
length = pcmp->length;
|
||||||
sum = 0;
|
sum = 0;
|
||||||
for(p = (uchar*)pcmp; length; length--)
|
for(p = (uchar*)pcmp; length; length--)
|
||||||
sum += *p++;
|
sum += *p++;
|
||||||
|
|
||||||
if(sum || (pcmp->version != 1 && pcmp->version != 4))
|
if(sum || (pcmp->version != 1 && pcmp->version != 4)){
|
||||||
|
pcmp = nil;
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if(cpuserver && m->havetsc)
|
if(cpuserver && m->havetsc)
|
||||||
archmp.fastclock = tscticks;
|
archmp.fastclock = tscticks;
|
||||||
|
|
||||||
return 0;
|
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* list;
|
||||||
Pcidev* link; /* next device on this bno */
|
Pcidev* link; /* next device on this bno */
|
||||||
|
|
||||||
|
Pcidev* parent; /* up a bus */
|
||||||
Pcidev* bridge; /* down a bus */
|
Pcidev* bridge; /* down a bus */
|
||||||
struct {
|
struct {
|
||||||
ulong bar;
|
ulong bar;
|
||||||
|
|
|
@ -68,6 +68,7 @@ LIB=\
|
||||||
/$objtype/lib/libsec.a\
|
/$objtype/lib/libsec.a\
|
||||||
/$objtype/lib/libmp.a\
|
/$objtype/lib/libmp.a\
|
||||||
/$objtype/lib/libfis.a\
|
/$objtype/lib/libfis.a\
|
||||||
|
/$objtype/lib/libaml.a\
|
||||||
|
|
||||||
ETHER=`{echo devether.c ether*.c | sed 's/\.c/.'$O'/g'}
|
ETHER=`{echo devether.c ether*.c | sed 's/\.c/.'$O'/g'}
|
||||||
VGA=`{echo devvga.c screen.c vga*.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 "mp.h"
|
||||||
#include "apbootstrap.h"
|
#include "apbootstrap.h"
|
||||||
|
|
||||||
static PCMP* mppcmp;
|
/* filled in by pcmpinit or acpiinit */
|
||||||
static Bus* mpbus;
|
Bus* mpbus;
|
||||||
static Bus* mpbuslast;
|
Bus* mpbuslast;
|
||||||
static int mpisabus = -1;
|
int mpisabus = -1;
|
||||||
static int mpeisabus = -1;
|
int mpeisabus = -1;
|
||||||
extern int i8259elcr; /* mask of level-triggered interrupts */
|
Apic *mpioapic[MaxAPICNO+1];
|
||||||
static Apic *mpioapic[MaxAPICNO+1];
|
Apic *mpapic[MaxAPICNO+1];
|
||||||
static Apic *mpapic[MaxAPICNO+1];
|
|
||||||
static int mpmachno = 1;
|
|
||||||
static Lock mpphysidlock;
|
|
||||||
static int mpphysid;
|
|
||||||
|
|
||||||
static char* buses[] = {
|
int
|
||||||
"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
|
|
||||||
mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
|
mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
|
||||||
{
|
{
|
||||||
int el, po, v;
|
int el, po, v;
|
||||||
|
@ -284,47 +90,6 @@ mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
|
||||||
return v;
|
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
|
static void
|
||||||
checkmtrr(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
|
static void
|
||||||
squidboy(Apic* apic)
|
squidboy(Apic* apic)
|
||||||
{
|
{
|
||||||
|
@ -483,141 +278,56 @@ mpstartap(Apic* apic)
|
||||||
nvramwrite(0x0F, 0x00);
|
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
|
void
|
||||||
mpinit(void)
|
mpinit(void)
|
||||||
{
|
{
|
||||||
int ncpu, i;
|
int ncpu, i;
|
||||||
|
Apic *apic;
|
||||||
char *cp;
|
char *cp;
|
||||||
PCMP *pcmp;
|
|
||||||
uchar *e, *p;
|
|
||||||
Apic *apic, *bpapic;
|
|
||||||
void *va;
|
|
||||||
|
|
||||||
i8259init();
|
i8259init();
|
||||||
syncclock();
|
syncclock();
|
||||||
|
|
||||||
if(_mp_ == 0)
|
if(getconf("*apicdebug")){
|
||||||
return;
|
Bus *b;
|
||||||
pcmp = KADDR(_mp_->physaddr);
|
Aintr *ai;
|
||||||
|
PCMPintr *pi;
|
||||||
|
|
||||||
/*
|
for(i=0; i<=MaxAPICNO; i++){
|
||||||
* Map the local APIC.
|
if(apic = mpapic[i])
|
||||||
*/
|
print("LAPIC%d: pa=%lux va=%lux flags=%x\n",
|
||||||
if((va = vmap(pcmp->lapicbase, 1024)) == nil)
|
i, apic->paddr, (ulong)apic->addr, apic->flags);
|
||||||
return;
|
if(apic = mpioapic[i])
|
||||||
mppcmp = pcmp;
|
print("IOAPIC%d: pa=%lux va=%lux flags=%x gsibase=%d mre=%d\n",
|
||||||
print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va);
|
i, apic->paddr, (ulong)apic->addr, apic->flags, apic->gsibase, apic->mre);
|
||||||
|
|
||||||
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(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apic = nil;
|
||||||
|
for(i=0; i<=MaxAPICNO; i++){
|
||||||
|
if(mpapic[i] == nil)
|
||||||
|
continue;
|
||||||
|
if(mpapic[i]->flags & PcmpBP){
|
||||||
|
apic = mpapic[i];
|
||||||
break;
|
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;
|
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if(apic == nil){
|
||||||
* No bootstrap processor, no need to go further.
|
panic("mpinit: no bootstrap processor");
|
||||||
*/
|
|
||||||
if(bpapic == 0)
|
|
||||||
return;
|
return;
|
||||||
bpapic->online = 1;
|
}
|
||||||
|
apic->online = 1;
|
||||||
lapicinit(bpapic);
|
lapicinit(apic);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These interrupts are local to the processor
|
* These interrupts are local to the processor
|
||||||
|
@ -670,6 +380,8 @@ mpinit(void)
|
||||||
static int
|
static int
|
||||||
mpintrcpu(void)
|
mpintrcpu(void)
|
||||||
{
|
{
|
||||||
|
static Lock physidlock;
|
||||||
|
static int physid;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -689,17 +401,17 @@ mpintrcpu(void)
|
||||||
* to more than one thread in a core, or to use a "noise" core.
|
* to more than one thread in a core, or to use a "noise" core.
|
||||||
* But, as usual, Intel make that an onerous task.
|
* But, as usual, Intel make that an onerous task.
|
||||||
*/
|
*/
|
||||||
lock(&mpphysidlock);
|
lock(&physidlock);
|
||||||
for(;;){
|
for(;;){
|
||||||
i = mpphysid++;
|
i = physid++;
|
||||||
if(mpphysid >= nelem(mpapic))
|
if(physid >= nelem(mpapic))
|
||||||
mpphysid = 0;
|
physid = 0;
|
||||||
if(mpapic[i] == nil)
|
if(mpapic[i] == nil)
|
||||||
continue;
|
continue;
|
||||||
if(mpapic[i]->online)
|
if(mpapic[i]->online)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
unlock(&mpphysidlock);
|
unlock(&physidlock);
|
||||||
|
|
||||||
return mpapic[i]->apicno;
|
return mpapic[i]->apicno;
|
||||||
}
|
}
|
||||||
|
@ -741,23 +453,41 @@ mpintrenablex(Vctl* v, int tbdf)
|
||||||
Aintr *aintr;
|
Aintr *aintr;
|
||||||
Apic *apic;
|
Apic *apic;
|
||||||
Pcidev *pcidev;
|
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);
|
type = BUSTYPE(tbdf);
|
||||||
bno = BUSBNO(tbdf);
|
bno = BUSBNO(tbdf);
|
||||||
dno = BUSDNO(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;
|
bno = mpisabus;
|
||||||
|
|
||||||
|
Findbus:
|
||||||
for(bus = mpbus; bus != nil; bus = bus->next){
|
for(bus = mpbus; bus != nil; bus = bus->next){
|
||||||
if(bus->type != type)
|
if(bus->type != type)
|
||||||
continue;
|
continue;
|
||||||
if(bus->busno == bno)
|
if(bus->busno == bno)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bus == nil){
|
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);
|
print("mpintrenable: can't find bus type %d, number %d\n", type, bno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -765,13 +495,11 @@ mpintrenablex(Vctl* v, int tbdf)
|
||||||
/*
|
/*
|
||||||
* For PCI devices the interrupt pin (INT[ABCD]) and device
|
* For PCI devices the interrupt pin (INT[ABCD]) and device
|
||||||
* number are encoded into the entry irq field, so create something
|
* number are encoded into the entry irq field, so create something
|
||||||
* to match on. The interrupt pin used by the device has to be
|
* to match on.
|
||||||
* obtained from the PCI config space.
|
|
||||||
*/
|
*/
|
||||||
if(bus->type == BusPCI){
|
if(bus->type == BusPCI){
|
||||||
pcidev = pcimatchtbdf(tbdf);
|
if(pin > 0)
|
||||||
if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0)
|
irq = (dno<<2)|(pin-1);
|
||||||
irq = (dno<<2)|(n-1);
|
|
||||||
else
|
else
|
||||||
irq = -1;
|
irq = -1;
|
||||||
}
|
}
|
||||||
|
@ -932,15 +660,16 @@ mpintrenable(Vctl* v)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Lock mpshutdownlock;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
mpshutdown(void)
|
mpshutdown(void)
|
||||||
{
|
{
|
||||||
|
static Lock shutdownlock;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To be done...
|
* To be done...
|
||||||
*/
|
*/
|
||||||
if(!canlock(&mpshutdownlock)){
|
if(!canlock(&shutdownlock)){
|
||||||
/*
|
/*
|
||||||
* If this processor received the CTRL-ALT-DEL from
|
* If this processor received the CTRL-ALT-DEL from
|
||||||
* the keyboard, acknowledge it. Send an INIT to self.
|
* the keyboard, acknowledge it. Send an INIT to self.
|
||||||
|
|
|
@ -162,6 +162,7 @@ typedef struct Apic {
|
||||||
|
|
||||||
Lock; /* I/O APIC: register access */
|
Lock; /* I/O APIC: register access */
|
||||||
int mre; /* I/O APIC: maximum redirection entry */
|
int mre; /* I/O APIC: maximum redirection entry */
|
||||||
|
int gsibase; /* I/O APIC: global system interrupt base (acpi) */
|
||||||
|
|
||||||
int lintr[2]; /* Local APIC */
|
int lintr[2]; /* Local APIC */
|
||||||
int machno;
|
int machno;
|
||||||
|
@ -228,8 +229,14 @@ extern void lapicspurious(Ureg*, void*);
|
||||||
extern void lapicstartap(Apic*, int);
|
extern void lapicstartap(Apic*, int);
|
||||||
extern void lapictimerset(uvlong);
|
extern void lapictimerset(uvlong);
|
||||||
|
|
||||||
|
extern int mpintrinit(Bus*, PCMPintr*, int, int);
|
||||||
extern void mpinit(void);
|
extern void mpinit(void);
|
||||||
extern int mpintrenable(Vctl*);
|
extern int mpintrenable(Vctl*);
|
||||||
extern void mpshutdown(void);
|
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
|
devpccard
|
||||||
devi82365
|
devi82365
|
||||||
cputemp
|
cputemp
|
||||||
acpi
|
|
||||||
apm apmjump
|
apm apmjump
|
||||||
ether2000 ether8390
|
ether2000 ether8390
|
||||||
ether2114x pci
|
ether2114x pci
|
||||||
|
@ -79,6 +78,7 @@ link
|
||||||
audiohda
|
audiohda
|
||||||
|
|
||||||
misc
|
misc
|
||||||
|
archacpi mp apic
|
||||||
archmp mp apic
|
archmp mp apic
|
||||||
mtrr
|
mtrr
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,6 @@ link
|
||||||
devpccard
|
devpccard
|
||||||
devi82365
|
devi82365
|
||||||
cputemp
|
cputemp
|
||||||
acpi
|
|
||||||
apm apmjump
|
apm apmjump
|
||||||
ether2000 ether8390
|
ether2000 ether8390
|
||||||
ether2114x pci
|
ether2114x pci
|
||||||
|
@ -81,6 +80,7 @@ link
|
||||||
audiohda
|
audiohda
|
||||||
|
|
||||||
misc
|
misc
|
||||||
|
archacpi mp apic
|
||||||
archmp mp apic
|
archmp mp apic
|
||||||
mtrr
|
mtrr
|
||||||
|
|
||||||
|
|
|
@ -367,7 +367,7 @@ pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pcilscan(int bno, Pcidev** list)
|
pcilscan(int bno, Pcidev** list, Pcidev *parent)
|
||||||
{
|
{
|
||||||
Pcidev *p, *head, *tail;
|
Pcidev *p, *head, *tail;
|
||||||
int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
|
int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
|
||||||
|
@ -453,6 +453,7 @@ pcilscan(int bno, Pcidev** list)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p->parent = parent;
|
||||||
if(head != nil)
|
if(head != nil)
|
||||||
tail->link = p;
|
tail->link = p;
|
||||||
else
|
else
|
||||||
|
@ -494,7 +495,7 @@ pcilscan(int bno, Pcidev** list)
|
||||||
l = (MaxUBN<<16)|(sbn<<8)|bno;
|
l = (MaxUBN<<16)|(sbn<<8)|bno;
|
||||||
pcicfgw32(p, PciPBN, l);
|
pcicfgw32(p, PciPBN, l);
|
||||||
pcicfgw16(p, PciSPSR, 0xFFFF);
|
pcicfgw16(p, PciSPSR, 0xFFFF);
|
||||||
maxubn = pcilscan(sbn, &p->bridge);
|
maxubn = pcilscan(sbn, &p->bridge, p);
|
||||||
l = (maxubn<<16)|(sbn<<8)|bno;
|
l = (maxubn<<16)|(sbn<<8)|bno;
|
||||||
|
|
||||||
pcicfgw32(p, PciPBN, l);
|
pcicfgw32(p, PciPBN, l);
|
||||||
|
@ -502,7 +503,7 @@ pcilscan(int bno, Pcidev** list)
|
||||||
else {
|
else {
|
||||||
if(ubn > maxubn)
|
if(ubn > maxubn)
|
||||||
maxubn = ubn;
|
maxubn = ubn;
|
||||||
pcilscan(sbn, &p->bridge);
|
pcilscan(sbn, &p->bridge, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,7 +516,7 @@ pciscan(int bno, Pcidev **list)
|
||||||
int ubn;
|
int ubn;
|
||||||
|
|
||||||
lock(&pcicfginitlock);
|
lock(&pcicfginitlock);
|
||||||
ubn = pcilscan(bno, list);
|
ubn = pcilscan(bno, list, nil);
|
||||||
unlock(&pcicfginitlock);
|
unlock(&pcicfginitlock);
|
||||||
return ubn;
|
return ubn;
|
||||||
}
|
}
|
||||||
|
@ -1004,7 +1005,7 @@ pcicfginit(void)
|
||||||
list = &pciroot;
|
list = &pciroot;
|
||||||
for(bno = 0; bno <= pcimaxbno; bno++) {
|
for(bno = 0; bno <= pcimaxbno; bno++) {
|
||||||
int sbno = bno;
|
int sbno = bno;
|
||||||
bno = pcilscan(bno, list);
|
bno = pcilscan(bno, list, nil);
|
||||||
|
|
||||||
while(*list)
|
while(*list)
|
||||||
list = &(*list)->link;
|
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…
Add table
Add a link
Reference in a new issue