xref: /plan9-contrib/sys/src/9k/k10/devacpi.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"io.h"
7 #include	"../port/error.h"
8 #include "mp.h"
9 #include "acpi.h"
10 
11 /*
12  * ACPI 4.0 Support.
13  * Still WIP.
14  *
15  * This driver locates tables and parses only the FADT
16  * and the XSDT. All other tables are mapped and kept there
17  * for a user-level interpreter.
18  */
19 
20 #define l16get(p)	(((p)[1]<<8)|(p)[0])
21 #define l32get(p)	(((u32int)l16get(p+2)<<16)|l16get(p))
22 static Atable* acpifadt(uchar*, int);
23 static Atable* acpitable(uchar*, int);
24 static Atable* acpimadt(uchar*, int);
25 static Atable* acpimsct(uchar*, int);
26 static Atable* acpisrat(uchar*, int);
27 static Atable* acpislit(uchar*, int);
28 static Atable* acpihpet(uchar*, int);
29 
30 #pragma	varargck	type	"G"	Gas*
31 
32 static Cmdtab ctls[] =
33 {
34 	{CMregion,	"region",	6},
35 	{CMgpe,		"gpe",		3},
36 };
37 
38 static Dirtab acpidir[]={
39 	".",		{Qdir, 0, QTDIR},	0,	DMDIR|0555,
40 	"acpictl",	{Qctl},			0,	0666,
41 	"acpitbl",	{Qtbl},			0,	0444,
42 	"acpiregio",	{Qio},			0,	0666,
43 };
44 
45 /*
46  * The DSDT is always given to the user interpreter.
47  * Tables listed here are also loaded from the XSDT:
48  * MSCT, MADT, and FADT are processed by us, because they are
49  * required to do early initialization before we have user processes.
50  * Other tables are given to the user level interpreter for
51  * execution.
52  */
53 static Parse ptables[] =
54 {
55 	"FACP", acpifadt,
56 	"APIC",	acpimadt,
57 	"SRAT",	acpisrat,
58 	"SLIT",	acpislit,
59 	"MSCT",	acpimsct,
60 	"HPET", acpihpet,
61 	"SSDT", acpitable,
62 };
63 
64 static Facs*	facs;	/* Firmware ACPI control structure */
65 static Fadt	fadt;	/* Fixed ACPI description. To reach ACPI registers */
66 static Xsdt*	xsdt;	/* XSDT table */
67 static Atable*	tfirst;	/* loaded DSDT/SSDT/... tables */
68 static Atable*	tlast;	/* pointer to last table */
69 	Madt*	apics;	/* APIC info */
70 static Srat*	srat;	/* System resource affinity, used by physalloc */
71 static Slit*	slit;	/* System locality information table used by the scheduler */
72 static Msct*	msct;	/* Maximum system characteristics table */
73 static Hpet*	hpet;
74 static Reg*	reg;	/* region used for I/O */
75 static Gpe*	gpes;	/* General purpose events */
76 static int	ngpes;
77 
78 static char* regnames[] = {
79 	"mem", "io", "pcicfg", "embed",
80 	"smb", "cmos", "pcibar",
81 };
82 
83 static char*
acpiregstr(int id)84 acpiregstr(int id)
85 {
86 	static char buf[20];	/* BUG */
87 
88 	if(id >= 0 && id < nelem(regnames))
89 		return regnames[id];
90 	seprint(buf, buf+sizeof(buf), "spc:%#x", id);
91 	return buf;
92 }
93 
94 static int
acpiregid(char * s)95 acpiregid(char *s)
96 {
97 	int i;
98 
99 	for(i = 0; i < nelem(regnames); i++)
100 		if(strcmp(regnames[i], s) == 0)
101 			return i;
102 	return -1;
103 }
104 
105 static u64int
l64get(u8int * p)106 l64get(u8int* p)
107 {
108 	/*
109 	 * Doing this as a define
110 	 * #define l64get(p)	(((u64int)l32get(p+4)<<32)|l32get(p))
111 	 * causes 8c to abort with "out of fixed registers" in
112 	 * rsdlink() below.
113 	 */
114 	return (((u64int)l32get(p+4)<<32)|l32get(p));
115 }
116 
117 static u8int
mget8(uintptr p,void *)118 mget8(uintptr p, void*)
119 {
120 	u8int *cp = (u8int*)p;
121 	return *cp;
122 }
123 
124 static void
mset8(uintptr p,u8int v,void *)125 mset8(uintptr p, u8int v, void*)
126 {
127 	u8int *cp = (u8int*)p;
128 	*cp = v;
129 }
130 
131 static u16int
mget16(uintptr p,void *)132 mget16(uintptr p, void*)
133 {
134 	u16int *cp = (u16int*)p;
135 	return *cp;
136 }
137 
138 static void
mset16(uintptr p,u16int v,void *)139 mset16(uintptr p, u16int v, void*)
140 {
141 	u16int *cp = (u16int*)p;
142 	*cp = v;
143 }
144 
145 static u32int
mget32(uintptr p,void *)146 mget32(uintptr p, void*)
147 {
148 	u32int *cp = (u32int*)p;
149 	return *cp;
150 }
151 
152 static void
mset32(uintptr p,u32int v,void *)153 mset32(uintptr p, u32int v, void*)
154 {
155 	u32int *cp = (u32int*)p;
156 	*cp = v;
157 }
158 
159 static u64int
mget64(uintptr p,void *)160 mget64(uintptr p, void*)
161 {
162 	u64int *cp = (u64int*)p;
163 	return *cp;
164 }
165 
166 static void
mset64(uintptr p,u64int v,void *)167 mset64(uintptr p, u64int v, void*)
168 {
169 	u64int *cp = (u64int*)p;
170 	*cp = v;
171 }
172 
173 static u8int
ioget8(uintptr p,void *)174 ioget8(uintptr p, void*)
175 {
176 	return inb(p);
177 }
178 
179 static void
ioset8(uintptr p,u8int v,void *)180 ioset8(uintptr p, u8int v, void*)
181 {
182 	outb(p, v);
183 }
184 
185 static u16int
ioget16(uintptr p,void *)186 ioget16(uintptr p, void*)
187 {
188 	return ins(p);
189 }
190 
191 static void
ioset16(uintptr p,u16int v,void *)192 ioset16(uintptr p, u16int v, void*)
193 {
194 	outs(p, v);
195 }
196 
197 static u32int
ioget32(uintptr p,void *)198 ioget32(uintptr p, void*)
199 {
200 	return inl(p);
201 }
202 
203 static void
ioset32(uintptr p,u32int v,void *)204 ioset32(uintptr p, u32int v, void*)
205 {
206 	outl(p, v);
207 }
208 
209 static u8int
cfgget8(uintptr p,void * r)210 cfgget8(uintptr p, void* r)
211 {
212 	Reg *ro = r;
213 	Pcidev d;
214 
215 	d.tbdf = ro->tbdf;
216 	return pcicfgr8(&d, p);
217 }
218 
219 static void
cfgset8(uintptr p,u8int v,void * r)220 cfgset8(uintptr p, u8int v, void* r)
221 {
222 	Reg *ro = r;
223 	Pcidev d;
224 
225 	d.tbdf = ro->tbdf;
226 	pcicfgw8(&d, p, v);
227 }
228 
229 static u16int
cfgget16(uintptr p,void * r)230 cfgget16(uintptr p, void* r)
231 {
232 	Reg *ro = r;
233 	Pcidev d;
234 
235 	d.tbdf = ro->tbdf;
236 	return pcicfgr16(&d, p);
237 }
238 
239 static void
cfgset16(uintptr p,u16int v,void * r)240 cfgset16(uintptr p, u16int v, void* r)
241 {
242 	Reg *ro = r;
243 	Pcidev d;
244 
245 	d.tbdf = ro->tbdf;
246 	pcicfgw16(&d, p, v);
247 }
248 
249 static u32int
cfgget32(uintptr p,void * r)250 cfgget32(uintptr p, void* r)
251 {
252 	Reg *ro = r;
253 	Pcidev d;
254 
255 	d.tbdf = ro->tbdf;
256 	return pcicfgr32(&d, p);
257 }
258 
259 static void
cfgset32(uintptr p,u32int v,void * r)260 cfgset32(uintptr p, u32int v, void* r)
261 {
262 	Reg *ro = r;
263 	Pcidev d;
264 
265 	d.tbdf = ro->tbdf;
266 	pcicfgw32(&d, p, v);
267 }
268 
269 static Regio memio =
270 {
271 	nil,
272 	mget8, mset8, mget16, mset16,
273 	mget32, mset32, mget64, mset64
274 };
275 
276 static Regio ioio =
277 {
278 	nil,
279 	ioget8, ioset8, ioget16, ioset16,
280 	ioget32, ioset32, nil, nil
281 };
282 
283 static Regio cfgio =
284 {
285 	nil,
286 	cfgget8, cfgset8, cfgget16, cfgset16,
287 	cfgget32, cfgset32, nil, nil
288 };
289 
290 /*
291  * Copy memory, 1/2/4/8-bytes at a time, to/from a region.
292  */
293 static long
regcpy(Regio * dio,uintptr da,Regio * sio,uintptr sa,long len,int align)294 regcpy(Regio *dio, uintptr da, Regio *sio, uintptr sa, long len, int align)
295 {
296 	int n, i;
297 
298 	DBG("regcpy %#ullx %#ullx %#ulx %#ux\n", da, sa, len, align);
299 	if((len%align) != 0)
300 		print("regcpy: bug: copy not aligned. truncated\n");
301 	n = len/align;
302 	for(i = 0; i < n; i++){
303 		switch(align){
304 		case 1:
305 			DBG("cpy8 %#p %#p\n", da, sa);
306 			dio->set8(da, sio->get8(sa, sio->arg), dio->arg);
307 			break;
308 		case 2:
309 			DBG("cpy16 %#p %#p\n", da, sa);
310 			dio->set16(da, sio->get16(sa, sio->arg), dio->arg);
311 			break;
312 		case 4:
313 			DBG("cpy32 %#p %#p\n", da, sa);
314 			dio->set32(da, sio->get32(sa, sio->arg), dio->arg);
315 			break;
316 		case 8:
317 			DBG("cpy64 %#p %#p\n", da, sa);
318 		//	dio->set64(da, sio->get64(sa, sio->arg), dio->arg);
319 			break;
320 		default:
321 			panic("regcpy: align bug");
322 		}
323 		da += align;
324 		sa += align;
325 	}
326 	return n*align;
327 }
328 
329 /*
330  * Perform I/O within region in access units of accsz bytes.
331  * All units in bytes.
332  */
333 static long
regio(Reg * r,void * p,ulong len,uintptr off,int iswr)334 regio(Reg *r, void *p, ulong len, uintptr off, int iswr)
335 {
336 	Regio rio;
337 	uintptr rp;
338 
339 	DBG("reg%s %s %#p %#ullx %#lx sz=%d\n",
340 		iswr ? "out" : "in", r->name, p, off, len, r->accsz);
341 	rp = 0;
342 	if(off + len > r->len){
343 		print("regio: access outside limits");
344 		len = r->len - off;
345 	}
346 	if(len <= 0){
347 		print("regio: zero len\n");
348 		return 0;
349 	}
350 	switch(r->spc){
351 	case Rsysmem:
352 		// XXX should map only what we are going to use
353 		// A region might be too large.
354 		if(r->p == nil)
355 			r->p = vmap(r->base, len);
356 		if(r->p == nil)
357 			error("regio: vmap failed");
358 		rp = (uintptr)r->p + off;
359 		rio = memio;
360 		break;
361 	case Rsysio:
362 		rp = r->base + off;
363 		rio = ioio;
364 		break;
365 	case Rpcicfg:
366 		rp = r->base + off;
367 		rio = cfgio;
368 		rio.arg = r;
369 		break;
370 	case Rpcibar:
371 	case Rembed:
372 	case Rsmbus:
373 	case Rcmos:
374 	case Ripmi:
375 	case Rfixedhw:
376 		print("regio: reg %s not supported\n", acpiregstr(r->spc));
377 		error("region not supported");
378 	}
379 	if(iswr)
380 		regcpy(&rio, rp, &memio, (uintptr)p, len, r->accsz);
381 	else
382 		regcpy(&memio, (uintptr)p, &rio, rp, len, r->accsz);
383 	return len;
384 }
385 
386 static Atable*
newtable(uchar * p)387 newtable(uchar *p)
388 {
389 	Atable *t;
390 	Sdthdr *h;
391 
392 	t = malloc(sizeof(Atable));
393 	if(t == nil)
394 		panic("no memory for more aml tables");
395 	t->tbl = p;
396 	h = (Sdthdr*)t->tbl;
397 	t->is64 = h->rev >= 2;
398 	t->dlen = l32get(h->length) - Sdthdrsz;
399 	memmove(t->sig, h->sig, sizeof(h->sig));
400 	t->sig[sizeof(t->sig)-1] = 0;
401 	memmove(t->oemid, h->oemid, sizeof(h->oemid));
402 	t->oemtblid[sizeof(t->oemtblid)-1] = 0;
403 	memmove(t->oemtblid, h->oemtblid, sizeof(h->oemtblid));
404 	t->oemtblid[sizeof(t->oemtblid)-1] = 0;
405 	t->next = nil;
406 	if(tfirst == nil)
407 		tfirst = tlast = t;
408 	else{
409 		tlast->next = t;
410 		tlast = t;
411 	}
412 	return t;
413 }
414 
415 static void*
sdtchecksum(void * addr,int len)416 sdtchecksum(void* addr, int len)
417 {
418 	u8int *p, sum;
419 
420 	sum = 0;
421 	for(p = addr; len-- > 0; p++)
422 		sum += *p;
423 	if(sum == 0)
424 		return addr;
425 
426 	return nil;
427 }
428 
429 static void *
sdtmap(uintmem pa,int * n,int cksum)430 sdtmap(uintmem pa, int *n, int cksum)
431 {
432 	Sdthdr* sdt;
433 
434 	sdt = vmap(pa, sizeof(Sdthdr));
435 	if(sdt == nil){
436 		DBG("acpi: vmap1: nil\n");
437 		return nil;
438 	}
439 	*n = l32get(sdt->length);
440 	vunmap(sdt, sizeof(Sdthdr));
441 	if((sdt = vmap(pa, *n)) == nil){
442 		DBG("acpi: nil vmap\n");
443 		return nil;
444 	}
445 	DBG("acpi: sdtmap %#P -> %#p, length %d\n", pa, sdt, *n);
446 	if(cksum != 0 && sdtchecksum(sdt, *n) == nil){
447 		DBG("acpi: SDT: bad checksum\n");
448 		vunmap(sdt, sizeof(Sdthdr));
449 		return nil;
450 	}
451 	return sdt;
452 }
453 
454 static int
loadfacs(uintmem pa)455 loadfacs(uintmem pa)
456 {
457 	int n;
458 
459 	facs = sdtmap(pa, &n, 0);
460 	if(facs == nil)
461 		return -1;
462 	if(memcmp(facs, "FACS", 4) != 0){
463 		vunmap(facs, n);
464 		facs = nil;
465 		return -1;
466 	}
467 	/* no unmap */
468 
469 	DBG("acpi: facs: hwsig: %#ux\n", facs->hwsig);
470 	DBG("acpi: facs: wakingv: %#ux\n", facs->wakingv);
471 	DBG("acpi: facs: flags: %#ux\n", facs->flags);
472 	DBG("acpi: facs: glock: %#ux\n", facs->glock);
473 	DBG("acpi: facs: xwakingv: %#llux\n", facs->xwakingv);
474 	DBG("acpi: facs: vers: %#ux\n", facs->vers);
475 	DBG("acpi: facs: ospmflags: %#ux\n", facs->ospmflags);
476 	return 0;
477 }
478 
479 static void
loaddsdt(uintmem pa)480 loaddsdt(uintmem pa)
481 {
482 	int n;
483 	uchar *dsdtp;
484 
485 	dsdtp = sdtmap(pa, &n, 1);
486 	if(dsdtp == nil)
487 		return;
488 	if(acpitable(dsdtp, n) == nil)
489 		vunmap(dsdtp, n);
490 }
491 
492 static void
gasget(Gas * gas,uchar * p)493 gasget(Gas *gas, uchar *p)
494 {
495 	gas->spc = p[0];
496 	gas->len = p[1];
497 	gas->off = p[2];
498 	gas->accsz = p[3];
499 	gas->addr = l64get(p+4);
500 }
501 
502 static void
dumpfadt(Fadt * fp,int revision)503 dumpfadt(Fadt *fp, int revision)
504 {
505 	USED(fp);
506 	DBG("acpi: fadt: facs: %#ux\n", fp->facs);
507 	DBG("acpi: fadt: dsdt: %#ux\n", fp->dsdt);
508 	DBG("acpi: fadt: pmprofile: %#ux\n", fp->pmprofile);
509 	DBG("acpi: fadt: sciint: %#ux\n", fp->sciint);
510 	DBG("acpi: fadt: smicmd: %#ux\n", fp->smicmd);
511 	DBG("acpi: fadt: acpienable: %#ux\n", fp->acpienable);
512 	DBG("acpi: fadt: acpidisable: %#ux\n", fp->acpidisable);
513 	DBG("acpi: fadt: s4biosreq: %#ux\n", fp->s4biosreq);
514 	DBG("acpi: fadt: pstatecnt: %#ux\n", fp->pstatecnt);
515 	DBG("acpi: fadt: pm1aevtblk: %#ux\n", fp->pm1aevtblk);
516 	DBG("acpi: fadt: pm1bevtblk: %#ux\n", fp->pm1bevtblk);
517 	DBG("acpi: fadt: pm1acntblk: %#ux\n", fp->pm1acntblk);
518 	DBG("acpi: fadt: pm1bcntblk: %#ux\n", fp->pm1bcntblk);
519 	DBG("acpi: fadt: pm2cntblk: %#ux\n", fp->pm2cntblk);
520 	DBG("acpi: fadt: pmtmrblk: %#ux\n", fp->pmtmrblk);
521 	DBG("acpi: fadt: gpe0blk: %#ux\n", fp->gpe0blk);
522 	DBG("acpi: fadt: gpe1blk: %#ux\n", fp->gpe1blk);
523 	DBG("acpi: fadt: pm1evtlen: %#ux\n", fp->pm1evtlen);
524 	DBG("acpi: fadt: pm1cntlen: %#ux\n", fp->pm1cntlen);
525 	DBG("acpi: fadt: pm2cntlen: %#ux\n", fp->pm2cntlen);
526 	DBG("acpi: fadt: pmtmrlen: %#ux\n", fp->pmtmrlen);
527 	DBG("acpi: fadt: gpe0blklen: %#ux\n", fp->gpe0blklen);
528 	DBG("acpi: fadt: gpe1blklen: %#ux\n", fp->gpe1blklen);
529 	DBG("acpi: fadt: gp1base: %#ux\n", fp->gp1base);
530 	DBG("acpi: fadt: cstcnt: %#ux\n", fp->cstcnt);
531 	DBG("acpi: fadt: plvl2lat: %#ux\n", fp->plvl2lat);
532 	DBG("acpi: fadt: plvl3lat: %#ux\n", fp->plvl3lat);
533 	DBG("acpi: fadt: flushsz: %#ux\n", fp->flushsz);
534 	DBG("acpi: fadt: flushstride: %#ux\n", fp->flushstride);
535 	DBG("acpi: fadt: dutyoff: %#ux\n", fp->dutyoff);
536 	DBG("acpi: fadt: dutywidth: %#ux\n", fp->dutywidth);
537 	DBG("acpi: fadt: dayalrm: %#ux\n", fp->dayalrm);
538 	DBG("acpi: fadt: monalrm: %#ux\n", fp->monalrm);
539 	DBG("acpi: fadt: century: %#ux\n", fp->century);
540 	DBG("acpi: fadt: iapcbootarch: %#ux\n", fp->iapcbootarch);
541 	DBG("acpi: fadt: flags: %#ux\n", fp->flags);
542 
543 	if(revision < 3)
544 		return;
545 
546 	DBG("acpi: fadt: resetreg: %G\n", &fp->resetreg);
547 	DBG("acpi: fadt: resetval: %#ux\n", fp->resetval);
548 	DBG("acpi: fadt: xfacs: %#llux\n", fp->xfacs);
549 	DBG("acpi: fadt: xdsdt: %#llux\n", fp->xdsdt);
550 	DBG("acpi: fadt: xpm1aevtblk: %G\n", &fp->xpm1aevtblk);
551 	DBG("acpi: fadt: xpm1bevtblk: %G\n", &fp->xpm1bevtblk);
552 	DBG("acpi: fadt: xpm1acntblk: %G\n", &fp->xpm1acntblk);
553 	DBG("acpi: fadt: xpm1bcntblk: %G\n", &fp->xpm1bcntblk);
554 	DBG("acpi: fadt: xpm2cntblk: %G\n", &fp->xpm2cntblk);
555 	DBG("acpi: fadt: xpmtmrblk: %G\n", &fp->xpmtmrblk);
556 	DBG("acpi: fadt: xgpe0blk: %G\n", &fp->xgpe0blk);
557 	DBG("acpi: fadt: xgpe1blk: %G\n", &fp->xgpe1blk);
558 }
559 
560 static Atable*
acpifadt(uchar * p,int)561 acpifadt(uchar *p, int)
562 {
563 	Fadt *fp;
564 	int revision;
565 
566 	fp = &fadt;
567 	revision = p[8];
568 	DBG("acpifadt %#p length %ud revision %ud\n", p, l32get(p+4), revision);
569 	fp->facs = l32get(p + 36);
570 	fp->dsdt = l32get(p + 40);
571 	fp->pmprofile = p[45];
572 	fp->sciint = l16get(p+46);
573 	fp->smicmd = l32get(p+48);
574 	fp->acpienable = p[52];
575 	fp->acpidisable = p[53];
576 	fp->s4biosreq = p[54];
577 	fp->pstatecnt = p[55];
578 	fp->pm1aevtblk = l32get(p+56);
579 	fp->pm1bevtblk = l32get(p+60);
580 	fp->pm1acntblk = l32get(p+64);
581 	fp->pm1bcntblk = l32get(p+68);
582 	fp->pm2cntblk = l32get(p+72);
583 	fp->pmtmrblk = l32get(p+76);
584 	fp->gpe0blk = l32get(p+80);
585 	fp->gpe1blk = l32get(p+84);
586 	fp->pm1evtlen = p[88];
587 	fp->pm1cntlen = p[89];
588 	fp->pm2cntlen = p[90];
589 	fp->pmtmrlen = p[91];
590 	fp->gpe0blklen = p[92];
591 	fp->gpe1blklen = p[93];
592 	fp->gp1base = p[94];
593 	fp->cstcnt = p[95];
594 	fp->plvl2lat = l16get(p+96);
595 	fp->plvl3lat = l16get(p+98);
596 	fp->flushsz = l16get(p+100);
597 	fp->flushstride = l16get(p+102);
598 	fp->dutyoff = p[104];
599 	fp->dutywidth = p[105];
600 	fp->dayalrm = p[106];
601 	fp->monalrm = p[107];
602 	fp->century = p[108];
603 	fp->iapcbootarch = l16get(p+109);
604 	fp->flags = l32get(p+112);
605 
606 	/*
607 	 * Revision 1 of this table stops here, and is described
608 	 * in The ACPI Specification 1.0, 22-Dec-1996.
609 	 * The ACPI Specification 2.0, 27-Jul-2000, bumped the revision
610 	 * number up to 3 and added the extra fields on the end.
611 	 * Thank you, QEMU.
612 	 */
613 	if(revision >= 3){
614 		gasget(&fp->resetreg, p+116);
615 
616 		fp->resetval = p[128];
617 		fp->xfacs = l64get(p+132);
618 		fp->xdsdt = l64get(p+140);
619 		gasget(&fp->xpm1aevtblk, p+148);
620 		gasget(&fp->xpm1bevtblk, p+160);
621 		gasget(&fp->xpm1acntblk, p+172);
622 		gasget(&fp->xpm1bcntblk, p+184);
623 		gasget(&fp->xpm2cntblk, p+196);
624 		gasget(&fp->xpmtmrblk, p+208);
625 		gasget(&fp->xgpe0blk, p+220);
626 		gasget(&fp->xgpe1blk, p+232);
627 	}
628 
629 	dumpfadt(fp, revision);
630 
631 	/* If xfacs or xdsdt are either nil
632 	 * or different from their 32-bit
633 	 * counter-parts, then go with
634 	 * the 32-bit addresses (as the
635 	 * ACPICA does), since those are
636 	 * tested by BIOS manufacturers.
637 	 */
638 
639 	if(fp->xfacs != 0 && fp->xfacs == fp->facs)
640 		loadfacs(fp->xfacs);
641 	else
642 		loadfacs(fp->facs);
643 
644 	if(fp->xdsdt != 0 && fp->xdsdt == fp->dsdt)
645 		loadfacs(fp->xdsdt);
646 	else
647 		loadfacs(fp->dsdt);
648 
649 	return nil;			/* can be unmapped once parsed */
650 }
651 
652 static void
dumpmsct(Msct * msct)653 dumpmsct(Msct *msct)
654 {
655 	Mdom *st;
656 
657 	DBG("acpi: msct: %d doms %d clkdoms %#ullx maxpa\n",
658 		msct->ndoms, msct->nclkdoms, msct->maxpa);
659 	for(st = msct->dom; st != nil; st = st->next)
660 		DBG("\t[%d:%d] %d maxproc %#ullx maxmmem\n",
661 			st->start, st->end, st->maxproc, st->maxmem);
662 	DBG("\n");
663 }
664 
665 /*
666  * XXX: should perhaps update our idea of available memory.
667  * Else we should remove this code.
668  */
669 static Atable*
acpimsct(uchar * p,int len)670 acpimsct(uchar *p, int len)
671 {
672 	uchar *pe;
673 	Mdom **stl, *st;
674 	int off;
675 
676 	msct = mallocz(sizeof(Msct), 1);
677 	msct->ndoms = l32get(p+40) + 1;
678 	msct->nclkdoms = l32get(p+44) + 1;
679 	msct->maxpa = l64get(p+48);
680 	msct->dom = nil;
681 	stl = &msct->dom;
682 	pe = p + len;
683 	off = l32get(p+36);
684 	for(p += off; p < pe; p += 22){
685 		st = mallocz(sizeof(Mdom), 1);
686 		st->next = nil;
687 		st->start = l32get(p+2);
688 		st->end = l32get(p+6);
689 		st->maxproc = l32get(p+10);
690 		st->maxmem = l64get(p+14);
691 		*stl = st;
692 		stl = &st->next;
693 	}
694 
695 	dumpmsct(msct);
696 	return nil;	/* can be unmapped once parsed */
697 }
698 
699 static Atable*
acpihpet(uchar * p,int)700 acpihpet(uchar *p, int)
701 {
702 	hpet = mallocz(sizeof(Hpet), 1);
703 	p += 36;
704 
705 	hpet->id = l32get(p);
706 	p += 4;
707 
708 	p += 4; /* it's a Gas */
709 	hpet->addr = l64get(p);
710 	p += 8;
711 
712 	hpet->seqno = *p;
713 	p++;
714 
715 	hpet->minticks = l16get(p);
716 	p += 2;
717 	hpet->attr = *p;
718 
719 	DBG("hpet: id %#ux addr %#p seqno %d ticks %d attr %#ux\n",
720 		hpet->id, hpet->addr, hpet->seqno, hpet->minticks, hpet->attr);
721 //	hpetinit(hpet->seqno, hpet->addr, hpet->minticks)
722 	return nil;	/* can be unmapped once parsed */
723 }
724 
725 
726 static void
dumpsrat(Srat * st)727 dumpsrat(Srat *st)
728 {
729 	DBG("acpi: srat:\n");
730 	for(; st != nil; st = st->next)
731 		switch(st->type){
732 		case SRlapic:
733 			DBG("\tlapic: dom %d apic %d sapic %d clk %d\n",
734 				st->lapic.dom, st->lapic.apic,
735 				st->lapic.sapic, st->lapic.clkdom);
736 			break;
737 		case SRmem:
738 			DBG("\tmem: dom %d %#ullx %#ullx %c%c\n",
739 				st->mem.dom, st->mem.addr, st->mem.len,
740 				st->mem.hplug?'h':'-',
741 				st->mem.nvram?'n':'-');
742 			break;
743 		case SRlx2apic:
744 			DBG("\tlx2apic: dom %d apic %d clk %d\n",
745 				st->lx2apic.dom, st->lx2apic.apic,
746 				st->lx2apic.clkdom);
747 			break;
748 		default:
749 			DBG("\t<unknown srat entry>\n");
750 		}
751 	DBG("\n");
752 }
753 
754 static Atable*
acpisrat(uchar * p,int len)755 acpisrat(uchar *p, int len)
756 {
757 	Srat **stl, *st;
758 	uchar *pe;
759 	int stlen, flags;
760 
761 	if(srat != nil){
762 		print("acpi: two SRATs?\n");
763 		return nil;
764 	}
765 
766 	stl = &srat;
767 	pe = p + len;
768 	for(p += 48; p < pe; p += stlen){
769 		st = mallocz(sizeof(Srat), 1);
770 		st->type = p[0];
771 		st->next = nil;
772 		stlen = p[1];
773 		switch(st->type){
774 		case SRlapic:
775 			st->lapic.dom = p[2] | p[9]<<24| p[10]<<16 | p[11]<<8;
776 			st->lapic.apic = p[3];
777 			st->lapic.sapic = p[8];
778 			st->lapic.clkdom = l32get(p+12);
779 			if(l32get(p+4) == 0){
780 				free(st);
781 				st = nil;
782 			}
783 			break;
784 		case SRmem:
785 			st->mem.dom = l32get(p+2);
786 			st->mem.addr = l64get(p+8);
787 			st->mem.len = l64get(p+16);
788 			flags = l32get(p+28);
789 			if((flags&1) == 0){	/* not enabled */
790 				free(st);
791 				st = nil;
792 			}else{
793 				st->mem.hplug = flags & 2;
794 				st->mem.nvram = flags & 4;
795 			}
796 			break;
797 		case SRlx2apic:
798 			st->lx2apic.dom = l32get(p+4);
799 			st->lx2apic.apic = l32get(p+8);
800 			st->lx2apic.clkdom = l32get(p+16);
801 			if(l32get(p+12) == 0){
802 				free(st);
803 				st = nil;
804 			}
805 			break;
806 		default:
807 			print("unknown SRAT structure\n");
808 			free(st);
809 			st = nil;
810 		}
811 		if(st != nil){
812 			*stl = st;
813 			stl = &st->next;
814 		}
815 	}
816 
817 	dumpsrat(srat);
818 	return nil;	/* can be unmapped once parsed */
819 }
820 
821 static void
dumpslit(Slit * sl)822 dumpslit(Slit *sl)
823 {
824 	int i;
825 
826 	DBG("acpi slit:\n");
827 	for(i = 0; i < sl->rowlen*sl->rowlen; i++){
828 		DBG(" %ux", sl->e[i/sl->rowlen][i%sl->rowlen].dist);
829 	}
830 	DBG("\n");
831 }
832 
833 static int
cmpslitent(void * v1,void * v2)834 cmpslitent(void* v1, void* v2)
835 {
836 	SlEntry *se1, *se2;
837 
838 	se1 = v1;
839 	se2 = v2;
840 	return se1->dist - se2->dist;
841 }
842 
843 static Atable*
acpislit(uchar * p,int len)844 acpislit(uchar *p, int len)
845 {
846 	uchar *pe;
847 	int i, j, k;
848 	SlEntry *se;
849 
850 	pe = p + len;
851 	slit = malloc(sizeof(*slit));
852 	slit->rowlen = l64get(p+36);
853 	slit->e = malloc(slit->rowlen*sizeof(SlEntry*));
854 	for(i = 0; i < slit->rowlen; i++)
855 		slit->e[i] = malloc(sizeof(SlEntry)*slit->rowlen);
856 
857 	i = 0;
858 	for(p += 44; p < pe; p++, i++){
859 		j = i/slit->rowlen;
860 		k = i%slit->rowlen;
861 		se = &slit->e[j][k];
862 		se->dom = k;
863 		se->dist = *p;
864 	}
865 	dumpslit(slit);
866 	for(i = 0; i < slit->rowlen; i++)
867 		qsort(slit->e[i], slit->rowlen, sizeof(slit->e[0][0]), cmpslitent);
868 
869 	dumpslit(slit);
870 	return nil;	/* can be unmapped once parsed */
871 }
872 
873 uintmem
acpimblocksize(uintmem addr,int * dom)874 acpimblocksize(uintmem addr, int *dom)
875 {
876 	Srat *sl;
877 
878 	for(sl = srat; sl != nil; sl = sl->next)
879 		if(sl->type == SRmem)
880 		if(sl->mem.addr <= addr && sl->mem.addr + sl->mem.len > addr){
881 			*dom = sl->mem.dom;
882 			return sl->mem.len - (addr - sl->mem.addr);
883 		}
884 	return 0;
885 }
886 
887 /*
888  * Return a number identifying a color for the memory at
889  * the given address (color identifies locality) and fill *sizep
890  * with the size for memory of the same color starting at addr.
891  */
892 int
memcolor(uintmem addr,uintmem * sizep)893 memcolor(uintmem addr, uintmem *sizep)
894 {
895 	Srat *sl;
896 
897 	for(sl = srat; sl != nil; sl = sl->next)
898 		if(sl->type == SRmem)
899 		if(sl->mem.addr <= addr && addr-sl->mem.addr < sl->mem.len){
900 			if(sizep != nil)
901 				*sizep = sl->mem.len - (addr - sl->mem.addr);
902 			if(sl->mem.dom >= NCOLOR)
903 				print("memcolor: NCOLOR too small");
904 			return sl->mem.dom%NCOLOR;
905 		}
906 	return -1;
907 }
908 
909 /*
910  * Being machno an index in sys->machptr, return the color
911  * for that mach (color identifies locality).
912  */
913 int
corecolor(int machno)914 corecolor(int machno)
915 {
916 	Srat *sl;
917 	Mach *m;
918 	static int colors[32];
919 
920 	if(machno < 0 || machno >= MACHMAX)
921 		return -1;
922 	m = sys->machptr[machno];
923 	if(m == nil)
924 		return -1;
925 
926 	if(machno >= 0 && machno < nelem(colors) && colors[machno] != 0)
927 		return colors[machno] - 1;
928 
929 	for(sl = srat; sl != nil; sl = sl->next)
930 		if(sl->type == SRlapic && sl->lapic.apic == m->apicno){
931 			if(machno >= 0 && machno < nelem(colors))
932 				colors[machno] = 1 + sl->lapic.dom;
933 			if(sl->lapic.dom >= NCOLOR)
934 				print("memcolor: NCOLOR too small");
935 			return sl->lapic.dom%NCOLOR;
936 		}
937 	return -1;
938 }
939 
940 
941 int
pickcore(int mycolor,int index)942 pickcore(int mycolor, int index)
943 {
944 	int color;
945 	int ncorepercol;
946 
947 	if(slit == nil)
948 		return index;
949 	ncorepercol = MACHMAX/slit->rowlen;
950 	color = slit->e[mycolor][index/ncorepercol].dom;
951 	return color * ncorepercol + index % ncorepercol;
952 }
953 
954 
955 static void
dumpmadt(Madt * apics)956 dumpmadt(Madt *apics)
957 {
958 	Apicst *st;
959 
960 	DBG("acpi: madt lapic paddr %llux pcat %d:\n", apics->lapicpa, apics->pcat);
961 	for(st = apics->st; st != nil; st = st->next)
962 		switch(st->type){
963 		case ASlapic:
964 			DBG("\tlapic pid %d id %d\n", st->lapic.pid, st->lapic.id);
965 			break;
966 		case ASioapic:
967 		case ASiosapic:
968 			DBG("\tioapic id %d addr %#llux ibase %d\n",
969 				st->ioapic.id, st->ioapic.addr, st->ioapic.ibase);
970 			break;
971 		case ASintovr:
972 			DBG("\tintovr irq %d intr %d flags %#ux\n",
973 				st->intovr.irq, st->intovr.intr,st->intovr.flags);
974 			break;
975 		case ASnmi:
976 			DBG("\tnmi intr %d flags %#ux\n",
977 				st->nmi.intr, st->nmi.flags);
978 			break;
979 		case ASlnmi:
980 			DBG("\tlnmi pid %d lint %d flags %#ux\n",
981 				st->lnmi.pid, st->lnmi.lint, st->lnmi.flags);
982 			break;
983 		case ASlsapic:
984 			DBG("\tlsapic pid %d id %d eid %d puid %d puids %s\n",
985 				st->lsapic.pid, st->lsapic.id,
986 				st->lsapic.eid, st->lsapic.puid,
987 				st->lsapic.puids);
988 			break;
989 		case ASintsrc:
990 			DBG("\tintr type %d pid %d peid %d iosv %d intr %d %#x\n",
991 				st->type, st->intsrc.pid,
992 				st->intsrc.peid, st->intsrc.iosv,
993 				st->intsrc.intr, st->intsrc.flags);
994 			break;
995 		case ASlx2apic:
996 			DBG("\tlx2apic puid %d id %d\n", st->lx2apic.puid, st->lx2apic.id);
997 			break;
998 		case ASlx2nmi:
999 			DBG("\tlx2nmi puid %d intr %d flags %#ux\n",
1000 				st->lx2nmi.puid, st->lx2nmi.intr, st->lx2nmi.flags);
1001 			break;
1002 		default:
1003 			DBG("\t<unknown madt entry>\n");
1004 		}
1005 	DBG("\n");
1006 }
1007 
1008 static Atable*
acpimadt(uchar * p,int len)1009 acpimadt(uchar *p, int len)
1010 {
1011 	uchar *pe;
1012 	Apicst *st, *l, **stl;
1013 	int stlen, id;
1014 
1015 	apics = mallocz(sizeof(Madt), 1);
1016 	apics->lapicpa = l32get(p+36);
1017 	apics->pcat = l32get(p+40);
1018 	apics->st = nil;
1019 	stl = &apics->st;
1020 	pe = p + len;
1021 	for(p += 44; p < pe; p += stlen){
1022 		st = mallocz(sizeof(Apicst), 1);
1023 		st->type = p[0];
1024 		st->next = nil;
1025 		stlen = p[1];
1026 		switch(st->type){
1027 		case ASlapic:
1028 			st->lapic.pid = p[2];
1029 			st->lapic.id = p[3];
1030 			if(l32get(p+4) == 0){
1031 				free(st);
1032 				st = nil;
1033 			}
1034 			break;
1035 		case ASioapic:
1036 			st->ioapic.id = id = p[2];
1037 			st->ioapic.addr = l32get(p+4);
1038 			st->ioapic.ibase = l32get(p+8);
1039 			/* iosapic overrides any ioapic entry for the same id */
1040 			for(l = apics->st; l != nil; l = l->next)
1041 				if(l->type == ASiosapic && l->iosapic.id == id){
1042 					st->ioapic = l->iosapic;
1043 					/* we leave it linked; could be removed */
1044 					break;
1045 				}
1046 			break;
1047 		case ASintovr:
1048 			st->intovr.irq = p[3];
1049 			st->intovr.intr = l32get(p+4);
1050 			st->intovr.flags = l16get(p+8);
1051 			break;
1052 		case ASnmi:
1053 			st->nmi.flags = l16get(p+2);
1054 			st->nmi.intr = l32get(p+4);
1055 			break;
1056 		case ASlnmi:
1057 			st->lnmi.pid = p[2];
1058 			st->lnmi.flags = l16get(p+3);
1059 			st->lnmi.lint = p[5];
1060 			break;
1061 		case ASladdr:
1062 			if(sizeof(apics->lapicpa) >= 8)
1063 				apics->lapicpa = l64get(p+8);
1064 			break;
1065 		case ASiosapic:
1066 			id = st->iosapic.id = p[2];
1067 			st->iosapic.ibase = l32get(p+4);
1068 			st->iosapic.addr = l64get(p+8);
1069 			/* iosapic overrides any ioapic entry for the same id */
1070 			for(l = apics->st; l != nil; l = l->next)
1071 				if(l->type == ASioapic && l->ioapic.id == id){
1072 					l->ioapic = st->iosapic;
1073 					free(st);
1074 					st = nil;
1075 					break;
1076 				}
1077 			break;
1078 		case ASlsapic:
1079 			st->lsapic.pid = p[2];
1080 			st->lsapic.id = p[3];
1081 			st->lsapic.eid = p[4];
1082 			st->lsapic.puid = l32get(p+12);
1083 			if(l32get(p+8) == 0){
1084 				free(st);
1085 				st = nil;
1086 			}else
1087 				kstrdup(&st->lsapic.puids, (char*)p+16);
1088 			break;
1089 		case ASintsrc:
1090 			st->intsrc.flags = l16get(p+2);
1091 			st->type = p[4];
1092 			st->intsrc.pid = p[5];
1093 			st->intsrc.peid = p[6];
1094 			st->intsrc.iosv = p[7];
1095 			st->intsrc.intr = l32get(p+8);
1096 			st->intsrc.any = l32get(p+12);
1097 			break;
1098 		case ASlx2apic:
1099 			st->lx2apic.id = l32get(p+4);
1100 			st->lx2apic.puid = l32get(p+12);
1101 			if(l32get(p+8) == 0){
1102 				free(st);
1103 				st = nil;
1104 			}
1105 			break;
1106 		case ASlx2nmi:
1107 			st->lx2nmi.flags = l16get(p+2);
1108 			st->lx2nmi.puid = l32get(p+4);
1109 			st->lx2nmi.intr = p[8];
1110 			break;
1111 		default:
1112 			print("unknown APIC structure\n");
1113 			free(st);
1114 			st = nil;
1115 		}
1116 		if(st != nil){
1117 			*stl = st;
1118 			stl = &st->next;
1119 		}
1120 	}
1121 
1122 	dumpmadt(apics);
1123 	return nil;	/* can be unmapped once parsed */
1124 }
1125 
1126 /*
1127  * Map the table and keep it there.
1128  */
1129 static Atable*
acpitable(uchar * p,int len)1130 acpitable(uchar *p, int len)
1131 {
1132 	if(len < Sdthdrsz)
1133 		return nil;
1134 	return newtable(p);
1135 }
1136 
1137 static void
dumptable(char * sig,uchar * p,int l)1138 dumptable(char *sig, uchar *p, int l)
1139 {
1140 	int n, i;
1141 
1142 	USED(sig);
1143 	if(DBGFLG > 1){
1144 		DBG("%s @ %#p\n", sig, p);
1145 		if(DBGFLG > 2)
1146 			n = l;
1147 		else
1148 			n = 256;
1149 		for(i = 0; i < n; i++){
1150 			if((i % 16) == 0)
1151 				DBG("%x: ", i);
1152 			DBG(" %2.2ux", p[i]);
1153 			if((i % 16) == 15)
1154 				DBG("\n");
1155 		}
1156 		DBG("\n");
1157 		DBG("\n");
1158 	}
1159 }
1160 
1161 static char*
seprinttable(char * s,char * e,Atable * t)1162 seprinttable(char *s, char *e, Atable *t)
1163 {
1164 	uchar *p;
1165 	int i, n;
1166 
1167 	p = (uchar*)t->tbl;	/* include header */
1168 	n = Sdthdrsz + t->dlen;
1169 	s = seprint(s, e, "%s @ %#p\n", t->sig, p);
1170 	for(i = 0; i < n; i++){
1171 		if((i % 16) == 0)
1172 			s = seprint(s, e, "%x: ", i);
1173 		s = seprint(s, e, " %2.2ux", p[i]);
1174 		if((i % 16) == 15)
1175 			s = seprint(s, e, "\n");
1176 	}
1177 	return seprint(s, e, "\n\n");
1178 }
1179 
1180 /*
1181  * process xsdt table and load tables with sig, or all if nil.
1182  * (XXX: should be able to search for sig, oemid, oemtblid)
1183  */
1184 static int
acpixsdtload(char * sig)1185 acpixsdtload(char *sig)
1186 {
1187 	int i, l, t, unmap, found;
1188 	uintmem dhpa;
1189 	uchar *sdt;
1190 	char tsig[5];
1191 
1192 	found = 0;
1193 	for(i = 0; i < xsdt->len; i += xsdt->asize){
1194 		if(xsdt->asize == 8)
1195 			dhpa = l64get(xsdt->p+i);
1196 		else
1197 			dhpa = l32get(xsdt->p+i);
1198 		if((sdt = sdtmap(dhpa, &l, 1)) == nil)
1199 			continue;
1200 		unmap = 1;
1201 		memmove(tsig, sdt, 4);
1202 		tsig[4] = 0;
1203 		if(sig == nil || strcmp(sig, tsig) == 0){
1204 			DBG("acpi: %s addr %#p\n", tsig, sdt);
1205 			for(t = 0; t < nelem(ptables); t++)
1206 				if(strcmp(tsig, ptables[t].sig) == 0){
1207 					dumptable(tsig, sdt, l);
1208 					unmap = ptables[t].f(sdt, l) == nil;
1209 					found = 1;
1210 					break;
1211 				}
1212 		}
1213 		if(unmap)
1214 			vunmap(sdt, l);
1215 	}
1216 	return found;
1217 }
1218 
1219 static void*
rsdscan(u8int * addr,int len,char * signature)1220 rsdscan(u8int* addr, int len, char* signature)
1221 {
1222 	int sl;
1223 	u8int *e, *p;
1224 
1225 	e = addr+len;
1226 	sl = strlen(signature);
1227 	for(p = addr; p+sl < e; p += 16){
1228 		if(memcmp(p, signature, sl))
1229 			continue;
1230 		return p;
1231 	}
1232 
1233 	return nil;
1234 }
1235 
1236 static void*
rsdsearch(char * signature)1237 rsdsearch(char* signature)
1238 {
1239 	uintmem p;
1240 	u8int *bda;
1241 	void *rsd;
1242 
1243 	/*
1244 	 * Search for the data structure signature:
1245 	 * 1) in the first KB of the EBDA;
1246 	 * 2) in the BIOS ROM between 0xE0000 and 0xFFFFF.
1247 	 */
1248 	if(strncmp((char*)KADDR(0xFFFD9), "EISA", 4) == 0){
1249 		bda = BIOSSEG(0x40);
1250 		if((p = (bda[0x0F]<<8)|bda[0x0E])){
1251 			if(rsd = rsdscan(KADDR(p), 1024, signature))
1252 				return rsd;
1253 		}
1254 	}
1255 	return rsdscan(BIOSSEG(0xE000), 0x20000, signature);
1256 }
1257 
1258 static void
acpirsdptr(void)1259 acpirsdptr(void)
1260 {
1261 	Rsdp *rsd;
1262 	int asize;
1263 	uintmem sdtpa;
1264 
1265 	if((rsd = rsdsearch("RSD PTR ")) == nil)
1266 		return;
1267 
1268 	assert(sizeof(Sdthdr) == 36);
1269 
1270 	DBG("acpi: RSD PTR@ %#p, physaddr %#ux length %ud %#llux rev %d\n",
1271 		rsd, l32get(rsd->raddr), l32get(rsd->length),
1272 		l64get(rsd->xaddr), rsd->revision);
1273 
1274 	if(rsd->revision >= 2){
1275 		if(sdtchecksum(rsd, 36) == nil){
1276 			DBG("acpi: RSD: bad checksum\n");
1277 			return;
1278 		}
1279 		sdtpa = l64get(rsd->xaddr);
1280 		asize = 8;
1281 	}
1282 	else{
1283 		if(sdtchecksum(rsd, 20) == nil){
1284 			DBG("acpi: RSD: bad checksum\n");
1285 			return;
1286 		}
1287 		sdtpa = l32get(rsd->raddr);
1288 		asize = 4;
1289 	}
1290 
1291 	/*
1292 	 * process the RSDT or XSDT table.
1293 	 */
1294 	xsdt = malloc(sizeof(Xsdt));
1295 	if(xsdt == nil){
1296 		DBG("acpi: malloc failed\n");
1297 		return;
1298 	}
1299 	if((xsdt->p = sdtmap(sdtpa, &xsdt->len, 1)) == nil){
1300 		DBG("acpi: sdtmap failed\n");
1301 		return;
1302 	}
1303 	if((xsdt->p[0] != 'R' && xsdt->p[0] != 'X') || memcmp(xsdt->p+1, "SDT", 3) != 0){
1304 		DBG("acpi: xsdt sig: %c%c%c%c\n",
1305 			xsdt->p[0], xsdt->p[1], xsdt->p[2], xsdt->p[3]);
1306 		free(xsdt);
1307 		xsdt = nil;
1308 		vunmap(xsdt, xsdt->len);
1309 		return;
1310 	}
1311 	xsdt->p += sizeof(Sdthdr);
1312 	xsdt->len -= sizeof(Sdthdr);
1313 	xsdt->asize = asize;
1314 	DBG("acpi: XSDT %#p\n", xsdt);
1315 	acpixsdtload(nil);
1316 	/* xsdt is kept and not unmapped */
1317 
1318 }
1319 
1320 static int
acpigen(Chan * c,char *,Dirtab * tab,int ntab,int i,Dir * dp)1321 acpigen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp)
1322 {
1323 	Qid qid;
1324 
1325 	if(i == DEVDOTDOT){
1326 		mkqid(&qid, Qdir, 0, QTDIR);
1327 		devdir(c, qid, ".", 0, eve, 0555, dp);
1328 		return 1;
1329 	}
1330 	i++; /* skip first element for . itself */
1331 	if(tab==0 || i>=ntab)
1332 		return -1;
1333 	tab += i;
1334 	qid = tab->qid;
1335 	qid.path &= ~Qdir;
1336 	qid.vers = 0;
1337 	devdir(c, qid, tab->name, tab->length, eve, tab->perm, dp);
1338 	return 1;
1339 }
1340 
1341 static int
Gfmt(Fmt * f)1342 Gfmt(Fmt* f)
1343 {
1344 	Gas *g;
1345 
1346 	g = va_arg(f->args, Gas*);
1347 	switch(g->spc){
1348 	case Rsysmem:
1349 	case Rsysio:
1350 	case Rembed:
1351 	case Rsmbus:
1352 	case Rcmos:
1353 	case Rpcibar:
1354 	case Ripmi:
1355 		fmtprint(f, "[%s ", acpiregstr(g->spc));
1356 		break;
1357 	case Rpcicfg:
1358 		fmtprint(f, "[pci ");
1359 		fmtprint(f, "dev %#ulx ", (ulong)(g->addr >> 32) & 0xFFFF);
1360 		fmtprint(f, "fn %#ulx ", (ulong)(g->addr & 0xFFFF0000) >> 16);
1361 		fmtprint(f, "adr %#ulx ", (ulong)(g->addr &0xFFFF));
1362 		break;
1363 	case Rfixedhw:
1364 		fmtprint(f, "[hw ");
1365 		break;
1366 	default:
1367 		fmtprint(f, "[spc=%#ux ", g->spc);
1368 	}
1369 	return fmtprint(f, "off %d len %d addr %#ullx sz%d]",
1370 		g->off, g->len, g->addr, g->accsz);
1371 }
1372 
1373 static uint
getbanked(int ra,int rb,int sz)1374 getbanked(int ra, int rb, int sz)
1375 {
1376 	uint r;
1377 
1378 	r = 0;
1379 	switch(sz){
1380 	case 1:
1381 		if(ra != 0)
1382 			r |= inb(ra);
1383 		if(rb != 0)
1384 			r |= inb(rb);
1385 		break;
1386 	case 2:
1387 		if(ra != 0)
1388 			r |= ins(ra);
1389 		if(rb != 0)
1390 			r |= ins(rb);
1391 		break;
1392 	case 4:
1393 		if(ra != 0)
1394 			r |= inl(ra);
1395 		if(rb != 0)
1396 			r |= inl(rb);
1397 		break;
1398 	default:
1399 		print("getbanked: wrong size\n");
1400 	}
1401 	return r;
1402 }
1403 
1404 static uint
setbanked(int ra,int rb,int sz,int v)1405 setbanked(int ra, int rb, int sz, int v)
1406 {
1407 	uint r;
1408 
1409 	r = -1;
1410 	switch(sz){
1411 	case 1:
1412 		if(ra != 0)
1413 			outb(ra, v);
1414 		if(rb != 0)
1415 			outb(rb, v);
1416 		break;
1417 	case 2:
1418 		if(ra != 0)
1419 			outs(ra, v);
1420 		if(rb != 0)
1421 			outs(rb, v);
1422 		break;
1423 	case 4:
1424 		if(ra != 0)
1425 			outl(ra, v);
1426 		if(rb != 0)
1427 			outl(rb, v);
1428 		break;
1429 	default:
1430 		print("setbanked: wrong size\n");
1431 	}
1432 	return r;
1433 }
1434 
1435 static uint
getpm1ctl(void)1436 getpm1ctl(void)
1437 {
1438 	return getbanked(fadt.pm1acntblk, fadt.pm1bcntblk, fadt.pm1cntlen);
1439 }
1440 
1441 static void
setpm1sts(uint v)1442 setpm1sts(uint v)
1443 {
1444 	DBG("acpi: setpm1sts %#ux\n", v);
1445 	setbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen/2, v);
1446 }
1447 
1448 static uint
getpm1sts(void)1449 getpm1sts(void)
1450 {
1451 	return getbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen/2);
1452 }
1453 
1454 static uint
getpm1en(void)1455 getpm1en(void)
1456 {
1457 	int sz;
1458 
1459 	sz = fadt.pm1evtlen/2;
1460 	return getbanked(fadt.pm1aevtblk+sz, fadt.pm1bevtblk+sz, sz);
1461 }
1462 
1463 static int
getgpeen(int n)1464 getgpeen(int n)
1465 {
1466 	return inb(gpes[n].enio) & 1<<gpes[n].enbit;
1467 }
1468 
1469 static void
setgpeen(int n,uint v)1470 setgpeen(int n, uint v)
1471 {
1472 	int old;
1473 
1474 	DBG("acpi: setgpe %d %d\n", n, v);
1475 	old = inb(gpes[n].enio);
1476 	if(v)
1477 		outb(gpes[n].enio, old | 1<<gpes[n].enbit);
1478 	else
1479 		outb(gpes[n].enio, old & ~(1<<gpes[n].enbit));
1480 }
1481 
1482 static void
clrgpests(int n)1483 clrgpests(int n)
1484 {
1485 	outb(gpes[n].stsio, 1<<gpes[n].stsbit);
1486 }
1487 
1488 static uint
getgpests(int n)1489 getgpests(int n)
1490 {
1491 	return inb(gpes[n].stsio) & 1<<gpes[n].stsbit;
1492 }
1493 
1494 static void
acpiintr(Ureg *,void *)1495 acpiintr(Ureg*, void*)
1496 {
1497 	int i;
1498 	uint sts, en;
1499 
1500 	print("acpi: intr\n");
1501 
1502 	for(i = 0; i < ngpes; i++)
1503 		if(getgpests(i)){
1504 			print("gpe %d on\n", i);
1505 			en = getgpeen(i);
1506 			setgpeen(i, 0);
1507 			clrgpests(i);
1508 			if(en != 0)
1509 				print("acpiitr: calling gpe %d\n", i);
1510 		//	queue gpe for calling gpe->ho in the
1511 		//	aml process.
1512 		//	enable it again when it returns.
1513 		}
1514 	sts = getpm1sts();
1515 	en = getpm1en();
1516 	print("acpiitr: pm1sts %#ux pm1en %#ux\n", sts, en);
1517 	if(sts&en)
1518 		print("have enabled events\n");
1519 	if(sts&1)
1520 		print("power button\n");
1521 	// XXX serve other interrupts here.
1522 	setpm1sts(sts);
1523 }
1524 
1525 static void
initgpes(void)1526 initgpes(void)
1527 {
1528 	int i, n0, n1;
1529 
1530 	n0 = fadt.gpe0blklen/2;
1531 	n1 = fadt.gpe1blklen/2;
1532 	ngpes = n0 + n1;
1533 	gpes = mallocz(sizeof(Gpe) * ngpes, 1);
1534 	for(i = 0; i < n0; i++){
1535 		gpes[i].nb = i;
1536 		gpes[i].stsbit = i&7;
1537 		gpes[i].stsio = fadt.gpe0blk + (i>>3);
1538 		gpes[i].enbit = (n0 + i)&7;
1539 		gpes[i].enio = fadt.gpe0blk + ((n0 + i)>>3);
1540 	}
1541 	for(i = 0; i + n0 < ngpes; i++){
1542 		gpes[i + n0].nb = fadt.gp1base + i;
1543 		gpes[i + n0].stsbit = i&7;
1544 		gpes[i + n0].stsio = fadt.gpe1blk + (i>>3);
1545 		gpes[i + n0].enbit = (n1 + i)&7;
1546 		gpes[i + n0].enio = fadt.gpe1blk + ((n1 + i)>>3);
1547 	}
1548 	for(i = 0; i < ngpes; i++){
1549 		setgpeen(i, 0);
1550 		clrgpests(i);
1551 	}
1552 }
1553 
1554 static void
acpiioalloc(uint addr,int len)1555 acpiioalloc(uint addr, int len)
1556 {
1557 	if(addr != 0)
1558 		ioalloc(addr, len, 0, "acpi");
1559 }
1560 
1561 int
acpiinit(void)1562 acpiinit(void)
1563 {
1564 	if(fadt.smicmd == 0){
1565 		fmtinstall('G', Gfmt);
1566 		acpirsdptr();
1567 		if(fadt.smicmd == 0)
1568 			return -1;
1569 	}
1570 	return 0;
1571 }
1572 
1573 static Chan*
acpiattach(char * spec)1574 acpiattach(char *spec)
1575 {
1576 	int i;
1577 
1578 	/*
1579 	 * This was written for the stock kernel.
1580 	 * This code must use 64bit registers to be acpi ready in nix.
1581 	 * Besides, we mostly want the locality and affinity tables.
1582 	 */
1583 	if(1 || acpiinit() < 0)
1584 		error("acpi not enabled");
1585 
1586 	/*
1587 	 * should use fadt->xpm* and fadt->xgpe* registers for 64 bits.
1588 	 * We are not ready in this kernel for that.
1589 	 */
1590 	DBG("acpi io alloc\n");
1591 	acpiioalloc(fadt.smicmd, 1);
1592 	acpiioalloc(fadt.pm1aevtblk, fadt.pm1evtlen);
1593 	acpiioalloc(fadt.pm1bevtblk, fadt.pm1evtlen );
1594 	acpiioalloc(fadt.pm1acntblk, fadt.pm1cntlen);
1595 	acpiioalloc(fadt.pm1bcntblk, fadt.pm1cntlen);
1596 	acpiioalloc(fadt.pm2cntblk, fadt.pm2cntlen);
1597 	acpiioalloc(fadt.pmtmrblk, fadt.pmtmrlen);
1598 	acpiioalloc(fadt.gpe0blk, fadt.gpe0blklen);
1599 	acpiioalloc(fadt.gpe1blk, fadt.gpe1blklen);
1600 
1601 	DBG("acpi init gpes\n");
1602 	initgpes();
1603 
1604 	/*
1605 	 * This starts ACPI, which may require we handle
1606 	 * power mgmt events ourselves. Use with care.
1607 	 */
1608 	DBG("acpi starting\n");
1609 	outb(fadt.smicmd, fadt.acpienable);
1610 	for(i = 0; i < 10; i++)
1611 		if(getpm1ctl() & Pm1SciEn)
1612 			break;
1613 	if(i == 10)
1614 		error("acpi: failed to enable\n");
1615 	if(fadt.sciint != 0)
1616 		intrenable(fadt.sciint, acpiintr, 0, BUSUNKNOWN, "acpi");
1617 	return devattach(L'α', spec);
1618 }
1619 
1620 static Walkqid*
acpiwalk(Chan * c,Chan * nc,char ** name,int nname)1621 acpiwalk(Chan *c, Chan *nc, char **name, int nname)
1622 {
1623 	return devwalk(c, nc, name, nname, acpidir, nelem(acpidir), acpigen);
1624 }
1625 
1626 static long
acpistat(Chan * c,uchar * dp,long n)1627 acpistat(Chan *c, uchar *dp, long n)
1628 {
1629 	return devstat(c, dp, n, acpidir, nelem(acpidir), acpigen);
1630 }
1631 
1632 static Chan*
acpiopen(Chan * c,int omode)1633 acpiopen(Chan *c, int omode)
1634 {
1635 	return devopen(c, omode, acpidir, nelem(acpidir), acpigen);
1636 }
1637 
1638 static void
acpiclose(Chan *)1639 acpiclose(Chan *)
1640 {
1641 }
1642 
1643 static char*ttext;
1644 static int tlen;
1645 
1646 static long
acpiread(Chan * c,void * a,long n,vlong off)1647 acpiread(Chan *c, void *a, long n, vlong off)
1648 {
1649 	long q;
1650 	Atable *t;
1651 	char *ns, *s, *e, *ntext;
1652 
1653 	q = c->qid.path;
1654 	switch(q){
1655 	case Qdir:
1656 		return devdirread(c, a, n, acpidir, nelem(acpidir), acpigen);
1657 	case Qtbl:
1658 		if(ttext == nil){
1659 			tlen = 1024;
1660 			ttext = malloc(tlen);
1661 			if(ttext == nil){
1662 				print("acpi: no memory\n");
1663 				return 0;
1664 			}
1665 			s = ttext;
1666 			e = ttext + tlen;
1667 			strcpy(s, "no tables\n");
1668 			for(t = tfirst; t != nil; t = t->next){
1669 				ns = seprinttable(s, e, t);
1670 				while(ns == e - 1){
1671 					DBG("acpiread: allocated %d\n", tlen*2);
1672 					ntext = realloc(ttext, tlen*2);
1673 					if(ntext == nil)
1674 						panic("acpi: no memory\n");
1675 					s = ntext + (ttext - s);
1676 					ttext = ntext;
1677 					tlen *= 2;
1678 					e = ttext + tlen;
1679 					ns = seprinttable(s, e, t);
1680 				}
1681 				s = ns;
1682 			}
1683 
1684 		}
1685 		return readstr(off, a, n, ttext);
1686 	case Qio:
1687 		if(reg == nil)
1688 			error("region not configured");
1689 		return regio(reg, a, n, off, 0);
1690 	}
1691 	error(Eperm);
1692 	return -1;
1693 }
1694 
1695 static long
acpiwrite(Chan * c,void * a,long n,vlong off)1696 acpiwrite(Chan *c, void *a, long n, vlong off)
1697 {
1698 	Cmdtab *ct;
1699 	Cmdbuf *cb;
1700 	Reg *r;
1701 	uint rno, fun, dev, bus, i;
1702 
1703 	if(c->qid.path == Qio){
1704 		if(reg == nil)
1705 			error("region not configured");
1706 		return regio(reg, a, n, off, 1);
1707 	}
1708 	if(c->qid.path != Qctl)
1709 		error(Eperm);
1710 
1711 	cb = parsecmd(a, n);
1712 	if(waserror()){
1713 		free(cb);
1714 		nexterror();
1715 	}
1716 	ct = lookupcmd(cb, ctls, nelem(ctls));
1717 	DBG("acpi ctl %s\n", cb->f[0]);
1718 	switch(ct->index){
1719 	case CMregion:
1720 		r = reg;
1721 		if(r == nil){
1722 			r = smalloc(sizeof(Reg));
1723 			r->name = nil;
1724 		}
1725 		kstrdup(&r->name, cb->f[1]);
1726 		r->spc = acpiregid(cb->f[2]);
1727 		if(r->spc < 0){
1728 			free(r);
1729 			reg = nil;
1730 			error("bad region type");
1731 		}
1732 		if(r->spc == Rpcicfg || r->spc == Rpcibar){
1733 			rno = r->base>>Rpciregshift & Rpciregmask;
1734 			fun = r->base>>Rpcifunshift & Rpcifunmask;
1735 			dev = r->base>>Rpcidevshift & Rpcidevmask;
1736 			bus = r->base>>Rpcibusshift & Rpcibusmask;
1737 			r->tbdf = MKBUS(BusPCI, bus, dev, fun);
1738 			r->base = rno;	/* register ~ our base addr */
1739 		}
1740 		r->base = strtoull(cb->f[3], nil, 0);
1741 		r->len = strtoull(cb->f[4], nil, 0);
1742 		r->accsz = strtoul(cb->f[5], nil, 0);
1743 		if(r->accsz < 1 || r->accsz > 4){
1744 			free(r);
1745 			reg = nil;
1746 			error("bad region access size");
1747 		}
1748 		reg = r;
1749 		DBG("region %s %s %llux %llux sz%d",
1750 			r->name, acpiregstr(r->spc), r->base, r->len, r->accsz);
1751 		break;
1752 	case CMgpe:
1753 		i = strtoul(cb->f[1], nil, 0);
1754 		if(i >= ngpes)
1755 			error("gpe out of range");
1756 		kstrdup(&gpes[i].obj, cb->f[2]);
1757 		DBG("gpe %d %s\n", i, gpes[i].obj);
1758 		setgpeen(i, 1);
1759 		break;
1760 	default:
1761 		panic("acpi: unknown ctl");
1762 	}
1763 	poperror();
1764 	free(cb);
1765 	return n;
1766 }
1767 
1768 
1769 Dev acpidevtab = {
1770 	L'α',
1771 	"acpi",
1772 
1773 	devreset,
1774 	devinit,
1775 	devshutdown,
1776 	acpiattach,
1777 	acpiwalk,
1778 	acpistat,
1779 	acpiopen,
1780 	devcreate,
1781 	acpiclose,
1782 	acpiread,
1783 	devbread,
1784 	acpiwrite,
1785 	devbwrite,
1786 	devremove,
1787 	devwstat,
1788 };
1789