diff -r 18027a7fe237 sys/include/aml.h
--- a/sys/include/aml.h	Wed Jun 26 02:30:43 2013 +0200
+++ b/sys/include/aml.h	Fri Jun 28 22:14:50 2013 +0400
@@ -24,6 +24,7 @@
 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	*amlmkbuf(void *, int);
 
 void*		amlroot;
 int		amldebug;
@@ -34,3 +35,6 @@
 /* to be provided by operating system */
 extern void*	amlalloc(int);
 extern void	amlfree(void*);
+extern void 	acpi_read(uchar, uvlong, uvlong, uvlong *);
+extern void 	acpi_write(uchar, uvlong, uvlong, uvlong);
+extern void 	acpi_delay(int);
diff -r 18027a7fe237 sys/src/9/pc/acpiec.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/9/pc/acpiec.c	Fri Jun 28 22:14:50 2013 +0400
@@ -0,0 +1,240 @@
+#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>
+
+struct Gas {
+	uchar 	space;
+	uchar 	bw;
+	uchar	bo;
+	uchar 	size;
+	uchar	addr[8];
+};
+
+struct Ecdt {
+	struct Gas	ec_cmd;
+	struct Gas 	ec_data;
+	uchar 		uid[4];
+	uchar 		gpe;
+	uchar 		id[1];
+};
+
+struct ec {
+	int cmd;
+	int data;
+	int ready;
+} ec;
+
+enum { 
+	/* status bits */
+	OutBufFull = 0x01, 
+	InBufFull  = 0x02,
+	DataIsCmd  = 0x08,
+	Burst      = 0x10,
+	SciEvt     = 0x20,
+	SmiEvt     = 0x40,
+	/* commands */
+	EcRead 	   = 0x80,
+	EcWrite    = 0x81,
+	EcBurstEn  = 0x82,
+	EcBurstDis = 0x83,
+	EcQuery	   = 0x84,
+};
+
+static void
+acpiec_wait(uchar mask, uchar val)
+{
+	uchar stat;
+
+	while((stat = inb(ec.cmd) & mask) != val) {
+		if (stat & Burst)
+			delay(1);
+	}
+}
+
+static uchar
+acpiec_read_data(void)
+{
+	acpiec_wait(OutBufFull, OutBufFull);
+	return inb(ec.data);
+}
+
+static void
+acpiec_write_data(uchar val)
+{
+	acpiec_wait(InBufFull, 0);
+	outb(ec.data, val);
+}
+
+static void
+acpiec_write_cmd(uchar val)
+{
+	acpiec_wait(InBufFull, 0);
+	outb(ec.cmd, val);
+}
+
+uchar
+acpiec_read(uchar addr)
+{
+	if (!ec.ready)
+		return 0;
+	acpiec_write_cmd(EcRead);
+	acpiec_write_data(addr);
+	
+	return acpiec_read_data();
+}
+
+void
+acpiec_write(uchar addr, uvlong val)
+{
+	int i;
+	uchar *v = (uchar*)&val;
+
+	if (!ec.ready)
+		return;
+
+	for(i = 0; i < sizeof(uvlong); i++) {
+		acpiec_write_cmd(EcWrite);
+		acpiec_write_data(addr + i); // ?
+		acpiec_write_data(v[i]);
+	}
+}
+
+static int
+acpiec_getreg(unsigned char *buf, int size, int *type, int *addr)
+{
+	enum { ResTypeMask = 0x80, ResLengthMask = 0x07,
+		   ResTypeIoPort = 0x47, ResTypeEndTag = 0x79 };
+
+	enum { SystemIoSpace = 1 };
+
+	int len, hlen;
+
+	if (size <= 0)
+		return 0;
+	if (*buf & ResTypeMask) {
+		/* large resource */
+		if (size < 3)
+			return 1;
+		len = (int)buf[1] + 256 * (int)buf[2];
+		hlen = 3;
+	} else {
+		/* small resource */
+		len = buf[0] & ResLengthMask;
+		hlen = 1;
+	}
+	if (*buf != ResTypeIoPort)
+		return 0;
+
+	if (size < hlen + len)
+		return 0;
+	
+	*type = SystemIoSpace;
+	*addr = (int)buf[2] + 256 * (int)buf[3];
+
+	return (hlen + len);
+}
+
+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);
+}
+
+void
+acpiec_init(void *dot, void *tbl)
+{
+	void *m;
+	char *buf;
+	void *p;
+	int gpe;
+	int rv, size, t;
+	int ec_sc, ec_data;
+	struct Ecdt *ecdt = tbl;
+
+	if(ec.ready)
+		return;
+	if(ecdt != nil) {
+		ecdt = (struct Ecdt*)tbl;
+		ec_sc = get64(ecdt->ec_cmd.addr);
+		ec_data = get64(ecdt->ec_data.addr);
+		gpe = ecdt->gpe;
+		goto done;
+	}
+
+	if((m = amlwalk(dot, "_GPE")) == 0) {
+		print("ec: no _GPE\n");
+		return;
+	}
+	if(amleval(m, "", &p) < 0) {
+		print("ec: _GPE not working\n");
+		return;
+	}
+
+	gpe = amlint(amlval(p));
+
+	if((m = amlwalk(dot, "_CRS")) == 0) {
+		print("ec: no _CRS\n");
+		return;
+	}
+	if(amleval(m, "", &buf) < 0) {
+		print("ec: _CRS not working\n");
+		return;
+	}
+	if(amltag(buf) != 'b') {
+		print("ec: unknown _CRS type\n");
+		return;
+	}
+	size = amllen(buf);
+	rv = acpiec_getreg(amlval(buf), size, &t, &ec_data);
+	//print("getreg: rv=%d t=%d ec_data=0x%x\n", rv, t, ec_data);
+
+	buf += rv;
+	size -= rv;
+
+	rv = acpiec_getreg(amlval(buf), size, &t, &ec_sc);
+	//print("getreg: rv=%d t=%d ec_sc=0x%x\n", rv, t, ec_sc);
+
+	buf += rv;
+	size -= rv;
+
+	if(size != 2 || *buf != 0x79) {
+		print("no crs endtag\n");
+	}
+
+	/* register */
+	enum { RegTypeEC = 3 };
+	if((m = amlwalk(dot, "_REG")) == 0) {
+		print("ec: no _REG\n");
+		return;
+	}
+	if(amleval(m, "ii", RegTypeEC, 1, nil) < 0) {
+		print("ec: _REG not working\n");
+		return;
+	}	
+done:
+	if(ioalloc(ec_data, 1, 0, "ec_data") < 0)
+		print("ec: ec_data port space in use");
+	if(ioalloc(ec_sc, 1, 0, "ec_sc") < 0)
+		print("ec: ec_sc port space in use");
+	print("ec: status: %d gpe: %d data: 0x%x s/c: 0x%x \n",
+		inb(ec_sc), gpe, ec_data, ec_sc);	
+	ec.cmd = ec_sc;
+	ec.data = ec_data;
+	ec.ready = 1;
+}
\ No newline at end of file
diff -r 18027a7fe237 sys/src/9/pc/archacpi.c
--- a/sys/src/9/pc/archacpi.c	Wed Jun 26 02:30:43 2013 +0200
+++ b/sys/src/9/pc/archacpi.c	Fri Jun 28 22:14:50 2013 +0400
@@ -41,6 +41,20 @@
 	Tblsz	= 4+4+1+1+6+8+4+4+4,
 };
 
+struct Fadt {
+	uchar firmware_ctl[4];
+	uchar dsdt[4];
+	uchar int_model;
+	uchar pm_profile;
+	uchar sci_int[2];
+	uchar smi_cmd[4];
+	uchar acpi_enable;
+	uchar acpi_disable;
+	uchar s4bios_req;
+	uchar pstate_cnt;
+	uchar data[];
+};
+
 static Rsd *rsd;
 
 /* physical addresses visited by maptable() */
@@ -51,6 +65,10 @@
 static int ntblmap;
 static Tbl *tblmap[64];
 
+extern void acpiec_init(void *, void *);
+extern uchar acpiec_read(uchar);
+extern void acpiec_write(uchar, uvlong);
+
 void*
 amlalloc(int n){
 	void *p;
@@ -333,6 +351,85 @@
 	return 1;
 }
 
+static int 
+findec(void *dot, void *)
+{
+	void *p;
+	char *id;
+
+	id = nil;
+	p = nil;
+	if(amleval(dot, "", &p) == 0)
+		id = eisaid(p);
+
+	/* EC is all we care about */
+	if(id && (!strcmp(id, "PNP0C09"))) {
+		acpiec_init(dot, nil);
+		return 0;
+	}
+	return -1;
+}
+
+void 
+acpi_read(uchar space, uvlong off, uvlong len, uvlong *buf)
+{
+	uintptr pa;
+	void *p;
+
+	pa = off;
+	//print("acpi_read: space %d off 0x%ullx len %ulld\n", space, off, len);
+	switch (space) {
+		case 0x00: // MemSpace
+			if (p = vmap(pa, len)) {
+				memmove(buf, p, len);
+				vunmap(p, len);
+			}
+			break;
+		case 0x01: // IoSpace
+			*buf = inb(off);
+			break;
+		case 0x03: // EbctlSpace
+			*buf = acpiec_read(off);
+			break;
+		default:
+			print("reading from space %d not implemented\n", space);
+			*buf = 0;
+	}
+}
+
+void 
+acpi_write(uchar space, uvlong off, uvlong len, uvlong val)
+{
+	uintptr pa;
+	void *p;
+
+	pa = off;
+	//print("acpi_write: space %d off 0x%ullx len %ulld\n", space, off, len);
+	switch (space) {
+		case 0x00:
+			//print("pa = 0x%ulx\n", pa);
+			if (p = vmap(pa, len)) {
+				memmove(p, &val, len);
+				vunmap(p, len);
+			}
+			break;
+		case 0x01:
+			outb(off, val);
+			break;
+		case 0x03: 
+			acpiec_write(off, val);
+			break;
+		default:
+			print("writing to space %d not implemented\n", space);
+	}
+}
+
+void 
+acpi_delay(int n)
+{
+	microdelay(n);
+}
+
 static void
 acpiinit(void)
 {
@@ -342,6 +439,7 @@
 	uchar *p, *e;
 	ulong lapicbase;
 	int machno, i, c;
+	struct Fadt *fadt;
 
 	maptables();
 
@@ -363,6 +461,13 @@
 			amlload(t->data, tbldlen(t));
 	}
 
+	for(i=0; i<ntblmap; i++){
+		t = tblmap[i];
+		if(memcmp(t->sig, "ECDT", 4) == 0){
+			acpiec_init(nil, t->data);
+			break;
+		}
+	}
 	/* set APIC mode */
 	amleval(amlwalk(amlroot, "_PIC"), "i", 1, nil);
 
@@ -452,6 +557,9 @@
 	for(i=0; i<16; i++)
 		addirq(i, BusISA, 0, i, 0);
 
+	/* look for EC if not yet found */
+	amlenum(amlroot, "_HID", findec, nil);
+
 	/* free the AML interpreter */
 	amlexit();
 
@@ -459,6 +567,18 @@
 	 * Ininitalize local APIC and start application processors.
 	 */
 	mpinit();
+
+	/* enable acpi */
+	for(i=0; i<ntblmap; i++){
+		t = tblmap[i];
+		if(memcmp(t->sig, "FACP", 4) == 0){
+			fadt = (struct Fadt*)t->data;
+			print("smi_cmd: 0x%x acpi_enable: 0x%x pstate_cnt: 0x%x\n",
+				get32(fadt->smi_cmd), fadt->acpi_enable, fadt->pstate_cnt);
+			outb(get32(fadt->smi_cmd), fadt->acpi_enable);
+			break;
+		}
+	}	
 }
 
 static int identify(void);
@@ -476,6 +596,34 @@
 };
 
 static long
+writeacpiec(Chan*, void *a, long n, vlong off)
+{
+	acpi_write(0x03, off, n, *((uvlong*)a));
+	return n;
+}
+
+static long
+readacpiec(Chan*, void *v, long n, vlong off)
+{
+	acpi_read(0x03, off, n, v);
+	return 1;
+}
+
+static long
+readacpimem(Chan*, void *v, long n, vlong off)
+{
+	acpi_read(0x00, off, n, v);
+	return n;
+}
+
+static long
+writeacpimem(Chan*, void *a, long n, vlong off)
+{
+	acpi_write(0x00, off, n, *((uvlong*)a));
+	return n;
+}
+
+static long
 readtbls(Chan*, void *v, long n, vlong o)
 {
 	int i, l, m;
@@ -515,6 +663,8 @@
 	if(checksum(rsd, 20) && checksum(rsd, 36))
 		return 1;
 	addarchfile("acpitbls", 0444, readtbls, nil);
+	addarchfile("acpiec", 0664, readacpiec, writeacpiec);
+	addarchfile("acpimem", 0664, readacpimem, writeacpimem);
 	if(strcmp(cp, "0") == 0)
 		return 1;
 	if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
diff -r 18027a7fe237 sys/src/9/pc/pcf
--- a/sys/src/9/pc/pcf	Wed Jun 26 02:30:43 2013 +0200
+++ b/sys/src/9/pc/pcf	Fri Jun 28 22:14:50 2013 +0400
@@ -84,6 +84,7 @@
 misc
 	archacpi	mp apic
 	archmp		mp apic
+	acpiec 		archacpi
 	mtrr
 
 	sdaoe
diff -r 18027a7fe237 sys/src/libaml/aml.c
--- a/sys/src/libaml/aml.c	Wed Jun 26 02:30:43 2013 +0200
+++ b/sys/src/libaml/aml.c	Fri Jun 28 22:14:50 2013 +0400
@@ -161,14 +161,14 @@
 	Onamec, Oname, Oscope, Oalias,
 	Oreg, Ofld, Oxfld, Opkg, Ovpkg, Oenv, Obuf, Omet, 
 	Odev, Ocpu, Othz, Oprc,
-	Oadd, Osub, Omod, Omul, Odiv, Oshl, Oshr, Oand, Onand, Oor,
+	Oadd, Oconc, 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, Ostall, Osleep,
+	Oacq, Orel, Oload, Ostall, Osleep,
 };
 
 static Op optab[];
@@ -283,6 +283,9 @@
 	Heap *h;
 	int a;
 
+	if(size < 0) {
+		print("mk(%c,%d): something bad is happening\n", tag, size);
+	}
 	a = sizeof(Heap) + size;
 	h = amlalloc(a);
 	h->size = size;
@@ -310,6 +313,14 @@
 	return r;
 }
 
+void*
+amlmkbuf(void *p, int len)
+{
+	uchar *r = mk('b', len);
+	memmove(r, p, len);
+	return r;
+}
+
 static int
 pkglen(uchar *p, uchar *e, uchar **np)
 {
@@ -451,6 +462,7 @@
 rwreg(void *reg, int off, int len, uvlong v, int write)
 {
 	Region *r;
+	uvlong ret;
 	uchar *p;
 	int i;
 
@@ -471,15 +483,21 @@
 		return v;
 	case 'r':
 		r = reg;
+		ret = 0;
 		if((off+len) > r->len)
 			break;
+		if(write)
+			acpi_write(r->space, r->off + off, len, v);
+		else
+			acpi_read(r->space, r->off + off, len, &ret);
+
 		if(amldebug){
-			print("rwreg: %s %-8s [%llux+%x]/%d %llux\n", 
+			print("rwreg: %s %-8s [%llux+%x]/%d %llux -> %llux\n", 
 				write ? "W" : "R", 
 				spacename[r->space],
-				r->off, off, len, v);
+				r->off, off, len, v, write ? v : ret);
 		}
-		break;
+		return (write ? v : ret);
 	}
 
 	return ~0;
@@ -1585,6 +1603,104 @@
 	return r;
 }
 
+static void*
+amlconvert(void *val, char type)
+{
+	void *r;
+	uvlong v;
+
+	if(amltag(val) == type)
+		return val;
+	r = nil;
+	switch(amltag(val)) {
+		case 'i':
+			switch(type){
+				case 'b':
+					r = mk('b', sizeof(uvlong));
+					v = amlint(val);
+					memmove(r, &v, sizeof(uvlong));
+					break;
+				default:
+					print("conversion %c -> %c not implemented\n", 
+						amltag(val), type);
+			}
+			break;
+		default:
+			print("conversion %c -> %c not implemented\n", 
+					amltag(val), type);
+	}
+	return r;
+}			
+
+static void*
+evalconcat(void)
+{
+	void *r, *v2;
+	int l1, l2;
+
+	r = nil;
+	v2 = amlconvert(FP->arg[1], amltag(FP->arg[0]));
+	if (v2 == nil)
+		return nil;
+	switch(amltag(FP->arg[0])) {
+		case 'b':
+			l1 = amllen(FP->arg[0]);
+			l2 = amllen(v2);
+			r = mk('b', l1+l2);
+			memmove(r, FP->arg[0], l1);
+			memmove((uchar*)r+l1, v2, l2);
+			break;
+		default:
+			print("concat(%c,%c) not implemented\n", amltag(FP->arg[0]), amltag(v2));
+	}
+	store(r, FP->arg[2]);
+	return r;
+}
+             
+static void*
+evalload(void)
+{
+	Region *r;
+	int l;
+	uchar *t, *p;
+	enum { LenOffset = 4, HdrLen = 36 };
+
+	if(FP->aux){
+		/* end of code to load */
+		if(PC >= FP->end){
+			/* restore */
+			FP->end = FP->aux;
+			FP->aux = nil;
+			PC = FP->end;
+		}
+
+		/* next instruction */
+		return nil;
+	}
+
+	if(amltag(FP->arg[0]) != 'r'){
+		print("tag: %d\n", amltag(FP->arg[0]));
+		return nil;
+	}
+	r = (Region*)amlval(FP->arg[0]);
+	t = amlalloc(r->len);
+	acpi_read(MemSpace, (uvlong)r->va+r->off, r->len, (uvlong*)t);
+
+	p = t + LenOffset;
+	l = (p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0]);
+
+	FP->dot = amlroot;
+	FP->env = nil;
+	FP->end = t + l;
+	FP->aux = PC;	/* save */
+
+	/* start executing code to load */
+	PC = t + HdrLen;
+
+	store(mki(1), FP->arg[1]); /* table id */
+	return nil;
+}
+
 static Op optab[] = {
 	[Obad]		"",			"",		evalbad,
 	[Onop]		"Noop",			"",		evalnop,
@@ -1625,6 +1741,7 @@
 	[Omet]		"Method",		"{N1",		evalmet,
 
 	[Oadd]		"Add",			"ii@",		evalarith,
+	[Oconc] 	"Concatenate", 	"**@", 		evalconcat,
 	[Osub]		"Subtract",		"ii@",		evalarith,
 	[Omod]		"Mod",			"ii@",		evalarith,
 	[Omul]		"Multiply",		"ii@",		evalarith,
@@ -1668,6 +1785,7 @@
 
 	[Oacq]		"Acquire",		"@2",		evalnop,
 	[Orel]		"Release",		"@",		evalnop,
+	[Oload] 	"Load", 		"*@}", 		evalload,
 	[Ostall]	"Stall",		"i",		evalnop,
 	[Osleep]	"Sleep",		"i",		evalnop,
 };
@@ -1687,7 +1805,7 @@
 /* 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,
+/* 70 */	Ostore,	Oref,	Oadd,	Oconc,	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,
@@ -1712,7 +1830,7 @@
 /* 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,	Ostall,	Osleep,	Oacq,	Obad,	Obad,	Obad,	Orel,
+/* 20 */	Oload,	Ostall,	Osleep,	Oacq,	Obad,	Obad,	Obad,	Orel,
 /* 28 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
 /* 30 */	Obad,	Odebug,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
 /* 38 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
@@ -1782,6 +1900,24 @@
 	return 0;
 }
 
+static void*
+evalosi(void)
+{
+	static char *w[] = { 
+		"Windows 2001",
+		"Windows 2001 SP1",
+		"Windows 2001 SP2",
+		"Windows 2006",
+	};
+	char *arg = (char*)(amlval(FP->arg[0]));
+	int i, res = 0;
+
+	for(i = 0; !res && (i < 4); i++)
+		res = !strcmp(w[i], arg);
+
+	return mki(res);
+}
+
 void
 amlinit(void)
 {
@@ -1811,7 +1947,7 @@
 
 		m = mk('m', sizeof(Method));
 		m->narg = 1;
-		m->eval = evalnop;
+		m->eval = evalosi;
 		m->name = n;
 		n->v = m;
 	}
@@ -1869,6 +2005,9 @@
 	e = mk('E', sizeof(Env));
 	for(i=0;*fmt;fmt++){
 		switch(*fmt){
+		case 'b':
+			e->arg[i++] = va_arg(a, void*);
+			break;
 		case 's':
 			e->arg[i++] = mks(va_arg(a, char*));
 			break;
