git: track the specific branch only
[akaros.git] / kern / include / acpi.h
index 92f08de..12fbfc7 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -7,9 +7,57 @@
  * 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 */
+       Sdthdrsz = 36,          /* size of SDT header */
 
        /* ACPI regions. Gas ids */
        Rsysmem = 0,
@@ -23,7 +71,7 @@ enum {
        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,
@@ -36,107 +84,153 @@ enum {
        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,
+       MCFG,
+       /* 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 {
-       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 Parse {
-       char *sig;
-       struct Atable *(*f) (uint8_t * unused_uint8_p_t, int);  /* return NULL to keep vmap */
+       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 *);
+       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 */
+       int spc;                /* io space */
+       uint64_t base;          /* address, physical */
+       uint8_t *p;             /* address, kmapped */
        uint64_t len;
        int tbdf;
-       int accsz;                                      /* access size */
+       int accsz;              /* access size */
 };
 
-/* Generic address structure. 
+/* 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) */
+       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.
@@ -148,23 +242,22 @@ struct Gas {
  *     - 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 signature[8];   /* "RSD PTR " */
        uint8_t rchecksum;
        uint8_t oemid[6];
        uint8_t revision;
-       uint8_t raddr[4];                       /* RSDT */
+       uint8_t raddr[4];       /* RSDT */
        uint8_t length[4];
-       uint8_t xaddr[8];                       /* XSDT */
-       uint8_t xchecksum;                      /* XSDT */
-       uint8_t _33_[3];                        /* reserved */
+       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 sig[4];         /* "FACP" or whatever */
        uint8_t length[4];
        uint8_t rev;
        uint8_t csum;
@@ -178,6 +271,8 @@ struct Sdthdr {
 /* Firmware control structure
  */
 struct Facs {
+       uint8_t sig[4];
+       uint8_t len[4];
        uint32_t hwsig;
        uint32_t wakingv;
        uint32_t glock;
@@ -190,19 +285,18 @@ struct Facs {
 /* Maximum System Characteristics table
  */
 struct Msct {
-       int ndoms;                                      /* number of domains */
-       int nclkdoms;                           /* number of clock domains */
-       uint64_t maxpa;                         /* max physical address */
-
-       struct Mdom *dom;                       /* domain information list */
+       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 {
-       struct Mdom *next;
-       int start;                                      /* start dom id */
-       int end;                                        /* end dom id */
-       int maxproc;                            /* max processor capacity */
-       uint64_t maxmem;                        /* max memory capacity */
+       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
@@ -212,57 +306,55 @@ struct Mdom {
  * 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 *st;                      /* list of Apic related structures */
+       uint64_t lapicpa;       /* local APIC addr */
+       int pcat;               /* the machine has PC/AT 8259s */
 };
 
 struct Apicst {
        int type;
-       struct Apicst *next;
        union {
                struct {
-                       int pid;                        /* processor id */
-                       int id;                         /* apic no */
+                       int pid;                /* processor id */
+                       int id;                 /* apic no */
                } lapic;
                struct {
-                       int id;                         /* io apic id */
+                       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 */
+                       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 */
+                       int intr;               /* system interrupt */
+                       int flags;              /* apic flags */
                } nmi;
                struct {
-                       int pid;                        /* processor id */
-                       int flags;                      /* lapic flags */
-                       int lint;                       /* lapic LINTn for nmi */
+                       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 */
+                       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 */
+                       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 */
+                       int id;                 /* x2 apic id */
+                       int puid;               /* processor uid */
                } lx2apic;
                struct {
                        int puid;
@@ -276,25 +368,24 @@ struct Apicst {
  */
 struct Srat {
        int type;
-       struct Srat *next;
        union {
                struct {
-                       int dom;                        /* proximity domain */
-                       int apic;                       /* apic id */
-                       int sapic;                      /* sapic id */
-                       int clkdom;                     /* clock domain */
+                       int dom;                /* proximity domain */
+                       int apic;               /* apic id */
+                       int sapic;              /* sapic id */
+                       int clkdom;             /* clock domain */
                } lapic;
                struct {
-                       int dom;                        /* proximity domain */
+                       int dom;                /* proximity domain */
                        uint64_t addr;          /* base address */
                        uint64_t len;
-                       int hplug;                      /* hot pluggable */
-                       int nvram;                      /* non volatile */
+                       int hplug;              /* hot pluggable */
+                       int nvram;              /* non volatile */
                } mem;
                struct {
-                       int dom;                        /* proximity domain */
-                       int apic;                       /* x2 apic id */
-                       int clkdom;                     /* clock domain */
+                       int dom;                /* proximity domain */
+                       int apic;               /* x2 apic id */
+                       int clkdom;             /* clock domain */
                } lx2apic;
        };
 };
@@ -307,8 +398,8 @@ struct Slit {
 };
 
 struct SlEntry {
-       int dom;                                        /* proximity domain */
-       unsigned int dist;                      /* distance to proximity domain */
+       int dom;                        /* proximity domain */
+       unsigned int dist;              /* distance to proximity domain */
 };
 
 /* Fixed ACPI description table.
@@ -375,11 +466,80 @@ struct Fadt {
 /* 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;
+};
+
+struct Dmar {
+       int haw;
+       /*
+        * If your firmware disables x2apic mode, you should not be here.
+        * We ignore that bit.
+        */
+       int intr_remap;
+};
+
+struct acpi_mcfg {
+       uint8_t sig[4];
+       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];
+       uint8_t _pad[8];
+       uint8_t entries[0];
+};
+
+struct acpi_mcfg_entry {
+       physaddr_t addr;
+       uint16_t segment;
+       uint8_t start_bus;
+       uint8_t end_bus;
+};
+
+struct acpi_mcfg_data {
+       size_t nr_entries;
+       struct acpi_mcfg_entry entries[];
+};
 
 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);
+physaddr_t acpi_pci_get_mmio_cfg_addr(int segment, int bus, int dev, int func);
+
+extern struct Atable *apics;
+extern struct Atable *dmar;
+extern struct Atable *srat;