| /* | 
 |  * 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; |