janwas
c9f10be090
wtime: "implement" CLOCK_MONOTONIC (that's what the timer already did, anyhow) main: move early init to GameSetup!EarlyInit (fixes atlas problem with timer) This was SVN commit r5101.
266 lines
6.0 KiB
C++
266 lines
6.0 KiB
C++
#include "precompiled.h"
|
|
#include "acpi.h"
|
|
|
|
#include "win/mahaf.h"
|
|
#include "lib/sysdep/cpu.h"
|
|
#include "lib/module_init.h"
|
|
|
|
#pragma pack(1)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// table utility functions
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// return 8-bit checksum of a buffer (should be 0)
|
|
static u8 ComputeChecksum(const void* buf, size_t numBytes)
|
|
{
|
|
u8 sum = 0;
|
|
const u8* end = (const u8*)buf+numBytes;
|
|
for(const u8* p = (const u8*)buf; p < end; p++)
|
|
sum += *p;
|
|
|
|
return sum;
|
|
}
|
|
|
|
|
|
// caller is responsible for verifying the table is valid and must
|
|
// free() the returned pointer.
|
|
static const AcpiTable* AllocateCopyOfTable(u64 physicalAddress)
|
|
{
|
|
// 4 KiB ought to be enough; if not, the table will be re-mapped.
|
|
const size_t initialSize = 4*KiB;
|
|
const AcpiTable* mappedTable = (const AcpiTable*)mahaf_MapPhysicalMemory(physicalAddress, initialSize);
|
|
if(!mappedTable)
|
|
return 0;
|
|
const size_t size = mappedTable->size;
|
|
|
|
if(size > initialSize)
|
|
{
|
|
// re-map with correct size
|
|
mahaf_UnmapPhysicalMemory((void*)mappedTable);
|
|
mappedTable = (const AcpiTable*)mahaf_MapPhysicalMemory(physicalAddress, size);
|
|
if(!mappedTable)
|
|
return 0;
|
|
}
|
|
|
|
AcpiTable* table = (AcpiTable*)malloc(size);
|
|
if(table)
|
|
cpu_memcpy(table, mappedTable, size);
|
|
|
|
mahaf_UnmapPhysicalMemory((void*)mappedTable);
|
|
return table;
|
|
}
|
|
|
|
|
|
static bool VerifyTable(const AcpiTable* table, const char* signature = 0)
|
|
{
|
|
// caller knowns the signature; make sure it matches
|
|
if(signature)
|
|
{
|
|
if(memcmp(table->signature, signature, 4) != 0)
|
|
return false;
|
|
}
|
|
// no specific signature is called for; just make sure it's 4 letters
|
|
else
|
|
{
|
|
for(int i = 0; i < 4; i++)
|
|
{
|
|
if(!isalpha(table->signature[i]))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// must be at least as large as the common header
|
|
if(table->size < sizeof(AcpiTable))
|
|
return false;
|
|
|
|
// checksum of table must be 0
|
|
// .. AMIBIOS OEMB table has an incorrect checksum (off-by-one),
|
|
// so don't complain about any OEM tables (ignored anyway).
|
|
const bool isOemTable = (memcmp(table->signature, "OEM", 3) == 0);
|
|
if(ComputeChecksum(table, table->size) != 0 && !isOemTable)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Root System Descriptor Pointer
|
|
//-----------------------------------------------------------------------------
|
|
|
|
struct RSDP
|
|
{
|
|
char signature[8]; // "RSD PTR "
|
|
u8 checksum; // sum of this struct = 0
|
|
char oemId[6];
|
|
u8 revision; // 0 for 1.0, 2 for 2.0
|
|
u32 rsdtPhysicalAddress;
|
|
};
|
|
|
|
static const size_t RSDP_ALIGNMENT = 16;
|
|
|
|
static const RSDP* LocateRsdp(const u8* buf, size_t numBytes)
|
|
{
|
|
const u8* const end = buf+numBytes;
|
|
for(const u8* p = buf; p < end; p += RSDP_ALIGNMENT)
|
|
{
|
|
const RSDP* rsdp = (const RSDP*)p;
|
|
|
|
if(memcmp(rsdp->signature, "RSD PTR ", 8) != 0)
|
|
continue;
|
|
|
|
if(ComputeChecksum(p, sizeof(RSDP)) != 0)
|
|
continue;
|
|
|
|
return rsdp;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static bool LocateAndRetrieveRsdp(uintptr_t physicalAddress, size_t numBytes, RSDP& rsdp)
|
|
{
|
|
void* virtualAddress = mahaf_MapPhysicalMemory(physicalAddress, numBytes);
|
|
|
|
const RSDP* prsdp = LocateRsdp((const u8*)virtualAddress, numBytes);
|
|
if(prsdp)
|
|
rsdp = *prsdp; // stash in output parameter before unmapping
|
|
|
|
mahaf_UnmapPhysicalMemory(virtualAddress);
|
|
return (prsdp != 0);
|
|
}
|
|
|
|
|
|
static uintptr_t LocateEbdaPhysicalAddress()
|
|
{
|
|
struct BiosDataArea
|
|
{
|
|
u16 serialBase[4];
|
|
u16 parallelBase[3];
|
|
u16 ebdaSegment;
|
|
// ...
|
|
};
|
|
const BiosDataArea* bda = (const BiosDataArea*)mahaf_MapPhysicalMemory(0x400, 0x100);
|
|
if(!bda)
|
|
return 0;
|
|
const uintptr_t ebdaPhysicalAddress = ((uintptr_t)bda->ebdaSegment) * 16;
|
|
|
|
return ebdaPhysicalAddress;
|
|
}
|
|
|
|
|
|
static bool RetrieveRsdp(RSDP& rsdp)
|
|
{
|
|
// See ACPIspec30b, section 5.2.5.1:
|
|
// RSDP is either in the first KIB of the extended BIOS data area,
|
|
if(LocateAndRetrieveRsdp(LocateEbdaPhysicalAddress(), 1*KiB, rsdp))
|
|
return true;
|
|
|
|
// or in read-only BIOS memory.
|
|
if(LocateAndRetrieveRsdp(0xE0000, 0x20000, rsdp))
|
|
return true;
|
|
|
|
return false; // not found
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Root System Descriptor Table
|
|
struct RSDT
|
|
{
|
|
AcpiTable header;
|
|
u32 tables[1];
|
|
};
|
|
|
|
// avoid std::map et al. because we are called before _cinit
|
|
static const AcpiTable** tables;
|
|
static size_t numTables;
|
|
|
|
static bool LatchAllTables()
|
|
{
|
|
RSDP rsdp;
|
|
if(!RetrieveRsdp(rsdp))
|
|
return false;
|
|
const RSDT* rsdt = (const RSDT*)AllocateCopyOfTable(rsdp.rsdtPhysicalAddress);
|
|
if(!rsdt)
|
|
return false;
|
|
if(!VerifyTable((const AcpiTable*)rsdt, "RSDT"))
|
|
{
|
|
free((void*)rsdt);
|
|
return false;
|
|
}
|
|
|
|
numTables = (rsdt->header.size - sizeof(AcpiTable)) / sizeof(rsdt->tables[0]);
|
|
tables = new const AcpiTable*[numTables];
|
|
|
|
for(size_t i = 0; i < numTables; i++)
|
|
{
|
|
const AcpiTable* table = AllocateCopyOfTable(rsdt->tables[i]);
|
|
if(!table)
|
|
continue;
|
|
if(!VerifyTable(table))
|
|
debug_warn("invalid ACPI table");
|
|
tables[i] = table; // transfers ownership
|
|
}
|
|
|
|
free((void*)rsdt);
|
|
return true;
|
|
}
|
|
|
|
|
|
static void FreeAllTables()
|
|
{
|
|
for(size_t i = 0; i < numTables; i++)
|
|
{
|
|
SAFE_FREE(tables[i]);
|
|
}
|
|
delete[] tables;
|
|
}
|
|
|
|
|
|
const AcpiTable* acpi_GetTable(const char* signature)
|
|
{
|
|
// (typically only a few tables, linear search is OK)
|
|
for(size_t i = 0; i < numTables; i++)
|
|
{
|
|
const AcpiTable* table = tables[i];
|
|
if(strncmp(table->signature, signature, 4) == 0)
|
|
return table;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static ModuleInitState initState;
|
|
|
|
bool acpi_Init()
|
|
{
|
|
if(!ModuleShouldInitialize(&initState))
|
|
return true;
|
|
|
|
if(!mahaf_Init())
|
|
{
|
|
ModuleSetError(&initState);
|
|
return false;
|
|
}
|
|
|
|
LatchAllTables();
|
|
return true;
|
|
}
|
|
|
|
void acpi_Shutdown()
|
|
{
|
|
if(!ModuleShouldShutdown(&initState))
|
|
return;
|
|
|
|
FreeAllTables();
|
|
|
|
mahaf_Shutdown();
|
|
}
|