summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2012-06-17 23:12:19 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2012-06-17 23:12:19 +0200
commita47521a3ede91ef06bf7938722c490893d5458f6 (patch)
tree9337bcdee5c2cea704a9a28652abb5b873947c32
parent9cb66f310b16b51526fd3f5480b69a54589e229e (diff)
experimental acpi support for apic irq routing
-rw-r--r--sys/include/aml.h36
-rw-r--r--sys/src/9/pc/acpi.c219
-rw-r--r--sys/src/9/pc/archacpi.c525
-rw-r--r--sys/src/9/pc/archmp.c392
-rw-r--r--sys/src/9/pc/io.h1
-rw-r--r--sys/src/9/pc/mkfile1
-rw-r--r--sys/src/9/pc/mp.c489
-rw-r--r--sys/src/9/pc/mp.h9
-rw-r--r--sys/src/9/pc/pccpuf2
-rw-r--r--sys/src/9/pc/pcf2
-rw-r--r--sys/src/9/pc/pci.c11
-rw-r--r--sys/src/libaml/aml.c1818
-rw-r--r--sys/src/libaml/mkfile15
13 files changed, 2876 insertions, 644 deletions
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; 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);
-}
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 <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;
+}
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;
+ return 0;
}
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;
-
-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;
+/* filled in by pcmpinit or acpiinit */
+Bus* mpbus;
+Bus* mpbuslast;
+int mpisabus = -1;
+int mpeisabus = -1;
+Apic *mpioapic[MaxAPICNO+1];
+Apic *mpapic[MaxAPICNO+1];
- apicno = p->apicno;
- if(!(p->flags & PcmpEN) || apicno >= nelem(mpioapic) || mpioapic[apicno] != nil)
- return 0;
- /*
- * Map the I/O APIC.
- */
- if((va = vmap(p->addr, 1024)) == nil)
- return 0;
- if((apic = xalloc(sizeof(Apic))) == nil)
- panic("mkioapic: no memory for Apic");
- apic->type = PcmpIOAPIC;
- apic->apicno = apicno;
- apic->addr = va;
- apic->paddr = p->addr;
- apic->flags = p->flags;
- mpioapic[apicno] = apic;
-
- return apic;
-}
-
-static Aintr*
-mkiointr(PCMPintr* p)
-{
- Bus *bus;
- Aintr *aintr;
- PCMPintr* pcmpintr;
-
- /*
- * According to the MultiProcessor Specification, a destination
- * I/O APIC of 0xFF means the signal is routed to all I/O APICs.
- * It's unclear how that can possibly be correct so treat it as
- * an error for now.
- */
- if(p->apicno >= nelem(mpioapic) || mpioapic[p->apicno] == nil)
- return 0;
-
- if((bus = mpgetbus(p->busno)) == 0)
- return 0;
-
- if((aintr = xalloc(sizeof(Aintr))) == nil)
- panic("iointr: no memory for Aintr");
- aintr->intr = p;
-
- if(0)
- print("iointr: type %d intr type %d flags %#o "
- "bus %d irq %d apicno %d intin %d\n",
- p->type, p->intr, p->flags,
- p->busno, p->irq, p->apicno, p->intin);
- /*
- * Hack for Intel SR1520ML motherboard, which BIOS describes
- * the i82575 dual ethernet controllers incorrectly.
- */
- if(memcmp(mppcmp->product, "INTEL X38MLST ", 20) == 0){
- if(p->busno == 1 && p->intin == 16 && p->irq == 1){
- if((pcmpintr = xalloc(sizeof(PCMPintr))) == nil)
- panic("iointr: no memory for PCMPintr");
- memmove(pcmpintr, p, sizeof(PCMPintr));
- print("mkiointr: %20.20s bus %d intin %d irq %d\n",
- (char*)mppcmp->product,
- pcmpintr->busno, pcmpintr->intin,
- pcmpintr->irq);
- pcmpintr->intin = 17;
- aintr->intr = pcmpintr;
- }
- }
- aintr->apic = mpioapic[p->apicno];
- aintr->next = bus->aintr;
- bus->aintr = aintr;
-
- return aintr;
-}
-
-static int
+int
mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
{
int el, po, v;
@@ -284,47 +90,6 @@ mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
return v;
}
-static int
-mklintr(PCMPintr* p)
-{
- Apic *apic;
- Bus *bus;
- int i, intin, v;
-
- /*
- * The offsets of vectors for LINT[01] are known to be
- * 0 and 1 from the local APIC vector space at VectorLAPIC.
- */
- if((bus = mpgetbus(p->busno)) == 0)
- return 0;
- intin = p->intin;
-
- /*
- * Pentium Pros have problems if LINT[01] are set to ExtINT
- * so just bag it, SMP mode shouldn't need ExtINT anyway.
- */
- if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
- v = ApicIMASK;
- else
- v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
-
- if(p->apicno == 0xFF){
- for(i=0; i<nelem(mpapic); i++){
- if((apic = mpapic[i]) == nil)
- continue;
- if(apic->flags & PcmpEN)
- apic->lintr[intin] = v;
- }
- }
- else{
- if(apic = mpapic[p->apicno])
- if(apic->flags & PcmpEN)
- apic->lintr[intin] = v;
- }
-
- return v;
-}
-
static void
checkmtrr(void)
{
@@ -377,6 +142,36 @@ checkmtrr(void)
}
}
+uvlong
+tscticks(uvlong *hz)
+{
+ if(hz != nil)
+ *hz = m->cpuhz;
+
+ cycles(&m->tscticks); /* Uses the rdtsc instruction */
+ return m->tscticks;
+}
+
+void
+syncclock(void)
+{
+ uvlong x;
+
+ if(arch->fastclock != tscticks)
+ return;
+
+ if(m->machno == 0){
+ wrmsr(0x10, 0);
+ m->tscticks = 0;
+ } else {
+ x = MACHP(0)->tscticks;
+ while(x == MACHP(0)->tscticks)
+ ;
+ wrmsr(0x10, MACHP(0)->tscticks);
+ cycles(&m->tscticks);
+ }
+}
+
static void
squidboy(Apic* apic)
{
@@ -483,141 +278,56 @@ mpstartap(Apic* apic)
nvramwrite(0x0F, 0x00);
}
-static void
-dumpmp(uchar *p, uchar *e)
-{
- int i;
-
- for(i = 0; p < e; p++) {
- if((i % 16) == 0) print("*mp%d=", i/16);
- print("%.2x ", *p);
- if((++i % 16) == 0) print("\n");
- }
- if((i % 16) != 0) print("\n");
-}
-
-static void
-mpoverride(uchar** newp, uchar** e)
-{
- int size, i, j;
- char buf[20];
- uchar* p;
- char* s;
-
- size = atoi(getconf("*mp"));
- if(size == 0) panic("mpoverride: invalid size in *mp");
- *newp = p = xalloc(size);
- if(p == nil) panic("mpoverride: can't allocate memory");
- *e = p + size;
- for(i = 0; ; i++){
- snprint(buf, sizeof buf, "*mp%d", i);
- s = getconf(buf);
- if(s == nil) break;
- while(*s){
- j = strtol(s, &s, 16);
- if(*s && *s != ' ' || j < 0 || j > 0xff) panic("mpoverride: invalid entry in %s", buf);
- if(p >= *e) panic("mpoverride: overflow in %s", buf);
- *p++ = j;
- }
- }
- if(p != *e) panic("mpoverride: size doesn't match");
-}
-
void
mpinit(void)
{
int ncpu, i;
+ Apic *apic;
char *cp;
- PCMP *pcmp;
- uchar *e, *p;
- Apic *apic, *bpapic;
- void *va;
i8259init();
syncclock();
- if(_mp_ == 0)
- return;
- pcmp = KADDR(_mp_->physaddr);
-
- /*
- * 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++;
+ if(getconf("*apicdebug")){
+ Bus *b;
+ Aintr *ai;
+ PCMPintr *pi;
+
+ 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;
+ 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);
+ }
+ }
+ }
- 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;
+ apic = nil;
+ for(i=0; i<=MaxAPICNO; i++){
+ if(mpapic[i] == nil)
+ continue;
+ if(mpapic[i]->flags & PcmpBP){
+ apic = mpapic[i];
+ break;
}
- 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)
+ if(apic == nil){
+ panic("mpinit: no bootstrap processor");
return;
- bpapic->online = 1;
-
- lapicinit(bpapic);
+ }
+ 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 <u.h>
+#include <libc.h>
+#include <aml.h>
+
+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; i<nelem(e->loc); i++)
+ gcmark(e->loc[i]);
+ for(i=0; i<nelem(e->arg); 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; i<a->n; 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; i<f->narg; 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<len; i++){
+ p[off+i] = v & 0xFF;
+ v >>= 8;
+ }
+ } else {
+ for(i=0; i<len; i++)
+ v |= ((uvlong)p[off+i]) << i*8;
+ }
+ return v;
+ case 'r':
+ r = reg;
+ if((off+len) > 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<SIZE(b); i++){
+ b[i] = w & 0xFF;
+ w >>= 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<<i;
+ w <<= ws;
+ if(wl != wd){
+ m = ((1LL<<wl)-1) << ws;
+ w |= rwreg(reg, wo*wa, wa, 0, 0) & ~m;
+ }
+ rwreg(reg, wo*wa, wa, w, 1);
+ } else {
+ w = rwreg(reg, wo*wa, wa, 0, 0) >> 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; i<SIZE(b); i++)
+ w |= ((uvlong)b[i]) << i*8;
+ return mki(w);
+}
+
+static void*
+deref(void *p){
+ if(p) switch(TAG(p)){
+ case 'N':
+ return ((Name*)p)->v;
+ 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; i<a->n; 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<n; i++){
+ if(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; i<f->narg; i++){
+ if(i > 0)
+ print(", ");
+ print("%V", f->arg[i]);
+ }
+ print(")\n");
+ if(e == f->env)
+ continue;
+ if(e = f->env){
+ for(i=0; i<nelem(e->arg); i++)
+ print("Arg%d=%V ", i, e->arg[i]);
+ print("\n");
+ for(i=0; i<nelem(e->loc); 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; i<FP->narg; 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 @@
+</$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