#define MODULE "acpi" #include "acpi/RSDT.h" #include "bootboot.h" #include "log/Log.h" #include "memory/MemoryManager.h" #include "misc/utils.h" #include "std/stdio.h" #include "std/string.h" extern BOOTBOOT bootboot; ACPI::SDTHeader* ACPI::get_rsdt_or_xsdt() { static SDTHeader* cache = nullptr; if (cache) return cache; kdbgln("First time accessing the RSDT/XSDT, mapping it into memory"); void* physical = (void*)bootboot.arch.x86_64.acpi_ptr; kdbgln("RSDT/XSDT physical address: %p", physical); SDTHeader* rsdt = (SDTHeader*)MemoryManager::get_unaligned_mapping(physical); uint64_t offset = (uint64_t)physical % PAGE_SIZE; uint64_t rsdt_pages = Utilities::get_blocks_from_size(PAGE_SIZE, (offset + rsdt->Length)); if (rsdt_pages > 1) { MemoryManager::release_unaligned_mapping(rsdt); rsdt = (SDTHeader*)MemoryManager::get_unaligned_mappings(cache, rsdt_pages); } kdbgln("Mapped RSDT/XSDT to virtual address %p, uses %ld pages", (void*)rsdt, rsdt_pages); cache = rsdt; return rsdt; } bool ACPI::validate_rsdt_or_xsdt(ACPI::SDTHeader* root_sdt) { if (!validate_sdt_header(root_sdt)) return false; if (strncmp(root_sdt->Signature, "XSDT", 4) == 0) return true; if (strncmp(root_sdt->Signature, "RSDT", 4) == 0) return true; return false; } bool ACPI::is_xsdt() { static bool cached = false; static bool cache = false; if (cached) return cache; SDTHeader* rootSDT = get_rsdt_or_xsdt(); cache = (strncmp(rootSDT->Signature, "XSDT", 4) == 0); cached = true; return cache; } void* ACPI::find_table(ACPI::SDTHeader* root_sdt, const char* signature) { bool isXSDT = is_xsdt(); uint64_t entries = (root_sdt->Length - sizeof(SDTHeader)) / (isXSDT ? 8 : 4); kdbgln("Searching for table %s in the %s at %p (table contains %ld entries)", signature, isXSDT ? "XSDT" : "RSDT", (void*)root_sdt, entries); for (uint64_t i = 0; i < entries; i++) { kdbgln("Testing for table %s in entry %ld", signature, i); SDTHeader* h; if (isXSDT) { uint64_t reversedAddress = (uint64_t)((XSDT*)root_sdt)->other_sdt[i]; uint64_t correctAddress = reversedAddress >> 32 | reversedAddress << 32; h = (SDTHeader*)correctAddress; } else { uint32_t entry = ((RSDT*)root_sdt)->other_sdt[i]; h = (SDTHeader*)(uint64_t)entry; } if (!h) { kwarnln("Entry %ld in the %s points to null", i, isXSDT ? "XSDT" : "RSDT"); continue; } kdbgln("Physical address of entry: %p", (void*)h); SDTHeader* realHeader = (SDTHeader*)MemoryManager::get_unaligned_mapping(h); kdbgln("Mapped entry to virtual address %p", (void*)realHeader); if (!validate_sdt_header(realHeader)) { kwarnln("Header of entry %ld is not valid, skipping this entry", i); MemoryManager::release_unaligned_mapping(realHeader); continue; } char tableSignature[5]; memcpy(tableSignature, h->Signature, 4); tableSignature[4] = 0; kdbgln("Comparing target signature (%s) to signature of entry (%s)", signature, tableSignature); if (strncmp(h->Signature, signature, 4) == 0) { kdbgln("Found table %s", signature); return (void*)realHeader; } kdbgln("Signatures do not match, unmapping entry and continuing"); MemoryManager::release_unaligned_mapping(realHeader); } return NULL; }