123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- /*
- * minimal acpi support for multiprocessors.
- *
- * avoids AML but that's only enough to discover
- * the processors, not the interrupt routing details.
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "mp.h"
- #include "mpacpi.h"
- /* 8c says: out of fixed registers */
- #define L64GET(p) ((uvlong)L32GET((p)+4) << 32 | L32GET(p))
- enum {
- /* apic types */
- Apiclproc,
- Apicio,
- Apicintrsrcoverride,
- Apicnmisrc,
- Apiclnmi,
- Apicladdroverride,
- Apicios,
- Apicls,
- Apicintrsrc,
- Apiclx2,
- Apiclx2nmi,
- PcmpUsed = 1ul<<31, /* Apic->flags addition */
- Lapicbase = 0x1b, /* msr */
- Lapicae = 1<<11, /* apic enable in Lapicbase */
- };
- #define dprint(...) if(mpdebug) print(__VA_ARGS__); else USED(mpdebug)
- /* from mp.c */
- int mpdebug;
- int mpmachno;
- Apic mpapic[MaxAPICNO+1];
- int machno2apicno[MaxAPICNO+1]; /* inverse map: machno -> APIC ID */
- Apic *bootapic;
- static int nprocid;
- static uvlong
- l64get(uchar *p)
- {
- return L64GET(p);
- }
- int
- apicset(Apic *apic, int type, int apicno, int f)
- {
- if(apicno > MaxAPICNO)
- return -1;
- apic->type = type;
- apic->apicno = apicno;
- apic->flags = f | PcmpEN | PcmpUsed;
- return 0;
- }
- int
- mpnewproc(Apic *apic, int apicno, int f)
- {
- if(apic->flags & PcmpUsed) {
- print("mpnewproc: apic already enabled\n");
- return -1;
- }
- if (apicset(apic, PcmpPROCESSOR, apicno, f) < 0)
- return -1;
- apic->lintr[1] = apic->lintr[0] = ApicIMASK;
- /* botch! just enumerate */
- if(apic->flags & PcmpBP)
- apic->machno = 0;
- else
- apic->machno = ++mpmachno;
- machno2apicno[apic->machno] = apicno;
- return 0;
- }
- static int
- mpacpiproc(uchar *p, ulong laddr)
- {
- int id, f;
- ulong *vladdr;
- vlong base;
- char *already;
- Apic *apic;
- /* p bytes: type (0), len (8), cpuid, cpu_lapic id, flags[4] */
- id = p[3];
- /* cpu unusable flag or id out of range? */
- if((L32GET(p+4) & 1) == 0 || id > MaxAPICNO)
- return -1;
- vladdr = nil;
- already = "";
- f = 0;
- apic = &mpapic[id];
- apic->paddr = laddr;
- if (nprocid++ == 0) {
- f = PcmpBP;
- vladdr = vmap(apic->paddr, 1024);
- if(apic->addr == nil){
- print("proc apic %d: failed to map %#p\n", id,
- apic->paddr);
- already = "(fail)";
- }
- bootapic = apic;
- }
- apic->addr = vladdr;
- if(apic->flags & PcmpUsed)
- already = "(on)";
- else
- mpnewproc(apic, id, f);
- if (0)
- dprint("\tapic proc %d/%d apicid %d flags%s%s %s\n", nprocid-1,
- apic->machno, id, f & PcmpBP? " boot": "",
- f & PcmpEN? " enabled": "", already);
- USED(already);
- rdmsr(Lapicbase, &base);
- if (!(base & Lapicae)) {
- dprint("mpacpiproc: enabling lapic\n");
- wrmsr(Lapicbase, base | Lapicae);
- }
- return 0;
- }
- static void
- mpacpicpus(Madt *madt)
- {
- int i, n;
- ulong laddr;
- uchar *p;
- laddr = L32GET(madt->addr);
- dprint("APIC mpacpicpus lapic addr %#lux, flags %#ux\n",
- laddr, L32GET(madt->flags));
- n = L32GET(&madt->sdthdr[4]);
- p = madt->structures;
- /* byte 0 is assumed to be type, 1 is assumed to be length */
- for(i = offsetof(Madt, structures[0]); i < n; i += p[1], p += p[1])
- switch(p[0]){
- case Apiclproc:
- mpacpiproc(p, laddr);
- break;
- }
- }
- /* returns nil iff checksum is bad */
- static void *
- mpacpirsdchecksum(void* addr, int length)
- {
- uchar *p, sum;
- sum = 0;
- for(p = addr; length-- > 0; p++)
- sum += *p;
- return sum == 0? addr: nil;
- }
- static void *
- mpacpirsdscan(uchar* addr, int len, char* signature)
- {
- int sl;
- uchar *e, *p;
- sl = strlen(signature);
- e = addr + len - sl;
- for(p = addr; p < e; p += 16)
- if(memcmp(p, signature, sl) == 0)
- return p;
- return nil;
- }
- static void *
- mpacpirsdsearch(char* signature)
- {
- uintptr p;
- uchar *bda;
- Rsd *rsd;
- /*
- * Search for the data structure signature:
- * 1) in the first KB of the EBDA;
- * 2) in the BIOS ROM between 0xE0000 and 0xFFFFF.
- */
- if(strncmp((char*)KADDR(0xFFFD9), "EISA", 4) == 0){
- bda = BIOSSEG(0x40);
- p = bda[0x0F]<<8 | bda[0x0E];
- if(p != 0 &&
- (rsd = mpacpirsdscan(KADDR(p), 1024, signature)) != nil)
- return rsd;
- }
- return mpacpirsdscan(BIOSSEG(0xE000), 0x20000, signature);
- }
- /* call func for each acpi table found */
- static void
- mpacpiscan(void (*func)(uchar *))
- {
- int asize, i, tbllen, sdtlen;
- uintptr dhpa, sdtpa;
- uchar *tbl, *sdt;
- Rsd *rsd;
- dprint("ACPI...");
- if((rsd = mpacpirsdsearch("RSD PTR ")) == nil) {
- dprint("none\n");
- return;
- }
- dprint("rsd %#p physaddr %#ux length %ud %#llux rev %d oem %.6s\n",
- rsd, L32GET(rsd->raddr), L32GET(rsd->length),
- l64get(rsd->xaddr), rsd->revision, (char*)rsd->oemid);
- if(rsd->revision == 2){
- if(mpacpirsdchecksum(rsd, 36) == nil)
- return;
- asize = 8;
- sdtpa = l64get(rsd->xaddr);
- } else {
- if(mpacpirsdchecksum(rsd, 20) == nil)
- return;
- asize = 4;
- sdtpa = L32GET(rsd->raddr);
- }
- if((sdt = vmap(sdtpa, 8)) == nil)
- return;
- if((sdt[0] != 'R' && sdt[0] != 'X') || memcmp(sdt+1, "SDT", 3) != 0){
- vunmap(sdt, 8);
- return;
- }
- sdtlen = L32GET(sdt + 4);
- vunmap(sdt, 8);
- if((sdt = vmap(sdtpa, sdtlen)) == nil)
- return;
- if(mpacpirsdchecksum(sdt, sdtlen) != nil)
- for(i = 36; i < sdtlen; i += asize){
- if(asize == 8)
- dhpa = l64get(sdt+i);
- else
- dhpa = L32GET(sdt+i);
-
- if((tbl = vmap(dhpa, 8)) == nil)
- continue;
- tbllen = L32GET(tbl + 4);
- vunmap(tbl, 8);
-
- if((tbl = vmap(dhpa, tbllen)) == nil)
- continue;
- if(mpacpirsdchecksum(tbl, tbllen) != nil)
- (*func)(tbl);
- vunmap(tbl, tbllen);
- }
- vunmap(sdt, sdtlen);
- }
- static void
- mpacpitbl(uchar *p)
- {
- /* for now, just activate any idle cpus */
- if (memcmp(p, "APIC", 4) == 0)
- mpacpicpus((Madt *)p);
- }
- static void
- mpacpi(void)
- {
- mpdebug = getconf("*debugmp") != nil;
- mpacpiscan(mpacpitbl);
- }
- void (*mpacpifunc)(void) = mpacpi;
|