#include #include #include #include #include #include #include #define ACPI_INTERNAL #include /* global state, idk a better way rn */ static struct acpi_state state; static bool checksum(uint8_t *data, size_t len) { unsigned char sum = 0; for (size_t i = 0; i < len; i++) sum += data[i]; return sum == 0; } static int read_s5_addr(struct dsdt *dsdt) { char *s5_addr = dsdt->s5_addr; int dsdt_len = dsdt->h.length - sizeof(struct acpi_header); while (0 < dsdt_len--) { if (memcmp(s5_addr, "_S5_", 4) == 0) break; s5_addr++; } if (dsdt_len > 0) { // check for valid AML structure if ( ( *(s5_addr-1) == 0x08 || ( *(s5_addr-2) == 0x08 && *(s5_addr-1) == '\\') ) && *(s5_addr+4) == 0x12 ) { s5_addr += 5; s5_addr += ((*s5_addr &0xC0)>>6) +2; // calculate PkgLength size if (*s5_addr == 0x0A) s5_addr++; // skip byteprefix state.SLP_TYPa = *(s5_addr)<<10; s5_addr++; if (*s5_addr == 0x0A) s5_addr++; // skip byteprefix state.SLP_TYPb = *(s5_addr)<<10; state.SLP_EN = 1<<13; state.SCI_EN = 1; } else { return -1; } } else { return -1; } return -1; } static void acpi_load_table(uint64_t addr); static void acpi_load_rsdt_tables(struct rsdt *rsdt) { int entries = (rsdt->h.length - sizeof(rsdt->h)) / 4; for (int i = 0; i < entries; i++) { uint32_t addr = rsdt->sdt_pointers[i]; acpi_load_table(addr); } } static void acpi_load_xsdt_tables(struct xsdt *xsdt) { int entries = (xsdt->h.length - sizeof(xsdt->h)) / 8; for (int i = 0; i < entries; i++) { uint64_t addr = xsdt->sdt_pointers[i]; acpi_load_table(addr); } } #define SIG_RSDT 0x54445352 #define SIG_XSDT 0x54445358 #define SIG_FACP 0x50434146 #define SIG_DSDT 0x54445344 #define SIG_APIC 0x43495041 #define SIG_HEPT 0x54455048 #define SIG_WAET 0x54454157 static void acpi_handle_table(struct acpi_header *header) { switch (header->signature) { case SIG_RSDT: state.sdt.rsdt = (struct rsdt *) header; acpi_load_rsdt_tables(state.sdt.rsdt); break; case SIG_XSDT: state.sdt.xsdt = (struct xsdt *) header; acpi_load_xsdt_tables(state.sdt.xsdt); break; case SIG_FACP: state.fadt = (struct fadt *) header; acpi_load_table(state.fadt->dsdt); break; case SIG_DSDT: state.dsdt = (struct dsdt *) header; read_s5_addr(state.dsdt); break; case SIG_APIC: state.apic = (struct apic *) header; break; case SIG_HEPT: state.hept = (struct hept *) header; break; case SIG_WAET: state.waet = (struct waet *) header; break; default: break; } } static void acpi_load_table(uint64_t addr) { struct acpi_header *temp, *mapped; uint32_t length; temp = (struct acpi_header * ) (uintptr_t) addr; mapped = mmap(temp, sizeof(struct acpi_header)); length = mapped->length; unmap(mapped); mapped = mmap(temp, length); if (!checksum((uint8_t *) mapped, mapped->length)) { unmap(mapped); return; } kprintf("%.*s: %#016lx\n", 4, (char*)&mapped->signature, (size_t)temp); acpi_handle_table(mapped); } int acpi_init(void *rootsdp) { memset(&state, 0, sizeof(struct acpi_state)); struct rsdp *rsdp = (struct rsdp *) rootsdp; if (!checksum((uint8_t *)rsdp, sizeof(struct rsdp))) { return -1; } if (memcmp(rsdp->signature, "RSD PTR ", 8) != 0) { panic("invalid acpi rsdp signature: %.*s\n", 8, rsdp->signature); } if (rsdp->revision == 0) { state.version = 0; kprintf("ACPI 1.0\n"); acpi_load_table(rsdp->rsdt_addr); } else if (rsdp->revision == 2) { state.version = 2; struct xsdp *xsdp = (struct xsdp *) rsdp; kprintf("ACPI 2.0\n"); acpi_load_table(xsdp->xsdt_addr); } else { panic("invalid acpi rev: %d\n", rsdp->revision); } kprintf("\n"); acpi_sys_enable(&state); return 0; } int acpi_shutdown(void) { return acpi_sys_shutdown(&state); }