git: 9front

Download patch

ref: 194c910a56cfc15c42fdc213f01eda3466d5b24c
parent: b4fa401072996fd74048016271bd8cd48d7bdcb8
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Sun Jun 17 19:12:19 EDT 2012

experimental acpi support for apic irq routing

--- /dev/null
+++ b/sys/include/aml.h
@@ -1,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*);
--- a/sys/src/9/pc/acpi.c
+++ /dev/null
@@ -1,219 +1,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);
-}
--- /dev/null
+++ b/sys/src/9/pc/archacpi.c
@@ -1,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;
+}
--- a/sys/src/9/pc/archmp.c
+++ b/sys/src/9/pc/archmp.c
@@ -7,8 +7,353 @@
 
 #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 @@
 .id=		"_MP_",	
 .ident=		identify,
 .reset=		mpshutdown,
-.intrinit=	mpinit,
+.intrinit=	pcmpinit,
 .intrenable=	mpintrenable,
 .intron=	lapicintron,
 .introff=	lapicintroff,
@@ -72,7 +417,7 @@
 identify(void)
 {
 	char *cp;
-	PCMP *pcmp;
+	_MP_ *_mp_;
 	uchar *p, sum;
 	ulong length;
 
@@ -90,8 +435,10 @@
 		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;
@@ -98,42 +445,13 @@
 	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;
 }
--- a/sys/src/9/pc/io.h
+++ b/sys/src/9/pc/io.h
@@ -271,6 +271,7 @@
 	Pcidev*	list;
 	Pcidev*	link;			/* next device on this bno */
 
+	Pcidev*	parent;			/* up a bus */
 	Pcidev*	bridge;			/* down a bus */
 	struct {
 		ulong	bar;
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -68,6 +68,7 @@
 	/$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'}
--- 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 @@
 	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 @@
 	}
 }
 
+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,142 +278,57 @@
 	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;
+	apic = nil;
+	for(i=0; i<=MaxAPICNO; i++){
+		if(mpapic[i] == nil)
+			continue;
+		if(mpapic[i]->flags & PcmpBP){
+			apic = mpapic[i];
+			break;
+		}
 	}
 
-	/*
-	 * No bootstrap processor, no need to go further.
-	 */
-	if(bpapic == 0)
+	if(apic == nil){
+		panic("mpinit: no bootstrap processor");
 		return;
-	bpapic->online = 1;
+	}
+	apic->online = 1;
+	lapicinit(apic);
 
-	lapicinit(bpapic);
-
 	/*
 	 * These interrupts are local to the processor
 	 * and do not appear in the I/O APIC so it is OK
@@ -670,6 +380,8 @@
 static int
 mpintrcpu(void)
 {
+	static Lock physidlock;
+	static int physid;
 	int i;
 
 	/*
@@ -689,17 +401,17 @@
 	 * 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,16 +453,21 @@
 	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;
@@ -757,7 +474,20 @@
 		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 @@
 	/*
 	 * 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 @@
 	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.
--- a/sys/src/9/pc/mp.h
+++ b/sys/src/9/pc/mp.h
@@ -162,6 +162,7 @@
 
 	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 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[];
--- a/sys/src/9/pc/pccpuf
+++ b/sys/src/9/pc/pccpuf
@@ -41,7 +41,6 @@
 	devpccard
 	devi82365
 	cputemp
-	acpi
 	apm		apmjump
 	ether2000	ether8390
 	ether2114x	pci
@@ -79,6 +78,7 @@
 	audiohda
 
 misc
+	archacpi	mp apic
 	archmp		mp apic
 	mtrr
 
--- a/sys/src/9/pc/pcf
+++ b/sys/src/9/pc/pcf
@@ -42,7 +42,6 @@
 	devpccard
 	devi82365
 	cputemp
-	acpi
 	apm		apmjump
 	ether2000	ether8390
 	ether2114x	pci
@@ -81,6 +80,7 @@
 	audiohda
 
 misc
+	archacpi	mp apic
 	archmp		mp apic
 	mtrr
 
--- a/sys/src/9/pc/pci.c
+++ b/sys/src/9/pc/pci.c
@@ -367,7 +367,7 @@
 }
 
 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 @@
 				break;
 			}
 
+			p->parent = parent;
 			if(head != nil)
 				tail->link = p;
 			else
@@ -494,7 +495,7 @@
 			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 @@
 		else {
 			if(ubn > maxubn)
 				maxubn = ubn;
-			pcilscan(sbn, &p->bridge);
+			pcilscan(sbn, &p->bridge, p);
 		}
 	}
 
@@ -515,7 +516,7 @@
 	int ubn;
 
 	lock(&pcicfginitlock);
-	ubn = pcilscan(bno, list);
+	ubn = pcilscan(bno, list, nil);
 	unlock(&pcicfginitlock);
 	return ubn;
 }
@@ -1004,7 +1005,7 @@
 	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;
--- /dev/null
+++ b/sys/src/libaml/aml.c
@@ -1,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;
+}
--- /dev/null
+++ b/sys/src/libaml/mkfile
@@ -1,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
--