#include #include #include #include static struct acpi_rsdp rsdp; static struct acpi_rsdp_10 *search_for_rsdp(void) { uint64_t *start = vm_phys_to_virt(0x80000); uint64_t *end = vm_phys_to_virt(0xFFFFF); for (uint64_t *i = start; i < end; i++) { if (*i == ACPI_SIG_RSDP) { return (struct acpi_rsdp_10 *)i; } } return NULL; } static int init_rsdt(void) { struct acpi_rsdp_10 *x = search_for_rsdp(); if (!x) { printk("acpi: not available"); return -1; } uint8_t *b = (uint8_t *)x; size_t chksum = 0; for (unsigned int i = 0; i < sizeof *x; i++) { chksum += b[i]; } if (chksum & 0xFF) { printk("acpi: not available"); return -1; } if (x->r_revision == 2) { chksum = 0; for (unsigned int i = sizeof *x; i < sizeof(struct acpi_rsdp_20); i++) { chksum += b[i]; } if (chksum & 0xFF) { printk("acpi: not available"); return -1; } } memcpy(&rsdp.rsdp_20, x, sizeof rsdp.rsdp_20); return 0; } static struct acpi_sdt *find_via_rsdt(uint32_t sig) { struct acpi_rsdt *rsdt = vm_phys_to_virt(rsdp.rsdp_10.r_rsdt_ptr); unsigned long nr_tables = (rsdt->r_header.s_length - sizeof(struct acpi_sdt)) / sizeof(uint32_t); for (unsigned long i = 0; i < nr_tables; i++) { struct acpi_sdt *table = vm_phys_to_virt(rsdt->r_tables[i]); if (*(uint32_t *)table == sig) { return table; } } return NULL; } static struct acpi_sdt *find_via_xsdt(uint32_t sig) { struct acpi_xsdt *xsdt = vm_phys_to_virt(rsdp.rsdp_20.r_xsdt_ptr); unsigned long nr_tables = (xsdt->x_header.s_length - sizeof(struct acpi_sdt)) / sizeof(uint64_t); for (unsigned long i = 0; i < nr_tables; i++) { struct acpi_sdt *table = vm_phys_to_virt(xsdt->x_tables[i]); if (*(uint32_t *)table == sig) { return table; } } return NULL; } struct acpi_sdt *acpi_find_sdt(uint32_t sig) { if (!rsdp.rsdp_10.r_sig[0]) { if (init_rsdt() != 0) { return NULL; } } if (rsdp.rsdp_10.r_revision == 0) { return find_via_rsdt(sig); } else { return find_via_xsdt(sig); } }