2022-09-08 16:23:39 +02:00
|
|
|
#define MODULE "acpi"
|
2022-09-07 19:41:08 +02:00
|
|
|
|
2022-09-05 16:13:51 +02:00
|
|
|
#include "acpi/RSDT.h"
|
|
|
|
#include "bootboot.h"
|
2022-09-07 19:41:08 +02:00
|
|
|
#include "log/Log.h"
|
2022-09-24 21:45:13 +02:00
|
|
|
#include "memory/MemoryManager.h"
|
2022-09-05 16:13:51 +02:00
|
|
|
#include "std/stdio.h"
|
|
|
|
#include "std/string.h"
|
|
|
|
|
|
|
|
extern BOOTBOOT bootboot;
|
|
|
|
|
2022-09-25 21:43:28 +02:00
|
|
|
ACPI::SDTHeader* ACPI::get_rsdt_or_xsdt()
|
2022-09-05 16:13:51 +02:00
|
|
|
{
|
2022-09-07 19:41:08 +02:00
|
|
|
static void* cache = nullptr;
|
|
|
|
if (cache) return (SDTHeader*)cache;
|
2022-09-08 17:03:17 +02:00
|
|
|
kdbgln("First time accessing the RSDT/XSDT, mapping it into memory");
|
2022-09-07 19:41:08 +02:00
|
|
|
void* physical = (void*)bootboot.arch.x86_64.acpi_ptr;
|
|
|
|
uint64_t offset = (uint64_t)physical % 4096;
|
2022-09-08 17:03:17 +02:00
|
|
|
kdbgln("RSDT/XSDT physical address: %lx", (uint64_t)physical);
|
2022-09-24 21:45:13 +02:00
|
|
|
cache = MemoryManager::get_unaligned_mapping(physical);
|
2022-09-07 19:41:08 +02:00
|
|
|
uint64_t numPages = 1;
|
|
|
|
while ((offset + ((SDTHeader*)cache)->Length) > (numPages * 4096))
|
|
|
|
{
|
2022-09-08 17:03:17 +02:00
|
|
|
kwarnln("RSDT/XSDT extends beyond the mapped page, mapping one more page");
|
2022-09-24 21:45:13 +02:00
|
|
|
MemoryManager::release_unaligned_mappings(cache, numPages);
|
2022-09-07 19:41:08 +02:00
|
|
|
numPages++;
|
2022-09-24 21:45:13 +02:00
|
|
|
cache = MemoryManager::get_unaligned_mappings(cache, numPages);
|
2022-09-07 19:41:08 +02:00
|
|
|
}
|
2022-09-08 17:03:17 +02:00
|
|
|
kdbgln("Mapped RSDT/XSDT to virtual address %lx, uses %ld pages", (uint64_t)cache, numPages);
|
2022-09-07 19:41:08 +02:00
|
|
|
SDTHeader* result = (SDTHeader*)cache;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-09-25 21:43:28 +02:00
|
|
|
bool ACPI::validate_rsdt_or_xsdt(ACPI::SDTHeader* root_sdt)
|
2022-09-07 19:41:08 +02:00
|
|
|
{
|
2022-09-25 21:43:28 +02:00
|
|
|
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;
|
2022-09-07 19:41:08 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-25 21:43:28 +02:00
|
|
|
bool ACPI::is_xsdt()
|
2022-09-07 19:41:08 +02:00
|
|
|
{
|
2022-09-10 18:42:40 +02:00
|
|
|
static bool cached = false;
|
|
|
|
static bool cache = false;
|
|
|
|
if (cached) return cache;
|
2022-09-25 21:43:28 +02:00
|
|
|
SDTHeader* rootSDT = get_rsdt_or_xsdt();
|
2022-09-10 18:42:40 +02:00
|
|
|
cache = (strncmp(rootSDT->Signature, "XSDT", 4) == 0);
|
|
|
|
cached = true;
|
|
|
|
return cache;
|
2022-09-05 16:13:51 +02:00
|
|
|
}
|
|
|
|
|
2022-09-25 21:43:28 +02:00
|
|
|
void* ACPI::find_table(ACPI::SDTHeader* root_sdt, const char* signature)
|
2022-09-05 16:13:51 +02:00
|
|
|
{
|
2022-09-25 21:43:28 +02:00
|
|
|
bool isXSDT = is_xsdt();
|
2022-10-06 17:13:34 +02:00
|
|
|
uint64_t entries = (root_sdt->Length - sizeof(SDTHeader)) / (isXSDT ? 8 : 4);
|
|
|
|
kdbgln("Searching for table %s in the %s at %lx (table contains %ld entries)", signature, isXSDT ? "XSDT" : "RSDT",
|
2022-09-25 21:43:28 +02:00
|
|
|
(uint64_t)root_sdt, entries);
|
2022-09-05 16:13:51 +02:00
|
|
|
|
2022-10-06 17:13:34 +02:00
|
|
|
for (uint64_t i = 0; i < entries; i++)
|
2022-09-05 16:13:51 +02:00
|
|
|
{
|
2022-10-06 17:13:34 +02:00
|
|
|
kdbgln("Testing for table %s in entry %ld", signature, i);
|
2022-09-05 16:13:51 +02:00
|
|
|
SDTHeader* h;
|
2022-09-07 19:41:08 +02:00
|
|
|
if (isXSDT)
|
|
|
|
{
|
2022-09-25 21:43:28 +02:00
|
|
|
uint64_t reversedAddress = (uint64_t)((XSDT*)root_sdt)->other_sdt[i];
|
2022-09-07 19:41:08 +02:00
|
|
|
uint64_t correctAddress = reversedAddress >> 32 | reversedAddress << 32;
|
|
|
|
h = (SDTHeader*)correctAddress;
|
|
|
|
}
|
2022-09-05 16:13:51 +02:00
|
|
|
else
|
2022-09-06 11:46:47 +02:00
|
|
|
{
|
2022-09-25 21:43:28 +02:00
|
|
|
uint32_t entry = ((RSDT*)root_sdt)->other_sdt[i];
|
2022-09-06 11:46:47 +02:00
|
|
|
h = (SDTHeader*)(uint64_t)entry;
|
|
|
|
}
|
2022-09-07 19:41:08 +02:00
|
|
|
if (!h)
|
|
|
|
{
|
2022-10-06 17:13:34 +02:00
|
|
|
kwarnln("Entry %ld in the %s points to null", i, isXSDT ? "XSDT" : "RSDT");
|
2022-09-07 19:41:08 +02:00
|
|
|
continue;
|
|
|
|
}
|
2022-09-08 17:03:17 +02:00
|
|
|
kdbgln("Physical address of entry: %lx", (uint64_t)h);
|
2022-09-24 21:45:13 +02:00
|
|
|
SDTHeader* realHeader = (SDTHeader*)MemoryManager::get_unaligned_mapping(h);
|
2022-09-08 17:03:17 +02:00
|
|
|
kdbgln("Mapped entry to virtual address %lx", (uint64_t)realHeader);
|
2022-09-25 21:43:28 +02:00
|
|
|
if (!validate_sdt_header(realHeader))
|
2022-09-07 19:41:08 +02:00
|
|
|
{
|
2022-10-06 17:13:34 +02:00
|
|
|
kwarnln("Header of entry %ld is not valid, skipping this entry", i);
|
2022-09-24 21:45:13 +02:00
|
|
|
MemoryManager::release_unaligned_mapping(realHeader);
|
2022-09-07 19:41:08 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
char tableSignature[5];
|
|
|
|
memcpy(tableSignature, h->Signature, 4);
|
|
|
|
tableSignature[4] = 0;
|
2022-09-08 17:03:17 +02:00
|
|
|
kdbgln("Comparing target signature (%s) to signature of entry (%s)", signature, tableSignature);
|
2022-09-07 19:41:08 +02:00
|
|
|
if (strncmp(h->Signature, signature, 4) == 0)
|
|
|
|
{
|
2022-09-08 17:03:17 +02:00
|
|
|
kdbgln("Found table %s", signature);
|
2022-09-07 19:41:08 +02:00
|
|
|
return (void*)realHeader;
|
|
|
|
}
|
2022-09-08 17:03:17 +02:00
|
|
|
kdbgln("Signatures do not match, unmapping entry and continuing");
|
2022-09-24 21:45:13 +02:00
|
|
|
MemoryManager::release_unaligned_mapping(realHeader);
|
2022-09-05 16:13:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|