2 #include "../port/lib.h"
7 #include "../port/pci.h"
8 #include "../port/error.h"
14 typedef struct Rsd Rsd;
15 typedef struct Tbl Tbl;
43 Tblsz = 4+4+1+1+6+8+4+4+4,
48 /* physical addresses visited by maptable() */
50 static uvlong tblpa[64];
52 /* successfully mapped tables */
54 static Tbl *tblmap[64];
58 return p[1]<<8 | p[0];
63 return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
71 return u<<32 | get32(p);
76 return get32(t->len) - Tblsz;
80 memcheck(uintptr pa, long len)
93 if(pa < PADDR(CPU0END))
95 if(pe >= PADDR(KTZERO) && pa < PADDR(end))
96 return PADDR(KTZERO) - pa;
97 for(i=0; i<nelem(conf.mem); i++){
101 if(pe >= cm->base && pa <= cm->base + cm->npage*BY2PG - 1)
102 return cm->base - pa;
118 if(ntblpa >= nelem(tblpa) || ntblmap >= nelem(tblmap))
121 for(i=0; i<ntblpa; i++){
125 tblpa[ntblpa++] = pa;
128 if((t = vmap(pa, 8)) == nil)
139 if((t = vmap(pa, l)) == nil)
145 tblmap[ntblmap++] = t;
149 if(memcmp("RSDT", t->sig, 4) == 0){
150 for(p = t->data; p+3 < e; p += 4)
154 if(memcmp("XSDT", t->sig, 4) == 0){
155 for(p = t->data; p+7 < e; p += 8)
159 if(memcmp("FACP", t->sig, 4) == 0){
162 maptable(get32(p + 40));
165 maptable(get64(p + 140));
173 if(rsd == nil || ntblmap > 0 || ntblpa > 0)
175 if(!checksum(rsd, 20))
176 maptable(get32(rsd->raddr));
178 if(!checksum(rsd, 36))
179 maptable(get64(rsd->xaddr));
184 findtable(char sig[4])
189 for(i=0; i<ntblmap; i++){
191 if(memcmp(t->sig, sig, 4) == 0)
198 findapic(int gsi, int *pintin)
203 for(i=0; i<=MaxAPICNO; i++){
204 if((a = mpioapic[i]) == nil)
206 if((a->flags & PcmpEN) == 0)
208 if(gsi >= a->gsibase && gsi <= a->gsibase+a->mre){
210 *pintin = gsi - a->gsibase;
214 print("findapic: no ioapic found for gsi %d\n", gsi);
219 addirq(int gsi, int type, int busno, int irq, int flags)
227 if((a = findapic(gsi, &intin)) == nil)
230 for(bus = mpbus; bus; bus = bus->next)
231 if(bus->type == type && bus->busno == busno)
234 if((bus = xalloc(sizeof(Bus))) == nil)
235 panic("addirq: no memory for Bus");
248 mpbuslast->next = bus;
254 for(ai = bus->aintr; ai; ai = ai->next)
255 if(ai->intr->irq == irq)
258 if((pi = xalloc(sizeof(PCMPintr))) == nil)
259 panic("addirq: no memory for PCMPintr");
260 pi->type = PcmpIOINTR;
262 pi->flags = flags & (PcmpPOMASK|PcmpELMASK);
265 pi->apicno = a->apicno;
268 if((ai = xalloc(sizeof(Aintr))) == nil)
269 panic("addirq: no memory for Aintr");
272 ai->next = bus->aintr;
287 for(l = 0, i=24; i>=0; i -= 8, b >>= 8)
288 l |= (b & 0xFF) << i;
290 for(i=6; i>=3; i--, l >>= 4)
291 id[i] = "0123456789ABCDEF"[l & 0xF];
292 for(i=2; i>=0; i--, l >>= 5)
293 id[i] = '@' + (l & 0x1F);
306 if((x = amlwalk(dot, "^_HID")) != nil)
307 if((p = amlval(x)) != nil)
309 if((x = amlwalk(dot, "^_BBN")) == nil)
310 if((x = amlwalk(dot, "^_ADR")) == nil)
313 if(amleval(x, "", &p) < 0)
316 /* if root bridge, then we are done here */
317 if(id != nil && (strcmp(id, "PNP0A03")==0 || strcmp(id, "PNP0A08")==0))
319 x = amlwalk(dot, "^");
320 if(x == nil || x == dot)
322 if((bno = pcibusno(x)) < 0)
324 tbdf = MKBUS(BusPCI, bno, adr>>16, adr&0xFFFF);
325 pdev = pcimatchtbdf(tbdf);
328 if(pdev->bridge == nil)
330 return BUSBNO(pdev->bridge->tbdf);
340 if((x = amlwalk(dot, "_ADR")) == nil){
341 x = amlwalk(dot, "^");
342 if(x == nil || x == dot)
347 if((bno = pcibusno(x)) < 0)
350 if(amleval(x, "", &p) < 0)
353 return MKBUS(BusPCI, bno, adr>>16, adr&0xFFFF);
359 getirqs(void *d, uchar pmask[32], int *pflags)
365 memset(pmask, 0, 32);
369 if(amllen(d) >= 2 && (p[0] == 0x22 || p[0] == 0x23)){
372 if(amllen(d) >= 3 && p[0] == 0x23)
373 *pflags = ((p[3] & (1<<0)) ? PcmpEDGE : PcmpLEVEL)
374 | ((p[3] & (1<<3)) ? PcmpLOW : PcmpHIGH);
377 if(amllen(d) >= 5 && p[0] == 0x89){
379 if(amllen(d) < 5+n*4)
382 m = get32(p+5 + i*4);
383 if(m >= 0 && m < 256)
384 pmask[m/8] |= 1<<(m%8);
386 *pflags = ((p[3] & (1<<1)) ? PcmpEDGE : PcmpLEVEL)
387 | ((p[3] & (1<<2)) ? PcmpLOW : PcmpHIGH);
394 setirq(void *d, uint irq)
400 p = amlnew('b', amllen(d));
401 memmove(p, d, amllen(p));
402 if(p[0] == 0x22 || p[0] == 0x23){
418 setuplink(void *link, int *pflags)
420 uchar im, pm[32], cm[32], *c;
421 static int lastirq = 1;
425 if(amltag(link) != 'N')
429 if(amleval(amlwalk(link, "_PRS"), "", &r) < 0)
431 if(getirqs(r, pm, pflags) < 0)
435 if(amleval(amlwalk(link, "_CRS"), "", &r) < 0)
437 if(getirqs(r, cm, pflags) < 0)
441 for(i=0; i<256; i++){
449 if(gsi > 0 || getconf("*nopcirouting") != nil)
452 for(i=0; i<256; i++){
453 gsi = lastirq++ & 0xFF; /* round robin */
456 if((c = setirq(r, gsi)) == nil)
458 if(amleval(amlwalk(link, "_SRS"), "b", c, nil) < 0)
467 enumprt(void *dot, void *)
470 int bno, dno, pin, gsi, flags;
477 /* evalulate _PRT method */
479 if(amleval(dot, "", &p) < 0)
488 if(amltag(a[i]) != 'p')
490 if(amllen(a[i]) != 4)
494 dno = amlint(b[0])>>16;
498 gsi = setuplink(b[2], &flags);
502 addirq(gsi, BusPCI, bno, (dno<<2)|pin, flags);
510 enumec(void *dot, void *)
512 int cmdport, dataport;
518 id = eisaid(amlval(amlwalk(dot, "^_HID")));
519 if(id == nil || strcmp(id, "PNP0C09") != 0)
521 if((x = amlwalk(dot, "^_CRS")) == nil)
523 if(amleval(x, "", &b) < 0 || amltag(b) != 'b' || amllen(b) < 16)
525 if(b[0] != 0x47 || b[8] != 0x47) /* two i/o port descriptors */
527 dataport = b[0+2] | b[0+3]<<8;
528 cmdport = b[8+2] | b[8+3]<<8;
529 ecinit(cmdport, dataport);
534 readmem(Chan*, void *v, long n, vlong o)
536 uvlong pa = (uvlong)o;
539 if((n = memcheck(pa, n)) <= 0)
541 if((t = vmap(pa, n)) == nil)
554 writemem(Chan*, void *v, long n, vlong o)
556 uvlong pa = (uvlong)o;
559 if(memcheck(pa, n) != n)
561 if((t = vmap(pa, n)) == nil)
586 if((t = findtable("DSDT")) != nil){
587 amlintmask = (~0ULL) >> (t->rev <= 1)*32;
588 amlload(t->data, tbldlen(t));
591 /* load SSDT, there can be multiple tables */
592 for(i=0; i<ntblmap; i++){
594 if(memcmp(t->sig, "SSDT", 4) == 0)
595 amlload(t->data, tbldlen(t));
599 amleval(amlwalk(amlroot, "_PIC"), "i", 1, nil);
601 t = findtable("APIC");
603 panic("acpiinit: no MADT (APIC) table");
607 lapicbase = get32(s); s += 8;
608 va = vmap(lapicbase, 1024);
609 print("LAPIC: %.8lux %#p\n", lapicbase, va);
611 panic("acpiinit: cannot map lapic %.8lux", lapicbase);
614 for(p = s; p < e; p += c){
616 if(c < 2 || (p+c) > e)
619 case 0x00: /* Processor Local APIC */
622 if((a = xalloc(sizeof(Apic))) == nil)
623 panic("acpiinit: no memory for Apic");
624 a->type = PcmpPROCESSOR;
626 a->paddr = lapicbase;
628 a->lintr[0] = ApicIMASK;
629 a->lintr[1] = ApicIMASK;
630 a->flags = p[4] & PcmpEN;
632 /* skip disabled processors */
633 if((a->flags & PcmpEN) == 0 || mpapic[a->apicno] != nil){
637 a->machno = machno++;
640 * platform firmware should list the boot processor
641 * as the first processor entry in the MADT
646 mpapic[a->apicno] = a;
648 case 0x01: /* I/O APIC */
651 if((a = xalloc(sizeof(Apic))) == nil)
652 panic("acpiinit: no memory for io Apic");
653 a->type = PcmpIOAPIC;
655 a->paddr = get32(p+4);
656 if((a->addr = vmap(a->paddr, 1024)) == nil)
657 panic("acpiinit: cannot map ioapic %.8lux", a->paddr);
658 a->gsibase = get32(p+8);
660 mpioapic[a->apicno] = a;
661 ioapicinit(a, a->apicno);
667 * need 2nd pass as vbox puts interrupt overrides
668 * *before* the ioapic entries (!)
670 for(p = s; p < e; p += c){
672 if(c < 2 || (p+c) > e)
675 case 0x02: /* Interrupt Source Override */
676 addirq(get32(p+4), BusISA, 0, p[3], get16(p+8));
678 case 0x03: /* NMI Source */
679 case 0x04: /* Local APIC NMI */
680 case 0x05: /* Local APIC Address Override */
681 case 0x06: /* I/O SAPIC */
682 case 0x07: /* Local SAPIC */
683 case 0x08: /* Platform Interrupt Sources */
684 case 0x09: /* Processor Local x2APIC */
685 case 0x0A: /* x2APIC NMI */
687 case 0x0C: /* GICD */
692 /* find embedded controller */
693 amlenum(amlroot, "_HID", enumec, nil);
695 /* look for PCI interrupt mappings */
696 amlenum(amlroot, "_PRT", enumprt, nil);
698 /* add identity mapped legacy isa interrupts */
700 addirq(i, BusISA, 0, i, 0);
702 /* free the AML interpreter */
706 * Ininitalize local APIC and start application processors.
717 /* stop application processors */
720 /* locate and write platform reset register */
721 while((t = findtable("FACP")) != nil){
722 if(get32(t->len) <= 128)
725 if((get32(p + 112) & (1<<10)) == 0)
727 if(p[116+0] != IoSpace)
729 outb(get32(p+116+4), p[128]);
733 /* acpi shutdown failed, try generic reset */
737 static int identify(void);
738 extern int i8259irqno(int, int);
739 extern void i8253init(void);
741 extern int hpetprobe(uvlong);
742 extern void hpetinit(void);
743 extern uvlong hpetread(uvlong*);
750 .intrassign= mpintrassign,
751 .intrirqno= i8259irqno,
752 .intron= lapicintron,
753 .introff= lapicintroff,
754 .clockinit= i8253init,
755 .fastclock= i8253read,
756 .timerset= lapictimerset,
760 readtbls(Chan*, void *v, long n, vlong o)
769 for(i=0; n > 0 && i < ntblmap; i++){
779 memmove(p, (uchar*)t + o, m);
784 return p - (uchar*)v;
794 if((cp = getconf("*acpi")) == nil)
795 cp = "1"; /* search for rsd by default */
796 v = (uintptr)strtoull(cp, nil, 16);
800 memreserve(v, sizeof(Rsd));
801 rsd = vmap(v, sizeof(Rsd));
805 if(checksum(rsd, 20) && checksum(rsd, 36))
808 addarchfile("acpitbls", 0444, readtbls, nil);
809 addarchfile("acpimem", 0600, readmem, writemem);
810 if(v == 0 || findtable("APIC") == nil)
812 if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
814 if(getconf("*nohpet") == nil
815 && (t = findtable("HPET")) != nil
816 && ((uchar*)t)[40] == 0
817 && hpetprobe(get64((uchar*)t+44)) == 0){
818 archacpi.clockinit = hpetinit;
819 archacpi.fastclock = hpetread;
821 if(m->havetsc && getconf("*notsc") == nil)
822 archacpi.fastclock = tscticks;
828 readpcicfg(Amlio *io, void *data, int n, int offset)
845 if(!(r & 3) && n == 4){
850 if(!(r & 1) && n == 2){
855 for(i = 0; i < n; i++){
865 readec(Amlio *io, void *data, int n, int off)
871 if(off < 0 || off >= 256)
876 for(port = off; port < off+n; port++){
877 if((v = ecread(port)) < 0)
885 writeec(Amlio *io, void *data, int n, int off)
891 if(off < 0 || off+n > 256)
894 for(port = off; port < off+n; port++)
895 if(ecwrite(port, *p++) < 0)
901 writepcicfg(Amlio *io, void *data, int n, int offset)
918 if(!(r & 3) && n == 4){
923 if(!(r & 1) && n == 2){
928 for(i = 0; i < n; i++){
938 readioport(Amlio *io, void *data, int len, int port)
946 PBIT32(a, inl(port));
949 PBIT16(a, ins(port));
959 writeioport(Amlio *io, void *data, int len, int port)
967 outl(port, GBIT32(a));
970 outs(port, GBIT16(a));
973 outb(port, GBIT8(a));
988 print("amlmapio: address space %x not implemented\n", io->space);
991 if(memcheck(io->off, io->len) != io->len){
992 print("amlmapio: [%#p-%#p) overlaps usable memory\n",
993 (uintptr)io->off, (uintptr)(io->off+io->len));
996 if((io->va = vmap(io->off, io->len)) == nil){
997 print("amlmapio: vmap failed\n");
1002 snprint(buf, sizeof(buf), "%N", io->name);
1003 if(ioalloc(io->off, io->len, 0, buf) < 0){
1004 print("amlmapio: ioalloc failed\n");
1007 io->read = readioport;
1008 io->write = writeioport;
1011 if((tbdf = pciaddr(io->name)) < 0){
1012 print("amlmapio: no address\n");
1015 if((pdev = pcimatchtbdf(tbdf)) == nil){
1016 print("amlmapio: no device %T\n", tbdf);
1020 io->read = readpcicfg;
1021 io->write = writepcicfg;
1025 io->write = writeec;
1028 print("amlmapio: mapping %N failed\n", io->name);
1033 amlunmapio(Amlio *io)
1037 vunmap(io->va, io->len);
1049 if((p = malloc(n)) == nil)
1050 panic("amlalloc: no memory");