From a47521a3ede91ef06bf7938722c490893d5458f6 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sun, 17 Jun 2012 23:12:19 +0200 Subject: [PATCH] experimental acpi support for apic irq routing --- sys/include/aml.h | 36 + sys/src/9/pc/acpi.c | 219 ----- sys/src/9/pc/archacpi.c | 525 +++++++++++ sys/src/9/pc/archmp.c | 392 ++++++++- sys/src/9/pc/io.h | 1 + sys/src/9/pc/mkfile | 1 + sys/src/9/pc/mp.c | 489 +++-------- sys/src/9/pc/mp.h | 9 +- sys/src/9/pc/pccpuf | 2 +- sys/src/9/pc/pcf | 2 +- sys/src/9/pc/pci.c | 11 +- sys/src/libaml/aml.c | 1818 +++++++++++++++++++++++++++++++++++++++ sys/src/libaml/mkfile | 15 + 13 files changed, 2876 insertions(+), 644 deletions(-) create mode 100644 sys/include/aml.h delete mode 100644 sys/src/9/pc/acpi.c create mode 100644 sys/src/9/pc/archacpi.c create mode 100644 sys/src/libaml/aml.c create mode 100644 sys/src/libaml/mkfile diff --git a/sys/include/aml.h b/sys/include/aml.h new file mode 100644 index 000000000..e1cd9c335 --- /dev/null +++ b/sys/include/aml.h @@ -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*); diff --git a/sys/src/9/pc/acpi.c b/sys/src/9/pc/acpi.c deleted file mode 100644 index 51b34adda..000000000 --- a/sys/src/9/pc/acpi.c +++ /dev/null @@ -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; isig, 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); -} diff --git a/sys/src/9/pc/archacpi.c b/sys/src/9/pc/archacpi.c new file mode 100644 index 000000000..145c60bf4 --- /dev/null +++ b/sys/src/9/pc/archacpi.c @@ -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 + +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; isig, 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>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; +} diff --git a/sys/src/9/pc/archmp.c b/sys/src/9/pc/archmp.c index 1df3c3fbc..7d72e0462 100644 --- a/sys/src/9/pc/archmp.c +++ b/sys/src/9/pc/archmp.c @@ -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; -} diff --git a/sys/src/9/pc/io.h b/sys/src/9/pc/io.h index 95d7d55eb..d33439b40 100644 --- a/sys/src/9/pc/io.h +++ b/sys/src/9/pc/io.h @@ -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; diff --git a/sys/src/9/pc/mkfile b/sys/src/9/pc/mkfile index 4e61f7237..6de41a5bb 100644 --- a/sys/src/9/pc/mkfile +++ b/sys/src/9/pc/mkfile @@ -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'} diff --git a/sys/src/9/pc/mp.c b/sys/src/9/pc/mp.c index 27695a609..b392c6a46 100644 --- a/sys/src/9/pc/mp.c +++ b/sys/src/9/pc/mp.c @@ -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; iflags & 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. diff --git a/sys/src/9/pc/mp.h b/sys/src/9/pc/mp.h index 31fd13e1f..145cd02bc 100644 --- a/sys/src/9/pc/mp.h +++ b/sys/src/9/pc/mp.h @@ -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[]; diff --git a/sys/src/9/pc/pccpuf b/sys/src/9/pc/pccpuf index 4625e2dc2..e9daaaa8c 100644 --- a/sys/src/9/pc/pccpuf +++ b/sys/src/9/pc/pccpuf @@ -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 diff --git a/sys/src/9/pc/pcf b/sys/src/9/pc/pcf index 8b2f54aae..74bac70f3 100644 --- a/sys/src/9/pc/pcf +++ b/sys/src/9/pc/pcf @@ -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 diff --git a/sys/src/9/pc/pci.c b/sys/src/9/pc/pci.c index 41904f322..370a7bd50 100644 --- a/sys/src/9/pc/pci.c +++ b/sys/src/9/pc/pci.c @@ -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; diff --git a/sys/src/libaml/aml.c b/sys/src/libaml/aml.c new file mode 100644 index 000000000..80df2b1b1 --- /dev/null +++ b/sys/src/libaml/aml.c @@ -0,0 +1,1818 @@ +#include +#include +#include + +typedef struct Interp Interp; +typedef struct Frame Frame; +typedef struct Heap Heap; + +typedef struct Package Package; +typedef struct Method Method; +typedef struct Region Region; +typedef struct Field Field; + +typedef struct Name Name; +typedef struct Ref Ref; +typedef struct Env Env; +typedef struct Op Op; + +struct Heap { + Heap *link; + short size; + uchar mark; + char tag; +}; + +#define H2D(h) (((Heap*)(h))+1) +#define D2H(d) (((Heap*)(d))-1) +#define TAG(d) D2H(d)->tag +#define SIZE(d) D2H(d)->size + +enum { + MemSpace = 0x00, + IoSpace = 0x01, + PcicfgSpace = 0x02, + EbctlSpace = 0x03, + SmbusSpace = 0x04, + CmosSpace = 0x05, + PcibarSpace = 0x06, + IpmiSpace = 0x07, +}; + +static char *spacename[] = { + "Mem", + "Io", + "Pcicfg", + "Ebctl", + "Smbus", + "Cmos", + "Pcibar", + "Ipmi" }; + +/* field flags */ +enum { + AnyAcc = 0x00, + ByteAcc = 0x01, + WordAcc = 0x02, + DWordAcc = 0x03, + QWordAcc = 0x04, + BufferAcc = 0x05, + AccMask = 0x07, + + NoLock = 0x10, + + Preserve = 0x00, + WriteAsOnes = 0x20, + WriteAsZeros = 0x40, + UpdateMask = 0x60, +}; + +struct Package { + int n; + void *a[]; +}; + +struct Method { + Name *name; + int narg; + void* (*eval)(void); + uchar *start; + uchar *end; +}; + +struct Region { + Name *name; + int space; + uvlong off; + uvlong len; + uchar *va; +}; + +struct Field { + void *reg; /* Buffer or Region */ + Field *index; + void *indexv; + int flags; + int bitoff; + int bitlen; +}; + +struct Name { + void *v; + + Name *up; + Name *next; + Name *fork; + Name *down; + + char seg[4]; +}; + +struct Ref { + void *ref; + void **ptr; +}; + +struct Env { + void *loc[8]; + void *arg[8]; +}; + +struct Op { + char *name; + char *sequence; + void* (*eval)(void); +}; + +struct Frame { + int tag; + char *phase; + uchar *start; + uchar *end; + Op *op; + Env *env; + Name *dot; + void *ref; + void *aux; + int narg; + void *arg[8]; +}; + +struct Interp { + uchar *pc; + Frame *fp; + int cond; +}; + +static Interp interp; +static Frame stack[32]; + +#define PC interp.pc +#define FP interp.fp +#define FB stack +#define FT &stack[nelem(stack)] + +static Heap *hp; + +enum { + Obad, Onop, + Ostr, Obyte, Oword, Odword, Oqword, Oconst, + Onamec, Oname, Oscope, + Oreg, Ofld, Oxfld, Opkg, Ovpkg, Oenv, Obuf, Omet, + Odev, Ocpu, Othz, Oprc, + Oadd, Osub, Omod, Omul, Odiv, Oshl, Oshr, Oand, Onand, Oor, + Onor, Oxor, Onot, Oinc, Odec, + Oland, Olor, Olnot, Oleq, Olgt, Ollt, + Oindex, Omutex, Oevent, + Ocfld, Ocfld0, Ocfld1, Ocfld2, Ocfld4, Ocfld8, + Oif, Oelse, Owhile, Obreak, Oret, Ocall, + Ostore, Oderef, Osize, Oref, Ocref, + Oacq, Orel, +}; + +static Op optab[]; +static uchar octab1[]; +static uchar octab2[]; + +static Name* +rootname(Name *dot){ + while(dot != dot->up) + dot = dot->up; + return dot; +} + +static void +gcmark(void *p){ + Heap *h; + + if(p == nil) + return; + h = D2H(p); + if(h->mark) + return; + h->mark = 1; + switch(h->tag){ + case 'E': + { + int i; + Env *e = p; + for(i=0; iloc); i++) + gcmark(e->loc[i]); + for(i=0; iarg); i++) + gcmark(e->arg[i]); + } + break; + case 'R': case 'A': case 'L': + gcmark(((Ref*)p)->ref); + break; + case 'N': + { + Name *d, *n = p; + gcmark(n->v); + for(d = n->down; d; d = d->next) + gcmark(d); + gcmark(n->fork); + gcmark(n->up); + } + break; + case 'p': + { + int i; + Package *a = p; + for(i=0; in; i++) + gcmark(a->a[i]); + } + break; + case 'r': + gcmark(((Region*)p)->name); + break; + case 'm': + gcmark(((Method*)p)->name); + break; + case 'f': + case 'u': + { + Field *f = p; + gcmark(f->reg); + gcmark(f->index); + gcmark(f->indexv); + } + break; + } +} + +static int +gc(void){ + Heap *h, **hh; + Frame *f; + int i; + + for(h = hp; h; h = h->link) + h->mark = 0; + + for(f = FP; f >= FB; f--){ + for(i=0; inarg; i++) + gcmark(f->arg[i]); + gcmark(f->env); + gcmark(f->dot); + gcmark(f->ref); + } + + gcmark(amlroot); + + i = 0; + hh = &hp; + while(h = *hh){ + if(h->mark){ + hh = &h->link; + continue; + } + *hh = h->link; + memset(h, ~0, sizeof(Heap)+h->size); + amlfree(h); + i++; + } + + return i; +} + +static void* +mk(int tag, int size){ + Heap *h; + int a; + + a = sizeof(Heap) + size; + h = amlalloc(a); + h->size = size; + h->tag = tag; + h->link = hp; + hp = h; + return h+1; +} + +static uvlong* +mki(uvlong i){ + uvlong *v = mk('i', sizeof(uvlong)); + *v = i; + return v; +} + +static char* +mks(char *s){ + char *r = mk('s', strlen(s)+1); + strcpy(r, s); + return r; +} + +static int +pkglen(uchar *p, uchar *e, uchar **np){ + ulong n; + uchar b; + + if(p >= e) + return -1; + b = *p++; + if(b <= 0x3F) + n = b; + else { + n = b & 0xF; + if(p >= e) + return -1; + n += *p++ << 4; + if(b >= 0x80){ + if(p >= e) + return -1; + n += *p++ << 12; + } + if(b >= 0xC0){ + if(p >= e) + return -1; + n += *p++ << 20; + } + } + if(np) + *np = p; + return n; +} + +static Name* +forkname(Name *dot){ + Name *n; + + n = mk('N', sizeof(Name)); + *n = *dot; + n->fork = dot; + n->next = n->down = nil; + if(dot->v == dot) + n->v = n; + if(dot->up == dot) + n->up = n; + else { + if(n->up = forkname(dot->up)) + n->up->down = n; + } + return n; +} + +static Name* +getseg(Name *dot, void *seg, int new){ + Name *n, *l; + + for(n = l = nil; dot; dot = dot->fork){ + for(n = dot->down; n; n = n->next){ + if(memcmp(seg, n->seg, 4) == 0) + return n; + l = n; + } + if(new){ + n = mk('N', sizeof(Name)); + memmove(n->seg, seg, sizeof(n->seg)); + n->up = dot; + if(l == nil) + dot->down = n; + else + l->next = n; + n->v = n; + break; + } + } + return n; +} + +Name* +getname(Name *dot, char *path, int new) +{ + char seg[4]; + int i, s; + Name *x; + + s = !new; + if(*path == '\\'){ + path++; + dot = rootname(dot); + s = 0; + } + while(*path == '^'){ + path++; + dot = dot->up; + s = 0; + } + do { + for(i=0; i<4; i++){ + if(*path == 0 || *path == '.') + break; + seg[i] = *path++; + } + if(i == 0) + break; + while(i < 4) + seg[i++] = '_'; + if(s && *path == 0){ + for(;;){ + if(x = getseg(dot, seg, 0)) + break; + if(dot == dot->up) + break; + dot = dot->up; + } + return x; + } + s = 0; + dot = getseg(dot, seg, new); + } while(*path++ == '.'); + + return dot; +} + +static uvlong +ival(void *p){ + if(p) switch(TAG(p)){ + case 'i': + return *((uvlong*)p); + case 's': + return strtoull((char*)p, 0, 0); + } + return 0; +} + +static uvlong +rwreg(void *reg, int off, int len, uvlong v, int write) +{ + Region *r; + uchar *p; + int i; + + switch(TAG(reg)){ + case 'b': + p = reg; + if((off+len) > SIZE(p)) + break; + if(write){ + for(i=0; i>= 8; + } + } else { + for(i=0; i r->len) + break; + if(amldebug){ + print("rwreg: %s %-8s [%llux+%x]/%d %llux\n", + write ? "W" : "R", + spacename[r->space], + r->off, off, len, v); + } + break; + } + + return ~0; +} + +static void *deref(void *p); +static void *store(void *s, void *d); + +static int +fieldalign(int flags) +{ + switch(flags & AccMask){ + default: + case AnyAcc: + case ByteAcc: + case BufferAcc: + return 1; + case WordAcc: + return 2; + case DWordAcc: + return 4; + case QWordAcc: + return 8; + } +} + +static void* +rwfield(Field *f, void *v, int write){ + int boff, blen, wo, ws, wl, wa, wd, i; + uvlong w, m; + void *reg; + uchar *b; + + if(f == nil || (reg = deref(f->reg)) == nil) + return nil; + if(f->index) + store(f->indexv, f->index); + blen = f->bitlen; + if(write){ + if(v && TAG(v) == 'b'){ + b = v; + if(SIZE(b)*8 < blen) + blen = SIZE(b)*8; + } else { + w = ival(v); + b = mk('b', (blen+7)/8); + for(i=0; i>= 8; + } + } + } else + b = mk('b', (blen+7)/8); + wa = fieldalign(f->flags); + wd = wa*8; + boff = 0; + while((wl = (blen-boff)) > 0){ + wo = (f->bitoff+boff) / wd; + ws = (f->bitoff+boff) % wd; + if(wl > (wd - ws)) + wl = wd - ws; + if(write){ + w = 0; + for(i = 0; i < wl; i++, boff++) + if(b[boff/8] & (1<<(boff%8))) + w |= 1LL<> ws; + for(i = 0; i < wl; i++, boff++){ + b[boff/8] |= (w&1)<<(boff%8); + w >>= 1; + } + } + } + if(write) + return nil; + if(blen > 64) + return b; + w = 0; + for(i=0; iv; + case 'R': case 'A': case 'L': + return *((Ref*)p)->ptr; + case 'f': case 'u': + return rwfield(p, nil, 0); + } + return p; +} + +static void* +copy(int tag, void *s){ + void *d; + if(s){ + int n; + if(tag == 0) + tag = TAG(s); + switch(tag){ + case 'b': + case 's': + n = SIZE(s); + if(tag == 's' && TAG(s) == 'b') + n++; + d = mk(tag, n); + memmove(d, s, n); + if(tag == 's') + ((uchar*)d)[n-1] = 0; + return d; + case 'i': + return mki(ival(s)); + } + } + return s; +} + +static void* +store(void *s, void *d){ + void *p, **pp; + + if(d == nil) + return nil; + switch(TAG(d)){ + default: + return nil; + case 'A': + s = deref(s); + /* no break */ + case 'R': case 'L': + pp = ((Ref*)d)->ptr; + while(p = *pp){ + switch(TAG(p)){ + case 'R': case 'A': case 'L': + pp = ((Ref*)p)->ptr; + continue; + case 'N': + pp = &((Name*)p)->v; + if(*pp != p) + continue; + } + break; + } + break; + case 'N': + pp = &((Name*)d)->v; + } + p = *pp; + if(p && TAG(p) != 'N'){ + switch(TAG(p)){ + case 'f': + case 'u': + rwfield(p, s, 1); + return d; + } + *pp = copy(TAG(p), s); + } else + *pp = copy(0, s); + return d; +} + +static int +Nfmt(Fmt *f){ + char buf[5]; + Name *n; + int i; + + n = va_arg(f->args, Name*); + if(n == nil) + return fmtprint(f, "?NIL"); + if(n == n->up) + return fmtprint(f, "\\"); + strncpy(buf, n->seg, 4); + buf[4] = 0; + for(i=3; i>0; i--){ + if(buf[i] != '_') + break; + buf[i] = 0; + } + if(n->up == n->up->up) + return fmtprint(f, "\\%s", buf); + return fmtprint(f, "%N.%s", n->up, buf); +} + +static int +Vfmt(Fmt *f){ + void *p; + int c; + + p = va_arg(f->args, void*); + if(p == nil) + return fmtprint(f, "nil"); + c = TAG(p); + switch(c){ + case 'N': + { + Name *n = p; + + if(n->v != n) + return fmtprint(f, "%N=%V", n, n->v); + return fmtprint(f, "%N=*", n); + } + case 'A': case 'L': + { + Ref *r = p; + Env *e = r->ref; + if(c == 'A') + return fmtprint(f, "Arg%ld=%V", r->ptr - e->arg, *r->ptr); + if(c == 'L') + return fmtprint(f, "Local%ld=%V", r->ptr - e->loc, *r->ptr); + } + case 's': + return fmtprint(f, "\"%s\"", (char*)p); + case 'i': + return fmtprint(f, "0x%llux", *((uvlong*)p)); + case 'p': + { + int i; + Package *a = p; + fmtprint(f, "Package(%d){", a->n); + for(i=0; in; i++){ + if(i > 0) + fmtprint(f, ", "); + fmtprint(f, "%V", a->a[i]); + } + fmtprint(f, "}"); + } + return 0; + case 'b': + { + int i, n; + n = SIZE(p); + fmtprint(f, "Buffer(%d){", n); + for(i=0; i 0) + fmtprint(f, ", "); + fmtprint(f, "%.2uX", ((uchar*)p)[i]); + } + fmtprint(f, "}"); + } + return 0; + case 'r': + { + Region *r = p; + return fmtprint(f, "Region(%s, 0x%llux, 0x%llux)", + spacename[r->space & 7], r->off, r->len); + } + case 'm': + { + int i; + Method *m = p; + fmtprint(f, "%N(", m->name); + for(i=0; i < m->narg; i++){ + if(i > 0) + fmtprint(f, ", "); + fmtprint(f, "Arg%d", i); + } + fmtprint(f, ")"); + return 0; + } + case 'u': + fmtprint(f, "Buffer"); + /* no break */ + case 'f': + { + Field *l = p; + if(l->index) + return fmtprint(f, "IndexField(%x, %x, %x) @ %V[%V]", + l->flags, l->bitoff, l->bitlen, l->index, l->indexv); + return fmtprint(f, "Field(%x, %x, %x) @ %V", + l->flags, l->bitoff, l->bitlen, l->reg); + } + default: + return fmtprint(f, "%c:%p", c, p); + } +} + +static void +dumpregs(void){ + Frame *f; + Env *e; + int i; + + print("\n*** dumpregs: PC=%p FP=%p\n", PC, FP); + e = nil; + for(f = FP; f >= FB; f--){ + print("%.8p.%.2lx: %-8s %N\t", f->start, f-FB, f->phase, f->dot); + if(f->op) + print("%s", f->op->name); + print("("); + for(i=0; inarg; i++){ + if(i > 0) + print(", "); + print("%V", f->arg[i]); + } + print(")\n"); + if(e == f->env) + continue; + if(e = f->env){ + for(i=0; iarg); i++) + print("Arg%d=%V ", i, e->arg[i]); + print("\n"); + for(i=0; iloc); i++) + print("Local%d=%V ", i, e->loc[i]); + print("\n"); + } + } +} + +static int +xec(uchar *pc, uchar *end, Name *dot, Env *env, void **pret){ + static int loop; + int i, c; + void *r; + + PC = pc; + FP = FB; + + FP->tag = 0; + FP->narg = 0; + FP->phase = "}"; + FP->start = PC; + FP->end = end; + FP->aux = end; + FB->ref = nil; + FP->dot = dot; + FP->env = env; + FP->op = nil; + + for(;;){ + if((++loop & 127) == 0) + gc(); + if(amldebug) + print("\n%.8p.%.2lx %-8s %d\t%N\t", PC, FP - FB, FP->phase, interp.cond, FP->dot); + r = nil; + c = *FP->phase++; + switch(c){ + default: + if(PC >= FP->end){ + Overrun: + print("PC overrun frame end"); + goto Out; + } + FP++; + if(FP >= FT){ + print("frame stack overflow"); + goto Out; + } + *FP = FP[-1]; + FP->aux = nil; + FP->ref = nil; + FP->tag = c; + FP->start = PC; + c = *PC++; + if(amldebug) print("%.2X", c); + if(c == '['){ + if(PC >= FP->end) + goto Overrun; + c = *PC++; + if(amldebug) print("%.2X", c); + c = octab2[c]; + }else + c = octab1[c]; + FP->op = &optab[c]; + FP->narg = 0; + FP->phase = FP->op->sequence; + if(amldebug) print("\t%s %s", FP->op->name, FP->phase); + continue; + case '{': + end = PC; + c = pkglen(PC, FP->end, &PC); + end += c; + if(c < 0 || end > FP->end) + goto Overrun; + FP->end = end; + continue; + case ',': + FP->start = PC; + continue; + case 's': + if(end = memchr(PC, 0, FP->end - PC)) + end++; + else + end = FP->end; + c = end - PC; + r = mk('s', c+1); + memmove(r, PC, c); + ((uchar*)r)[c] = 0; + PC = end; + break; + case '1': case '2': case '4': case '8': + end = PC+(c-'0'); + if(end > FP->end) + goto Overrun; + else { + r = mki(*PC++); + for(i = 8; PC < end; i += 8) + *((uvlong*)r) |= ((uvlong)*PC++) << i; + } + break; + case '}': + case 0: + if(FP->op){ + if(amldebug){ + print("*%p,%V\t%s(", FP->aux, FP->ref, FP->op->name); + for(i = 0; i < FP->narg; i++){ + if(i > 0) + print(", "); + print("%V", FP->arg[i]); + } + print(")"); + } + for(i = FP->narg; i < nelem(FP->arg); i++) + FP->arg[i] = nil; + r = FP->op->eval(); + if(amldebug) + print(" -> %V", r); + } + + c = FP->phase[-1]; + if(c == '}' && PC < FP->end){ + FP->narg = 0; + FP->phase = "*}"; + continue; + } + + if(r) switch(FP->tag){ + case '@': + break; + case 'n': + case 'N': + if(TAG(r) != 'N') + r = nil; + break; + default: + if((r = deref(r)) == nil) + break; + switch(TAG(r)){ + case 'f': case 'u': + r = rwfield(r, nil, 0); + break; + case 'm': { + Method *m = r; + FP->ref = m; + FP->narg = 0; + FP->phase = "********}" + (8 - m->narg); + FP->op = &optab[Ocall]; + continue; + } + } + } + FP--; + break; + } + if(FP < FB){ + if(pret){ + if(amldebug) print(" => %V\n", r); + *pret = r; + } + return 0; + } + FP->arg[FP->narg++] = r; + } +Out: + if(amldebug) + dumpregs(); + return -1; +} + +static void* +evalnamec(void){ + int s, c, new; + Name *x, *dot; + + dot = FP->dot; + new = FP->tag == 'N'; + s = !new; + c = 1; + PC = FP->start; + if(*PC == '\\'){ + PC++; + dot = rootname(dot); + s = 0; + } + while(*PC == '^'){ + PC++; + dot = dot->up; + s = 0; + } + if(*PC == '.'){ + PC++; + c = 2; + } else if(*PC == '/'){ + PC++; + c = *PC++; + } else if(*PC == 0){ + PC++; + c = 0; + } else if(s){ + for(;;){ + if(x = getseg(dot, PC, 0)) + break; + if(dot == dot->up) + break; + dot = dot->up; + } + PC += 4; + return x; + } + while(c > 0){ + dot = getseg(dot, PC, new); + PC += 4; + c--; + } + return dot; +} + +static void* +evaliarg0(){ + return FP->arg[0]; +} + +static void* +evalconst(void){ + switch(FP->start[0]){ + case 0x01: + return mki(1); + case 0xFF: + return mki(-1); + } + return nil; +} + +static void* +evalbuf(void){ + int n, m; + uchar *p; + + n = ival(FP->arg[0]); + p = mk('b', n); + m = FP->end - PC; + if(m > n) + m = n; + memmove(p, PC, m); + PC = FP->end; + return p; +} + +static void* +evalpkg(void){ + Package *p; + int n; + + if(p = FP->ref){ + n = sizeof(Package)+p->n*sizeof(void*); + if(n < SIZE(p)) + p->a[p->n++] = FP->arg[0]; + }else { + n = sizeof(Package)+ival(FP->arg[0])*sizeof(void*); + p = mk('p', n); + FP->ref = p; + } + return p; +} + +static void* +evalname(void){ + Name *n; + + if(n = FP->arg[0]) + n->v = FP->arg[1]; + else + PC = FP->end; + return nil; +} + +static void* +evalscope(void){ + Name *n; + + if(n = FP->arg[0]) + FP->dot = n; + else + PC = FP->end; + FP->op = nil; + return nil; +} + +static void* +evalmet(void){ + Name *n; + if(n = FP->arg[0]){ + Method *m; + m = mk('m', sizeof(Method)); + m->narg = ival(FP->arg[1]) & 7; + m->start = PC; + m->end = FP->end; + m->name = n; + n->v = m; + } + PC = FP->end; + return nil; +} + +static void* +evalreg(void){ + Name *n; + if(n = FP->arg[0]){ + Region *r; + r = mk('r', sizeof(Region)); + r->space = ival(FP->arg[1]); + r->off = ival(FP->arg[2]); + r->len = ival(FP->arg[3]); + r->name = n; + n->v = r; + } + return nil; +} + +static void* +evalcfield(void){ + void *r; + Field *f; + Name *n; + int c; + + r = FP->arg[0]; + if(r == nil || (TAG(r) != 'b' && TAG(r) != 'r')) + return nil; + c = FP->op - optab; + if(c == Ocfld) + n = FP->arg[3]; + else + n = FP->arg[2]; + if(n == nil || TAG(n) != 'N') + return nil; + if(TAG(r) == 'b') + f = mk('u', sizeof(Field)); + else + f = mk('f', sizeof(Field)); + switch(c){ + case Ocfld: + f->bitoff = ival(FP->arg[1]); + f->bitlen = ival(FP->arg[2]); + break; + case Ocfld0: + f->bitoff = ival(FP->arg[1]); + f->bitlen = 1; + break; + case Ocfld1: + case Ocfld2: + case Ocfld4: + case Ocfld8: + f->bitoff = 8*ival(FP->arg[1]); + f->bitlen = 8*(c - Ocfld0); + break; + } + f->reg = r; + n->v = f; + return nil; +} + +static void* +evalfield(void){ + int flags, bitoff, wa, n; + Field *f, *df; + Name *d; + uchar *p; + + df = nil; + flags = 0; + bitoff = 0; + switch(FP->op - optab){ + case Ofld: + flags = ival(FP->arg[1]); + break; + case Oxfld: + df = deref(FP->arg[1]); + if(df == nil || TAG(df) != 'f') + goto Out; + flags = ival(FP->arg[2]); + break; + } + p = PC; + if(p >= FP->end) + return nil; + while(p < FP->end){ + if(*p == 0x00){ + p++; + if((n = pkglen(p, FP->end, &p)) < 0) + break; + bitoff += n; + continue; + } + if(*p == 0x01){ + p++; + flags = *p; + p += 2; + continue; + } + if(p+4 >= FP->end) + break; + if((d = getseg(FP->dot, p, 1)) == nil) + break; + if((n = pkglen(p+4, FP->end, &p)) < 0) + break; + f = mk('f', sizeof(Field)); + f->flags = flags; + f->bitlen = n; + switch(FP->op - optab){ + case Ofld: + f->reg = FP->arg[0]; + f->bitoff = bitoff; + break; + case Oxfld: + wa = fieldalign(df->flags); + f->reg = df->reg; + f->bitoff = df->bitoff + (bitoff % (wa*8)); + f->indexv = mki((bitoff/(wa*8))*wa); + f->index = FP->arg[0]; + break; + } + bitoff += n; + d->v = f; + } +Out: + PC = FP->end; + return nil; +} + +static void* +evalnop(void){ + return nil; +} + +static void* +evalbad(void){ + int i; + + print("bad opcode %p: ", PC); + for(i=0; i < 8 && (FP->start+i) < FP->end; i++){ + if(i > 0) + print(" "); + print("%.2X", FP->start[i]); + } + if((FP->start+i) < FP->end) + print("..."); + print("\n"); + PC = FP->end; + return nil; +} + +static void* +evalcond(void){ + switch(FP->op - optab){ + case Oif: + interp.cond = ival(FP->arg[0]) != 0; + if(!interp.cond) + PC = FP->end; + break; + case Oelse: + if(interp.cond) + PC = FP->end; + break; + case Owhile: + if(FP->aux){ + if(PC >= FP->end){ + PC = FP->start; + FP->aux = nil; + } + return nil; + } + FP->aux = FP->end; + interp.cond = ival(FP->arg[0]) != 0; + if(!interp.cond){ + PC = FP->end; + break; + } + return nil; + } + FP->op = nil; + return nil; +} + +static void* +evalcmp(void){ + void *a, *b; + int c; + + if((a = FP->arg[0]) == nil) + a = mki(0); + if((b = FP->arg[1]) == nil) + b = mki(0); + + switch(TAG(a)){ + default: + return nil; + case 'i': + c = ival(a) - ival(b); + break; + case 's': + if(TAG(b) != 's') + b = copy('s', b); + c = strcmp((char*)a, (char*)b); + break; + case 'b': + if(TAG(b) != 'b') + b = copy('b', b); + if((c = SIZE(a) - SIZE(b)) == 0) + c = memcmp(a, b, SIZE(a)); + break; + } + + switch(FP->op - optab){ + case Oleq: + if(c == 0) return mki(1); + break; + case Olgt: + if(c > 0) return mki(1); + break; + case Ollt: + if(c < 0) return mki(1); + break; + } + + return nil; +} + +static void* +evalcall(void){ + Method *m; + Env *e; + int i; + + if(FP->aux){ + if(PC >= FP->end){ + PC = FP->aux; + FP->end = PC; + } + return nil; + } + m = FP->ref; + e = mk('E', sizeof(Env)); + for(i=0; inarg; i++) + e->arg[i] = deref(FP->arg[i]); + FP->env = e; + FP->narg = 0; + FP->dot = m->name; + if(m->eval){ + FP->op = nil; + FP->end = PC; + return (*m->eval)(); + } + FP->dot = forkname(FP->dot); + FP->aux = PC; + FP->start = m->start; + FP->end = m->end; + PC = FP->start; + return nil; +} + +static void* +evalret(void){ + void *r = FP->arg[0]; + int brk = (FP->op - optab) != Oret; + while(--FP >= FB){ + switch(FP->op - optab){ + case Owhile: + if(!brk) + continue; + PC = FP->end; + return nil; + case Ocall: + PC = FP->aux; + return r; + } + } + FP = FB; + PC = FB->end; + return r; +} + +static void* +evalenv(void){ + Ref *r; + Env *e; + int c; + + if((e = FP->env) == nil) + return nil; + c = FP->start[0]; + if(c >= 0x60 && c <= 0x67){ + r = mk('L', sizeof(Ref)); + r->ptr = &e->loc[c - 0x60]; + } else if(c >= 0x68 && c <= 0x6E){ + r = mk('A', sizeof(Ref)); + r->ptr = &e->arg[c - 0x68]; + } else + return nil; + r->ref = e; + return r; +} + +static void* +evalstore(void){ + return store(FP->arg[0], FP->arg[1]); +} + +static void* +evalindex(void){ + Field *f; + void *p; + Ref *r; + int x; + + x = ival(FP->arg[1]); + if(p = FP->arg[0]) switch(TAG(p)){ + case 's': + if(x >= strlen((char*)p)) + break; + /* no break */ + case 'b': + if(x < 0 || x >= SIZE(p)) + break; + f = mk('u', sizeof(Field)); + f->reg = p; + f->bitlen = 8; + f->bitoff = 8*x; + store(f, FP->arg[2]); + return f; + case 'p': + if(x < 0 || x >= ((Package*)p)->n) + break; + r = mk('R', sizeof(Ref)); + r->ref = p; + r->ptr = &((Package*)p)->a[x]; + store(r, FP->arg[2]); + return r; + } + return nil; +} + +static void* +evalcondref(void){ + void *s; + if((s = FP->arg[0]) == nil) + return nil; + store(s, FP->arg[1]); + return mki(1); +} + +static void* +evalsize(void){ + return mki(amllen(FP->arg[0])); +} + +static void* +evalderef(void){ + void *p; + + if(p = FP->arg[0]){ + if(TAG(p) == 's') + p = getname(FP->dot, (char*)p, 0); + p = deref(p); + } + return p; +} + +static void* +evalarith(void){ + void *r = nil; + switch(FP->op - optab){ + case Oadd: + r = mki(ival(FP->arg[0]) + ival(FP->arg[1])); + break; + case Osub: + r = mki(ival(FP->arg[0]) - ival(FP->arg[1])); + break; + case Omod: + { + uvlong d; + d = ival(FP->arg[1]); + r = mki(ival(FP->arg[0]) % d); + } + break; + case Omul: + r = mki(ival(FP->arg[0]) * ival(FP->arg[1])); + break; + case Odiv: + { + uvlong v, d; + v = ival(FP->arg[0]); + d = ival(FP->arg[1]); + r = mki(v / d); + if(FP->arg[2]) + store(mki(v % d), FP->arg[2]); + store(r, FP->arg[3]); + return r; + } + case Oshl: + r = mki(ival(FP->arg[0]) << ival(FP->arg[1])); + break; + case Oshr: + r = mki(ival(FP->arg[0]) >> ival(FP->arg[1])); + break; + case Oand: + r = mki(ival(FP->arg[0]) & ival(FP->arg[1])); + break; + case Onand: + r = mki(~(ival(FP->arg[0]) & ival(FP->arg[1]))); + break; + case Oor: + r = mki(ival(FP->arg[0]) | ival(FP->arg[1])); + break; + case Onor: + r = mki(~(ival(FP->arg[0]) | ival(FP->arg[1]))); + break; + case Oxor: + r = mki(ival(FP->arg[0]) ^ ival(FP->arg[1])); + break; + case Onot: + r = mki(~ival(FP->arg[0])); + store(r, FP->arg[1]); + return r; + case Oland: + return mki(ival(FP->arg[0]) && ival(FP->arg[1])); + case Olor: + return mki(ival(FP->arg[0]) || ival(FP->arg[1])); + case Olnot: + return mki(ival(FP->arg[0]) == 0); + + case Oinc: + r = mki(ival(deref(FP->arg[0]))+1); + store(r, FP->arg[0]); + return r; + case Odec: + r = mki(ival(deref(FP->arg[0]))-1); + store(r, FP->arg[0]); + return r; + } + + store(r, FP->arg[2]); + return r; +} + +static Op optab[] = { + [Obad] "", "", evalbad, + [Onop] "Noop", "", evalnop, + + [Ostr] ".str", "s", evaliarg0, + [Obyte] ".byte", "1", evaliarg0, + [Oword] ".word", "2", evaliarg0, + [Odword] ".dword", "4", evaliarg0, + [Oqword] ".qword", "8", evaliarg0, + [Oconst] ".const", "", evalconst, + [Onamec] ".name", "", evalnamec, + [Oenv] ".env", "", evalenv, + + [Oname] "Name", "N*", evalname, + [Oscope] "Scope", "{n}", evalscope, + + [Odev] "Device", "{N}", evalscope, + [Ocpu] "Processor", "{N141}", evalscope, + [Othz] "ThermalZone", "{N}", evalscope, + [Oprc] "PowerResource", "{N12}", evalscope, + + [Oreg] "OperationRegion", "N1ii", evalreg, + [Ofld] "Field", "{n1", evalfield, + [Oxfld] "IndexField", "{nn1", evalfield, + + [Ocfld] "CreateField", "*iiN", evalcfield, + [Ocfld0] "CreateBitField", "*iN", evalcfield, + [Ocfld1] "CreateByteField", "*iN", evalcfield, + [Ocfld2] "CreateWordField", "*iN", evalcfield, + [Ocfld4] "CreateDWordField", "*iN", evalcfield, + [Ocfld8] "CreateQWordField", "*iN", evalcfield, + + [Opkg] "Package", "{1}", evalpkg, + [Ovpkg] "VarPackage", "{i}", evalpkg, + [Obuf] "Buffer", "{i", evalbuf, + [Omet] "Method", "{N1", evalmet, + + [Oadd] "Add", "ii@", evalarith, + [Osub] "Subtract", "ii@", evalarith, + [Omod] "Mod", "ii@", evalarith, + [Omul] "Multiply", "ii@", evalarith, + [Odiv] "Divide", "ii@@", evalarith, + [Oshl] "ShiftLef", "ii@", evalarith, + [Oshr] "ShiftRight", "ii@", evalarith, + [Oand] "And", "ii@", evalarith, + [Onand] "Nand", "ii@", evalarith, + [Oor] "Or", "ii@", evalarith, + [Onor] "Nor", "ii@", evalarith, + [Oxor] "Xor", "ii@", evalarith, + [Onot] "Not", "i@", evalarith, + + [Oinc] "Increment", "@", evalarith, + [Odec] "Decrement", "@", evalarith, + + [Oland] "LAnd", "ii", evalarith, + [Olor] "LOr", "ii", evalarith, + [Olnot] "LNot", "i", evalarith, + + [Oleq] "LEqual", "**", evalcmp, + [Olgt] "LGreater", "**", evalcmp, + [Ollt] "LLess", "**", evalcmp, + + [Omutex] "Mutex", "N1", evalnop, + [Oevent] "Event", "N", evalnop, + + [Oif] "If", "{i}", evalcond, + [Oelse] "Else", "{}", evalcond, + [Owhile] "While", "{,i}", evalcond, + [Obreak] "Break", "", evalret, + [Oret] "Return", "*", evalret, + [Ocall] "Call", "", evalcall, + + [Ostore] "Store", "*@", evalstore, + [Oindex] "Index", "*i@", evalindex, + [Osize] "SizeOf", "*", evalsize, + [Oref] "RefOf", "@", evaliarg0, + [Ocref] "CondRefOf", "@@", evalcondref, + [Oderef] "DerefOf", "@", evalderef, + + [Oacq] "Acquire", "@2", evalnop, + [Orel] "Release", "@", evalnop, +}; + +static uchar octab1[] = { +/* 00 */ Oconst, Oconst, Obad, Obad, Obad, Obad, Obad, Obad, +/* 08 */ Oname, Obad, Obyte, Oword, Odword, Ostr, Oqword, Obad, +/* 10 */ Oscope, Obuf, Opkg, Ovpkg, Omet, Obad, Obad, Obad, +/* 18 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 20 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 28 */ Obad, Obad, Obad, Obad, Obad, Obad, Onamec, Onamec, +/* 30 */ Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, +/* 38 */ Onamec, Onamec, Obad, Obad, Obad, Obad, Obad, Obad, +/* 40 */ Obad, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, +/* 48 */ Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, +/* 50 */ Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, +/* 58 */ Onamec, Onamec, Onamec, Obad, Onamec, Obad, Onamec, Onamec, +/* 60 */ Oenv, Oenv, Oenv, Oenv, Oenv, Oenv, Oenv, Oenv, +/* 68 */ Oenv, Oenv, Oenv, Oenv, Oenv, Oenv, Oenv, Obad, +/* 70 */ Ostore, Oref, Oadd, Obad, Osub, Oinc, Odec, Omul, +/* 78 */ Odiv, Oshl, Oshr, Oand, Onand, Oor, Onor, Oxor, +/* 80 */ Onot, Obad, Obad, Oderef, Obad, Omod, Obad, Osize, +/* 88 */ Oindex, Obad, Ocfld4, Ocfld2, Ocfld1, Ocfld0, Obad, Ocfld8, +/* 90 */ Oland, Olor, Olnot, Oleq, Olgt, Ollt, Obad, Obad, +/* 98 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* A0 */ Oif, Oelse, Owhile, Onop, Oret, Obreak, Obad, Obad, +/* A8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* B0 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* B8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* C0 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* C8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* D0 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* D8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* E0 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* E8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* F0 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* F8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Oconst, +}; + +static uchar octab2[] = { +/* 00 */ Obad, Omutex, Oevent, Obad, Obad, Obad, Obad, Obad, +/* 08 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 10 */ Obad, Obad, Ocref, Ocfld, Obad, Obad, Obad, Obad, +/* 18 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 20 */ Obad, Obad, Obad, Oacq, Obad, Obad, Obad, Orel, +/* 28 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 30 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 38 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 40 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 48 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 50 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 58 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 60 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 68 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 70 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 78 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 80 */ Oreg, Ofld, Odev, Ocpu, Oprc, Othz, Oxfld, Obad, +/* 88 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 90 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 98 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* A0 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* A8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* B0 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* B8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* C0 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* C8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* D0 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* D8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* E0 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* E8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* F0 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* F8 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +}; + +int +amltag(void *p){ + return p ? TAG(p) : 0; +} + +void* +amlval(void *p){ + p = deref(p); + if(p && TAG(p) == 'p') + p = ((Package*)p)->a; + return p; +} + +uvlong +amlint(void *p){ + return ival(p); +} + +int +amllen(void *p){ + while(p){ + switch(TAG(p)){ + case 'R': + p = *((Ref*)p)->ptr; + continue; + case 's': + return strlen((char*)p); + case 'p': + return ((Package*)p)->n; + default: + return SIZE(p); + } + } + return 0; +} + +void +amlinit(void){ + Name *n; + + fmtinstall('V', Vfmt); + fmtinstall('N', Nfmt); + + n = mk('N', sizeof(Name)); + n->up = n; + + amlroot = n; + + getname(amlroot, "_GPE", 1); + getname(amlroot, "_PR", 1); + getname(amlroot, "_SB", 1); + getname(amlroot, "_TZ", 1); + getname(amlroot, "_SI", 1); + + if(n = getname(amlroot, "_REV", 1)) + n->v = mki(2); + if(n = getname(amlroot, "_OS", 1)) + n->v = mks("Microsoft Windows"); + if(n = getname(amlroot, "_OSI", 1)){ + Method *m; + + m = mk('m', sizeof(Method)); + m->narg = 1; + m->eval = evalnop; + m->name = n; + n->v = m; + } +} + +void +amlexit(void){ + amlroot = nil; + FP = FB-1; + gc(); +} + +int +amlload(uchar *data, int len){ + return xec(data, data+len, amlroot, nil, nil); +} + +void* +amlwalk(void *dot, char *name){ + return getname(dot, name, 0); +} + +void +amlenum(void *dot, char *seg, int (*proc)(void *, void *), void *arg){ + Name *n, *d; + int rec; + + d = dot; + if(d == nil || TAG(d) != 'N') + return; + do { + rec = 1; + if(seg == nil || memcmp(seg, d->seg, sizeof(d->seg)) == 0) + rec = (*proc)(d, arg) == 0; + for(n = d->down; n && rec; n = n->next) + amlenum(n, seg, proc, arg); + d = d->fork; + } while(d); +} + +int +amleval(void *dot, char *fmt, ...){ + va_list a; + Method *m; + void **r; + Env *e; + int i; + + va_start(a, fmt); + e = *fmt ? mk('E', sizeof(Env)) : nil; + for(i=0;*fmt;fmt++){ + switch(*fmt){ + case 's': + e->arg[i++] = mks(va_arg(a, char*)); + break; + case 'i': + e->arg[i++] = mki(va_arg(a, int)); + break; + case 'I': + e->arg[i++] = mki(va_arg(a, uvlong)); + break; + } + } + r = va_arg(a, void**); + va_end(a); + if(dot = deref(dot)) switch(TAG(dot)){ + case 'm': + m = dot; + if(i != m->narg) + return -1; + return xec(m->start, m->end, forkname(m->name), e, r); + } + if(r) *r = dot; + return 0; +} diff --git a/sys/src/libaml/mkfile b/sys/src/libaml/mkfile new file mode 100644 index 000000000..2195e6006 --- /dev/null +++ b/sys/src/libaml/mkfile @@ -0,0 +1,15 @@ +