Luna/kernel/src/acpi/RSDT.cpp

106 lines
3.7 KiB
C++
Raw Normal View History

#define MODULE "acpi/rsdt"
2022-09-05 16:13:51 +02:00
#include "acpi/RSDT.h"
#include "bootboot.h"
2022-09-07 10:33:22 +02:00
#include "log/Address.h"
#include "log/Log.h"
2022-09-07 10:33:22 +02:00
#include "memory/KernelMemoryManager.h"
2022-09-05 16:13:51 +02:00
#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;
2022-09-05 16:13:51 +02:00
}
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);
2022-09-05 16:13:51 +02:00
for (int i = 0; i < entries; i++)
{
kinfoln("Testing for table %s in entry %d", signature, i);
2022-09-05 16:13:51 +02:00
SDTHeader* h;
if (isXSDT)
{
uint64_t reversedAddress = (uint64_t)((XSDT*)rootSDT)->PointerToOtherSDT[i];
uint64_t correctAddress = reversedAddress >> 32 | reversedAddress << 32;
h = (SDTHeader*)correctAddress;
}
2022-09-05 16:13:51 +02:00
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);
2022-09-07 10:33:22 +02:00
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");
2022-09-07 10:33:22 +02:00
KernelMemoryManager::release_unaligned_mapping(realHeader);
2022-09-05 16:13:51 +02:00
}
return NULL;
}