| /* |
| * This file is part of the UCB release of Plan 9. It is subject to the license |
| * terms in the LICENSE file found in the top-level directory of this |
| * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No |
| * part of the UCB release of Plan 9, including this file, may be copied, |
| * modified, propagated, or distributed except according to the terms contained |
| * in the LICENSE file. |
| */ |
| |
| /* ----------------------------------------------------------------------------- |
| * ACPI is a table of tables. The tables define a hierarchy. |
| * |
| * From the hardware's perspective: |
| * Each table that we care about has a header, and the header has a |
| * length that includes the the length of all its subtables. So, even |
| * if you can't completely parse a table, you can find the next table. |
| * |
| * The process of parsing is to find the RSDP, and then for each subtable |
| * see what type it is and parse it. The process is recursive except for |
| * a few issues: The RSDP signature and header differs from the header of |
| * its subtables; their headers differ from the signatures of the tables |
| * they contain. As you walk down the tree, you need different parsers. |
| * |
| * The parser is recursive descent. Each parsing function takes a pointer |
| * to the parent of the node it is parsing and will attach itself to the parent |
| * via that pointer. Parsing functions are responsible for building the data |
| * structures that represent their node and recursive invocations of the parser |
| * for subtables. |
| * |
| * So, in this case, it's something like this: |
| * |
| * RSDP is the root. It has a standard header and size. You map that |
| * memory. You find the first header, get its type and size, and |
| * parse as much of it as you can. Parsing will involve either a |
| * function or case statement for each element type. DMARs are complex |
| * and need functions; APICs are simple and we can get by with case |
| * statements. |
| * |
| * Each node in the tree is represented as a 'struct Atable'. This has a |
| * pointer to the actual node data, a type tag, a name, pointers to this |
| * node's children (if any) and a parent pointer. It also has a QID so that |
| * the entire structure can be exposed as a filesystem. The Atable doesn't |
| * contain any table data per se; it's metadata. The table pointer contains |
| * the table data as well as a pointer back to it's corresponding Atable. |
| * |
| * In the end we present a directory tree for #apic that looks, in this example: |
| * #acpi/DMAR/DRHD/0/{pretty,raw} |
| * |
| * 'cat pretty' will return JSON-encoded data described the element. |
| * 'cat raw' gets you the raw bytes. |
| */ |
| |
| #pragma once |
| |
| #include <ns.h> |
| #include <slice.h> |
| |
| enum { |
| |
| Sdthdrsz = 36, /* size of SDT header */ |
| |
| /* ACPI regions. Gas ids */ |
| Rsysmem = 0, |
| Rsysio, |
| Rpcicfg, |
| Rembed, |
| Rsmbus, |
| Rcmos, |
| Rpcibar, |
| Ripmi, |
| Rfixedhw = 0x7f, |
| |
| /* ACPI PM1 control */ |
| Pm1SciEn = 0x1, /* Generate SCI and not SMI */ |
| |
| /* ACPI tbdf as encoded in acpi region base addresses */ |
| Rpciregshift = 0, |
| Rpciregmask = 0xFFFF, |
| Rpcifunshift = 16, |
| Rpcifunmask = 0xFFFF, |
| Rpcidevshift = 32, |
| Rpcidevmask = 0xFFFF, |
| Rpcibusshift = 48, |
| Rpcibusmask = 0xFFFF, |
| |
| /* Apic structure types */ |
| ASlapic = 0, /* processor local apic */ |
| ASioapic, /* I/O apic */ |
| ASintovr, /* Interrupt source override */ |
| ASnmi, /* NMI source */ |
| ASlnmi, /* local apic nmi */ |
| ASladdr, /* local apic address override */ |
| ASiosapic, /* I/O sapic */ |
| ASlsapic, /* local sapic */ |
| ASintsrc, /* platform interrupt sources */ |
| ASlx2apic, /* local x2 apic */ |
| ASlx2nmi, /* local x2 apic NMI */ |
| |
| /* Apic flags */ |
| AFbus = 0, /* polarity/trigger like in ISA */ |
| AFhigh = 1, /* active high */ |
| AFlow = 3, /* active low */ |
| AFpmask = 3, /* polarity bits */ |
| AFedge = 1 << 2, /* edge triggered */ |
| AFlevel = 3 << 2, /* level triggered */ |
| AFtmask = 3 << 2, /* trigger bits */ |
| |
| /* Table types. */ |
| RSDP = 0, |
| SDTH, |
| RSDT, |
| FADT, |
| FACS, |
| DSDT, |
| SSDT, |
| MADT, |
| SBST, |
| XSDT, |
| ECDT, |
| SLIT, |
| SRAT, |
| CPEP, |
| MSCT, |
| RASF, |
| MPST, |
| PMTT, |
| BGRT, |
| FPDT, |
| GTDT, |
| HPET, |
| APIC, |
| DMAR, |
| /* DMAR types */ |
| DRHD, |
| RMRR, |
| ATSR, |
| RHSA, |
| ANDD, |
| NACPITBLS, /* Number of ACPI tables */ |
| |
| /* SRAT types */ |
| SRlapic = 0, /* Local apic/sapic affinity */ |
| SRmem, /* Memory affinity */ |
| SRlx2apic, /* x2 apic affinity */ |
| |
| /* Atable constants */ |
| SIGSZ = 4+1, /* Size of the signature (including NUL) */ |
| OEMIDSZ = 6+1, /* Size of the OEM ID (including NUL) */ |
| OEMTBLIDSZ = 8+1, /* Size of the OEM Table ID (including NUL) */ |
| |
| /* Arg for _PIC */ |
| Ppic = 0, /* PIC interrupt model */ |
| Papic, /* APIC interrupt model */ |
| Psapic, /* SAPIC interrupt model */ |
| |
| CMregion = 0, /* regio name spc base len accsz */ |
| CMgpe, /* gpe name id */ |
| }; |
| |
| /* |
| * ACPI table (sw) |
| * |
| * This Atable struct corresponds to an interpretation of the standard header |
| * for all table types we support. It has a pointer to the converted data, i.e. |
| * the structs created by functions like acpimadt and so on. Note: althouh the |
| * various things in this are a superset of many ACPI table names (DRHD, DRHD |
| * scopes, etc). The raw data follows this header. |
| * |
| * Child entries in the table are kept in an array of pointers. Each entry has |
| * a pointer to it's logically "next" sibling, thus forming a linked list. But |
| * these lists are purely for convenience and all point to nodes within the |
| * same array. |
| */ |
| struct Atable { |
| struct qid qid; /* QID corresponding to this table. */ |
| struct qid rqid; /* This table's 'raw' QID. */ |
| struct qid pqid; /* This table's 'pretty' QID. */ |
| struct qid tqid; /* This table's 'table' QID. */ |
| int type; /* This table's type */ |
| void *tbl; /* pointer to the converted table, e.g. madt. */ |
| char name[16]; /* name of this table */ |
| |
| struct Atable *parent; /* Parent pointer */ |
| struct Atable **children; /* children of this node (an array). */ |
| struct dirtab *cdirs; /* child directory entries of this node. */ |
| size_t nchildren; /* count of this node's children */ |
| struct Atable *next; /* Pointer to the next sibling. */ |
| |
| size_t rawsize; /* Total size of raw table */ |
| uint8_t *raw; /* Raw data. */ |
| }; |
| |
| struct Gpe { |
| uintptr_t stsio; /* port used for status */ |
| int stsbit; /* bit number */ |
| uintptr_t enio; /* port used for enable */ |
| int enbit; /* bit number */ |
| int nb; /* event number */ |
| char *obj; /* handler object */ |
| int id; /* id as supplied by user */ |
| }; |
| |
| struct Regio { |
| void *arg; |
| uint8_t (*get8)(uintptr_t, void *); |
| void (*set8)(uintptr_t, uint8_t unused_int, void *); |
| uint16_t (*get16)(uintptr_t, void *); |
| void (*set16)(uintptr_t, uint16_t unused_int, void *); |
| uint32_t (*get32)(uintptr_t, void *); |
| void (*set32)(uintptr_t, uint32_t, void *); |
| uint64_t (*get64)(uintptr_t, void *); |
| void (*set64)(uintptr_t, uint64_t unused_int, void *); |
| }; |
| |
| struct Reg { |
| char *name; |
| int spc; /* io space */ |
| uint64_t base; /* address, physical */ |
| uint8_t *p; /* address, kmapped */ |
| uint64_t len; |
| int tbdf; |
| int accsz; /* access size */ |
| }; |
| |
| /* Generic address structure. |
| */ |
| struct Gas { |
| uint8_t spc; /* address space id */ |
| uint8_t len; /* register size in bits */ |
| uint8_t off; /* bit offset */ |
| uint8_t accsz; /* 1: byte; 2: word; 3: dword; 4: qword */ |
| uint64_t addr; /* address (or acpi encoded tbdf + reg) */ |
| }; |
| |
| /* Root system description table pointer. |
| * Used to locate the root system description table RSDT |
| * (or the extended system description table from version 2) XSDT. |
| * The XDST contains (after the DST header) a list of pointers to tables: |
| * - FADT fixed acpi description table. |
| * It points to the DSDT, AML code making the acpi namespace. |
| * - SSDTs tables with AML code to add to the acpi namespace. |
| * - pointers to other tables for apics, etc. |
| */ |
| struct Rsdp { |
| uint8_t signature[8]; /* "RSD PTR " */ |
| uint8_t rchecksum; |
| uint8_t oemid[6]; |
| uint8_t revision; |
| uint8_t raddr[4]; /* RSDT */ |
| uint8_t length[4]; |
| uint8_t xaddr[8]; /* XSDT */ |
| uint8_t xchecksum; /* XSDT */ |
| uint8_t _reserved[3]; /* reserved */ |
| }; |
| |
| /* Header for ACPI description tables |
| */ |
| struct Sdthdr { |
| uint8_t sig[4]; /* "FACP" or whatever */ |
| uint8_t length[4]; |
| uint8_t rev; |
| uint8_t csum; |
| uint8_t oemid[6]; |
| uint8_t oemtblid[8]; |
| uint8_t oemrev[4]; |
| uint8_t creatorid[4]; |
| uint8_t creatorrev[4]; |
| }; |
| |
| /* Firmware control structure |
| */ |
| struct Facs { |
| uint8_t sig[4]; |
| uint8_t len[4]; |
| uint32_t hwsig; |
| uint32_t wakingv; |
| uint32_t glock; |
| uint32_t flags; |
| uint64_t xwakingv; |
| uint8_t vers; |
| uint32_t ospmflags; |
| }; |
| |
| /* Maximum System Characteristics table |
| */ |
| struct Msct { |
| int ndoms; /* number of domains */ |
| int nclkdoms; /* number of clock domains */ |
| uint64_t maxpa; /* max physical address */ |
| size_t nmdom; /* number of discovered domains */ |
| struct Mdom *dom; /* array of domains */ |
| }; |
| |
| struct Mdom { |
| int start; /* start dom id */ |
| int end; /* end dom id */ |
| int maxproc; /* max processor capacity */ |
| uint64_t maxmem; /* max memory capacity */ |
| }; |
| |
| /* Multiple APIC description table |
| * Interrupts are virtualized by ACPI and each APIC has |
| * a `virtual interrupt base' where its interrupts start. |
| * Addresses are processor-relative physical addresses. |
| * Only enabled devices are linked, others are filtered out. |
| */ |
| struct Madt { |
| uint64_t lapicpa; /* local APIC addr */ |
| int pcat; /* the machine has PC/AT 8259s */ |
| }; |
| |
| struct Apicst { |
| int type; |
| union { |
| struct { |
| int pid; /* processor id */ |
| int id; /* apic no */ |
| } lapic; |
| struct { |
| int id; /* io apic id */ |
| uint32_t ibase; /* interrupt base addr. */ |
| uint64_t addr; /* base address */ |
| } ioapic, iosapic; |
| struct { |
| int irq; /* bus intr. source (ISA only) */ |
| int intr; /* system interrupt */ |
| int flags; /* apic flags */ |
| } intovr; |
| struct { |
| int intr; /* system interrupt */ |
| int flags; /* apic flags */ |
| } nmi; |
| struct { |
| int pid; /* processor id */ |
| int flags; /* lapic flags */ |
| int lint; /* lapic LINTn for nmi */ |
| } lnmi; |
| struct { |
| int pid; /* processor id */ |
| int id; /* apic id */ |
| int eid; /* apic eid */ |
| int puid; /* processor uid */ |
| char *puids; /* same thing */ |
| } lsapic; |
| struct { |
| int pid; /* processor id */ |
| int peid; /* processor eid */ |
| int iosv; /* io sapic vector */ |
| int intr; /* global sys intr. */ |
| int type; /* intr type */ |
| int flags; /* apic flags */ |
| int any; /* err sts at any proc */ |
| } intsrc; |
| struct { |
| int id; /* x2 apic id */ |
| int puid; /* processor uid */ |
| } lx2apic; |
| struct { |
| int puid; |
| int flags; |
| int intr; |
| } lx2nmi; |
| }; |
| }; |
| |
| /* System resource affinity table |
| */ |
| struct Srat { |
| int type; |
| union { |
| struct { |
| int dom; /* proximity domain */ |
| int apic; /* apic id */ |
| int sapic; /* sapic id */ |
| int clkdom; /* clock domain */ |
| } lapic; |
| struct { |
| int dom; /* proximity domain */ |
| uint64_t addr; /* base address */ |
| uint64_t len; |
| int hplug; /* hot pluggable */ |
| int nvram; /* non volatile */ |
| } mem; |
| struct { |
| int dom; /* proximity domain */ |
| int apic; /* x2 apic id */ |
| int clkdom; /* clock domain */ |
| } lx2apic; |
| }; |
| }; |
| |
| /* System locality information table |
| */ |
| struct Slit { |
| uint64_t rowlen; |
| struct SlEntry **e; |
| }; |
| |
| struct SlEntry { |
| int dom; /* proximity domain */ |
| unsigned int dist; /* distance to proximity domain */ |
| }; |
| |
| /* Fixed ACPI description table. |
| * Describes implementation and hardware registers. |
| * PM* blocks are low level functions. |
| * GPE* blocks refer to general purpose events. |
| * P_* blocks are for processor features. |
| * Has address for the DSDT. |
| */ |
| struct Fadt { |
| uint32_t facs; |
| uint32_t dsdt; |
| /* 1 reserved */ |
| uint8_t pmprofile; |
| uint16_t sciint; |
| uint32_t smicmd; |
| uint8_t acpienable; |
| uint8_t acpidisable; |
| uint8_t s4biosreq; |
| uint8_t pstatecnt; |
| uint32_t pm1aevtblk; |
| uint32_t pm1bevtblk; |
| uint32_t pm1acntblk; |
| uint32_t pm1bcntblk; |
| uint32_t pm2cntblk; |
| uint32_t pmtmrblk; |
| uint32_t gpe0blk; |
| uint32_t gpe1blk; |
| uint8_t pm1evtlen; |
| uint8_t pm1cntlen; |
| uint8_t pm2cntlen; |
| uint8_t pmtmrlen; |
| uint8_t gpe0blklen; |
| uint8_t gpe1blklen; |
| uint8_t gp1base; |
| uint8_t cstcnt; |
| uint16_t plvl2lat; |
| uint16_t plvl3lat; |
| uint16_t flushsz; |
| uint16_t flushstride; |
| uint8_t dutyoff; |
| uint8_t dutywidth; |
| uint8_t dayalrm; |
| uint8_t monalrm; |
| uint8_t century; |
| uint16_t iapcbootarch; |
| /* 1 reserved */ |
| uint32_t flags; |
| struct Gas resetreg; |
| uint8_t resetval; |
| /* 3 reserved */ |
| uint64_t xfacs; |
| uint64_t xdsdt; |
| struct Gas xpm1aevtblk; |
| struct Gas xpm1bevtblk; |
| struct Gas xpm1acntblk; |
| struct Gas xpm1bcntblk; |
| struct Gas xpm2cntblk; |
| struct Gas xpmtmrblk; |
| struct Gas xgpe0blk; |
| struct Gas xgpe1blk; |
| }; |
| |
| /* XSDT/RSDT. 4/8 byte addresses starting at p. |
| */ |
| struct Xsdt { |
| size_t len; |
| size_t asize; |
| uint8_t *p; |
| }; |
| |
| /* DMAR. |
| */ |
| /* |
| * Device scope. |
| */ |
| struct DevScope { |
| int enumeration_id; |
| int start_bus_number; |
| int npath; |
| int *paths; |
| }; |
| /* |
| * The device scope is basic tbdf as uint32_t. There is a special value |
| * that means "everything" and if we see that we set "all" in the Drhd. |
| */ |
| struct Drhd { |
| int flags; |
| int segment; |
| uintptr_t rba; |
| uintptr_t all; // This drhd scope is for everything. |
| size_t nscope; |
| struct DevScope *scopes; |
| }; |
| |
| struct Dmar { |
| int haw; |
| /* |
| * If your firmware disables x2apic mode, you should not be here. |
| * We ignore that bit. |
| */ |
| int intr_remap; |
| }; |
| |
| int acpiinit(void); |
| struct Atable *mkatable(struct Atable *parent, |
| int type, char *name, uint8_t *raw, |
| size_t rawsize, size_t addsize); |
| struct Atable *finatable(struct Atable *t, struct slice *slice); |
| struct Atable *finatable_nochildren(struct Atable *t); |
| int get_early_num_cores(void); |
| |
| extern struct Atable *apics; |
| extern struct Atable *dmar; |
| extern struct Atable *srat; |