#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"#include "mp.h"#include "acpi.h" /* * ACPI 4.0 Support. * Still WIP. * * This driver locates tables and parses only the FADT * and the XSDT. All other tables are mapped and kept there * for the user-level interpreter. */ #define l16get(p) (((p)[1]<<8)|(p)[0])#define l32get(p) (((u32int)l16get(p+2)<<16)|l16get(p))static Atable* acpifadt(uchar*, int);static Atable* acpitable(uchar*, int);static Atable* acpimadt(uchar*, int);static Atable* acpimsct(uchar*, int);static Atable* acpisrat(uchar*, int);static Atable* acpimcfg(uchar*, int);static Atable* acpihpet(uchar*, int); #pragma varargck type "G" Gas* static Cmdtab ctls[] ={ {CMregion, "region", 6}, {CMgpe, "gpe", 3},}; static Dirtab acpidir[]={ ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "acpictl", {Qctl}, 0, 0666, "acpitbl", {Qtbl}, 0, 0444, "acpiregio", {Qio}, 0, 0666,}; /* * The DSDT is always given to the user interpreter. * Tables listed here are also loaded from the XSDT: * MSCT, MADT, and FADT are processed by us, because they are * required to do early initialization before we have user processes. * Other tables are given to the user level interpreter for * execution. */static Parse ptables[] ={ "FACP", acpifadt, "APIC", acpimadt, "SRAT", acpisrat, "MSCT", acpimsct, "SSDT", acpitable, "MCFG", acpimcfg, "HPET", acpihpet,}; static Facs* facs; /* Firmware ACPI control structure */static Fadt fadt; /* Fixed ACPI description. To reach ACPI registers */static Xsdt* xsdt; /* XSDT table */static Atable* tfirst; /* loaded DSDT/SSDT/... tables */static Atable* tlast; /* pointer to last table */ Madt* apics; /* APIC info */static Srat* srat; /* System resource affinity, used by physalloc */static Msct* msct; /* Maximum system characteristics table */static Reg* reg; /* region used for I/O */static Gpe* gpes; /* General purpose events */static int ngpes; static char* regnames[] = { "mem", "io", "pcicfg", "embed", "smb", "cmos", "pcibar",}; static char*acpiregstr(int id){ static char buf[20]; /* BUG */ if(id >= 0 && id < nelem(regnames)) return regnames[id]; seprint(buf, buf+sizeof(buf), "spc:%#x", id); return buf;} static intacpiregid(char *s){ int i; for(i = 0; i < nelem(regnames); i++) if(strcmp(regnames[i], s) == 0) return i; return -1;} static u64intl64get(u8int* p){ /* * Doing this as a define * #define l64get(p) (((u64int)l32get(p+4)<<32)|l32get(p)) * causes 8c to abort with "out of fixed registers" in * rsdlink() below. */ return (((u64int)l32get(p+4)<<32)|l32get(p));} static u8intmget8(uintptr p, void*){ u8int *cp = (u8int*)p; return *cp;} static voidmset8(uintptr p, u8int v, void*){ u8int *cp = (u8int*)p; *cp = v;} static u16intmget16(uintptr p, void*){ u16int *cp = (u16int*)p; return *cp;} static voidmset16(uintptr p, u16int v, void*){ u16int *cp = (u16int*)p; *cp = v;} static u32intmget32(uintptr p, void*){ u32int *cp = (u32int*)p; return *cp;} static voidmset32(uintptr p, u32int v, void*){ u32int *cp = (u32int*)p; *cp = v;} static u64intmget64(uintptr p, void*){ u64int *cp = (u64int*)p; return *cp;} static voidmset64(uintptr p, u64int v, void*){ u64int *cp = (u64int*)p; *cp = v;} static u8intioget8(uintptr p, void*){ return inb(p);} static voidioset8(uintptr p, u8int v, void*){ outb(p, v);} static u16intioget16(uintptr p, void*){ return ins(p);} static voidioset16(uintptr p, u16int v, void*){ outs(p, v);} static u32intioget32(uintptr p, void*){ return inl(p);} static voidioset32(uintptr p, u32int v, void*){ outl(p, v);} static u8intcfgget8(uintptr p, void* r){ Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; return pcicfgr8(&d, p);} static voidcfgset8(uintptr p, u8int v, void* r){ Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; pcicfgw8(&d, p, v);} static u16intcfgget16(uintptr p, void* r){ Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; return pcicfgr16(&d, p);} static voidcfgset16(uintptr p, u16int v, void* r){ Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; pcicfgw16(&d, p, v);} static u32intcfgget32(uintptr p, void* r){ Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; return pcicfgr32(&d, p);} static voidcfgset32(uintptr p, u32int v, void* r){ Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; pcicfgw32(&d, p, v);} static Regio memio = { nil, mget8, mset8, mget16, mset16, mget32, mset32, mget64, mset64}; static Regio ioio = { nil, ioget8, ioset8, ioget16, ioset16, ioget32, ioset32, nil, nil}; static Regio cfgio = { nil, cfgget8, cfgset8, cfgget16, cfgset16, cfgget32, cfgset32, nil, nil}; /* * Copy memory, 1/2/4/8-bytes at a time, to/from a region. */static longregcpy(Regio *dio, uintptr da, Regio *sio, uintptr sa, long len, int align){ int n, i; DBG("regcpy %#ullx %#ullx %#ulx %#ux\n", da, sa, len, align); if((len%align) != 0) print("regcpy: bug: copy not aligned. truncated\n"); n = len/align; for(i = 0; i < n; i++){ switch(align){ case 1: DBG("cpy8 %#p %#p\n", da, sa); dio->set8(da, sio->get8(sa, sio->arg), dio->arg); break; case 2: DBG("cpy16 %#p %#p\n", da, sa); dio->set16(da, sio->get16(sa, sio->arg), dio->arg); break; case 4: DBG("cpy32 %#p %#p\n", da, sa); dio->set32(da, sio->get32(sa, sio->arg), dio->arg); break; case 8: DBG("cpy64 %#p %#p\n", da, sa); // dio->set64(da, sio->get64(sa, sio->arg), dio->arg); break; default: panic("regcpy: align bug"); } da += align; sa += align; } return n*align;} /* * Perform I/O within region in access units of accsz bytes. * All units in bytes. */static longregio(Reg *r, void *p, usize len, uintptr off, int iswr){ Regio rio; uintptr rp; DBG("reg%s %s %#p %#ullx %#lx sz=%d\n", iswr ? "out" : "in", r->name, p, off, len, r->accsz); rp = 0; if(off + len > r->len){ print("regio: access outside limits"); len = r->len - off; } if(len <= 0){ print("regio: zero len\n"); return 0; } switch(r->spc){ case Rsysmem:print("RSYMMEM %p %ld\n", r->base, len); if(r->p == nil) r->p = vmap(r->base, len); if(r->p == nil) error("regio: vmap failed"); rp = (uintptr)r->p + off; rio = memio; break; case Rsysio: rp = r->base + off; rio = ioio; break; case Rpcicfg: rp = r->base + off; rio = cfgio; rio.arg = r; break; case Rpcibar: case Rembed: case Rsmbus: case Rcmos: case Ripmi: case Rfixedhw: print("regio: reg %s not supported\n", acpiregstr(r->spc)); error("region not supported"); } if(iswr) regcpy(&rio, rp, &memio, (uintptr)p, len, r->accsz); else regcpy(&memio, (uintptr)p, &rio, rp, len, r->accsz); return len;} static Atable*newtable(uchar *p){ Atable *t; Sdthdr *h; t = malloc(sizeof(Atable)); if(t == nil) panic("no memory for more aml tables"); t->tbl = p; h = (Sdthdr*)t->tbl; t->is64 = h->rev >= 2; t->dlen = l32get(h->length) - Sdthdrsz; memmove(t->sig, h->sig, sizeof(h->sig)); t->sig[sizeof(t->sig)-1] = 0; memmove(t->oemid, h->oemid, sizeof(h->oemid)); t->oemtblid[sizeof(t->oemtblid)-1] = 0; memmove(t->oemtblid, h->oemtblid, sizeof(h->oemtblid)); t->oemtblid[sizeof(t->oemtblid)-1] = 0; t->next = nil; if(tfirst == nil) tfirst = tlast = t; else{ tlast->next = t; tlast = t; } return t;} static void*sdtchecksum(void* addr, int len){ u8int *p, sum; sum = 0; for(p = addr; len-- > 0; p++) sum += *p; if(sum == 0) return addr; return nil;} /* * sleezy code to deal with overlapping allocations. * please remove this by either just mapping all acpi * memory (can we count on good acpi tables?), or * keeping one map at a time. */typedef struct Sdtmap Sdtmap;struct Sdtmap { uintmem map[150]; uint n;};static Sdtmap smap; static void*findmap(uintmem pa0, uint size){ int i, o; uintmem pa, p; o = pa0 - (pa0 & ~(PGSZ-1)); pa = pa0 - o; size = ROUNDUP(size+o, PGSZ); if(pa+size < 1ull*MiB) return KADDR(pa); if(pa < 1ull*MiB) return nil; for(p = pa; p < pa+size; p += PGSZ){ for(i = 0; i < smap.n; i++) if(p == smap.map[i]) break; if(i == smap.n){ if(smap.n == nelem(smap.map)) panic("smap.map too small %d", smap.n); if(vmap(p, PGSZ) == nil) return nil; smap.map[smap.n++] = p; } } /* sleezy assumption, we know everything's direct mapped at KSEG2 */ return UINT2PTR(KSEG2 + pa0);} static voidsdtunmap(void *va, usize sz){ /* first cut */ USED(va, sz);} static void*sdtmap(uintmem pa, int *n, int cksum){ Sdthdr* sdt; sdt = findmap(pa, sizeof *sdt); if(sdt == nil){ DBG("acpi: findmap: nil\n"); return nil; } *n = l32get(sdt->length); if(*n>200000){ char tsig[5]; memmove(tsig, sdt, 4); tsig[4] = 0; print("%s (too big %d)", tsig, *n); return nil;} sdtunmap(sdt, sizeof(Sdthdr)); if((sdt = findmap(pa, *n)) == nil){ DBG("acpi: findmap: nil\n"); return nil;Lines 1–500 of 1780. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "mp.h" #include "acpi.h" /* * ACPI 4.0 Support. * Still WIP. * * This driver locates tables and parses only the FADT * and the XSDT. All other tables are mapped and kept there * for the user-level interpreter. */ #define l16get(p) (((p)[1]<<8)|(p)[0]) #define l32get(p) (((u32int)l16get(p+2)<<16)|l16get(p)) static Atable* acpifadt(uchar*, int); static Atable* acpitable(uchar*, int); static Atable* acpimadt(uchar*, int); static Atable* acpimsct(uchar*, int); static Atable* acpisrat(uchar*, int); static Atable* acpimcfg(uchar*, int); static Atable* acpihpet(uchar*, int); #pragma varargck type "G" Gas* static Cmdtab ctls[] = { {CMregion, "region", 6}, {CMgpe, "gpe", 3}, }; static Dirtab acpidir[]={ ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "acpictl", {Qctl}, 0, 0666, "acpitbl", {Qtbl}, 0, 0444, "acpiregio", {Qio}, 0, 0666, }; /* * The DSDT is always given to the user interpreter. * Tables listed here are also loaded from the XSDT: * MSCT, MADT, and FADT are processed by us, because they are * required to do early initialization before we have user processes. * Other tables are given to the user level interpreter for * execution. */ static Parse ptables[] = { "FACP", acpifadt, "APIC", acpimadt, "SRAT", acpisrat, "MSCT", acpimsct, "SSDT", acpitable, "MCFG", acpimcfg, "HPET", acpihpet, }; static Facs* facs; /* Firmware ACPI control structure */ static Fadt fadt; /* Fixed ACPI description. To reach ACPI registers */ static Xsdt* xsdt; /* XSDT table */ static Atable* tfirst; /* loaded DSDT/SSDT/... tables */ static Atable* tlast; /* pointer to last table */ Madt* apics; /* APIC info */ static Srat* srat; /* System resource affinity, used by physalloc */ static Msct* msct; /* Maximum system characteristics table */ static Reg* reg; /* region used for I/O */ static Gpe* gpes; /* General purpose events */ static int ngpes; static char* regnames[] = { "mem", "io", "pcicfg", "embed", "smb", "cmos", "pcibar", }; static char* acpiregstr(int id) { static char buf[20]; /* BUG */ if(id >= 0 && id < nelem(regnames)) return regnames[id]; seprint(buf, buf+sizeof(buf), "spc:%#x", id); return buf; } static int acpiregid(char *s) { int i; for(i = 0; i < nelem(regnames); i++) if(strcmp(regnames[i], s) == 0) return i; return -1; } static u64int l64get(u8int* p) { /* * Doing this as a define * #define l64get(p) (((u64int)l32get(p+4)<<32)|l32get(p)) * causes 8c to abort with "out of fixed registers" in * rsdlink() below. */ return (((u64int)l32get(p+4)<<32)|l32get(p)); } static u8int mget8(uintptr p, void*) { u8int *cp = (u8int*)p; return *cp; } static void mset8(uintptr p, u8int v, void*) { u8int *cp = (u8int*)p; *cp = v; } static u16int mget16(uintptr p, void*) { u16int *cp = (u16int*)p; return *cp; } static void mset16(uintptr p, u16int v, void*) { u16int *cp = (u16int*)p; *cp = v; } static u32int mget32(uintptr p, void*) { u32int *cp = (u32int*)p; return *cp; } static void mset32(uintptr p, u32int v, void*) { u32int *cp = (u32int*)p; *cp = v; } static u64int mget64(uintptr p, void*) { u64int *cp = (u64int*)p; return *cp; } static void mset64(uintptr p, u64int v, void*) { u64int *cp = (u64int*)p; *cp = v; } static u8int ioget8(uintptr p, void*) { return inb(p); } static void ioset8(uintptr p, u8int v, void*) { outb(p, v); } static u16int ioget16(uintptr p, void*) { return ins(p); } static void ioset16(uintptr p, u16int v, void*) { outs(p, v); } static u32int ioget32(uintptr p, void*) { return inl(p); } static void ioset32(uintptr p, u32int v, void*) { outl(p, v); } static u8int cfgget8(uintptr p, void* r) { Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; return pcicfgr8(&d, p); } static void cfgset8(uintptr p, u8int v, void* r) { Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; pcicfgw8(&d, p, v); } static u16int cfgget16(uintptr p, void* r) { Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; return pcicfgr16(&d, p); } static void cfgset16(uintptr p, u16int v, void* r) { Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; pcicfgw16(&d, p, v); } static u32int cfgget32(uintptr p, void* r) { Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; return pcicfgr32(&d, p); } static void cfgset32(uintptr p, u32int v, void* r) { Reg *ro = r; Pcidev d; d.tbdf = ro->tbdf; pcicfgw32(&d, p, v); } static Regio memio = { nil, mget8, mset8, mget16, mset16, mget32, mset32, mget64, mset64 }; static Regio ioio = { nil, ioget8, ioset8, ioget16, ioset16, ioget32, ioset32, nil, nil }; static Regio cfgio = { nil, cfgget8, cfgset8, cfgget16, cfgset16, cfgget32, cfgset32, nil, nil }; /* * Copy memory, 1/2/4/8-bytes at a time, to/from a region. */ static long regcpy(Regio *dio, uintptr da, Regio *sio, uintptr sa, long len, int align) { int n, i; DBG("regcpy %#ullx %#ullx %#ulx %#ux\n", da, sa, len, align); if((len%align) != 0) print("regcpy: bug: copy not aligned. truncated\n"); n = len/align; for(i = 0; i < n; i++){ switch(align){ case 1: DBG("cpy8 %#p %#p\n", da, sa); dio->set8(da, sio->get8(sa, sio->arg), dio->arg); break; case 2: DBG("cpy16 %#p %#p\n", da, sa); dio->set16(da, sio->get16(sa, sio->arg), dio->arg); break; case 4: DBG("cpy32 %#p %#p\n", da, sa); dio->set32(da, sio->get32(sa, sio->arg), dio->arg); break; case 8: DBG("cpy64 %#p %#p\n", da, sa); // dio->set64(da, sio->get64(sa, sio->arg), dio->arg); break; default: panic("regcpy: align bug"); } da += align; sa += align; } return n*align; } /* * Perform I/O within region in access units of accsz bytes. * All units in bytes. */ static long regio(Reg *r, void *p, usize len, uintptr off, int iswr) { Regio rio; uintptr rp; DBG("reg%s %s %#p %#ullx %#lx sz=%d\n", iswr ? "out" : "in", r->name, p, off, len, r->accsz); rp = 0; if(off + len > r->len){ print("regio: access outside limits"); len = r->len - off; } if(len <= 0){ print("regio: zero len\n"); return 0; } switch(r->spc){ case Rsysmem: print("RSYMMEM %p %ld\n", r->base, len); if(r->p == nil) r->p = vmap(r->base, len); if(r->p == nil) error("regio: vmap failed"); rp = (uintptr)r->p + off; rio = memio; break; case Rsysio: rp = r->base + off; rio = ioio; break; case Rpcicfg: rp = r->base + off; rio = cfgio; rio.arg = r; break; case Rpcibar: case Rembed: case Rsmbus: case Rcmos: case Ripmi: case Rfixedhw: print("regio: reg %s not supported\n", acpiregstr(r->spc)); error("region not supported"); } if(iswr) regcpy(&rio, rp, &memio, (uintptr)p, len, r->accsz); else regcpy(&memio, (uintptr)p, &rio, rp, len, r->accsz); return len; } static Atable* newtable(uchar *p) { Atable *t; Sdthdr *h; t = malloc(sizeof(Atable)); if(t == nil) panic("no memory for more aml tables"); t->tbl = p; h = (Sdthdr*)t->tbl; t->is64 = h->rev >= 2; t->dlen = l32get(h->length) - Sdthdrsz; memmove(t->sig, h->sig, sizeof(h->sig)); t->sig[sizeof(t->sig)-1] = 0; memmove(t->oemid, h->oemid, sizeof(h->oemid)); t->oemtblid[sizeof(t->oemtblid)-1] = 0; memmove(t->oemtblid, h->oemtblid, sizeof(h->oemtblid)); t->oemtblid[sizeof(t->oemtblid)-1] = 0; t->next = nil; if(tfirst == nil) tfirst = tlast = t; else{ tlast->next = t; tlast = t; } return t; } static void* sdtchecksum(void* addr, int len) { u8int *p, sum; sum = 0; for(p = addr; len-- > 0; p++) sum += *p; if(sum == 0) return addr; return nil; } /* * sleezy code to deal with overlapping allocations. * please remove this by either just mapping all acpi * memory (can we count on good acpi tables?), or * keeping one map at a time. */ typedef struct Sdtmap Sdtmap; struct Sdtmap { uintmem map[150]; uint n; }; static Sdtmap smap; static void* findmap(uintmem pa0, uint size) { int i, o; uintmem pa, p; o = pa0 - (pa0 & ~(PGSZ-1)); pa = pa0 - o; size = ROUNDUP(size+o, PGSZ); if(pa+size < 1ull*MiB) return KADDR(pa); if(pa < 1ull*MiB) return nil; for(p = pa; p < pa+size; p += PGSZ){ for(i = 0; i < smap.n; i++) if(p == smap.map[i]) break; if(i == smap.n){ if(smap.n == nelem(smap.map)) panic("smap.map too small %d", smap.n); if(vmap(p, PGSZ) == nil) return nil; smap.map[smap.n++] = p; } } /* sleezy assumption, we know everything's direct mapped at KSEG2 */ return UINT2PTR(KSEG2 + pa0); } static void sdtunmap(void *va, usize sz) { /* first cut */ USED(va, sz); } static void* sdtmap(uintmem pa, int *n, int cksum) { Sdthdr* sdt; sdt = findmap(pa, sizeof *sdt); if(sdt == nil){ DBG("acpi: findmap: nil\n"); return nil; } *n = l32get(sdt->length); if(*n>200000){ char tsig[5]; memmove(tsig, sdt, 4); tsig[4] = 0; print("%s (too big %d)", tsig, *n); return nil; } sdtunmap(sdt, sizeof(Sdthdr)); if((sdt = findmap(pa, *n)) == nil){ DBG("acpi: findmap: nil\n"); return nil;