xref: /plan9-contrib/sys/src/9k/k10/devacpi.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"io.h"
79ef1f84bSDavid du Colombier #include	"../port/error.h"
89ef1f84bSDavid du Colombier #include "mp.h"
99ef1f84bSDavid du Colombier #include "acpi.h"
109ef1f84bSDavid du Colombier 
119ef1f84bSDavid du Colombier /*
129ef1f84bSDavid du Colombier  * ACPI 4.0 Support.
139ef1f84bSDavid du Colombier  * Still WIP.
149ef1f84bSDavid du Colombier  *
159ef1f84bSDavid du Colombier  * This driver locates tables and parses only the FADT
169ef1f84bSDavid du Colombier  * and the XSDT. All other tables are mapped and kept there
179ef1f84bSDavid du Colombier  * for a user-level interpreter.
189ef1f84bSDavid du Colombier  */
199ef1f84bSDavid du Colombier 
209ef1f84bSDavid du Colombier #define l16get(p)	(((p)[1]<<8)|(p)[0])
219ef1f84bSDavid du Colombier #define l32get(p)	(((u32int)l16get(p+2)<<16)|l16get(p))
229ef1f84bSDavid du Colombier static Atable* acpifadt(uchar*, int);
239ef1f84bSDavid du Colombier static Atable* acpitable(uchar*, int);
249ef1f84bSDavid du Colombier static Atable* acpimadt(uchar*, int);
259ef1f84bSDavid du Colombier static Atable* acpimsct(uchar*, int);
269ef1f84bSDavid du Colombier static Atable* acpisrat(uchar*, int);
279ef1f84bSDavid du Colombier static Atable* acpislit(uchar*, int);
289ef1f84bSDavid du Colombier static Atable* acpihpet(uchar*, int);
299ef1f84bSDavid du Colombier 
309ef1f84bSDavid du Colombier #pragma	varargck	type	"G"	Gas*
319ef1f84bSDavid du Colombier 
329ef1f84bSDavid du Colombier static Cmdtab ctls[] =
339ef1f84bSDavid du Colombier {
349ef1f84bSDavid du Colombier 	{CMregion,	"region",	6},
359ef1f84bSDavid du Colombier 	{CMgpe,		"gpe",		3},
369ef1f84bSDavid du Colombier };
379ef1f84bSDavid du Colombier 
389ef1f84bSDavid du Colombier static Dirtab acpidir[]={
399ef1f84bSDavid du Colombier 	".",		{Qdir, 0, QTDIR},	0,	DMDIR|0555,
409ef1f84bSDavid du Colombier 	"acpictl",	{Qctl},			0,	0666,
419ef1f84bSDavid du Colombier 	"acpitbl",	{Qtbl},			0,	0444,
429ef1f84bSDavid du Colombier 	"acpiregio",	{Qio},			0,	0666,
439ef1f84bSDavid du Colombier };
449ef1f84bSDavid du Colombier 
459ef1f84bSDavid du Colombier /*
469ef1f84bSDavid du Colombier  * The DSDT is always given to the user interpreter.
479ef1f84bSDavid du Colombier  * Tables listed here are also loaded from the XSDT:
489ef1f84bSDavid du Colombier  * MSCT, MADT, and FADT are processed by us, because they are
499ef1f84bSDavid du Colombier  * required to do early initialization before we have user processes.
509ef1f84bSDavid du Colombier  * Other tables are given to the user level interpreter for
519ef1f84bSDavid du Colombier  * execution.
529ef1f84bSDavid du Colombier  */
539ef1f84bSDavid du Colombier static Parse ptables[] =
549ef1f84bSDavid du Colombier {
559ef1f84bSDavid du Colombier 	"FACP", acpifadt,
569ef1f84bSDavid du Colombier 	"APIC",	acpimadt,
579ef1f84bSDavid du Colombier 	"SRAT",	acpisrat,
589ef1f84bSDavid du Colombier 	"SLIT",	acpislit,
599ef1f84bSDavid du Colombier 	"MSCT",	acpimsct,
609ef1f84bSDavid du Colombier 	"HPET", acpihpet,
619ef1f84bSDavid du Colombier 	"SSDT", acpitable,
629ef1f84bSDavid du Colombier };
639ef1f84bSDavid du Colombier 
649ef1f84bSDavid du Colombier static Facs*	facs;	/* Firmware ACPI control structure */
659ef1f84bSDavid du Colombier static Fadt	fadt;	/* Fixed ACPI description. To reach ACPI registers */
669ef1f84bSDavid du Colombier static Xsdt*	xsdt;	/* XSDT table */
679ef1f84bSDavid du Colombier static Atable*	tfirst;	/* loaded DSDT/SSDT/... tables */
689ef1f84bSDavid du Colombier static Atable*	tlast;	/* pointer to last table */
699ef1f84bSDavid du Colombier 	Madt*	apics;	/* APIC info */
709ef1f84bSDavid du Colombier static Srat*	srat;	/* System resource affinity, used by physalloc */
719ef1f84bSDavid du Colombier static Slit*	slit;	/* System locality information table used by the scheduler */
729ef1f84bSDavid du Colombier static Msct*	msct;	/* Maximum system characteristics table */
739ef1f84bSDavid du Colombier static Hpet*	hpet;
749ef1f84bSDavid du Colombier static Reg*	reg;	/* region used for I/O */
759ef1f84bSDavid du Colombier static Gpe*	gpes;	/* General purpose events */
769ef1f84bSDavid du Colombier static int	ngpes;
779ef1f84bSDavid du Colombier 
789ef1f84bSDavid du Colombier static char* regnames[] = {
799ef1f84bSDavid du Colombier 	"mem", "io", "pcicfg", "embed",
809ef1f84bSDavid du Colombier 	"smb", "cmos", "pcibar",
819ef1f84bSDavid du Colombier };
829ef1f84bSDavid du Colombier 
839ef1f84bSDavid du Colombier static char*
acpiregstr(int id)849ef1f84bSDavid du Colombier acpiregstr(int id)
859ef1f84bSDavid du Colombier {
869ef1f84bSDavid du Colombier 	static char buf[20];	/* BUG */
879ef1f84bSDavid du Colombier 
889ef1f84bSDavid du Colombier 	if(id >= 0 && id < nelem(regnames))
899ef1f84bSDavid du Colombier 		return regnames[id];
909ef1f84bSDavid du Colombier 	seprint(buf, buf+sizeof(buf), "spc:%#x", id);
919ef1f84bSDavid du Colombier 	return buf;
929ef1f84bSDavid du Colombier }
939ef1f84bSDavid du Colombier 
949ef1f84bSDavid du Colombier static int
acpiregid(char * s)959ef1f84bSDavid du Colombier acpiregid(char *s)
969ef1f84bSDavid du Colombier {
979ef1f84bSDavid du Colombier 	int i;
989ef1f84bSDavid du Colombier 
999ef1f84bSDavid du Colombier 	for(i = 0; i < nelem(regnames); i++)
1009ef1f84bSDavid du Colombier 		if(strcmp(regnames[i], s) == 0)
1019ef1f84bSDavid du Colombier 			return i;
1029ef1f84bSDavid du Colombier 	return -1;
1039ef1f84bSDavid du Colombier }
1049ef1f84bSDavid du Colombier 
1059ef1f84bSDavid du Colombier static u64int
l64get(u8int * p)1069ef1f84bSDavid du Colombier l64get(u8int* p)
1079ef1f84bSDavid du Colombier {
1089ef1f84bSDavid du Colombier 	/*
1099ef1f84bSDavid du Colombier 	 * Doing this as a define
1109ef1f84bSDavid du Colombier 	 * #define l64get(p)	(((u64int)l32get(p+4)<<32)|l32get(p))
1119ef1f84bSDavid du Colombier 	 * causes 8c to abort with "out of fixed registers" in
1129ef1f84bSDavid du Colombier 	 * rsdlink() below.
1139ef1f84bSDavid du Colombier 	 */
1149ef1f84bSDavid du Colombier 	return (((u64int)l32get(p+4)<<32)|l32get(p));
1159ef1f84bSDavid du Colombier }
1169ef1f84bSDavid du Colombier 
1179ef1f84bSDavid du Colombier static u8int
mget8(uintptr p,void *)1189ef1f84bSDavid du Colombier mget8(uintptr p, void*)
1199ef1f84bSDavid du Colombier {
1209ef1f84bSDavid du Colombier 	u8int *cp = (u8int*)p;
1219ef1f84bSDavid du Colombier 	return *cp;
1229ef1f84bSDavid du Colombier }
1239ef1f84bSDavid du Colombier 
1249ef1f84bSDavid du Colombier static void
mset8(uintptr p,u8int v,void *)1259ef1f84bSDavid du Colombier mset8(uintptr p, u8int v, void*)
1269ef1f84bSDavid du Colombier {
1279ef1f84bSDavid du Colombier 	u8int *cp = (u8int*)p;
1289ef1f84bSDavid du Colombier 	*cp = v;
1299ef1f84bSDavid du Colombier }
1309ef1f84bSDavid du Colombier 
1319ef1f84bSDavid du Colombier static u16int
mget16(uintptr p,void *)1329ef1f84bSDavid du Colombier mget16(uintptr p, void*)
1339ef1f84bSDavid du Colombier {
1349ef1f84bSDavid du Colombier 	u16int *cp = (u16int*)p;
1359ef1f84bSDavid du Colombier 	return *cp;
1369ef1f84bSDavid du Colombier }
1379ef1f84bSDavid du Colombier 
1389ef1f84bSDavid du Colombier static void
mset16(uintptr p,u16int v,void *)1399ef1f84bSDavid du Colombier mset16(uintptr p, u16int v, void*)
1409ef1f84bSDavid du Colombier {
1419ef1f84bSDavid du Colombier 	u16int *cp = (u16int*)p;
1429ef1f84bSDavid du Colombier 	*cp = v;
1439ef1f84bSDavid du Colombier }
1449ef1f84bSDavid du Colombier 
1459ef1f84bSDavid du Colombier static u32int
mget32(uintptr p,void *)1469ef1f84bSDavid du Colombier mget32(uintptr p, void*)
1479ef1f84bSDavid du Colombier {
1489ef1f84bSDavid du Colombier 	u32int *cp = (u32int*)p;
1499ef1f84bSDavid du Colombier 	return *cp;
1509ef1f84bSDavid du Colombier }
1519ef1f84bSDavid du Colombier 
1529ef1f84bSDavid du Colombier static void
mset32(uintptr p,u32int v,void *)1539ef1f84bSDavid du Colombier mset32(uintptr p, u32int v, void*)
1549ef1f84bSDavid du Colombier {
1559ef1f84bSDavid du Colombier 	u32int *cp = (u32int*)p;
1569ef1f84bSDavid du Colombier 	*cp = v;
1579ef1f84bSDavid du Colombier }
1589ef1f84bSDavid du Colombier 
1599ef1f84bSDavid du Colombier static u64int
mget64(uintptr p,void *)1609ef1f84bSDavid du Colombier mget64(uintptr p, void*)
1619ef1f84bSDavid du Colombier {
1629ef1f84bSDavid du Colombier 	u64int *cp = (u64int*)p;
1639ef1f84bSDavid du Colombier 	return *cp;
1649ef1f84bSDavid du Colombier }
1659ef1f84bSDavid du Colombier 
1669ef1f84bSDavid du Colombier static void
mset64(uintptr p,u64int v,void *)1679ef1f84bSDavid du Colombier mset64(uintptr p, u64int v, void*)
1689ef1f84bSDavid du Colombier {
1699ef1f84bSDavid du Colombier 	u64int *cp = (u64int*)p;
1709ef1f84bSDavid du Colombier 	*cp = v;
1719ef1f84bSDavid du Colombier }
1729ef1f84bSDavid du Colombier 
1739ef1f84bSDavid du Colombier static u8int
ioget8(uintptr p,void *)1749ef1f84bSDavid du Colombier ioget8(uintptr p, void*)
1759ef1f84bSDavid du Colombier {
1769ef1f84bSDavid du Colombier 	return inb(p);
1779ef1f84bSDavid du Colombier }
1789ef1f84bSDavid du Colombier 
1799ef1f84bSDavid du Colombier static void
ioset8(uintptr p,u8int v,void *)1809ef1f84bSDavid du Colombier ioset8(uintptr p, u8int v, void*)
1819ef1f84bSDavid du Colombier {
1829ef1f84bSDavid du Colombier 	outb(p, v);
1839ef1f84bSDavid du Colombier }
1849ef1f84bSDavid du Colombier 
1859ef1f84bSDavid du Colombier static u16int
ioget16(uintptr p,void *)1869ef1f84bSDavid du Colombier ioget16(uintptr p, void*)
1879ef1f84bSDavid du Colombier {
1889ef1f84bSDavid du Colombier 	return ins(p);
1899ef1f84bSDavid du Colombier }
1909ef1f84bSDavid du Colombier 
1919ef1f84bSDavid du Colombier static void
ioset16(uintptr p,u16int v,void *)1929ef1f84bSDavid du Colombier ioset16(uintptr p, u16int v, void*)
1939ef1f84bSDavid du Colombier {
1949ef1f84bSDavid du Colombier 	outs(p, v);
1959ef1f84bSDavid du Colombier }
1969ef1f84bSDavid du Colombier 
1979ef1f84bSDavid du Colombier static u32int
ioget32(uintptr p,void *)1989ef1f84bSDavid du Colombier ioget32(uintptr p, void*)
1999ef1f84bSDavid du Colombier {
2009ef1f84bSDavid du Colombier 	return inl(p);
2019ef1f84bSDavid du Colombier }
2029ef1f84bSDavid du Colombier 
2039ef1f84bSDavid du Colombier static void
ioset32(uintptr p,u32int v,void *)2049ef1f84bSDavid du Colombier ioset32(uintptr p, u32int v, void*)
2059ef1f84bSDavid du Colombier {
2069ef1f84bSDavid du Colombier 	outl(p, v);
2079ef1f84bSDavid du Colombier }
2089ef1f84bSDavid du Colombier 
2099ef1f84bSDavid du Colombier static u8int
cfgget8(uintptr p,void * r)2109ef1f84bSDavid du Colombier cfgget8(uintptr p, void* r)
2119ef1f84bSDavid du Colombier {
2129ef1f84bSDavid du Colombier 	Reg *ro = r;
2139ef1f84bSDavid du Colombier 	Pcidev d;
2149ef1f84bSDavid du Colombier 
2159ef1f84bSDavid du Colombier 	d.tbdf = ro->tbdf;
2169ef1f84bSDavid du Colombier 	return pcicfgr8(&d, p);
2179ef1f84bSDavid du Colombier }
2189ef1f84bSDavid du Colombier 
2199ef1f84bSDavid du Colombier static void
cfgset8(uintptr p,u8int v,void * r)2209ef1f84bSDavid du Colombier cfgset8(uintptr p, u8int v, void* r)
2219ef1f84bSDavid du Colombier {
2229ef1f84bSDavid du Colombier 	Reg *ro = r;
2239ef1f84bSDavid du Colombier 	Pcidev d;
2249ef1f84bSDavid du Colombier 
2259ef1f84bSDavid du Colombier 	d.tbdf = ro->tbdf;
2269ef1f84bSDavid du Colombier 	pcicfgw8(&d, p, v);
2279ef1f84bSDavid du Colombier }
2289ef1f84bSDavid du Colombier 
2299ef1f84bSDavid du Colombier static u16int
cfgget16(uintptr p,void * r)2309ef1f84bSDavid du Colombier cfgget16(uintptr p, void* r)
2319ef1f84bSDavid du Colombier {
2329ef1f84bSDavid du Colombier 	Reg *ro = r;
2339ef1f84bSDavid du Colombier 	Pcidev d;
2349ef1f84bSDavid du Colombier 
2359ef1f84bSDavid du Colombier 	d.tbdf = ro->tbdf;
2369ef1f84bSDavid du Colombier 	return pcicfgr16(&d, p);
2379ef1f84bSDavid du Colombier }
2389ef1f84bSDavid du Colombier 
2399ef1f84bSDavid du Colombier static void
cfgset16(uintptr p,u16int v,void * r)2409ef1f84bSDavid du Colombier cfgset16(uintptr p, u16int v, void* r)
2419ef1f84bSDavid du Colombier {
2429ef1f84bSDavid du Colombier 	Reg *ro = r;
2439ef1f84bSDavid du Colombier 	Pcidev d;
2449ef1f84bSDavid du Colombier 
2459ef1f84bSDavid du Colombier 	d.tbdf = ro->tbdf;
2469ef1f84bSDavid du Colombier 	pcicfgw16(&d, p, v);
2479ef1f84bSDavid du Colombier }
2489ef1f84bSDavid du Colombier 
2499ef1f84bSDavid du Colombier static u32int
cfgget32(uintptr p,void * r)2509ef1f84bSDavid du Colombier cfgget32(uintptr p, void* r)
2519ef1f84bSDavid du Colombier {
2529ef1f84bSDavid du Colombier 	Reg *ro = r;
2539ef1f84bSDavid du Colombier 	Pcidev d;
2549ef1f84bSDavid du Colombier 
2559ef1f84bSDavid du Colombier 	d.tbdf = ro->tbdf;
2569ef1f84bSDavid du Colombier 	return pcicfgr32(&d, p);
2579ef1f84bSDavid du Colombier }
2589ef1f84bSDavid du Colombier 
2599ef1f84bSDavid du Colombier static void
cfgset32(uintptr p,u32int v,void * r)2609ef1f84bSDavid du Colombier cfgset32(uintptr p, u32int v, void* r)
2619ef1f84bSDavid du Colombier {
2629ef1f84bSDavid du Colombier 	Reg *ro = r;
2639ef1f84bSDavid du Colombier 	Pcidev d;
2649ef1f84bSDavid du Colombier 
2659ef1f84bSDavid du Colombier 	d.tbdf = ro->tbdf;
2669ef1f84bSDavid du Colombier 	pcicfgw32(&d, p, v);
2679ef1f84bSDavid du Colombier }
2689ef1f84bSDavid du Colombier 
2699ef1f84bSDavid du Colombier static Regio memio =
2709ef1f84bSDavid du Colombier {
2719ef1f84bSDavid du Colombier 	nil,
2729ef1f84bSDavid du Colombier 	mget8, mset8, mget16, mset16,
2739ef1f84bSDavid du Colombier 	mget32, mset32, mget64, mset64
2749ef1f84bSDavid du Colombier };
2759ef1f84bSDavid du Colombier 
2769ef1f84bSDavid du Colombier static Regio ioio =
2779ef1f84bSDavid du Colombier {
2789ef1f84bSDavid du Colombier 	nil,
2799ef1f84bSDavid du Colombier 	ioget8, ioset8, ioget16, ioset16,
2809ef1f84bSDavid du Colombier 	ioget32, ioset32, nil, nil
2819ef1f84bSDavid du Colombier };
2829ef1f84bSDavid du Colombier 
2839ef1f84bSDavid du Colombier static Regio cfgio =
2849ef1f84bSDavid du Colombier {
2859ef1f84bSDavid du Colombier 	nil,
2869ef1f84bSDavid du Colombier 	cfgget8, cfgset8, cfgget16, cfgset16,
2879ef1f84bSDavid du Colombier 	cfgget32, cfgset32, nil, nil
2889ef1f84bSDavid du Colombier };
2899ef1f84bSDavid du Colombier 
2909ef1f84bSDavid du Colombier /*
2919ef1f84bSDavid du Colombier  * Copy memory, 1/2/4/8-bytes at a time, to/from a region.
2929ef1f84bSDavid du Colombier  */
2939ef1f84bSDavid du Colombier static long
regcpy(Regio * dio,uintptr da,Regio * sio,uintptr sa,long len,int align)2949ef1f84bSDavid du Colombier regcpy(Regio *dio, uintptr da, Regio *sio, uintptr sa, long len, int align)
2959ef1f84bSDavid du Colombier {
2969ef1f84bSDavid du Colombier 	int n, i;
2979ef1f84bSDavid du Colombier 
2989ef1f84bSDavid du Colombier 	DBG("regcpy %#ullx %#ullx %#ulx %#ux\n", da, sa, len, align);
2999ef1f84bSDavid du Colombier 	if((len%align) != 0)
3009ef1f84bSDavid du Colombier 		print("regcpy: bug: copy not aligned. truncated\n");
3019ef1f84bSDavid du Colombier 	n = len/align;
3029ef1f84bSDavid du Colombier 	for(i = 0; i < n; i++){
3039ef1f84bSDavid du Colombier 		switch(align){
3049ef1f84bSDavid du Colombier 		case 1:
3059ef1f84bSDavid du Colombier 			DBG("cpy8 %#p %#p\n", da, sa);
3069ef1f84bSDavid du Colombier 			dio->set8(da, sio->get8(sa, sio->arg), dio->arg);
3079ef1f84bSDavid du Colombier 			break;
3089ef1f84bSDavid du Colombier 		case 2:
3099ef1f84bSDavid du Colombier 			DBG("cpy16 %#p %#p\n", da, sa);
3109ef1f84bSDavid du Colombier 			dio->set16(da, sio->get16(sa, sio->arg), dio->arg);
3119ef1f84bSDavid du Colombier 			break;
3129ef1f84bSDavid du Colombier 		case 4:
3139ef1f84bSDavid du Colombier 			DBG("cpy32 %#p %#p\n", da, sa);
3149ef1f84bSDavid du Colombier 			dio->set32(da, sio->get32(sa, sio->arg), dio->arg);
3159ef1f84bSDavid du Colombier 			break;
3169ef1f84bSDavid du Colombier 		case 8:
3179ef1f84bSDavid du Colombier 			DBG("cpy64 %#p %#p\n", da, sa);
3189ef1f84bSDavid du Colombier 		//	dio->set64(da, sio->get64(sa, sio->arg), dio->arg);
3199ef1f84bSDavid du Colombier 			break;
3209ef1f84bSDavid du Colombier 		default:
3219ef1f84bSDavid du Colombier 			panic("regcpy: align bug");
3229ef1f84bSDavid du Colombier 		}
3239ef1f84bSDavid du Colombier 		da += align;
3249ef1f84bSDavid du Colombier 		sa += align;
3259ef1f84bSDavid du Colombier 	}
3269ef1f84bSDavid du Colombier 	return n*align;
3279ef1f84bSDavid du Colombier }
3289ef1f84bSDavid du Colombier 
3299ef1f84bSDavid du Colombier /*
3309ef1f84bSDavid du Colombier  * Perform I/O within region in access units of accsz bytes.
3319ef1f84bSDavid du Colombier  * All units in bytes.
3329ef1f84bSDavid du Colombier  */
3339ef1f84bSDavid du Colombier static long
regio(Reg * r,void * p,ulong len,uintptr off,int iswr)3349ef1f84bSDavid du Colombier regio(Reg *r, void *p, ulong len, uintptr off, int iswr)
3359ef1f84bSDavid du Colombier {
3369ef1f84bSDavid du Colombier 	Regio rio;
3379ef1f84bSDavid du Colombier 	uintptr rp;
3389ef1f84bSDavid du Colombier 
3399ef1f84bSDavid du Colombier 	DBG("reg%s %s %#p %#ullx %#lx sz=%d\n",
3409ef1f84bSDavid du Colombier 		iswr ? "out" : "in", r->name, p, off, len, r->accsz);
3419ef1f84bSDavid du Colombier 	rp = 0;
3429ef1f84bSDavid du Colombier 	if(off + len > r->len){
3439ef1f84bSDavid du Colombier 		print("regio: access outside limits");
3449ef1f84bSDavid du Colombier 		len = r->len - off;
3459ef1f84bSDavid du Colombier 	}
3469ef1f84bSDavid du Colombier 	if(len <= 0){
3479ef1f84bSDavid du Colombier 		print("regio: zero len\n");
3489ef1f84bSDavid du Colombier 		return 0;
3499ef1f84bSDavid du Colombier 	}
3509ef1f84bSDavid du Colombier 	switch(r->spc){
3519ef1f84bSDavid du Colombier 	case Rsysmem:
3529ef1f84bSDavid du Colombier 		// XXX should map only what we are going to use
3539ef1f84bSDavid du Colombier 		// A region might be too large.
3549ef1f84bSDavid du Colombier 		if(r->p == nil)
3559ef1f84bSDavid du Colombier 			r->p = vmap(r->base, len);
3569ef1f84bSDavid du Colombier 		if(r->p == nil)
3579ef1f84bSDavid du Colombier 			error("regio: vmap failed");
3589ef1f84bSDavid du Colombier 		rp = (uintptr)r->p + off;
3599ef1f84bSDavid du Colombier 		rio = memio;
3609ef1f84bSDavid du Colombier 		break;
3619ef1f84bSDavid du Colombier 	case Rsysio:
3629ef1f84bSDavid du Colombier 		rp = r->base + off;
3639ef1f84bSDavid du Colombier 		rio = ioio;
3649ef1f84bSDavid du Colombier 		break;
3659ef1f84bSDavid du Colombier 	case Rpcicfg:
3669ef1f84bSDavid du Colombier 		rp = r->base + off;
3679ef1f84bSDavid du Colombier 		rio = cfgio;
3689ef1f84bSDavid du Colombier 		rio.arg = r;
3699ef1f84bSDavid du Colombier 		break;
3709ef1f84bSDavid du Colombier 	case Rpcibar:
3719ef1f84bSDavid du Colombier 	case Rembed:
3729ef1f84bSDavid du Colombier 	case Rsmbus:
3739ef1f84bSDavid du Colombier 	case Rcmos:
3749ef1f84bSDavid du Colombier 	case Ripmi:
3759ef1f84bSDavid du Colombier 	case Rfixedhw:
3769ef1f84bSDavid du Colombier 		print("regio: reg %s not supported\n", acpiregstr(r->spc));
3779ef1f84bSDavid du Colombier 		error("region not supported");
3789ef1f84bSDavid du Colombier 	}
3799ef1f84bSDavid du Colombier 	if(iswr)
3809ef1f84bSDavid du Colombier 		regcpy(&rio, rp, &memio, (uintptr)p, len, r->accsz);
3819ef1f84bSDavid du Colombier 	else
3829ef1f84bSDavid du Colombier 		regcpy(&memio, (uintptr)p, &rio, rp, len, r->accsz);
3839ef1f84bSDavid du Colombier 	return len;
3849ef1f84bSDavid du Colombier }
3859ef1f84bSDavid du Colombier 
3869ef1f84bSDavid du Colombier static Atable*
newtable(uchar * p)3879ef1f84bSDavid du Colombier newtable(uchar *p)
3889ef1f84bSDavid du Colombier {
3899ef1f84bSDavid du Colombier 	Atable *t;
3909ef1f84bSDavid du Colombier 	Sdthdr *h;
3919ef1f84bSDavid du Colombier 
3929ef1f84bSDavid du Colombier 	t = malloc(sizeof(Atable));
3939ef1f84bSDavid du Colombier 	if(t == nil)
3949ef1f84bSDavid du Colombier 		panic("no memory for more aml tables");
3959ef1f84bSDavid du Colombier 	t->tbl = p;
3969ef1f84bSDavid du Colombier 	h = (Sdthdr*)t->tbl;
3979ef1f84bSDavid du Colombier 	t->is64 = h->rev >= 2;
3989ef1f84bSDavid du Colombier 	t->dlen = l32get(h->length) - Sdthdrsz;
3999ef1f84bSDavid du Colombier 	memmove(t->sig, h->sig, sizeof(h->sig));
4009ef1f84bSDavid du Colombier 	t->sig[sizeof(t->sig)-1] = 0;
4019ef1f84bSDavid du Colombier 	memmove(t->oemid, h->oemid, sizeof(h->oemid));
4029ef1f84bSDavid du Colombier 	t->oemtblid[sizeof(t->oemtblid)-1] = 0;
4039ef1f84bSDavid du Colombier 	memmove(t->oemtblid, h->oemtblid, sizeof(h->oemtblid));
4049ef1f84bSDavid du Colombier 	t->oemtblid[sizeof(t->oemtblid)-1] = 0;
4059ef1f84bSDavid du Colombier 	t->next = nil;
4069ef1f84bSDavid du Colombier 	if(tfirst == nil)
4079ef1f84bSDavid du Colombier 		tfirst = tlast = t;
4089ef1f84bSDavid du Colombier 	else{
4099ef1f84bSDavid du Colombier 		tlast->next = t;
4109ef1f84bSDavid du Colombier 		tlast = t;
4119ef1f84bSDavid du Colombier 	}
4129ef1f84bSDavid du Colombier 	return t;
4139ef1f84bSDavid du Colombier }
4149ef1f84bSDavid du Colombier 
4159ef1f84bSDavid du Colombier static void*
sdtchecksum(void * addr,int len)4169ef1f84bSDavid du Colombier sdtchecksum(void* addr, int len)
4179ef1f84bSDavid du Colombier {
4189ef1f84bSDavid du Colombier 	u8int *p, sum;
4199ef1f84bSDavid du Colombier 
4209ef1f84bSDavid du Colombier 	sum = 0;
4219ef1f84bSDavid du Colombier 	for(p = addr; len-- > 0; p++)
4229ef1f84bSDavid du Colombier 		sum += *p;
4239ef1f84bSDavid du Colombier 	if(sum == 0)
4249ef1f84bSDavid du Colombier 		return addr;
4259ef1f84bSDavid du Colombier 
4269ef1f84bSDavid du Colombier 	return nil;
4279ef1f84bSDavid du Colombier }
4289ef1f84bSDavid du Colombier 
4299ef1f84bSDavid du Colombier static void *
sdtmap(uintmem pa,int * n,int cksum)4309ef1f84bSDavid du Colombier sdtmap(uintmem pa, int *n, int cksum)
4319ef1f84bSDavid du Colombier {
4329ef1f84bSDavid du Colombier 	Sdthdr* sdt;
4339ef1f84bSDavid du Colombier 
4349ef1f84bSDavid du Colombier 	sdt = vmap(pa, sizeof(Sdthdr));
4359ef1f84bSDavid du Colombier 	if(sdt == nil){
4369ef1f84bSDavid du Colombier 		DBG("acpi: vmap1: nil\n");
4379ef1f84bSDavid du Colombier 		return nil;
4389ef1f84bSDavid du Colombier 	}
4399ef1f84bSDavid du Colombier 	*n = l32get(sdt->length);
4409ef1f84bSDavid du Colombier 	vunmap(sdt, sizeof(Sdthdr));
4419ef1f84bSDavid du Colombier 	if((sdt = vmap(pa, *n)) == nil){
4429ef1f84bSDavid du Colombier 		DBG("acpi: nil vmap\n");
4439ef1f84bSDavid du Colombier 		return nil;
4449ef1f84bSDavid du Colombier 	}
4459ef1f84bSDavid du Colombier 	DBG("acpi: sdtmap %#P -> %#p, length %d\n", pa, sdt, *n);
4469ef1f84bSDavid du Colombier 	if(cksum != 0 && sdtchecksum(sdt, *n) == nil){
4479ef1f84bSDavid du Colombier 		DBG("acpi: SDT: bad checksum\n");
4489ef1f84bSDavid du Colombier 		vunmap(sdt, sizeof(Sdthdr));
4499ef1f84bSDavid du Colombier 		return nil;
4509ef1f84bSDavid du Colombier 	}
4519ef1f84bSDavid du Colombier 	return sdt;
4529ef1f84bSDavid du Colombier }
4539ef1f84bSDavid du Colombier 
4549ef1f84bSDavid du Colombier static int
loadfacs(uintmem pa)4559ef1f84bSDavid du Colombier loadfacs(uintmem pa)
4569ef1f84bSDavid du Colombier {
4579ef1f84bSDavid du Colombier 	int n;
4589ef1f84bSDavid du Colombier 
4599ef1f84bSDavid du Colombier 	facs = sdtmap(pa, &n, 0);
4609ef1f84bSDavid du Colombier 	if(facs == nil)
4619ef1f84bSDavid du Colombier 		return -1;
4629ef1f84bSDavid du Colombier 	if(memcmp(facs, "FACS", 4) != 0){
4639ef1f84bSDavid du Colombier 		vunmap(facs, n);
4649ef1f84bSDavid du Colombier 		facs = nil;
4659ef1f84bSDavid du Colombier 		return -1;
4669ef1f84bSDavid du Colombier 	}
4679ef1f84bSDavid du Colombier 	/* no unmap */
4689ef1f84bSDavid du Colombier 
4699ef1f84bSDavid du Colombier 	DBG("acpi: facs: hwsig: %#ux\n", facs->hwsig);
4709ef1f84bSDavid du Colombier 	DBG("acpi: facs: wakingv: %#ux\n", facs->wakingv);
4719ef1f84bSDavid du Colombier 	DBG("acpi: facs: flags: %#ux\n", facs->flags);
4729ef1f84bSDavid du Colombier 	DBG("acpi: facs: glock: %#ux\n", facs->glock);
4739ef1f84bSDavid du Colombier 	DBG("acpi: facs: xwakingv: %#llux\n", facs->xwakingv);
4749ef1f84bSDavid du Colombier 	DBG("acpi: facs: vers: %#ux\n", facs->vers);
4759ef1f84bSDavid du Colombier 	DBG("acpi: facs: ospmflags: %#ux\n", facs->ospmflags);
4769ef1f84bSDavid du Colombier 	return 0;
4779ef1f84bSDavid du Colombier }
4789ef1f84bSDavid du Colombier 
4799ef1f84bSDavid du Colombier static void
loaddsdt(uintmem pa)4809ef1f84bSDavid du Colombier loaddsdt(uintmem pa)
4819ef1f84bSDavid du Colombier {
4829ef1f84bSDavid du Colombier 	int n;
4839ef1f84bSDavid du Colombier 	uchar *dsdtp;
4849ef1f84bSDavid du Colombier 
4859ef1f84bSDavid du Colombier 	dsdtp = sdtmap(pa, &n, 1);
4869ef1f84bSDavid du Colombier 	if(dsdtp == nil)
4879ef1f84bSDavid du Colombier 		return;
4889ef1f84bSDavid du Colombier 	if(acpitable(dsdtp, n) == nil)
4899ef1f84bSDavid du Colombier 		vunmap(dsdtp, n);
4909ef1f84bSDavid du Colombier }
4919ef1f84bSDavid du Colombier 
4929ef1f84bSDavid du Colombier static void
gasget(Gas * gas,uchar * p)4939ef1f84bSDavid du Colombier gasget(Gas *gas, uchar *p)
4949ef1f84bSDavid du Colombier {
4959ef1f84bSDavid du Colombier 	gas->spc = p[0];
4969ef1f84bSDavid du Colombier 	gas->len = p[1];
4979ef1f84bSDavid du Colombier 	gas->off = p[2];
4989ef1f84bSDavid du Colombier 	gas->accsz = p[3];
4999ef1f84bSDavid du Colombier 	gas->addr = l64get(p+4);
5009ef1f84bSDavid du Colombier }
5019ef1f84bSDavid du Colombier 
5029ef1f84bSDavid du Colombier static void
dumpfadt(Fadt * fp,int revision)5039ef1f84bSDavid du Colombier dumpfadt(Fadt *fp, int revision)
5049ef1f84bSDavid du Colombier {
5059ef1f84bSDavid du Colombier 	USED(fp);
5069ef1f84bSDavid du Colombier 	DBG("acpi: fadt: facs: %#ux\n", fp->facs);
5079ef1f84bSDavid du Colombier 	DBG("acpi: fadt: dsdt: %#ux\n", fp->dsdt);
5089ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pmprofile: %#ux\n", fp->pmprofile);
5099ef1f84bSDavid du Colombier 	DBG("acpi: fadt: sciint: %#ux\n", fp->sciint);
5109ef1f84bSDavid du Colombier 	DBG("acpi: fadt: smicmd: %#ux\n", fp->smicmd);
5119ef1f84bSDavid du Colombier 	DBG("acpi: fadt: acpienable: %#ux\n", fp->acpienable);
5129ef1f84bSDavid du Colombier 	DBG("acpi: fadt: acpidisable: %#ux\n", fp->acpidisable);
5139ef1f84bSDavid du Colombier 	DBG("acpi: fadt: s4biosreq: %#ux\n", fp->s4biosreq);
5149ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pstatecnt: %#ux\n", fp->pstatecnt);
5159ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pm1aevtblk: %#ux\n", fp->pm1aevtblk);
5169ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pm1bevtblk: %#ux\n", fp->pm1bevtblk);
5179ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pm1acntblk: %#ux\n", fp->pm1acntblk);
5189ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pm1bcntblk: %#ux\n", fp->pm1bcntblk);
5199ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pm2cntblk: %#ux\n", fp->pm2cntblk);
5209ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pmtmrblk: %#ux\n", fp->pmtmrblk);
5219ef1f84bSDavid du Colombier 	DBG("acpi: fadt: gpe0blk: %#ux\n", fp->gpe0blk);
5229ef1f84bSDavid du Colombier 	DBG("acpi: fadt: gpe1blk: %#ux\n", fp->gpe1blk);
5239ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pm1evtlen: %#ux\n", fp->pm1evtlen);
5249ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pm1cntlen: %#ux\n", fp->pm1cntlen);
5259ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pm2cntlen: %#ux\n", fp->pm2cntlen);
5269ef1f84bSDavid du Colombier 	DBG("acpi: fadt: pmtmrlen: %#ux\n", fp->pmtmrlen);
5279ef1f84bSDavid du Colombier 	DBG("acpi: fadt: gpe0blklen: %#ux\n", fp->gpe0blklen);
5289ef1f84bSDavid du Colombier 	DBG("acpi: fadt: gpe1blklen: %#ux\n", fp->gpe1blklen);
5299ef1f84bSDavid du Colombier 	DBG("acpi: fadt: gp1base: %#ux\n", fp->gp1base);
5309ef1f84bSDavid du Colombier 	DBG("acpi: fadt: cstcnt: %#ux\n", fp->cstcnt);
5319ef1f84bSDavid du Colombier 	DBG("acpi: fadt: plvl2lat: %#ux\n", fp->plvl2lat);
5329ef1f84bSDavid du Colombier 	DBG("acpi: fadt: plvl3lat: %#ux\n", fp->plvl3lat);
5339ef1f84bSDavid du Colombier 	DBG("acpi: fadt: flushsz: %#ux\n", fp->flushsz);
5349ef1f84bSDavid du Colombier 	DBG("acpi: fadt: flushstride: %#ux\n", fp->flushstride);
5359ef1f84bSDavid du Colombier 	DBG("acpi: fadt: dutyoff: %#ux\n", fp->dutyoff);
5369ef1f84bSDavid du Colombier 	DBG("acpi: fadt: dutywidth: %#ux\n", fp->dutywidth);
5379ef1f84bSDavid du Colombier 	DBG("acpi: fadt: dayalrm: %#ux\n", fp->dayalrm);
5389ef1f84bSDavid du Colombier 	DBG("acpi: fadt: monalrm: %#ux\n", fp->monalrm);
5399ef1f84bSDavid du Colombier 	DBG("acpi: fadt: century: %#ux\n", fp->century);
5409ef1f84bSDavid du Colombier 	DBG("acpi: fadt: iapcbootarch: %#ux\n", fp->iapcbootarch);
5419ef1f84bSDavid du Colombier 	DBG("acpi: fadt: flags: %#ux\n", fp->flags);
5429ef1f84bSDavid du Colombier 
5439ef1f84bSDavid du Colombier 	if(revision < 3)
5449ef1f84bSDavid du Colombier 		return;
5459ef1f84bSDavid du Colombier 
5469ef1f84bSDavid du Colombier 	DBG("acpi: fadt: resetreg: %G\n", &fp->resetreg);
5479ef1f84bSDavid du Colombier 	DBG("acpi: fadt: resetval: %#ux\n", fp->resetval);
5489ef1f84bSDavid du Colombier 	DBG("acpi: fadt: xfacs: %#llux\n", fp->xfacs);
5499ef1f84bSDavid du Colombier 	DBG("acpi: fadt: xdsdt: %#llux\n", fp->xdsdt);
5509ef1f84bSDavid du Colombier 	DBG("acpi: fadt: xpm1aevtblk: %G\n", &fp->xpm1aevtblk);
5519ef1f84bSDavid du Colombier 	DBG("acpi: fadt: xpm1bevtblk: %G\n", &fp->xpm1bevtblk);
5529ef1f84bSDavid du Colombier 	DBG("acpi: fadt: xpm1acntblk: %G\n", &fp->xpm1acntblk);
5539ef1f84bSDavid du Colombier 	DBG("acpi: fadt: xpm1bcntblk: %G\n", &fp->xpm1bcntblk);
5549ef1f84bSDavid du Colombier 	DBG("acpi: fadt: xpm2cntblk: %G\n", &fp->xpm2cntblk);
5559ef1f84bSDavid du Colombier 	DBG("acpi: fadt: xpmtmrblk: %G\n", &fp->xpmtmrblk);
5569ef1f84bSDavid du Colombier 	DBG("acpi: fadt: xgpe0blk: %G\n", &fp->xgpe0blk);
5579ef1f84bSDavid du Colombier 	DBG("acpi: fadt: xgpe1blk: %G\n", &fp->xgpe1blk);
5589ef1f84bSDavid du Colombier }
5599ef1f84bSDavid du Colombier 
5609ef1f84bSDavid du Colombier static Atable*
acpifadt(uchar * p,int)5619ef1f84bSDavid du Colombier acpifadt(uchar *p, int)
5629ef1f84bSDavid du Colombier {
5639ef1f84bSDavid du Colombier 	Fadt *fp;
5649ef1f84bSDavid du Colombier 	int revision;
5659ef1f84bSDavid du Colombier 
5669ef1f84bSDavid du Colombier 	fp = &fadt;
5679ef1f84bSDavid du Colombier 	revision = p[8];
5689ef1f84bSDavid du Colombier 	DBG("acpifadt %#p length %ud revision %ud\n", p, l32get(p+4), revision);
5699ef1f84bSDavid du Colombier 	fp->facs = l32get(p + 36);
5709ef1f84bSDavid du Colombier 	fp->dsdt = l32get(p + 40);
5719ef1f84bSDavid du Colombier 	fp->pmprofile = p[45];
5729ef1f84bSDavid du Colombier 	fp->sciint = l16get(p+46);
5739ef1f84bSDavid du Colombier 	fp->smicmd = l32get(p+48);
5749ef1f84bSDavid du Colombier 	fp->acpienable = p[52];
5759ef1f84bSDavid du Colombier 	fp->acpidisable = p[53];
5769ef1f84bSDavid du Colombier 	fp->s4biosreq = p[54];
5779ef1f84bSDavid du Colombier 	fp->pstatecnt = p[55];
5789ef1f84bSDavid du Colombier 	fp->pm1aevtblk = l32get(p+56);
5799ef1f84bSDavid du Colombier 	fp->pm1bevtblk = l32get(p+60);
5809ef1f84bSDavid du Colombier 	fp->pm1acntblk = l32get(p+64);
5819ef1f84bSDavid du Colombier 	fp->pm1bcntblk = l32get(p+68);
5829ef1f84bSDavid du Colombier 	fp->pm2cntblk = l32get(p+72);
5839ef1f84bSDavid du Colombier 	fp->pmtmrblk = l32get(p+76);
5849ef1f84bSDavid du Colombier 	fp->gpe0blk = l32get(p+80);
5859ef1f84bSDavid du Colombier 	fp->gpe1blk = l32get(p+84);
5869ef1f84bSDavid du Colombier 	fp->pm1evtlen = p[88];
5879ef1f84bSDavid du Colombier 	fp->pm1cntlen = p[89];
5889ef1f84bSDavid du Colombier 	fp->pm2cntlen = p[90];
5899ef1f84bSDavid du Colombier 	fp->pmtmrlen = p[91];
5909ef1f84bSDavid du Colombier 	fp->gpe0blklen = p[92];
5919ef1f84bSDavid du Colombier 	fp->gpe1blklen = p[93];
5929ef1f84bSDavid du Colombier 	fp->gp1base = p[94];
5939ef1f84bSDavid du Colombier 	fp->cstcnt = p[95];
5949ef1f84bSDavid du Colombier 	fp->plvl2lat = l16get(p+96);
5959ef1f84bSDavid du Colombier 	fp->plvl3lat = l16get(p+98);
5969ef1f84bSDavid du Colombier 	fp->flushsz = l16get(p+100);
5979ef1f84bSDavid du Colombier 	fp->flushstride = l16get(p+102);
5989ef1f84bSDavid du Colombier 	fp->dutyoff = p[104];
5999ef1f84bSDavid du Colombier 	fp->dutywidth = p[105];
6009ef1f84bSDavid du Colombier 	fp->dayalrm = p[106];
6019ef1f84bSDavid du Colombier 	fp->monalrm = p[107];
6029ef1f84bSDavid du Colombier 	fp->century = p[108];
6039ef1f84bSDavid du Colombier 	fp->iapcbootarch = l16get(p+109);
6049ef1f84bSDavid du Colombier 	fp->flags = l32get(p+112);
6059ef1f84bSDavid du Colombier 
6069ef1f84bSDavid du Colombier 	/*
6079ef1f84bSDavid du Colombier 	 * Revision 1 of this table stops here, and is described
6089ef1f84bSDavid du Colombier 	 * in The ACPI Specification 1.0, 22-Dec-1996.
6099ef1f84bSDavid du Colombier 	 * The ACPI Specification 2.0, 27-Jul-2000, bumped the revision
6109ef1f84bSDavid du Colombier 	 * number up to 3 and added the extra fields on the end.
6119ef1f84bSDavid du Colombier 	 * Thank you, QEMU.
6129ef1f84bSDavid du Colombier 	 */
6139ef1f84bSDavid du Colombier 	if(revision >= 3){
6149ef1f84bSDavid du Colombier 		gasget(&fp->resetreg, p+116);
6159ef1f84bSDavid du Colombier 
6169ef1f84bSDavid du Colombier 		fp->resetval = p[128];
6179ef1f84bSDavid du Colombier 		fp->xfacs = l64get(p+132);
6189ef1f84bSDavid du Colombier 		fp->xdsdt = l64get(p+140);
6199ef1f84bSDavid du Colombier 		gasget(&fp->xpm1aevtblk, p+148);
6209ef1f84bSDavid du Colombier 		gasget(&fp->xpm1bevtblk, p+160);
6219ef1f84bSDavid du Colombier 		gasget(&fp->xpm1acntblk, p+172);
6229ef1f84bSDavid du Colombier 		gasget(&fp->xpm1bcntblk, p+184);
6239ef1f84bSDavid du Colombier 		gasget(&fp->xpm2cntblk, p+196);
6249ef1f84bSDavid du Colombier 		gasget(&fp->xpmtmrblk, p+208);
6259ef1f84bSDavid du Colombier 		gasget(&fp->xgpe0blk, p+220);
6269ef1f84bSDavid du Colombier 		gasget(&fp->xgpe1blk, p+232);
6279ef1f84bSDavid du Colombier 	}
6289ef1f84bSDavid du Colombier 
6299ef1f84bSDavid du Colombier 	dumpfadt(fp, revision);
6309ef1f84bSDavid du Colombier 
6319ef1f84bSDavid du Colombier 	/* If xfacs or xdsdt are either nil
6329ef1f84bSDavid du Colombier 	 * or different from their 32-bit
6339ef1f84bSDavid du Colombier 	 * counter-parts, then go with
6349ef1f84bSDavid du Colombier 	 * the 32-bit addresses (as the
6359ef1f84bSDavid du Colombier 	 * ACPICA does), since those are
6369ef1f84bSDavid du Colombier 	 * tested by BIOS manufacturers.
6379ef1f84bSDavid du Colombier 	 */
6389ef1f84bSDavid du Colombier 
6399ef1f84bSDavid du Colombier 	if(fp->xfacs != 0 && fp->xfacs == fp->facs)
6409ef1f84bSDavid du Colombier 		loadfacs(fp->xfacs);
6419ef1f84bSDavid du Colombier 	else
6429ef1f84bSDavid du Colombier 		loadfacs(fp->facs);
6439ef1f84bSDavid du Colombier 
6449ef1f84bSDavid du Colombier 	if(fp->xdsdt != 0 && fp->xdsdt == fp->dsdt)
6459ef1f84bSDavid du Colombier 		loadfacs(fp->xdsdt);
6469ef1f84bSDavid du Colombier 	else
6479ef1f84bSDavid du Colombier 		loadfacs(fp->dsdt);
6489ef1f84bSDavid du Colombier 
6499ef1f84bSDavid du Colombier 	return nil;			/* can be unmapped once parsed */
6509ef1f84bSDavid du Colombier }
6519ef1f84bSDavid du Colombier 
6529ef1f84bSDavid du Colombier static void
dumpmsct(Msct * msct)6539ef1f84bSDavid du Colombier dumpmsct(Msct *msct)
6549ef1f84bSDavid du Colombier {
6559ef1f84bSDavid du Colombier 	Mdom *st;
6569ef1f84bSDavid du Colombier 
6579ef1f84bSDavid du Colombier 	DBG("acpi: msct: %d doms %d clkdoms %#ullx maxpa\n",
6589ef1f84bSDavid du Colombier 		msct->ndoms, msct->nclkdoms, msct->maxpa);
6599ef1f84bSDavid du Colombier 	for(st = msct->dom; st != nil; st = st->next)
6609ef1f84bSDavid du Colombier 		DBG("\t[%d:%d] %d maxproc %#ullx maxmmem\n",
6619ef1f84bSDavid du Colombier 			st->start, st->end, st->maxproc, st->maxmem);
6629ef1f84bSDavid du Colombier 	DBG("\n");
6639ef1f84bSDavid du Colombier }
6649ef1f84bSDavid du Colombier 
6659ef1f84bSDavid du Colombier /*
6669ef1f84bSDavid du Colombier  * XXX: should perhaps update our idea of available memory.
6679ef1f84bSDavid du Colombier  * Else we should remove this code.
6689ef1f84bSDavid du Colombier  */
6699ef1f84bSDavid du Colombier static Atable*
acpimsct(uchar * p,int len)6709ef1f84bSDavid du Colombier acpimsct(uchar *p, int len)
6719ef1f84bSDavid du Colombier {
6729ef1f84bSDavid du Colombier 	uchar *pe;
6739ef1f84bSDavid du Colombier 	Mdom **stl, *st;
6749ef1f84bSDavid du Colombier 	int off;
6759ef1f84bSDavid du Colombier 
6769ef1f84bSDavid du Colombier 	msct = mallocz(sizeof(Msct), 1);
6779ef1f84bSDavid du Colombier 	msct->ndoms = l32get(p+40) + 1;
6789ef1f84bSDavid du Colombier 	msct->nclkdoms = l32get(p+44) + 1;
6799ef1f84bSDavid du Colombier 	msct->maxpa = l64get(p+48);
6809ef1f84bSDavid du Colombier 	msct->dom = nil;
6819ef1f84bSDavid du Colombier 	stl = &msct->dom;
6829ef1f84bSDavid du Colombier 	pe = p + len;
6839ef1f84bSDavid du Colombier 	off = l32get(p+36);
6849ef1f84bSDavid du Colombier 	for(p += off; p < pe; p += 22){
6859ef1f84bSDavid du Colombier 		st = mallocz(sizeof(Mdom), 1);
6869ef1f84bSDavid du Colombier 		st->next = nil;
6879ef1f84bSDavid du Colombier 		st->start = l32get(p+2);
6889ef1f84bSDavid du Colombier 		st->end = l32get(p+6);
6899ef1f84bSDavid du Colombier 		st->maxproc = l32get(p+10);
6909ef1f84bSDavid du Colombier 		st->maxmem = l64get(p+14);
6919ef1f84bSDavid du Colombier 		*stl = st;
6929ef1f84bSDavid du Colombier 		stl = &st->next;
6939ef1f84bSDavid du Colombier 	}
6949ef1f84bSDavid du Colombier 
6959ef1f84bSDavid du Colombier 	dumpmsct(msct);
6969ef1f84bSDavid du Colombier 	return nil;	/* can be unmapped once parsed */
6979ef1f84bSDavid du Colombier }
6989ef1f84bSDavid du Colombier 
6999ef1f84bSDavid du Colombier static Atable*
acpihpet(uchar * p,int)7009ef1f84bSDavid du Colombier acpihpet(uchar *p, int)
7019ef1f84bSDavid du Colombier {
7029ef1f84bSDavid du Colombier 	hpet = mallocz(sizeof(Hpet), 1);
7039ef1f84bSDavid du Colombier 	p += 36;
7049ef1f84bSDavid du Colombier 
7059ef1f84bSDavid du Colombier 	hpet->id = l32get(p);
7069ef1f84bSDavid du Colombier 	p += 4;
7079ef1f84bSDavid du Colombier 
7089ef1f84bSDavid du Colombier 	p += 4; /* it's a Gas */
7099ef1f84bSDavid du Colombier 	hpet->addr = l64get(p);
7109ef1f84bSDavid du Colombier 	p += 8;
7119ef1f84bSDavid du Colombier 
7129ef1f84bSDavid du Colombier 	hpet->seqno = *p;
7139ef1f84bSDavid du Colombier 	p++;
7149ef1f84bSDavid du Colombier 
7159ef1f84bSDavid du Colombier 	hpet->minticks = l16get(p);
7169ef1f84bSDavid du Colombier 	p += 2;
7179ef1f84bSDavid du Colombier 	hpet->attr = *p;
7189ef1f84bSDavid du Colombier 
7199ef1f84bSDavid du Colombier 	DBG("hpet: id %#ux addr %#p seqno %d ticks %d attr %#ux\n",
7209ef1f84bSDavid du Colombier 		hpet->id, hpet->addr, hpet->seqno, hpet->minticks, hpet->attr);
7219ef1f84bSDavid du Colombier //	hpetinit(hpet->seqno, hpet->addr, hpet->minticks)
7229ef1f84bSDavid du Colombier 	return nil;	/* can be unmapped once parsed */
7239ef1f84bSDavid du Colombier }
7249ef1f84bSDavid du Colombier 
7259ef1f84bSDavid du Colombier 
7269ef1f84bSDavid du Colombier static void
dumpsrat(Srat * st)7279ef1f84bSDavid du Colombier dumpsrat(Srat *st)
7289ef1f84bSDavid du Colombier {
7299ef1f84bSDavid du Colombier 	DBG("acpi: srat:\n");
7309ef1f84bSDavid du Colombier 	for(; st != nil; st = st->next)
7319ef1f84bSDavid du Colombier 		switch(st->type){
7329ef1f84bSDavid du Colombier 		case SRlapic:
7339ef1f84bSDavid du Colombier 			DBG("\tlapic: dom %d apic %d sapic %d clk %d\n",
7349ef1f84bSDavid du Colombier 				st->lapic.dom, st->lapic.apic,
7359ef1f84bSDavid du Colombier 				st->lapic.sapic, st->lapic.clkdom);
7369ef1f84bSDavid du Colombier 			break;
7379ef1f84bSDavid du Colombier 		case SRmem:
7389ef1f84bSDavid du Colombier 			DBG("\tmem: dom %d %#ullx %#ullx %c%c\n",
7399ef1f84bSDavid du Colombier 				st->mem.dom, st->mem.addr, st->mem.len,
7409ef1f84bSDavid du Colombier 				st->mem.hplug?'h':'-',
7419ef1f84bSDavid du Colombier 				st->mem.nvram?'n':'-');
7429ef1f84bSDavid du Colombier 			break;
7439ef1f84bSDavid du Colombier 		case SRlx2apic:
7449ef1f84bSDavid du Colombier 			DBG("\tlx2apic: dom %d apic %d clk %d\n",
7459ef1f84bSDavid du Colombier 				st->lx2apic.dom, st->lx2apic.apic,
7469ef1f84bSDavid du Colombier 				st->lx2apic.clkdom);
7479ef1f84bSDavid du Colombier 			break;
7489ef1f84bSDavid du Colombier 		default:
7499ef1f84bSDavid du Colombier 			DBG("\t<unknown srat entry>\n");
7509ef1f84bSDavid du Colombier 		}
7519ef1f84bSDavid du Colombier 	DBG("\n");
7529ef1f84bSDavid du Colombier }
7539ef1f84bSDavid du Colombier 
7549ef1f84bSDavid du Colombier static Atable*
acpisrat(uchar * p,int len)7559ef1f84bSDavid du Colombier acpisrat(uchar *p, int len)
7569ef1f84bSDavid du Colombier {
7579ef1f84bSDavid du Colombier 	Srat **stl, *st;
7589ef1f84bSDavid du Colombier 	uchar *pe;
7599ef1f84bSDavid du Colombier 	int stlen, flags;
7609ef1f84bSDavid du Colombier 
7619ef1f84bSDavid du Colombier 	if(srat != nil){
7629ef1f84bSDavid du Colombier 		print("acpi: two SRATs?\n");
7639ef1f84bSDavid du Colombier 		return nil;
7649ef1f84bSDavid du Colombier 	}
7659ef1f84bSDavid du Colombier 
7669ef1f84bSDavid du Colombier 	stl = &srat;
7679ef1f84bSDavid du Colombier 	pe = p + len;
7689ef1f84bSDavid du Colombier 	for(p += 48; p < pe; p += stlen){
7699ef1f84bSDavid du Colombier 		st = mallocz(sizeof(Srat), 1);
7709ef1f84bSDavid du Colombier 		st->type = p[0];
7719ef1f84bSDavid du Colombier 		st->next = nil;
7729ef1f84bSDavid du Colombier 		stlen = p[1];
7739ef1f84bSDavid du Colombier 		switch(st->type){
7749ef1f84bSDavid du Colombier 		case SRlapic:
7759ef1f84bSDavid du Colombier 			st->lapic.dom = p[2] | p[9]<<24| p[10]<<16 | p[11]<<8;
7769ef1f84bSDavid du Colombier 			st->lapic.apic = p[3];
7779ef1f84bSDavid du Colombier 			st->lapic.sapic = p[8];
7789ef1f84bSDavid du Colombier 			st->lapic.clkdom = l32get(p+12);
7799ef1f84bSDavid du Colombier 			if(l32get(p+4) == 0){
7809ef1f84bSDavid du Colombier 				free(st);
7819ef1f84bSDavid du Colombier 				st = nil;
7829ef1f84bSDavid du Colombier 			}
7839ef1f84bSDavid du Colombier 			break;
7849ef1f84bSDavid du Colombier 		case SRmem:
7859ef1f84bSDavid du Colombier 			st->mem.dom = l32get(p+2);
7869ef1f84bSDavid du Colombier 			st->mem.addr = l64get(p+8);
7879ef1f84bSDavid du Colombier 			st->mem.len = l64get(p+16);
7889ef1f84bSDavid du Colombier 			flags = l32get(p+28);
7899ef1f84bSDavid du Colombier 			if((flags&1) == 0){	/* not enabled */
7909ef1f84bSDavid du Colombier 				free(st);
7919ef1f84bSDavid du Colombier 				st = nil;
7929ef1f84bSDavid du Colombier 			}else{
7939ef1f84bSDavid du Colombier 				st->mem.hplug = flags & 2;
7949ef1f84bSDavid du Colombier 				st->mem.nvram = flags & 4;
7959ef1f84bSDavid du Colombier 			}
7969ef1f84bSDavid du Colombier 			break;
7979ef1f84bSDavid du Colombier 		case SRlx2apic:
7989ef1f84bSDavid du Colombier 			st->lx2apic.dom = l32get(p+4);
7999ef1f84bSDavid du Colombier 			st->lx2apic.apic = l32get(p+8);
8009ef1f84bSDavid du Colombier 			st->lx2apic.clkdom = l32get(p+16);
8019ef1f84bSDavid du Colombier 			if(l32get(p+12) == 0){
8029ef1f84bSDavid du Colombier 				free(st);
8039ef1f84bSDavid du Colombier 				st = nil;
8049ef1f84bSDavid du Colombier 			}
8059ef1f84bSDavid du Colombier 			break;
8069ef1f84bSDavid du Colombier 		default:
8079ef1f84bSDavid du Colombier 			print("unknown SRAT structure\n");
8089ef1f84bSDavid du Colombier 			free(st);
8099ef1f84bSDavid du Colombier 			st = nil;
8109ef1f84bSDavid du Colombier 		}
8119ef1f84bSDavid du Colombier 		if(st != nil){
8129ef1f84bSDavid du Colombier 			*stl = st;
8139ef1f84bSDavid du Colombier 			stl = &st->next;
8149ef1f84bSDavid du Colombier 		}
8159ef1f84bSDavid du Colombier 	}
8169ef1f84bSDavid du Colombier 
8179ef1f84bSDavid du Colombier 	dumpsrat(srat);
8189ef1f84bSDavid du Colombier 	return nil;	/* can be unmapped once parsed */
8199ef1f84bSDavid du Colombier }
8209ef1f84bSDavid du Colombier 
8219ef1f84bSDavid du Colombier static void
dumpslit(Slit * sl)8229ef1f84bSDavid du Colombier dumpslit(Slit *sl)
8239ef1f84bSDavid du Colombier {
8249ef1f84bSDavid du Colombier 	int i;
8259ef1f84bSDavid du Colombier 
8269ef1f84bSDavid du Colombier 	DBG("acpi slit:\n");
8279ef1f84bSDavid du Colombier 	for(i = 0; i < sl->rowlen*sl->rowlen; i++){
8289ef1f84bSDavid du Colombier 		DBG(" %ux", sl->e[i/sl->rowlen][i%sl->rowlen].dist);
8299ef1f84bSDavid du Colombier 	}
8309ef1f84bSDavid du Colombier 	DBG("\n");
8319ef1f84bSDavid du Colombier }
8329ef1f84bSDavid du Colombier 
8339ef1f84bSDavid du Colombier static int
cmpslitent(void * v1,void * v2)8349ef1f84bSDavid du Colombier cmpslitent(void* v1, void* v2)
8359ef1f84bSDavid du Colombier {
8369ef1f84bSDavid du Colombier 	SlEntry *se1, *se2;
8379ef1f84bSDavid du Colombier 
8389ef1f84bSDavid du Colombier 	se1 = v1;
8399ef1f84bSDavid du Colombier 	se2 = v2;
8409ef1f84bSDavid du Colombier 	return se1->dist - se2->dist;
8419ef1f84bSDavid du Colombier }
8429ef1f84bSDavid du Colombier 
8439ef1f84bSDavid du Colombier static Atable*
acpislit(uchar * p,int len)8449ef1f84bSDavid du Colombier acpislit(uchar *p, int len)
8459ef1f84bSDavid du Colombier {
8469ef1f84bSDavid du Colombier 	uchar *pe;
8479ef1f84bSDavid du Colombier 	int i, j, k;
8489ef1f84bSDavid du Colombier 	SlEntry *se;
8499ef1f84bSDavid du Colombier 
8509ef1f84bSDavid du Colombier 	pe = p + len;
8519ef1f84bSDavid du Colombier 	slit = malloc(sizeof(*slit));
8529ef1f84bSDavid du Colombier 	slit->rowlen = l64get(p+36);
8539ef1f84bSDavid du Colombier 	slit->e = malloc(slit->rowlen*sizeof(SlEntry*));
8549ef1f84bSDavid du Colombier 	for(i = 0; i < slit->rowlen; i++)
8559ef1f84bSDavid du Colombier 		slit->e[i] = malloc(sizeof(SlEntry)*slit->rowlen);
8569ef1f84bSDavid du Colombier 
8579ef1f84bSDavid du Colombier 	i = 0;
8589ef1f84bSDavid du Colombier 	for(p += 44; p < pe; p++, i++){
8599ef1f84bSDavid du Colombier 		j = i/slit->rowlen;
8609ef1f84bSDavid du Colombier 		k = i%slit->rowlen;
8619ef1f84bSDavid du Colombier 		se = &slit->e[j][k];
8629ef1f84bSDavid du Colombier 		se->dom = k;
8639ef1f84bSDavid du Colombier 		se->dist = *p;
8649ef1f84bSDavid du Colombier 	}
8659ef1f84bSDavid du Colombier 	dumpslit(slit);
8669ef1f84bSDavid du Colombier 	for(i = 0; i < slit->rowlen; i++)
8679ef1f84bSDavid du Colombier 		qsort(slit->e[i], slit->rowlen, sizeof(slit->e[0][0]), cmpslitent);
8689ef1f84bSDavid du Colombier 
8699ef1f84bSDavid du Colombier 	dumpslit(slit);
8709ef1f84bSDavid du Colombier 	return nil;	/* can be unmapped once parsed */
8719ef1f84bSDavid du Colombier }
8729ef1f84bSDavid du Colombier 
873*094d6818SDavid du Colombier uintmem
acpimblocksize(uintmem addr,int * dom)874*094d6818SDavid du Colombier acpimblocksize(uintmem addr, int *dom)
875*094d6818SDavid du Colombier {
876*094d6818SDavid du Colombier 	Srat *sl;
877*094d6818SDavid du Colombier 
878*094d6818SDavid du Colombier 	for(sl = srat; sl != nil; sl = sl->next)
879*094d6818SDavid du Colombier 		if(sl->type == SRmem)
880*094d6818SDavid du Colombier 		if(sl->mem.addr <= addr && sl->mem.addr + sl->mem.len > addr){
881*094d6818SDavid du Colombier 			*dom = sl->mem.dom;
882*094d6818SDavid du Colombier 			return sl->mem.len - (addr - sl->mem.addr);
883*094d6818SDavid du Colombier 		}
884*094d6818SDavid du Colombier 	return 0;
885*094d6818SDavid du Colombier }
886*094d6818SDavid du Colombier 
8879ef1f84bSDavid du Colombier /*
8889ef1f84bSDavid du Colombier  * Return a number identifying a color for the memory at
8899ef1f84bSDavid du Colombier  * the given address (color identifies locality) and fill *sizep
8909ef1f84bSDavid du Colombier  * with the size for memory of the same color starting at addr.
8919ef1f84bSDavid du Colombier  */
8929ef1f84bSDavid du Colombier int
memcolor(uintmem addr,uintmem * sizep)8939ef1f84bSDavid du Colombier memcolor(uintmem addr, uintmem *sizep)
8949ef1f84bSDavid du Colombier {
8959ef1f84bSDavid du Colombier 	Srat *sl;
8969ef1f84bSDavid du Colombier 
8979ef1f84bSDavid du Colombier 	for(sl = srat; sl != nil; sl = sl->next)
8989ef1f84bSDavid du Colombier 		if(sl->type == SRmem)
8999ef1f84bSDavid du Colombier 		if(sl->mem.addr <= addr && addr-sl->mem.addr < sl->mem.len){
9009ef1f84bSDavid du Colombier 			if(sizep != nil)
9019ef1f84bSDavid du Colombier 				*sizep = sl->mem.len - (addr - sl->mem.addr);
9029ef1f84bSDavid du Colombier 			if(sl->mem.dom >= NCOLOR)
9039ef1f84bSDavid du Colombier 				print("memcolor: NCOLOR too small");
9049ef1f84bSDavid du Colombier 			return sl->mem.dom%NCOLOR;
9059ef1f84bSDavid du Colombier 		}
9069ef1f84bSDavid du Colombier 	return -1;
9079ef1f84bSDavid du Colombier }
9089ef1f84bSDavid du Colombier 
9099ef1f84bSDavid du Colombier /*
9109ef1f84bSDavid du Colombier  * Being machno an index in sys->machptr, return the color
9119ef1f84bSDavid du Colombier  * for that mach (color identifies locality).
9129ef1f84bSDavid du Colombier  */
9139ef1f84bSDavid du Colombier int
corecolor(int machno)9149ef1f84bSDavid du Colombier corecolor(int machno)
9159ef1f84bSDavid du Colombier {
9169ef1f84bSDavid du Colombier 	Srat *sl;
9179ef1f84bSDavid du Colombier 	Mach *m;
9189ef1f84bSDavid du Colombier 	static int colors[32];
9199ef1f84bSDavid du Colombier 
9209ef1f84bSDavid du Colombier 	if(machno < 0 || machno >= MACHMAX)
9219ef1f84bSDavid du Colombier 		return -1;
9229ef1f84bSDavid du Colombier 	m = sys->machptr[machno];
9239ef1f84bSDavid du Colombier 	if(m == nil)
9249ef1f84bSDavid du Colombier 		return -1;
9259ef1f84bSDavid du Colombier 
9269ef1f84bSDavid du Colombier 	if(machno >= 0 && machno < nelem(colors) && colors[machno] != 0)
9279ef1f84bSDavid du Colombier 		return colors[machno] - 1;
9289ef1f84bSDavid du Colombier 
9299ef1f84bSDavid du Colombier 	for(sl = srat; sl != nil; sl = sl->next)
9309ef1f84bSDavid du Colombier 		if(sl->type == SRlapic && sl->lapic.apic == m->apicno){
9319ef1f84bSDavid du Colombier 			if(machno >= 0 && machno < nelem(colors))
9329ef1f84bSDavid du Colombier 				colors[machno] = 1 + sl->lapic.dom;
9339ef1f84bSDavid du Colombier 			if(sl->lapic.dom >= NCOLOR)
9349ef1f84bSDavid du Colombier 				print("memcolor: NCOLOR too small");
9359ef1f84bSDavid du Colombier 			return sl->lapic.dom%NCOLOR;
9369ef1f84bSDavid du Colombier 		}
9379ef1f84bSDavid du Colombier 	return -1;
9389ef1f84bSDavid du Colombier }
9399ef1f84bSDavid du Colombier 
9409ef1f84bSDavid du Colombier 
9419ef1f84bSDavid du Colombier int
pickcore(int mycolor,int index)9429ef1f84bSDavid du Colombier pickcore(int mycolor, int index)
9439ef1f84bSDavid du Colombier {
9449ef1f84bSDavid du Colombier 	int color;
9459ef1f84bSDavid du Colombier 	int ncorepercol;
9469ef1f84bSDavid du Colombier 
9479ef1f84bSDavid du Colombier 	if(slit == nil)
9489ef1f84bSDavid du Colombier 		return index;
9499ef1f84bSDavid du Colombier 	ncorepercol = MACHMAX/slit->rowlen;
9509ef1f84bSDavid du Colombier 	color = slit->e[mycolor][index/ncorepercol].dom;
9519ef1f84bSDavid du Colombier 	return color * ncorepercol + index % ncorepercol;
9529ef1f84bSDavid du Colombier }
9539ef1f84bSDavid du Colombier 
9549ef1f84bSDavid du Colombier 
9559ef1f84bSDavid du Colombier static void
dumpmadt(Madt * apics)9569ef1f84bSDavid du Colombier dumpmadt(Madt *apics)
9579ef1f84bSDavid du Colombier {
9589ef1f84bSDavid du Colombier 	Apicst *st;
9599ef1f84bSDavid du Colombier 
9609ef1f84bSDavid du Colombier 	DBG("acpi: madt lapic paddr %llux pcat %d:\n", apics->lapicpa, apics->pcat);
9619ef1f84bSDavid du Colombier 	for(st = apics->st; st != nil; st = st->next)
9629ef1f84bSDavid du Colombier 		switch(st->type){
9639ef1f84bSDavid du Colombier 		case ASlapic:
9649ef1f84bSDavid du Colombier 			DBG("\tlapic pid %d id %d\n", st->lapic.pid, st->lapic.id);
9659ef1f84bSDavid du Colombier 			break;
9669ef1f84bSDavid du Colombier 		case ASioapic:
9679ef1f84bSDavid du Colombier 		case ASiosapic:
9689ef1f84bSDavid du Colombier 			DBG("\tioapic id %d addr %#llux ibase %d\n",
9699ef1f84bSDavid du Colombier 				st->ioapic.id, st->ioapic.addr, st->ioapic.ibase);
9709ef1f84bSDavid du Colombier 			break;
9719ef1f84bSDavid du Colombier 		case ASintovr:
9729ef1f84bSDavid du Colombier 			DBG("\tintovr irq %d intr %d flags %#ux\n",
9739ef1f84bSDavid du Colombier 				st->intovr.irq, st->intovr.intr,st->intovr.flags);
9749ef1f84bSDavid du Colombier 			break;
9759ef1f84bSDavid du Colombier 		case ASnmi:
9769ef1f84bSDavid du Colombier 			DBG("\tnmi intr %d flags %#ux\n",
9779ef1f84bSDavid du Colombier 				st->nmi.intr, st->nmi.flags);
9789ef1f84bSDavid du Colombier 			break;
9799ef1f84bSDavid du Colombier 		case ASlnmi:
9809ef1f84bSDavid du Colombier 			DBG("\tlnmi pid %d lint %d flags %#ux\n",
9819ef1f84bSDavid du Colombier 				st->lnmi.pid, st->lnmi.lint, st->lnmi.flags);
9829ef1f84bSDavid du Colombier 			break;
9839ef1f84bSDavid du Colombier 		case ASlsapic:
9849ef1f84bSDavid du Colombier 			DBG("\tlsapic pid %d id %d eid %d puid %d puids %s\n",
9859ef1f84bSDavid du Colombier 				st->lsapic.pid, st->lsapic.id,
9869ef1f84bSDavid du Colombier 				st->lsapic.eid, st->lsapic.puid,
9879ef1f84bSDavid du Colombier 				st->lsapic.puids);
9889ef1f84bSDavid du Colombier 			break;
9899ef1f84bSDavid du Colombier 		case ASintsrc:
9909ef1f84bSDavid du Colombier 			DBG("\tintr type %d pid %d peid %d iosv %d intr %d %#x\n",
9919ef1f84bSDavid du Colombier 				st->type, st->intsrc.pid,
9929ef1f84bSDavid du Colombier 				st->intsrc.peid, st->intsrc.iosv,
9939ef1f84bSDavid du Colombier 				st->intsrc.intr, st->intsrc.flags);
9949ef1f84bSDavid du Colombier 			break;
9959ef1f84bSDavid du Colombier 		case ASlx2apic:
9969ef1f84bSDavid du Colombier 			DBG("\tlx2apic puid %d id %d\n", st->lx2apic.puid, st->lx2apic.id);
9979ef1f84bSDavid du Colombier 			break;
9989ef1f84bSDavid du Colombier 		case ASlx2nmi:
9999ef1f84bSDavid du Colombier 			DBG("\tlx2nmi puid %d intr %d flags %#ux\n",
10009ef1f84bSDavid du Colombier 				st->lx2nmi.puid, st->lx2nmi.intr, st->lx2nmi.flags);
10019ef1f84bSDavid du Colombier 			break;
10029ef1f84bSDavid du Colombier 		default:
10039ef1f84bSDavid du Colombier 			DBG("\t<unknown madt entry>\n");
10049ef1f84bSDavid du Colombier 		}
10059ef1f84bSDavid du Colombier 	DBG("\n");
10069ef1f84bSDavid du Colombier }
10079ef1f84bSDavid du Colombier 
10089ef1f84bSDavid du Colombier static Atable*
acpimadt(uchar * p,int len)10099ef1f84bSDavid du Colombier acpimadt(uchar *p, int len)
10109ef1f84bSDavid du Colombier {
10119ef1f84bSDavid du Colombier 	uchar *pe;
10129ef1f84bSDavid du Colombier 	Apicst *st, *l, **stl;
10139ef1f84bSDavid du Colombier 	int stlen, id;
10149ef1f84bSDavid du Colombier 
10159ef1f84bSDavid du Colombier 	apics = mallocz(sizeof(Madt), 1);
10169ef1f84bSDavid du Colombier 	apics->lapicpa = l32get(p+36);
10179ef1f84bSDavid du Colombier 	apics->pcat = l32get(p+40);
10189ef1f84bSDavid du Colombier 	apics->st = nil;
10199ef1f84bSDavid du Colombier 	stl = &apics->st;
10209ef1f84bSDavid du Colombier 	pe = p + len;
10219ef1f84bSDavid du Colombier 	for(p += 44; p < pe; p += stlen){
10229ef1f84bSDavid du Colombier 		st = mallocz(sizeof(Apicst), 1);
10239ef1f84bSDavid du Colombier 		st->type = p[0];
10249ef1f84bSDavid du Colombier 		st->next = nil;
10259ef1f84bSDavid du Colombier 		stlen = p[1];
10269ef1f84bSDavid du Colombier 		switch(st->type){
10279ef1f84bSDavid du Colombier 		case ASlapic:
10289ef1f84bSDavid du Colombier 			st->lapic.pid = p[2];
10299ef1f84bSDavid du Colombier 			st->lapic.id = p[3];
10309ef1f84bSDavid du Colombier 			if(l32get(p+4) == 0){
10319ef1f84bSDavid du Colombier 				free(st);
10329ef1f84bSDavid du Colombier 				st = nil;
10339ef1f84bSDavid du Colombier 			}
10349ef1f84bSDavid du Colombier 			break;
10359ef1f84bSDavid du Colombier 		case ASioapic:
10369ef1f84bSDavid du Colombier 			st->ioapic.id = id = p[2];
10379ef1f84bSDavid du Colombier 			st->ioapic.addr = l32get(p+4);
10389ef1f84bSDavid du Colombier 			st->ioapic.ibase = l32get(p+8);
10399ef1f84bSDavid du Colombier 			/* iosapic overrides any ioapic entry for the same id */
10409ef1f84bSDavid du Colombier 			for(l = apics->st; l != nil; l = l->next)
10419ef1f84bSDavid du Colombier 				if(l->type == ASiosapic && l->iosapic.id == id){
10429ef1f84bSDavid du Colombier 					st->ioapic = l->iosapic;
10439ef1f84bSDavid du Colombier 					/* we leave it linked; could be removed */
10449ef1f84bSDavid du Colombier 					break;
10459ef1f84bSDavid du Colombier 				}
10469ef1f84bSDavid du Colombier 			break;
10479ef1f84bSDavid du Colombier 		case ASintovr:
10489ef1f84bSDavid du Colombier 			st->intovr.irq = p[3];
10499ef1f84bSDavid du Colombier 			st->intovr.intr = l32get(p+4);
10509ef1f84bSDavid du Colombier 			st->intovr.flags = l16get(p+8);
10519ef1f84bSDavid du Colombier 			break;
10529ef1f84bSDavid du Colombier 		case ASnmi:
10539ef1f84bSDavid du Colombier 			st->nmi.flags = l16get(p+2);
10549ef1f84bSDavid du Colombier 			st->nmi.intr = l32get(p+4);
10559ef1f84bSDavid du Colombier 			break;
10569ef1f84bSDavid du Colombier 		case ASlnmi:
10579ef1f84bSDavid du Colombier 			st->lnmi.pid = p[2];
10589ef1f84bSDavid du Colombier 			st->lnmi.flags = l16get(p+3);
10599ef1f84bSDavid du Colombier 			st->lnmi.lint = p[5];
10609ef1f84bSDavid du Colombier 			break;
10619ef1f84bSDavid du Colombier 		case ASladdr:
10629ef1f84bSDavid du Colombier 			if(sizeof(apics->lapicpa) >= 8)
10639ef1f84bSDavid du Colombier 				apics->lapicpa = l64get(p+8);
10649ef1f84bSDavid du Colombier 			break;
10659ef1f84bSDavid du Colombier 		case ASiosapic:
10669ef1f84bSDavid du Colombier 			id = st->iosapic.id = p[2];
10679ef1f84bSDavid du Colombier 			st->iosapic.ibase = l32get(p+4);
10689ef1f84bSDavid du Colombier 			st->iosapic.addr = l64get(p+8);
10699ef1f84bSDavid du Colombier 			/* iosapic overrides any ioapic entry for the same id */
10709ef1f84bSDavid du Colombier 			for(l = apics->st; l != nil; l = l->next)
10719ef1f84bSDavid du Colombier 				if(l->type == ASioapic && l->ioapic.id == id){
10729ef1f84bSDavid du Colombier 					l->ioapic = st->iosapic;
10739ef1f84bSDavid du Colombier 					free(st);
10749ef1f84bSDavid du Colombier 					st = nil;
10759ef1f84bSDavid du Colombier 					break;
10769ef1f84bSDavid du Colombier 				}
10779ef1f84bSDavid du Colombier 			break;
10789ef1f84bSDavid du Colombier 		case ASlsapic:
10799ef1f84bSDavid du Colombier 			st->lsapic.pid = p[2];
10809ef1f84bSDavid du Colombier 			st->lsapic.id = p[3];
10819ef1f84bSDavid du Colombier 			st->lsapic.eid = p[4];
10829ef1f84bSDavid du Colombier 			st->lsapic.puid = l32get(p+12);
10839ef1f84bSDavid du Colombier 			if(l32get(p+8) == 0){
10849ef1f84bSDavid du Colombier 				free(st);
10859ef1f84bSDavid du Colombier 				st = nil;
10869ef1f84bSDavid du Colombier 			}else
10879ef1f84bSDavid du Colombier 				kstrdup(&st->lsapic.puids, (char*)p+16);
10889ef1f84bSDavid du Colombier 			break;
10899ef1f84bSDavid du Colombier 		case ASintsrc:
10909ef1f84bSDavid du Colombier 			st->intsrc.flags = l16get(p+2);
10919ef1f84bSDavid du Colombier 			st->type = p[4];
10929ef1f84bSDavid du Colombier 			st->intsrc.pid = p[5];
10939ef1f84bSDavid du Colombier 			st->intsrc.peid = p[6];
10949ef1f84bSDavid du Colombier 			st->intsrc.iosv = p[7];
10959ef1f84bSDavid du Colombier 			st->intsrc.intr = l32get(p+8);
10969ef1f84bSDavid du Colombier 			st->intsrc.any = l32get(p+12);
10979ef1f84bSDavid du Colombier 			break;
10989ef1f84bSDavid du Colombier 		case ASlx2apic:
10999ef1f84bSDavid du Colombier 			st->lx2apic.id = l32get(p+4);
11009ef1f84bSDavid du Colombier 			st->lx2apic.puid = l32get(p+12);
11019ef1f84bSDavid du Colombier 			if(l32get(p+8) == 0){
11029ef1f84bSDavid du Colombier 				free(st);
11039ef1f84bSDavid du Colombier 				st = nil;
11049ef1f84bSDavid du Colombier 			}
11059ef1f84bSDavid du Colombier 			break;
11069ef1f84bSDavid du Colombier 		case ASlx2nmi:
11079ef1f84bSDavid du Colombier 			st->lx2nmi.flags = l16get(p+2);
11089ef1f84bSDavid du Colombier 			st->lx2nmi.puid = l32get(p+4);
11099ef1f84bSDavid du Colombier 			st->lx2nmi.intr = p[8];
11109ef1f84bSDavid du Colombier 			break;
11119ef1f84bSDavid du Colombier 		default:
11129ef1f84bSDavid du Colombier 			print("unknown APIC structure\n");
11139ef1f84bSDavid du Colombier 			free(st);
11149ef1f84bSDavid du Colombier 			st = nil;
11159ef1f84bSDavid du Colombier 		}
11169ef1f84bSDavid du Colombier 		if(st != nil){
11179ef1f84bSDavid du Colombier 			*stl = st;
11189ef1f84bSDavid du Colombier 			stl = &st->next;
11199ef1f84bSDavid du Colombier 		}
11209ef1f84bSDavid du Colombier 	}
11219ef1f84bSDavid du Colombier 
11229ef1f84bSDavid du Colombier 	dumpmadt(apics);
11239ef1f84bSDavid du Colombier 	return nil;	/* can be unmapped once parsed */
11249ef1f84bSDavid du Colombier }
11259ef1f84bSDavid du Colombier 
11269ef1f84bSDavid du Colombier /*
11279ef1f84bSDavid du Colombier  * Map the table and keep it there.
11289ef1f84bSDavid du Colombier  */
11299ef1f84bSDavid du Colombier static Atable*
acpitable(uchar * p,int len)11309ef1f84bSDavid du Colombier acpitable(uchar *p, int len)
11319ef1f84bSDavid du Colombier {
11329ef1f84bSDavid du Colombier 	if(len < Sdthdrsz)
11339ef1f84bSDavid du Colombier 		return nil;
11349ef1f84bSDavid du Colombier 	return newtable(p);
11359ef1f84bSDavid du Colombier }
11369ef1f84bSDavid du Colombier 
11379ef1f84bSDavid du Colombier static void
dumptable(char * sig,uchar * p,int l)11389ef1f84bSDavid du Colombier dumptable(char *sig, uchar *p, int l)
11399ef1f84bSDavid du Colombier {
11409ef1f84bSDavid du Colombier 	int n, i;
11419ef1f84bSDavid du Colombier 
11429ef1f84bSDavid du Colombier 	USED(sig);
11439ef1f84bSDavid du Colombier 	if(DBGFLG > 1){
11449ef1f84bSDavid du Colombier 		DBG("%s @ %#p\n", sig, p);
11459ef1f84bSDavid du Colombier 		if(DBGFLG > 2)
11469ef1f84bSDavid du Colombier 			n = l;
11479ef1f84bSDavid du Colombier 		else
11489ef1f84bSDavid du Colombier 			n = 256;
11499ef1f84bSDavid du Colombier 		for(i = 0; i < n; i++){
11509ef1f84bSDavid du Colombier 			if((i % 16) == 0)
11519ef1f84bSDavid du Colombier 				DBG("%x: ", i);
11529ef1f84bSDavid du Colombier 			DBG(" %2.2ux", p[i]);
11539ef1f84bSDavid du Colombier 			if((i % 16) == 15)
11549ef1f84bSDavid du Colombier 				DBG("\n");
11559ef1f84bSDavid du Colombier 		}
11569ef1f84bSDavid du Colombier 		DBG("\n");
11579ef1f84bSDavid du Colombier 		DBG("\n");
11589ef1f84bSDavid du Colombier 	}
11599ef1f84bSDavid du Colombier }
11609ef1f84bSDavid du Colombier 
11619ef1f84bSDavid du Colombier static char*
seprinttable(char * s,char * e,Atable * t)11629ef1f84bSDavid du Colombier seprinttable(char *s, char *e, Atable *t)
11639ef1f84bSDavid du Colombier {
11649ef1f84bSDavid du Colombier 	uchar *p;
11659ef1f84bSDavid du Colombier 	int i, n;
11669ef1f84bSDavid du Colombier 
11679ef1f84bSDavid du Colombier 	p = (uchar*)t->tbl;	/* include header */
11689ef1f84bSDavid du Colombier 	n = Sdthdrsz + t->dlen;
11699ef1f84bSDavid du Colombier 	s = seprint(s, e, "%s @ %#p\n", t->sig, p);
11709ef1f84bSDavid du Colombier 	for(i = 0; i < n; i++){
11719ef1f84bSDavid du Colombier 		if((i % 16) == 0)
11729ef1f84bSDavid du Colombier 			s = seprint(s, e, "%x: ", i);
11739ef1f84bSDavid du Colombier 		s = seprint(s, e, " %2.2ux", p[i]);
11749ef1f84bSDavid du Colombier 		if((i % 16) == 15)
11759ef1f84bSDavid du Colombier 			s = seprint(s, e, "\n");
11769ef1f84bSDavid du Colombier 	}
11779ef1f84bSDavid du Colombier 	return seprint(s, e, "\n\n");
11789ef1f84bSDavid du Colombier }
11799ef1f84bSDavid du Colombier 
11809ef1f84bSDavid du Colombier /*
11819ef1f84bSDavid du Colombier  * process xsdt table and load tables with sig, or all if nil.
11829ef1f84bSDavid du Colombier  * (XXX: should be able to search for sig, oemid, oemtblid)
11839ef1f84bSDavid du Colombier  */
11849ef1f84bSDavid du Colombier static int
acpixsdtload(char * sig)11859ef1f84bSDavid du Colombier acpixsdtload(char *sig)
11869ef1f84bSDavid du Colombier {
11879ef1f84bSDavid du Colombier 	int i, l, t, unmap, found;
11889ef1f84bSDavid du Colombier 	uintmem dhpa;
11899ef1f84bSDavid du Colombier 	uchar *sdt;
11909ef1f84bSDavid du Colombier 	char tsig[5];
11919ef1f84bSDavid du Colombier 
11929ef1f84bSDavid du Colombier 	found = 0;
11939ef1f84bSDavid du Colombier 	for(i = 0; i < xsdt->len; i += xsdt->asize){
11949ef1f84bSDavid du Colombier 		if(xsdt->asize == 8)
11959ef1f84bSDavid du Colombier 			dhpa = l64get(xsdt->p+i);
11969ef1f84bSDavid du Colombier 		else
11979ef1f84bSDavid du Colombier 			dhpa = l32get(xsdt->p+i);
11989ef1f84bSDavid du Colombier 		if((sdt = sdtmap(dhpa, &l, 1)) == nil)
11999ef1f84bSDavid du Colombier 			continue;
12009ef1f84bSDavid du Colombier 		unmap = 1;
12019ef1f84bSDavid du Colombier 		memmove(tsig, sdt, 4);
12029ef1f84bSDavid du Colombier 		tsig[4] = 0;
12039ef1f84bSDavid du Colombier 		if(sig == nil || strcmp(sig, tsig) == 0){
12049ef1f84bSDavid du Colombier 			DBG("acpi: %s addr %#p\n", tsig, sdt);
12059ef1f84bSDavid du Colombier 			for(t = 0; t < nelem(ptables); t++)
12069ef1f84bSDavid du Colombier 				if(strcmp(tsig, ptables[t].sig) == 0){
12079ef1f84bSDavid du Colombier 					dumptable(tsig, sdt, l);
12089ef1f84bSDavid du Colombier 					unmap = ptables[t].f(sdt, l) == nil;
12099ef1f84bSDavid du Colombier 					found = 1;
12109ef1f84bSDavid du Colombier 					break;
12119ef1f84bSDavid du Colombier 				}
12129ef1f84bSDavid du Colombier 		}
12139ef1f84bSDavid du Colombier 		if(unmap)
12149ef1f84bSDavid du Colombier 			vunmap(sdt, l);
12159ef1f84bSDavid du Colombier 	}
12169ef1f84bSDavid du Colombier 	return found;
12179ef1f84bSDavid du Colombier }
12189ef1f84bSDavid du Colombier 
12199ef1f84bSDavid du Colombier static void*
rsdscan(u8int * addr,int len,char * signature)12209ef1f84bSDavid du Colombier rsdscan(u8int* addr, int len, char* signature)
12219ef1f84bSDavid du Colombier {
12229ef1f84bSDavid du Colombier 	int sl;
12239ef1f84bSDavid du Colombier 	u8int *e, *p;
12249ef1f84bSDavid du Colombier 
12259ef1f84bSDavid du Colombier 	e = addr+len;
12269ef1f84bSDavid du Colombier 	sl = strlen(signature);
12279ef1f84bSDavid du Colombier 	for(p = addr; p+sl < e; p += 16){
12289ef1f84bSDavid du Colombier 		if(memcmp(p, signature, sl))
12299ef1f84bSDavid du Colombier 			continue;
12309ef1f84bSDavid du Colombier 		return p;
12319ef1f84bSDavid du Colombier 	}
12329ef1f84bSDavid du Colombier 
12339ef1f84bSDavid du Colombier 	return nil;
12349ef1f84bSDavid du Colombier }
12359ef1f84bSDavid du Colombier 
12369ef1f84bSDavid du Colombier static void*
rsdsearch(char * signature)12379ef1f84bSDavid du Colombier rsdsearch(char* signature)
12389ef1f84bSDavid du Colombier {
12399ef1f84bSDavid du Colombier 	uintmem p;
12409ef1f84bSDavid du Colombier 	u8int *bda;
12419ef1f84bSDavid du Colombier 	void *rsd;
12429ef1f84bSDavid du Colombier 
12439ef1f84bSDavid du Colombier 	/*
12449ef1f84bSDavid du Colombier 	 * Search for the data structure signature:
12459ef1f84bSDavid du Colombier 	 * 1) in the first KB of the EBDA;
12469ef1f84bSDavid du Colombier 	 * 2) in the BIOS ROM between 0xE0000 and 0xFFFFF.
12479ef1f84bSDavid du Colombier 	 */
12489ef1f84bSDavid du Colombier 	if(strncmp((char*)KADDR(0xFFFD9), "EISA", 4) == 0){
12499ef1f84bSDavid du Colombier 		bda = BIOSSEG(0x40);
12509ef1f84bSDavid du Colombier 		if((p = (bda[0x0F]<<8)|bda[0x0E])){
12519ef1f84bSDavid du Colombier 			if(rsd = rsdscan(KADDR(p), 1024, signature))
12529ef1f84bSDavid du Colombier 				return rsd;
12539ef1f84bSDavid du Colombier 		}
12549ef1f84bSDavid du Colombier 	}
12559ef1f84bSDavid du Colombier 	return rsdscan(BIOSSEG(0xE000), 0x20000, signature);
12569ef1f84bSDavid du Colombier }
12579ef1f84bSDavid du Colombier 
12589ef1f84bSDavid du Colombier static void
acpirsdptr(void)12599ef1f84bSDavid du Colombier acpirsdptr(void)
12609ef1f84bSDavid du Colombier {
12619ef1f84bSDavid du Colombier 	Rsdp *rsd;
12629ef1f84bSDavid du Colombier 	int asize;
12639ef1f84bSDavid du Colombier 	uintmem sdtpa;
12649ef1f84bSDavid du Colombier 
12659ef1f84bSDavid du Colombier 	if((rsd = rsdsearch("RSD PTR ")) == nil)
12669ef1f84bSDavid du Colombier 		return;
12679ef1f84bSDavid du Colombier 
12689ef1f84bSDavid du Colombier 	assert(sizeof(Sdthdr) == 36);
12699ef1f84bSDavid du Colombier 
12709ef1f84bSDavid du Colombier 	DBG("acpi: RSD PTR@ %#p, physaddr %#ux length %ud %#llux rev %d\n",
12719ef1f84bSDavid du Colombier 		rsd, l32get(rsd->raddr), l32get(rsd->length),
12729ef1f84bSDavid du Colombier 		l64get(rsd->xaddr), rsd->revision);
12739ef1f84bSDavid du Colombier 
12749ef1f84bSDavid du Colombier 	if(rsd->revision >= 2){
12759ef1f84bSDavid du Colombier 		if(sdtchecksum(rsd, 36) == nil){
12769ef1f84bSDavid du Colombier 			DBG("acpi: RSD: bad checksum\n");
12779ef1f84bSDavid du Colombier 			return;
12789ef1f84bSDavid du Colombier 		}
12799ef1f84bSDavid du Colombier 		sdtpa = l64get(rsd->xaddr);
12809ef1f84bSDavid du Colombier 		asize = 8;
12819ef1f84bSDavid du Colombier 	}
12829ef1f84bSDavid du Colombier 	else{
12839ef1f84bSDavid du Colombier 		if(sdtchecksum(rsd, 20) == nil){
12849ef1f84bSDavid du Colombier 			DBG("acpi: RSD: bad checksum\n");
12859ef1f84bSDavid du Colombier 			return;
12869ef1f84bSDavid du Colombier 		}
12879ef1f84bSDavid du Colombier 		sdtpa = l32get(rsd->raddr);
12889ef1f84bSDavid du Colombier 		asize = 4;
12899ef1f84bSDavid du Colombier 	}
12909ef1f84bSDavid du Colombier 
12919ef1f84bSDavid du Colombier 	/*
12929ef1f84bSDavid du Colombier 	 * process the RSDT or XSDT table.
12939ef1f84bSDavid du Colombier 	 */
12949ef1f84bSDavid du Colombier 	xsdt = malloc(sizeof(Xsdt));
12959ef1f84bSDavid du Colombier 	if(xsdt == nil){
12969ef1f84bSDavid du Colombier 		DBG("acpi: malloc failed\n");
12979ef1f84bSDavid du Colombier 		return;
12989ef1f84bSDavid du Colombier 	}
12999ef1f84bSDavid du Colombier 	if((xsdt->p = sdtmap(sdtpa, &xsdt->len, 1)) == nil){
13009ef1f84bSDavid du Colombier 		DBG("acpi: sdtmap failed\n");
13019ef1f84bSDavid du Colombier 		return;
13029ef1f84bSDavid du Colombier 	}
13039ef1f84bSDavid du Colombier 	if((xsdt->p[0] != 'R' && xsdt->p[0] != 'X') || memcmp(xsdt->p+1, "SDT", 3) != 0){
13049ef1f84bSDavid du Colombier 		DBG("acpi: xsdt sig: %c%c%c%c\n",
13059ef1f84bSDavid du Colombier 			xsdt->p[0], xsdt->p[1], xsdt->p[2], xsdt->p[3]);
13069ef1f84bSDavid du Colombier 		free(xsdt);
13079ef1f84bSDavid du Colombier 		xsdt = nil;
13089ef1f84bSDavid du Colombier 		vunmap(xsdt, xsdt->len);
13099ef1f84bSDavid du Colombier 		return;
13109ef1f84bSDavid du Colombier 	}
13119ef1f84bSDavid du Colombier 	xsdt->p += sizeof(Sdthdr);
13129ef1f84bSDavid du Colombier 	xsdt->len -= sizeof(Sdthdr);
13139ef1f84bSDavid du Colombier 	xsdt->asize = asize;
13149ef1f84bSDavid du Colombier 	DBG("acpi: XSDT %#p\n", xsdt);
13159ef1f84bSDavid du Colombier 	acpixsdtload(nil);
13169ef1f84bSDavid du Colombier 	/* xsdt is kept and not unmapped */
13179ef1f84bSDavid du Colombier 
13189ef1f84bSDavid du Colombier }
13199ef1f84bSDavid du Colombier 
13209ef1f84bSDavid du Colombier static int
acpigen(Chan * c,char *,Dirtab * tab,int ntab,int i,Dir * dp)13219ef1f84bSDavid du Colombier acpigen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp)
13229ef1f84bSDavid du Colombier {
13239ef1f84bSDavid du Colombier 	Qid qid;
13249ef1f84bSDavid du Colombier 
13259ef1f84bSDavid du Colombier 	if(i == DEVDOTDOT){
13269ef1f84bSDavid du Colombier 		mkqid(&qid, Qdir, 0, QTDIR);
13279ef1f84bSDavid du Colombier 		devdir(c, qid, ".", 0, eve, 0555, dp);
13289ef1f84bSDavid du Colombier 		return 1;
13299ef1f84bSDavid du Colombier 	}
13309ef1f84bSDavid du Colombier 	i++; /* skip first element for . itself */
13319ef1f84bSDavid du Colombier 	if(tab==0 || i>=ntab)
13329ef1f84bSDavid du Colombier 		return -1;
13339ef1f84bSDavid du Colombier 	tab += i;
13349ef1f84bSDavid du Colombier 	qid = tab->qid;
13359ef1f84bSDavid du Colombier 	qid.path &= ~Qdir;
13369ef1f84bSDavid du Colombier 	qid.vers = 0;
13379ef1f84bSDavid du Colombier 	devdir(c, qid, tab->name, tab->length, eve, tab->perm, dp);
13389ef1f84bSDavid du Colombier 	return 1;
13399ef1f84bSDavid du Colombier }
13409ef1f84bSDavid du Colombier 
13419ef1f84bSDavid du Colombier static int
Gfmt(Fmt * f)13429ef1f84bSDavid du Colombier Gfmt(Fmt* f)
13439ef1f84bSDavid du Colombier {
13449ef1f84bSDavid du Colombier 	Gas *g;
13459ef1f84bSDavid du Colombier 
13469ef1f84bSDavid du Colombier 	g = va_arg(f->args, Gas*);
13479ef1f84bSDavid du Colombier 	switch(g->spc){
13489ef1f84bSDavid du Colombier 	case Rsysmem:
13499ef1f84bSDavid du Colombier 	case Rsysio:
13509ef1f84bSDavid du Colombier 	case Rembed:
13519ef1f84bSDavid du Colombier 	case Rsmbus:
13529ef1f84bSDavid du Colombier 	case Rcmos:
13539ef1f84bSDavid du Colombier 	case Rpcibar:
13549ef1f84bSDavid du Colombier 	case Ripmi:
13559ef1f84bSDavid du Colombier 		fmtprint(f, "[%s ", acpiregstr(g->spc));
13569ef1f84bSDavid du Colombier 		break;
13579ef1f84bSDavid du Colombier 	case Rpcicfg:
13589ef1f84bSDavid du Colombier 		fmtprint(f, "[pci ");
13599ef1f84bSDavid du Colombier 		fmtprint(f, "dev %#ulx ", (ulong)(g->addr >> 32) & 0xFFFF);
13609ef1f84bSDavid du Colombier 		fmtprint(f, "fn %#ulx ", (ulong)(g->addr & 0xFFFF0000) >> 16);
13619ef1f84bSDavid du Colombier 		fmtprint(f, "adr %#ulx ", (ulong)(g->addr &0xFFFF));
13629ef1f84bSDavid du Colombier 		break;
13639ef1f84bSDavid du Colombier 	case Rfixedhw:
13649ef1f84bSDavid du Colombier 		fmtprint(f, "[hw ");
13659ef1f84bSDavid du Colombier 		break;
13669ef1f84bSDavid du Colombier 	default:
13679ef1f84bSDavid du Colombier 		fmtprint(f, "[spc=%#ux ", g->spc);
13689ef1f84bSDavid du Colombier 	}
13699ef1f84bSDavid du Colombier 	return fmtprint(f, "off %d len %d addr %#ullx sz%d]",
13709ef1f84bSDavid du Colombier 		g->off, g->len, g->addr, g->accsz);
13719ef1f84bSDavid du Colombier }
13729ef1f84bSDavid du Colombier 
13739ef1f84bSDavid du Colombier static uint
getbanked(int ra,int rb,int sz)13749ef1f84bSDavid du Colombier getbanked(int ra, int rb, int sz)
13759ef1f84bSDavid du Colombier {
13769ef1f84bSDavid du Colombier 	uint r;
13779ef1f84bSDavid du Colombier 
13789ef1f84bSDavid du Colombier 	r = 0;
13799ef1f84bSDavid du Colombier 	switch(sz){
13809ef1f84bSDavid du Colombier 	case 1:
13819ef1f84bSDavid du Colombier 		if(ra != 0)
13829ef1f84bSDavid du Colombier 			r |= inb(ra);
13839ef1f84bSDavid du Colombier 		if(rb != 0)
13849ef1f84bSDavid du Colombier 			r |= inb(rb);
13859ef1f84bSDavid du Colombier 		break;
13869ef1f84bSDavid du Colombier 	case 2:
13879ef1f84bSDavid du Colombier 		if(ra != 0)
13889ef1f84bSDavid du Colombier 			r |= ins(ra);
13899ef1f84bSDavid du Colombier 		if(rb != 0)
13909ef1f84bSDavid du Colombier 			r |= ins(rb);
13919ef1f84bSDavid du Colombier 		break;
13929ef1f84bSDavid du Colombier 	case 4:
13939ef1f84bSDavid du Colombier 		if(ra != 0)
13949ef1f84bSDavid du Colombier 			r |= inl(ra);
13959ef1f84bSDavid du Colombier 		if(rb != 0)
13969ef1f84bSDavid du Colombier 			r |= inl(rb);
13979ef1f84bSDavid du Colombier 		break;
13989ef1f84bSDavid du Colombier 	default:
13999ef1f84bSDavid du Colombier 		print("getbanked: wrong size\n");
14009ef1f84bSDavid du Colombier 	}
14019ef1f84bSDavid du Colombier 	return r;
14029ef1f84bSDavid du Colombier }
14039ef1f84bSDavid du Colombier 
14049ef1f84bSDavid du Colombier static uint
setbanked(int ra,int rb,int sz,int v)14059ef1f84bSDavid du Colombier setbanked(int ra, int rb, int sz, int v)
14069ef1f84bSDavid du Colombier {
14079ef1f84bSDavid du Colombier 	uint r;
14089ef1f84bSDavid du Colombier 
14099ef1f84bSDavid du Colombier 	r = -1;
14109ef1f84bSDavid du Colombier 	switch(sz){
14119ef1f84bSDavid du Colombier 	case 1:
14129ef1f84bSDavid du Colombier 		if(ra != 0)
14139ef1f84bSDavid du Colombier 			outb(ra, v);
14149ef1f84bSDavid du Colombier 		if(rb != 0)
14159ef1f84bSDavid du Colombier 			outb(rb, v);
14169ef1f84bSDavid du Colombier 		break;
14179ef1f84bSDavid du Colombier 	case 2:
14189ef1f84bSDavid du Colombier 		if(ra != 0)
14199ef1f84bSDavid du Colombier 			outs(ra, v);
14209ef1f84bSDavid du Colombier 		if(rb != 0)
14219ef1f84bSDavid du Colombier 			outs(rb, v);
14229ef1f84bSDavid du Colombier 		break;
14239ef1f84bSDavid du Colombier 	case 4:
14249ef1f84bSDavid du Colombier 		if(ra != 0)
14259ef1f84bSDavid du Colombier 			outl(ra, v);
14269ef1f84bSDavid du Colombier 		if(rb != 0)
14279ef1f84bSDavid du Colombier 			outl(rb, v);
14289ef1f84bSDavid du Colombier 		break;
14299ef1f84bSDavid du Colombier 	default:
14309ef1f84bSDavid du Colombier 		print("setbanked: wrong size\n");
14319ef1f84bSDavid du Colombier 	}
14329ef1f84bSDavid du Colombier 	return r;
14339ef1f84bSDavid du Colombier }
14349ef1f84bSDavid du Colombier 
14359ef1f84bSDavid du Colombier static uint
getpm1ctl(void)14369ef1f84bSDavid du Colombier getpm1ctl(void)
14379ef1f84bSDavid du Colombier {
14389ef1f84bSDavid du Colombier 	return getbanked(fadt.pm1acntblk, fadt.pm1bcntblk, fadt.pm1cntlen);
14399ef1f84bSDavid du Colombier }
14409ef1f84bSDavid du Colombier 
14419ef1f84bSDavid du Colombier static void
setpm1sts(uint v)14429ef1f84bSDavid du Colombier setpm1sts(uint v)
14439ef1f84bSDavid du Colombier {
14449ef1f84bSDavid du Colombier 	DBG("acpi: setpm1sts %#ux\n", v);
14459ef1f84bSDavid du Colombier 	setbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen/2, v);
14469ef1f84bSDavid du Colombier }
14479ef1f84bSDavid du Colombier 
14489ef1f84bSDavid du Colombier static uint
getpm1sts(void)14499ef1f84bSDavid du Colombier getpm1sts(void)
14509ef1f84bSDavid du Colombier {
14519ef1f84bSDavid du Colombier 	return getbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen/2);
14529ef1f84bSDavid du Colombier }
14539ef1f84bSDavid du Colombier 
14549ef1f84bSDavid du Colombier static uint
getpm1en(void)14559ef1f84bSDavid du Colombier getpm1en(void)
14569ef1f84bSDavid du Colombier {
14579ef1f84bSDavid du Colombier 	int sz;
14589ef1f84bSDavid du Colombier 
14599ef1f84bSDavid du Colombier 	sz = fadt.pm1evtlen/2;
14609ef1f84bSDavid du Colombier 	return getbanked(fadt.pm1aevtblk+sz, fadt.pm1bevtblk+sz, sz);
14619ef1f84bSDavid du Colombier }
14629ef1f84bSDavid du Colombier 
14639ef1f84bSDavid du Colombier static int
getgpeen(int n)14649ef1f84bSDavid du Colombier getgpeen(int n)
14659ef1f84bSDavid du Colombier {
14669ef1f84bSDavid du Colombier 	return inb(gpes[n].enio) & 1<<gpes[n].enbit;
14679ef1f84bSDavid du Colombier }
14689ef1f84bSDavid du Colombier 
14699ef1f84bSDavid du Colombier static void
setgpeen(int n,uint v)14709ef1f84bSDavid du Colombier setgpeen(int n, uint v)
14719ef1f84bSDavid du Colombier {
14729ef1f84bSDavid du Colombier 	int old;
14739ef1f84bSDavid du Colombier 
14749ef1f84bSDavid du Colombier 	DBG("acpi: setgpe %d %d\n", n, v);
14759ef1f84bSDavid du Colombier 	old = inb(gpes[n].enio);
14769ef1f84bSDavid du Colombier 	if(v)
14779ef1f84bSDavid du Colombier 		outb(gpes[n].enio, old | 1<<gpes[n].enbit);
14789ef1f84bSDavid du Colombier 	else
14799ef1f84bSDavid du Colombier 		outb(gpes[n].enio, old & ~(1<<gpes[n].enbit));
14809ef1f84bSDavid du Colombier }
14819ef1f84bSDavid du Colombier 
14829ef1f84bSDavid du Colombier static void
clrgpests(int n)14839ef1f84bSDavid du Colombier clrgpests(int n)
14849ef1f84bSDavid du Colombier {
14859ef1f84bSDavid du Colombier 	outb(gpes[n].stsio, 1<<gpes[n].stsbit);
14869ef1f84bSDavid du Colombier }
14879ef1f84bSDavid du Colombier 
14889ef1f84bSDavid du Colombier static uint
getgpests(int n)14899ef1f84bSDavid du Colombier getgpests(int n)
14909ef1f84bSDavid du Colombier {
14919ef1f84bSDavid du Colombier 	return inb(gpes[n].stsio) & 1<<gpes[n].stsbit;
14929ef1f84bSDavid du Colombier }
14939ef1f84bSDavid du Colombier 
14949ef1f84bSDavid du Colombier static void
acpiintr(Ureg *,void *)14959ef1f84bSDavid du Colombier acpiintr(Ureg*, void*)
14969ef1f84bSDavid du Colombier {
14979ef1f84bSDavid du Colombier 	int i;
14989ef1f84bSDavid du Colombier 	uint sts, en;
14999ef1f84bSDavid du Colombier 
15009ef1f84bSDavid du Colombier 	print("acpi: intr\n");
15019ef1f84bSDavid du Colombier 
15029ef1f84bSDavid du Colombier 	for(i = 0; i < ngpes; i++)
15039ef1f84bSDavid du Colombier 		if(getgpests(i)){
15049ef1f84bSDavid du Colombier 			print("gpe %d on\n", i);
15059ef1f84bSDavid du Colombier 			en = getgpeen(i);
15069ef1f84bSDavid du Colombier 			setgpeen(i, 0);
15079ef1f84bSDavid du Colombier 			clrgpests(i);
15089ef1f84bSDavid du Colombier 			if(en != 0)
15099ef1f84bSDavid du Colombier 				print("acpiitr: calling gpe %d\n", i);
15109ef1f84bSDavid du Colombier 		//	queue gpe for calling gpe->ho in the
15119ef1f84bSDavid du Colombier 		//	aml process.
15129ef1f84bSDavid du Colombier 		//	enable it again when it returns.
15139ef1f84bSDavid du Colombier 		}
15149ef1f84bSDavid du Colombier 	sts = getpm1sts();
15159ef1f84bSDavid du Colombier 	en = getpm1en();
15169ef1f84bSDavid du Colombier 	print("acpiitr: pm1sts %#ux pm1en %#ux\n", sts, en);
15179ef1f84bSDavid du Colombier 	if(sts&en)
15189ef1f84bSDavid du Colombier 		print("have enabled events\n");
15199ef1f84bSDavid du Colombier 	if(sts&1)
15209ef1f84bSDavid du Colombier 		print("power button\n");
15219ef1f84bSDavid du Colombier 	// XXX serve other interrupts here.
15229ef1f84bSDavid du Colombier 	setpm1sts(sts);
15239ef1f84bSDavid du Colombier }
15249ef1f84bSDavid du Colombier 
15259ef1f84bSDavid du Colombier static void
initgpes(void)15269ef1f84bSDavid du Colombier initgpes(void)
15279ef1f84bSDavid du Colombier {
15289ef1f84bSDavid du Colombier 	int i, n0, n1;
15299ef1f84bSDavid du Colombier 
15309ef1f84bSDavid du Colombier 	n0 = fadt.gpe0blklen/2;
15319ef1f84bSDavid du Colombier 	n1 = fadt.gpe1blklen/2;
15329ef1f84bSDavid du Colombier 	ngpes = n0 + n1;
15339ef1f84bSDavid du Colombier 	gpes = mallocz(sizeof(Gpe) * ngpes, 1);
15349ef1f84bSDavid du Colombier 	for(i = 0; i < n0; i++){
15359ef1f84bSDavid du Colombier 		gpes[i].nb = i;
15369ef1f84bSDavid du Colombier 		gpes[i].stsbit = i&7;
15379ef1f84bSDavid du Colombier 		gpes[i].stsio = fadt.gpe0blk + (i>>3);
15389ef1f84bSDavid du Colombier 		gpes[i].enbit = (n0 + i)&7;
15399ef1f84bSDavid du Colombier 		gpes[i].enio = fadt.gpe0blk + ((n0 + i)>>3);
15409ef1f84bSDavid du Colombier 	}
15419ef1f84bSDavid du Colombier 	for(i = 0; i + n0 < ngpes; i++){
15429ef1f84bSDavid du Colombier 		gpes[i + n0].nb = fadt.gp1base + i;
15439ef1f84bSDavid du Colombier 		gpes[i + n0].stsbit = i&7;
15449ef1f84bSDavid du Colombier 		gpes[i + n0].stsio = fadt.gpe1blk + (i>>3);
15459ef1f84bSDavid du Colombier 		gpes[i + n0].enbit = (n1 + i)&7;
15469ef1f84bSDavid du Colombier 		gpes[i + n0].enio = fadt.gpe1blk + ((n1 + i)>>3);
15479ef1f84bSDavid du Colombier 	}
15489ef1f84bSDavid du Colombier 	for(i = 0; i < ngpes; i++){
15499ef1f84bSDavid du Colombier 		setgpeen(i, 0);
15509ef1f84bSDavid du Colombier 		clrgpests(i);
15519ef1f84bSDavid du Colombier 	}
15529ef1f84bSDavid du Colombier }
15539ef1f84bSDavid du Colombier 
15549ef1f84bSDavid du Colombier static void
acpiioalloc(uint addr,int len)15559ef1f84bSDavid du Colombier acpiioalloc(uint addr, int len)
15569ef1f84bSDavid du Colombier {
15579ef1f84bSDavid du Colombier 	if(addr != 0)
15589ef1f84bSDavid du Colombier 		ioalloc(addr, len, 0, "acpi");
15599ef1f84bSDavid du Colombier }
15609ef1f84bSDavid du Colombier 
15619ef1f84bSDavid du Colombier int
acpiinit(void)15629ef1f84bSDavid du Colombier acpiinit(void)
15639ef1f84bSDavid du Colombier {
15649ef1f84bSDavid du Colombier 	if(fadt.smicmd == 0){
15659ef1f84bSDavid du Colombier 		fmtinstall('G', Gfmt);
15669ef1f84bSDavid du Colombier 		acpirsdptr();
15679ef1f84bSDavid du Colombier 		if(fadt.smicmd == 0)
15689ef1f84bSDavid du Colombier 			return -1;
15699ef1f84bSDavid du Colombier 	}
15709ef1f84bSDavid du Colombier 	return 0;
15719ef1f84bSDavid du Colombier }
15729ef1f84bSDavid du Colombier 
15739ef1f84bSDavid du Colombier static Chan*
acpiattach(char * spec)15749ef1f84bSDavid du Colombier acpiattach(char *spec)
15759ef1f84bSDavid du Colombier {
15769ef1f84bSDavid du Colombier 	int i;
15779ef1f84bSDavid du Colombier 
15789ef1f84bSDavid du Colombier 	/*
15799ef1f84bSDavid du Colombier 	 * This was written for the stock kernel.
15809ef1f84bSDavid du Colombier 	 * This code must use 64bit registers to be acpi ready in nix.
15819ef1f84bSDavid du Colombier 	 * Besides, we mostly want the locality and affinity tables.
15829ef1f84bSDavid du Colombier 	 */
15839ef1f84bSDavid du Colombier 	if(1 || acpiinit() < 0)
15849ef1f84bSDavid du Colombier 		error("acpi not enabled");
15859ef1f84bSDavid du Colombier 
15869ef1f84bSDavid du Colombier 	/*
15879ef1f84bSDavid du Colombier 	 * should use fadt->xpm* and fadt->xgpe* registers for 64 bits.
15889ef1f84bSDavid du Colombier 	 * We are not ready in this kernel for that.
15899ef1f84bSDavid du Colombier 	 */
15909ef1f84bSDavid du Colombier 	DBG("acpi io alloc\n");
15919ef1f84bSDavid du Colombier 	acpiioalloc(fadt.smicmd, 1);
15929ef1f84bSDavid du Colombier 	acpiioalloc(fadt.pm1aevtblk, fadt.pm1evtlen);
15939ef1f84bSDavid du Colombier 	acpiioalloc(fadt.pm1bevtblk, fadt.pm1evtlen );
15949ef1f84bSDavid du Colombier 	acpiioalloc(fadt.pm1acntblk, fadt.pm1cntlen);
15959ef1f84bSDavid du Colombier 	acpiioalloc(fadt.pm1bcntblk, fadt.pm1cntlen);
15969ef1f84bSDavid du Colombier 	acpiioalloc(fadt.pm2cntblk, fadt.pm2cntlen);
15979ef1f84bSDavid du Colombier 	acpiioalloc(fadt.pmtmrblk, fadt.pmtmrlen);
15989ef1f84bSDavid du Colombier 	acpiioalloc(fadt.gpe0blk, fadt.gpe0blklen);
15999ef1f84bSDavid du Colombier 	acpiioalloc(fadt.gpe1blk, fadt.gpe1blklen);
16009ef1f84bSDavid du Colombier 
16019ef1f84bSDavid du Colombier 	DBG("acpi init gpes\n");
16029ef1f84bSDavid du Colombier 	initgpes();
16039ef1f84bSDavid du Colombier 
16049ef1f84bSDavid du Colombier 	/*
16059ef1f84bSDavid du Colombier 	 * This starts ACPI, which may require we handle
16069ef1f84bSDavid du Colombier 	 * power mgmt events ourselves. Use with care.
16079ef1f84bSDavid du Colombier 	 */
16089ef1f84bSDavid du Colombier 	DBG("acpi starting\n");
16099ef1f84bSDavid du Colombier 	outb(fadt.smicmd, fadt.acpienable);
16109ef1f84bSDavid du Colombier 	for(i = 0; i < 10; i++)
16119ef1f84bSDavid du Colombier 		if(getpm1ctl() & Pm1SciEn)
16129ef1f84bSDavid du Colombier 			break;
16139ef1f84bSDavid du Colombier 	if(i == 10)
16149ef1f84bSDavid du Colombier 		error("acpi: failed to enable\n");
16159ef1f84bSDavid du Colombier 	if(fadt.sciint != 0)
16169ef1f84bSDavid du Colombier 		intrenable(fadt.sciint, acpiintr, 0, BUSUNKNOWN, "acpi");
16179ef1f84bSDavid du Colombier 	return devattach(L'α', spec);
16189ef1f84bSDavid du Colombier }
16199ef1f84bSDavid du Colombier 
16209ef1f84bSDavid du Colombier static Walkqid*
acpiwalk(Chan * c,Chan * nc,char ** name,int nname)16219ef1f84bSDavid du Colombier acpiwalk(Chan *c, Chan *nc, char **name, int nname)
16229ef1f84bSDavid du Colombier {
16239ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, acpidir, nelem(acpidir), acpigen);
16249ef1f84bSDavid du Colombier }
16259ef1f84bSDavid du Colombier 
16269ef1f84bSDavid du Colombier static long
acpistat(Chan * c,uchar * dp,long n)16279ef1f84bSDavid du Colombier acpistat(Chan *c, uchar *dp, long n)
16289ef1f84bSDavid du Colombier {
16299ef1f84bSDavid du Colombier 	return devstat(c, dp, n, acpidir, nelem(acpidir), acpigen);
16309ef1f84bSDavid du Colombier }
16319ef1f84bSDavid du Colombier 
16329ef1f84bSDavid du Colombier static Chan*
acpiopen(Chan * c,int omode)16339ef1f84bSDavid du Colombier acpiopen(Chan *c, int omode)
16349ef1f84bSDavid du Colombier {
16359ef1f84bSDavid du Colombier 	return devopen(c, omode, acpidir, nelem(acpidir), acpigen);
16369ef1f84bSDavid du Colombier }
16379ef1f84bSDavid du Colombier 
16389ef1f84bSDavid du Colombier static void
acpiclose(Chan *)16399ef1f84bSDavid du Colombier acpiclose(Chan *)
16409ef1f84bSDavid du Colombier {
16419ef1f84bSDavid du Colombier }
16429ef1f84bSDavid du Colombier 
16439ef1f84bSDavid du Colombier static char*ttext;
16449ef1f84bSDavid du Colombier static int tlen;
16459ef1f84bSDavid du Colombier 
16469ef1f84bSDavid du Colombier static long
acpiread(Chan * c,void * a,long n,vlong off)16479ef1f84bSDavid du Colombier acpiread(Chan *c, void *a, long n, vlong off)
16489ef1f84bSDavid du Colombier {
16499ef1f84bSDavid du Colombier 	long q;
16509ef1f84bSDavid du Colombier 	Atable *t;
16519ef1f84bSDavid du Colombier 	char *ns, *s, *e, *ntext;
16529ef1f84bSDavid du Colombier 
16539ef1f84bSDavid du Colombier 	q = c->qid.path;
16549ef1f84bSDavid du Colombier 	switch(q){
16559ef1f84bSDavid du Colombier 	case Qdir:
16569ef1f84bSDavid du Colombier 		return devdirread(c, a, n, acpidir, nelem(acpidir), acpigen);
16579ef1f84bSDavid du Colombier 	case Qtbl:
16589ef1f84bSDavid du Colombier 		if(ttext == nil){
16599ef1f84bSDavid du Colombier 			tlen = 1024;
16609ef1f84bSDavid du Colombier 			ttext = malloc(tlen);
16619ef1f84bSDavid du Colombier 			if(ttext == nil){
16629ef1f84bSDavid du Colombier 				print("acpi: no memory\n");
16639ef1f84bSDavid du Colombier 				return 0;
16649ef1f84bSDavid du Colombier 			}
16659ef1f84bSDavid du Colombier 			s = ttext;
16669ef1f84bSDavid du Colombier 			e = ttext + tlen;
16679ef1f84bSDavid du Colombier 			strcpy(s, "no tables\n");
16689ef1f84bSDavid du Colombier 			for(t = tfirst; t != nil; t = t->next){
16699ef1f84bSDavid du Colombier 				ns = seprinttable(s, e, t);
16709ef1f84bSDavid du Colombier 				while(ns == e - 1){
16719ef1f84bSDavid du Colombier 					DBG("acpiread: allocated %d\n", tlen*2);
16729ef1f84bSDavid du Colombier 					ntext = realloc(ttext, tlen*2);
16739ef1f84bSDavid du Colombier 					if(ntext == nil)
16749ef1f84bSDavid du Colombier 						panic("acpi: no memory\n");
16759ef1f84bSDavid du Colombier 					s = ntext + (ttext - s);
16769ef1f84bSDavid du Colombier 					ttext = ntext;
16779ef1f84bSDavid du Colombier 					tlen *= 2;
16789ef1f84bSDavid du Colombier 					e = ttext + tlen;
16799ef1f84bSDavid du Colombier 					ns = seprinttable(s, e, t);
16809ef1f84bSDavid du Colombier 				}
16819ef1f84bSDavid du Colombier 				s = ns;
16829ef1f84bSDavid du Colombier 			}
16839ef1f84bSDavid du Colombier 
16849ef1f84bSDavid du Colombier 		}
16859ef1f84bSDavid du Colombier 		return readstr(off, a, n, ttext);
16869ef1f84bSDavid du Colombier 	case Qio:
16879ef1f84bSDavid du Colombier 		if(reg == nil)
16889ef1f84bSDavid du Colombier 			error("region not configured");
16899ef1f84bSDavid du Colombier 		return regio(reg, a, n, off, 0);
16909ef1f84bSDavid du Colombier 	}
16919ef1f84bSDavid du Colombier 	error(Eperm);
16929ef1f84bSDavid du Colombier 	return -1;
16939ef1f84bSDavid du Colombier }
16949ef1f84bSDavid du Colombier 
16959ef1f84bSDavid du Colombier static long
acpiwrite(Chan * c,void * a,long n,vlong off)16969ef1f84bSDavid du Colombier acpiwrite(Chan *c, void *a, long n, vlong off)
16979ef1f84bSDavid du Colombier {
16989ef1f84bSDavid du Colombier 	Cmdtab *ct;
16999ef1f84bSDavid du Colombier 	Cmdbuf *cb;
17009ef1f84bSDavid du Colombier 	Reg *r;
17019ef1f84bSDavid du Colombier 	uint rno, fun, dev, bus, i;
17029ef1f84bSDavid du Colombier 
17039ef1f84bSDavid du Colombier 	if(c->qid.path == Qio){
17049ef1f84bSDavid du Colombier 		if(reg == nil)
17059ef1f84bSDavid du Colombier 			error("region not configured");
17069ef1f84bSDavid du Colombier 		return regio(reg, a, n, off, 1);
17079ef1f84bSDavid du Colombier 	}
17089ef1f84bSDavid du Colombier 	if(c->qid.path != Qctl)
17099ef1f84bSDavid du Colombier 		error(Eperm);
17109ef1f84bSDavid du Colombier 
17119ef1f84bSDavid du Colombier 	cb = parsecmd(a, n);
17129ef1f84bSDavid du Colombier 	if(waserror()){
17139ef1f84bSDavid du Colombier 		free(cb);
17149ef1f84bSDavid du Colombier 		nexterror();
17159ef1f84bSDavid du Colombier 	}
17169ef1f84bSDavid du Colombier 	ct = lookupcmd(cb, ctls, nelem(ctls));
17179ef1f84bSDavid du Colombier 	DBG("acpi ctl %s\n", cb->f[0]);
17189ef1f84bSDavid du Colombier 	switch(ct->index){
17199ef1f84bSDavid du Colombier 	case CMregion:
17209ef1f84bSDavid du Colombier 		r = reg;
17219ef1f84bSDavid du Colombier 		if(r == nil){
17229ef1f84bSDavid du Colombier 			r = smalloc(sizeof(Reg));
17239ef1f84bSDavid du Colombier 			r->name = nil;
17249ef1f84bSDavid du Colombier 		}
17259ef1f84bSDavid du Colombier 		kstrdup(&r->name, cb->f[1]);
17269ef1f84bSDavid du Colombier 		r->spc = acpiregid(cb->f[2]);
17279ef1f84bSDavid du Colombier 		if(r->spc < 0){
17289ef1f84bSDavid du Colombier 			free(r);
17299ef1f84bSDavid du Colombier 			reg = nil;
17309ef1f84bSDavid du Colombier 			error("bad region type");
17319ef1f84bSDavid du Colombier 		}
17329ef1f84bSDavid du Colombier 		if(r->spc == Rpcicfg || r->spc == Rpcibar){
17339ef1f84bSDavid du Colombier 			rno = r->base>>Rpciregshift & Rpciregmask;
17349ef1f84bSDavid du Colombier 			fun = r->base>>Rpcifunshift & Rpcifunmask;
17359ef1f84bSDavid du Colombier 			dev = r->base>>Rpcidevshift & Rpcidevmask;
17369ef1f84bSDavid du Colombier 			bus = r->base>>Rpcibusshift & Rpcibusmask;
17379ef1f84bSDavid du Colombier 			r->tbdf = MKBUS(BusPCI, bus, dev, fun);
17389ef1f84bSDavid du Colombier 			r->base = rno;	/* register ~ our base addr */
17399ef1f84bSDavid du Colombier 		}
17409ef1f84bSDavid du Colombier 		r->base = strtoull(cb->f[3], nil, 0);
17419ef1f84bSDavid du Colombier 		r->len = strtoull(cb->f[4], nil, 0);
17429ef1f84bSDavid du Colombier 		r->accsz = strtoul(cb->f[5], nil, 0);
17439ef1f84bSDavid du Colombier 		if(r->accsz < 1 || r->accsz > 4){
17449ef1f84bSDavid du Colombier 			free(r);
17459ef1f84bSDavid du Colombier 			reg = nil;
17469ef1f84bSDavid du Colombier 			error("bad region access size");
17479ef1f84bSDavid du Colombier 		}
17489ef1f84bSDavid du Colombier 		reg = r;
17499ef1f84bSDavid du Colombier 		DBG("region %s %s %llux %llux sz%d",
17509ef1f84bSDavid du Colombier 			r->name, acpiregstr(r->spc), r->base, r->len, r->accsz);
17519ef1f84bSDavid du Colombier 		break;
17529ef1f84bSDavid du Colombier 	case CMgpe:
17539ef1f84bSDavid du Colombier 		i = strtoul(cb->f[1], nil, 0);
17549ef1f84bSDavid du Colombier 		if(i >= ngpes)
17559ef1f84bSDavid du Colombier 			error("gpe out of range");
17569ef1f84bSDavid du Colombier 		kstrdup(&gpes[i].obj, cb->f[2]);
17579ef1f84bSDavid du Colombier 		DBG("gpe %d %s\n", i, gpes[i].obj);
17589ef1f84bSDavid du Colombier 		setgpeen(i, 1);
17599ef1f84bSDavid du Colombier 		break;
17609ef1f84bSDavid du Colombier 	default:
17619ef1f84bSDavid du Colombier 		panic("acpi: unknown ctl");
17629ef1f84bSDavid du Colombier 	}
17639ef1f84bSDavid du Colombier 	poperror();
17649ef1f84bSDavid du Colombier 	free(cb);
17659ef1f84bSDavid du Colombier 	return n;
17669ef1f84bSDavid du Colombier }
17679ef1f84bSDavid du Colombier 
17689ef1f84bSDavid du Colombier 
17699ef1f84bSDavid du Colombier Dev acpidevtab = {
17709ef1f84bSDavid du Colombier 	L'α',
17719ef1f84bSDavid du Colombier 	"acpi",
17729ef1f84bSDavid du Colombier 
17739ef1f84bSDavid du Colombier 	devreset,
17749ef1f84bSDavid du Colombier 	devinit,
17759ef1f84bSDavid du Colombier 	devshutdown,
17769ef1f84bSDavid du Colombier 	acpiattach,
17779ef1f84bSDavid du Colombier 	acpiwalk,
17789ef1f84bSDavid du Colombier 	acpistat,
17799ef1f84bSDavid du Colombier 	acpiopen,
17809ef1f84bSDavid du Colombier 	devcreate,
17819ef1f84bSDavid du Colombier 	acpiclose,
17829ef1f84bSDavid du Colombier 	acpiread,
17839ef1f84bSDavid du Colombier 	devbread,
17849ef1f84bSDavid du Colombier 	acpiwrite,
17859ef1f84bSDavid du Colombier 	devbwrite,
17869ef1f84bSDavid du Colombier 	devremove,
17879ef1f84bSDavid du Colombier 	devwstat,
17889ef1f84bSDavid du Colombier };
1789