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