#define MODULE "acpi/rsdt" #include "acpi/RSDT.h" #include "bootboot.h" #include "log/Address.h" #include "log/Log.h" #include "memory/KernelMemoryManager.h" #include "std/stdio.h" #include "std/string.h" extern BOOTBOOT bootboot; ACPI::SDTHeader* ACPI::GetRSDTOrXSDT() { static void* cache = nullptr; if (cache) return (SDTHeader*)cache; kinfoln("First time accessing the RSDT/XSDT, mapping it into memory"); void* physical = (void*)bootboot.arch.x86_64.acpi_ptr; uint64_t offset = (uint64_t)physical % 4096; kinfoln("RSDT/XSDT physical address: %lx", (uint64_t)physical); cache = KernelMemoryManager::get_unaligned_mapping(physical); uint64_t numPages = 1; while ((offset + ((SDTHeader*)cache)->Length) > (numPages * 4096)) { kinfoln("RSDT/XSDT extends beyond the mapped page, mapping one more page"); KernelMemoryManager::release_unaligned_mappings(cache, numPages); numPages++; cache = KernelMemoryManager::get_unaligned_mappings(cache, numPages); } kinfoln("Mapped RSDT/XSDT to virtual address %lx, uses %ld pages", (uint64_t)cache, numPages); SDTHeader* result = (SDTHeader*)cache; char OEMID[7]; memcpy(OEMID, result->OEMID, 6); OEMID[6] = 0; kinfoln("OEMID: %s", OEMID); char OEMTableID[9]; memcpy(OEMTableID, result->OEMTableID, 8); OEMTableID[8] = 0; kinfoln("OEMTableID: %s", OEMTableID); return result; } bool ACPI::ValidateRSDTOrXSDT(ACPI::SDTHeader* rootSDT) { if (!ValidateSDTHeader(rootSDT)) return false; if (strncmp(rootSDT->Signature, "XSDT", 4) == 0) return true; if (strncmp(rootSDT->Signature, "RSDT", 4) == 0) return true; return false; } bool ACPI::IsXSDT(ACPI::SDTHeader* rootSDT) { return strncmp(rootSDT->Signature, "XSDT", 4) == 0; } void* ACPI::FindTable(ACPI::SDTHeader* rootSDT, const char* signature) { bool isXSDT = (strncmp(rootSDT->Signature, "XSDT", 4) == 0); int entries = (rootSDT->Length - sizeof(SDTHeader)) / (isXSDT ? 8 : 4); kinfoln("Searching for table %s in the %s at %lx (table contains %d entries)", signature, isXSDT ? "XSDT" : "RSDT", (uint64_t)rootSDT, entries); for (int i = 0; i < entries; i++) { kinfoln("Testing for table %s in entry %d", signature, i); SDTHeader* h; if (isXSDT) { uint64_t reversedAddress = (uint64_t)((XSDT*)rootSDT)->PointerToOtherSDT[i]; uint64_t correctAddress = reversedAddress >> 32 | reversedAddress << 32; h = (SDTHeader*)correctAddress; } else { uint32_t entry = ((RSDT*)rootSDT)->PointerToOtherSDT[i]; h = (SDTHeader*)(uint64_t)entry; } if (!h) { kinfoln("Entry points to null"); continue; } kinfoln("Physical address of entry: %lx", (uint64_t)h); SDTHeader* realHeader = (SDTHeader*)KernelMemoryManager::get_unaligned_mapping(h); kinfoln("Mapped entry to virtual address %lx", (uint64_t)realHeader); if (!ValidateSDTHeader(realHeader)) { kinfoln("Header is not valid, skipping this entry"); KernelMemoryManager::release_unaligned_mapping(realHeader); continue; } char tableSignature[5]; memcpy(tableSignature, h->Signature, 4); tableSignature[4] = 0; kinfoln("Comparing target signature (%s) to signature of entry (%s)", signature, tableSignature); if (strncmp(h->Signature, signature, 4) == 0) { kinfoln("Found table %s", signature); return (void*)realHeader; } kinfoln("Signatures do not match, unmapping entry and continuing"); KernelMemoryManager::release_unaligned_mapping(realHeader); } return NULL; }