-/*
+/*
* 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
* in the LICENSE file.
*/
-#ifndef ROS_KERN_ACPI_H
-#define ROS_KERN_ACPI_H
+/* -----------------------------------------------------------------------------
+ * 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 */
+ Sdthdrsz = 36, /* size of SDT header */
/* ACPI regions. Gas ids */
Rsysmem = 0,
Rfixedhw = 0x7f,
/* ACPI PM1 control */
- Pm1SciEn = 0x1, /* Generate SCI and not SMI */
+ Pm1SciEn = 0x1, /* Generate SCI and not SMI */
/* ACPI tbdf as encoded in acpi region base addresses */
Rpciregshift = 0,
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 */
+ 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 */
+ 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 */
+ 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 */
-
- Qdir = 0,
- Qctl,
- Qtbl,
- Qio,
- Qpretty,
- Qioapic,
- Qapic,
+ 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 Atable *next; /* next table in list */
- int is64; /* uses 64bits */
- char sig[5]; /* signature */
- char oemid[7]; /* oem id str. */
- char oemtblid[9]; /* oem tbl. id str. */
- uint8_t *tbl; /* pointer to table in memory */
- long dlen; /* size of data in table, after Stdhdr */
+ 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 {
int id; /* id as supplied by user */
};
-struct Parse {
- char *sig;
- struct Atable *(*f) (uint8_t * unused_uint8_p_t, int); /* return NULL to keep vmap */
-};
-
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 *);
+ 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 {
int accsz; /* access size */
};
-/* Generic address structure.
+/* Generic address structure.
*/
struct Gas {
uint8_t spc; /* address space id */
* - 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 length[4];
uint8_t xaddr[8]; /* XSDT */
uint8_t xchecksum; /* XSDT */
- uint8_t _33_[3]; /* reserved */
+ uint8_t _reserved[3]; /* reserved */
};
/* Header for ACPI description tables
/* Firmware control structure
*/
struct Facs {
+ uint8_t sig[4];
+ uint8_t len[4];
uint32_t hwsig;
uint32_t wakingv;
uint32_t glock;
int ndoms; /* number of domains */
int nclkdoms; /* number of clock domains */
uint64_t maxpa; /* max physical address */
-
- struct Mdom *dom; /* domain information list */
+ size_t nmdom; /* number of discovered domains */
+ struct Mdom *dom; /* array of domains */
};
struct Mdom {
- struct Mdom *next;
int start; /* start dom id */
int end; /* end dom id */
int maxproc; /* max processor capacity */
struct Madt {
uint64_t lapicpa; /* local APIC addr */
int pcat; /* the machine has PC/AT 8259s */
- struct Apicst *st; /* list of Apic related structures */
};
struct Apicst {
int type;
- struct Apicst *next;
union {
struct {
int pid; /* processor id */
*/
struct Srat {
int type;
- struct Srat *next;
union {
struct {
int dom; /* proximity domain */
/* XSDT/RSDT. 4/8 byte addresses starting at p.
*/
struct Xsdt {
- int len;
- int asize;
+ size_t len;
+ size_t asize;
uint8_t *p;
};
-extern uintptr_t acpimblocksize(uintptr_t, int *);
+/* 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;
+};
-int acpiinit(void);
-struct Atable *new_acpi_table(uint8_t *p);
-extern struct Madt *apics;
-extern struct Srat *srat;
+struct Dmar {
+ int haw;
+ /*
+ * If your firmware disables x2apic mode, you should not be here.
+ * We ignore that bit.
+ */
+ int intr_remap;
+};
-#endif /* ROS_KERN_ACPI_H */
+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);
+
+extern struct Atable *apics;
+extern struct Atable *dmar;
+extern struct Atable *srat;