mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-12 09:54:36 +01:00
6ff5bab8a5
Move OptionsBits and FlagsBits in GlobalConfig. Move OEMVendor, OEMProduct, OEMBoard in GlobalConfig. Move KernelPatchesAllowed, KextPatchesAllowed, EnabledCores and BlockKexts in GlobalConfig. Create RomVersionUsed, EfiVersionUsed and ReleaseDateUsed in GlobalConfig. Move gFwFeatures, gFwFeaturesMask, gPlatformFeature, SlotDevices in Smbios section. Move UserInUse, UserChannels and User from gRAM to Smbios settings section. Rename enum LANGUAGES to LanguageCode.
2560 lines
91 KiB
C++
2560 lines
91 KiB
C++
/**
|
|
initial concept of DSDT patching by mackerintel
|
|
|
|
Re-Work by Slice 2011.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
**/
|
|
|
|
#include <Platform.h> // Only use angled for Platform, else, xcode project won't compile
|
|
#include <Efi.h>
|
|
|
|
#include "../libeg/BmLib.h"
|
|
#include "StateGenerator.h"
|
|
#include "AmlGenerator.h"
|
|
#include "AcpiPatcher.h"
|
|
#include "FixBiosDsdt.h"
|
|
#include "platformdata.h"
|
|
#include "smbios.h"
|
|
#include "cpu.h"
|
|
#include "Self.h"
|
|
#include "SelfOem.h"
|
|
|
|
#define EBDA_BASE_ADDRESS 0x40E
|
|
|
|
#define HPET_SIGN SIGNATURE_32('H','P','E','T')
|
|
#define APIC_SIGN SIGNATURE_32('A','P','I','C')
|
|
#define MCFG_SIGN SIGNATURE_32('M','C','F','G')
|
|
#define ECDT_SIGN SIGNATURE_32('E','C','D','T')
|
|
#define DMAR_SIGN SIGNATURE_32('D','M','A','R')
|
|
#define BGRT_SIGN SIGNATURE_32('B','G','R','T')
|
|
#define SLIC_SIGN SIGNATURE_32('S','L','I','C')
|
|
#define APPLE_OEM_ID { 'A', 'P', 'P', 'L', 'E', ' ' }
|
|
#define APPLE_OEM_TABLE_ID { 'A', 'p', 'p', 'l', 'e', '0', '0', ' ' }
|
|
#define APPLE_CREATOR_ID { 'L', 'o', 'k', 'i' }
|
|
|
|
#define IGNORE_INDEX (~((UINTN)0)) // index ignored for matching (not ignored for >= 0)
|
|
#define AUTOMERGE_PASS1 1 // load just those that match existing entries
|
|
#define AUTOMERGE_PASS2 2 // load the rest
|
|
|
|
CONST CHAR8 oemID[6] = APPLE_OEM_ID;
|
|
CONST CHAR8 oemTableID[8] = APPLE_OEM_TABLE_ID;
|
|
CONST CHAR8 creatorID[4] = APPLE_CREATOR_ID;
|
|
|
|
//Global pointers
|
|
RSDT_TABLE *Rsdt = NULL;
|
|
XSDT_TABLE *Xsdt = NULL;
|
|
UINTN *XsdtReplaceSizes = NULL;
|
|
|
|
#define IndexFromEntryPtr(xsdt_or_rsdt, entry_ptr) \
|
|
((UINT32)(((CHAR8*)(entry_ptr) - (CHAR8*)&(xsdt_or_rsdt)->Entry)/sizeof((xsdt_or_rsdt)->Entry)))
|
|
#define IndexFromRsdtEntryPtr(entry_ptr) IndexFromEntryPtr(Rsdt, entry_ptr)
|
|
#define IndexFromXsdtEntryPtr(entry_ptr) IndexFromEntryPtr(Xsdt, entry_ptr)
|
|
#define TableCount(xsdt_or_rsdt) \
|
|
(((xsdt_or_rsdt)->Header.Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) / sizeof((xsdt_or_rsdt)->Entry))
|
|
#define RsdtTableCount() TableCount(Rsdt)
|
|
#define XsdtTableCount() TableCount(Xsdt)
|
|
#define RsdtEntryPtrFromIndex(index) (&Rsdt->Entry + index)
|
|
#define XsdtEntryPtrFromIndex(index) ((UINT64*)((CHAR8*)&Xsdt->Entry + sizeof(UINT64)*(index)))
|
|
#define RsdtEntryFromIndex(index) (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)*RsdtEntryPtrFromIndex(index)
|
|
#define XsdtEntryFromIndex(index) (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)ReadUnaligned64(XsdtEntryPtrFromIndex(index))
|
|
|
|
UINT64 BiosDsdt;
|
|
UINT32 BiosDsdtLen;
|
|
UINT8 acpi_cpu_count;
|
|
CHAR8* acpi_cpu_name[acpi_cpu_max];
|
|
UINT8 acpi_cpu_processor_id[acpi_cpu_max];
|
|
CHAR8* acpi_cpu_score;
|
|
|
|
UINT64 machineSignature;
|
|
|
|
extern OPER_REGION *gRegions;
|
|
//-----------------------------------
|
|
|
|
|
|
UINT8 pmBlock[] = {
|
|
|
|
/*0070: 0xA5, 0x84, 0x00, 0x00,*/ 0x01, 0x08, 0x00, 0x01, 0xF9, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
/*0080:*/ 0x06, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x67, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x6F, 0xBF,
|
|
/*0090:*/ 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
/*00A0:*/ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x02,
|
|
/*00B0:*/ 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
/*00C0:*/ 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
/*00D0:*/ 0x01, 0x20, 0x00, 0x03, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x01,
|
|
/*00E0:*/ 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
|
/*00F0:*/ 0x00, 0x00, 0x00, 0x00
|
|
|
|
};
|
|
|
|
// RehabMan: for stripping trailing spaces
|
|
static void stripTrailingSpaces(CHAR8* sgn)
|
|
{
|
|
CHAR8* lastNonSpace = sgn-1;
|
|
for (; *sgn; sgn++) {
|
|
if (*sgn != ' ') {
|
|
lastNonSpace = sgn;
|
|
}
|
|
}
|
|
lastNonSpace[1] = 0;
|
|
}
|
|
|
|
void* FindAcpiRsdPtr()
|
|
{
|
|
UINTN Address;
|
|
UINTN Index;
|
|
//
|
|
// First Seach 0x0e0000 - 0x0fffff for RSD Ptr
|
|
//
|
|
for (Address = 0xe0000; Address < 0xfffff; Address += 0x10) {
|
|
if (*(UINT64 *)(Address) == EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE) {
|
|
return (void *)Address;
|
|
}
|
|
}
|
|
//
|
|
// Search EBDA
|
|
//
|
|
Address = (*(UINT16 *)(UINTN)(EBDA_BASE_ADDRESS)) << 4;
|
|
if ( Address == 0 ) return 0; // Jief : if Address==0, the first access at *(UINT64 *)(Address + Index) is at address 0. It's supposed to crash.
|
|
for (Index = 0; Index < 0x400 ; Index += 16) {
|
|
if (*(UINT64 *)(Address + Index) == EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE) {
|
|
return (void *)Address;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
UINT8 Checksum8(void* startPtr, UINT32 len)
|
|
{
|
|
UINT8 Value = 0;
|
|
UINT8 *ptr = (UINT8*)startPtr;
|
|
UINT8 *endPtr = ptr + len;
|
|
while (ptr < endPtr)
|
|
Value += *ptr++;
|
|
return Value;
|
|
}
|
|
|
|
void FixChecksum(EFI_ACPI_DESCRIPTION_HEADER* Table)
|
|
{
|
|
Table->Checksum = 0;
|
|
Table->Checksum = (UINT8)(256-Checksum8(Table, Table->Length));
|
|
}
|
|
|
|
void SaveMergedXsdtEntrySize(UINT32 Index, UINTN Size)
|
|
{
|
|
// manage XsdtReplaceSizes (free existing, store new)
|
|
if (XsdtReplaceSizes) {
|
|
if (XsdtReplaceSizes[Index]) {
|
|
// came from patched table in ACPI/patched, so free original pages
|
|
gBS->FreePages((EFI_PHYSICAL_ADDRESS)(UINTN)XsdtEntryFromIndex(Index), XsdtReplaceSizes[Index]);
|
|
XsdtReplaceSizes[Index] = 0;
|
|
}
|
|
XsdtReplaceSizes[Index] = EFI_SIZE_TO_PAGES(Size);
|
|
}
|
|
}
|
|
|
|
BOOLEAN IsXsdtEntryMerged(UINT32 Index)
|
|
{
|
|
if (!XsdtReplaceSizes) {
|
|
return FALSE;
|
|
}
|
|
return 0 != XsdtReplaceSizes[Index];
|
|
}
|
|
|
|
UINT32* ScanRSDT2(UINT32 Signature, UINT64 TableId, UINTN MatchIndex)
|
|
{
|
|
if (!Rsdt || (0 == Signature && 0 == TableId)) {
|
|
return NULL;
|
|
}
|
|
|
|
UINT32 Count = RsdtTableCount();
|
|
UINTN MatchingCount = 0;
|
|
UINT32* Ptr = RsdtEntryPtrFromIndex(0);
|
|
UINT32* EndPtr = RsdtEntryPtrFromIndex(Count);
|
|
for (; Ptr < EndPtr; Ptr++) {
|
|
EFI_ACPI_DESCRIPTION_HEADER* Table = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)*Ptr;
|
|
if (!Table) {
|
|
// skip NULL entry
|
|
continue;
|
|
}
|
|
if (0 == Signature || Table->Signature == Signature) {
|
|
if ((0 == TableId || Table->OemTableId == TableId) && (IGNORE_INDEX == MatchIndex || MatchingCount == MatchIndex)) {
|
|
return Ptr; // pointer to the matching entry
|
|
}
|
|
++MatchingCount;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
UINT32* ScanRSDT(UINT32 Signature, UINT64 TableId)
|
|
{
|
|
return ScanRSDT2(Signature, TableId, IGNORE_INDEX);
|
|
}
|
|
|
|
UINT64* ScanXSDT2(UINT32 Signature, UINT64 TableId, UINTN MatchIndex)
|
|
{
|
|
if (!Xsdt || (0 == Signature && 0 == TableId)) {
|
|
return NULL;
|
|
}
|
|
|
|
UINT32 Count = XsdtTableCount();
|
|
UINTN MatchingCount = 0;
|
|
UINT64* Ptr = XsdtEntryPtrFromIndex(0);
|
|
UINT64* EndPtr = XsdtEntryPtrFromIndex(Count);
|
|
for (; Ptr < EndPtr; Ptr++) {
|
|
EFI_ACPI_DESCRIPTION_HEADER* Table = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)ReadUnaligned64(Ptr);
|
|
if (!Table) {
|
|
// skip NULL entry
|
|
continue;
|
|
}
|
|
if (0 == Signature || Table->Signature == Signature) {
|
|
if ((0 == TableId || Table->OemTableId == TableId) && (IGNORE_INDEX == MatchIndex || MatchingCount == MatchIndex)) {
|
|
return Ptr; // pointer to the matching entry
|
|
}
|
|
++MatchingCount;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
UINT64* ScanXSDT(UINT32 Signature, UINT64 TableId)
|
|
{
|
|
return ScanXSDT2(Signature, TableId, IGNORE_INDEX);
|
|
}
|
|
|
|
|
|
void AddDropTable(EFI_ACPI_DESCRIPTION_HEADER* Table, UINT32 Index)
|
|
{
|
|
CHAR8 sign[5], OTID[9];
|
|
sign[4] = 0;
|
|
OTID[8] = 0;
|
|
CopyMem(&sign[0], &Table->Signature, 4);
|
|
CopyMem(&OTID[0], &Table->OemTableId, 8);
|
|
//DBG(" Found table: %s %s len=%d\n", sign, OTID, (INT32)Table->Length);
|
|
DBG(" - [%02d]: %s %s len=%d\n", Index, sign, OTID, (INT32)Table->Length);
|
|
ACPI_DROP_TABLE* DropTable = new ACPI_DROP_TABLE;
|
|
DropTable->Signature = Table->Signature;
|
|
DropTable->TableId = Table->OemTableId;
|
|
DropTable->Length = Table->Length;
|
|
DropTable->MenuItem.BValue = FALSE;
|
|
DropTable->Next = GlobalConfig.ACPIDropTables;
|
|
GlobalConfig.ACPIDropTables = DropTable;
|
|
}
|
|
|
|
void GetAcpiTablesList()
|
|
{
|
|
DbgHeader("GetAcpiTablesList");
|
|
|
|
GetFadt(); //this is a first call to acpi, we need it to make a pointer to Xsdt
|
|
GlobalConfig.ACPIDropTables = NULL;
|
|
|
|
DBG("Get Acpi Tables List ");
|
|
if (Xsdt) {
|
|
UINT32 Count = XsdtTableCount();
|
|
UINT64* Ptr = XsdtEntryPtrFromIndex(0);
|
|
UINT64* EndPtr = XsdtEntryPtrFromIndex(Count);
|
|
DBG("from XSDT:\n");
|
|
for (; Ptr < EndPtr; Ptr++) {
|
|
EFI_ACPI_DESCRIPTION_HEADER* Table = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)ReadUnaligned64(Ptr);
|
|
if (!Table) {
|
|
// skip NULL entry
|
|
continue;
|
|
}
|
|
AddDropTable(Table, IndexFromXsdtEntryPtr(Ptr));
|
|
}
|
|
} else if (Rsdt) {
|
|
DBG("from RSDT:\n");
|
|
UINT32 Count = RsdtTableCount();
|
|
UINT32* Ptr = RsdtEntryPtrFromIndex(0);
|
|
UINT32* EndPtr = RsdtEntryPtrFromIndex(Count);
|
|
for (; Ptr < EndPtr; Ptr++) {
|
|
EFI_ACPI_DESCRIPTION_HEADER* Table = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)*Ptr;
|
|
if (!Table) {
|
|
// skip NULL entry
|
|
continue;
|
|
}
|
|
AddDropTable(Table, IndexFromRsdtEntryPtr(Ptr));
|
|
}
|
|
} else {
|
|
DBG(": [!] Error! ACPI not found:\n");
|
|
}
|
|
}
|
|
|
|
|
|
void DropTableFromRSDT(UINT32 Signature, UINT64 TableId, UINT32 Length)
|
|
{
|
|
if (!Rsdt || (0 == Signature && 0 == TableId)) {
|
|
return;
|
|
}
|
|
|
|
CHAR8 sign[5], OTID[9];
|
|
sign[4] = 0;
|
|
OTID[8] = 0;
|
|
CopyMem(&sign[0], &Signature, 4);
|
|
CopyMem(&OTID[0], &TableId, 8);
|
|
DBG("Drop tables from RSDT, SIGN=%s TableID=%s Length=%d\n", sign, OTID, (INT32)Length);
|
|
|
|
UINT32 Count = RsdtTableCount();
|
|
//DBG(" Rsdt has tables count=%d\n", Count);
|
|
UINT32* Ptr = RsdtEntryPtrFromIndex(0);
|
|
UINT32* EndPtr = RsdtEntryPtrFromIndex(Count);
|
|
for (; Ptr < EndPtr; Ptr++) {
|
|
EFI_ACPI_DESCRIPTION_HEADER* Table = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)*Ptr;
|
|
if (!Table) {
|
|
// skip NULL entry
|
|
continue;
|
|
}
|
|
CopyMem(&sign[0], &Table->Signature, 4);
|
|
CopyMem(&OTID[0], &Table->OemTableId, 8);
|
|
//DBG(" Found table: %s %s\n", sign, OTID);
|
|
if (!((Signature && Table->Signature == Signature) &&
|
|
(!TableId || Table->OemTableId == TableId) &&
|
|
(!Length || Table->Length == Length))) {
|
|
continue;
|
|
}
|
|
if (IsXsdtEntryMerged(IndexFromXsdtEntryPtr(Ptr))) {
|
|
DBG(" attempt to drop already merged table[%d]: %s %s %d ignored\n", IndexFromXsdtEntryPtr(Ptr), sign, OTID, (INT32)Table->Length);
|
|
continue;
|
|
}
|
|
// drop matching table by simply replacing entry with NULL
|
|
*Ptr = 0;
|
|
DBG(" Table[%d]: %s %s %d dropped\n", IndexFromXsdtEntryPtr(Ptr), sign, OTID, (INT32)Table->Length);
|
|
}
|
|
}
|
|
|
|
void DropTableFromXSDT(UINT32 Signature, UINT64 TableId, UINT32 Length)
|
|
{
|
|
if (!Xsdt || (0 == Signature && 0 == TableId)) {
|
|
return;
|
|
}
|
|
|
|
CHAR8 sign[5], OTID[9];
|
|
sign[4] = 0;
|
|
OTID[8] = 0;
|
|
CopyMem(&sign[0], &Signature, 4);
|
|
CopyMem(&OTID[0], &TableId, 8);
|
|
DBG("Drop tables from XSDT, SIGN=%s TableID=%s Length=%d\n", sign, OTID, (INT32)Length);
|
|
|
|
UINT32 Count = XsdtTableCount();
|
|
//DBG(" Xsdt has tables count=%d\n", Count);
|
|
UINT64* Ptr = XsdtEntryPtrFromIndex(0);
|
|
UINT64* EndPtr = XsdtEntryPtrFromIndex(Count);
|
|
for (; Ptr < EndPtr; Ptr++) {
|
|
EFI_ACPI_DESCRIPTION_HEADER* Table = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)ReadUnaligned64(Ptr);
|
|
if (!Table) {
|
|
// skip NULL entry
|
|
continue;
|
|
}
|
|
CopyMem(&sign[0], &Table->Signature, 4);
|
|
CopyMem(&OTID[0], &Table->OemTableId, 8);
|
|
//DBG(" Found table: %s %s\n", sign, OTID);
|
|
if (!((Signature && Table->Signature == Signature) &&
|
|
(!TableId || Table->OemTableId == TableId) &&
|
|
(!Length || Table->Length == Length))) {
|
|
continue;
|
|
}
|
|
if (IsXsdtEntryMerged(IndexFromXsdtEntryPtr(Ptr))) {
|
|
DBG(" attempt to drop already merged table[%d]: %s %s %d ignored\n", IndexFromXsdtEntryPtr(Ptr), sign, OTID, (INT32)Table->Length);
|
|
continue;
|
|
}
|
|
// drop matching table by simply replacing entry with NULL
|
|
WriteUnaligned64(Ptr, 0);
|
|
DBG(" Table[%d]: %s %s %d dropped\n", IndexFromXsdtEntryPtr(Ptr), sign, OTID, (INT32)Table->Length);
|
|
}
|
|
}
|
|
|
|
|
|
// by cecekpawon, edited by Slice, further edits by RehabMan
|
|
BOOLEAN FixAsciiTableHeader(UINT8 *Str, UINTN Len)
|
|
{
|
|
BOOLEAN NonAscii = FALSE;
|
|
UINT8* StrEnd = Str + Len;
|
|
for (; Str < StrEnd; Str++) {
|
|
if (!*Str) continue; // NUL is allowed
|
|
if (*Str < ' ') {
|
|
*Str = ' ';
|
|
NonAscii = TRUE;
|
|
}
|
|
else if (*Str > 0x7e) {
|
|
*Str = '_';
|
|
NonAscii = TRUE;
|
|
}
|
|
}
|
|
return NonAscii;
|
|
}
|
|
|
|
BOOLEAN PatchTableHeader(EFI_ACPI_DESCRIPTION_HEADER *Header)
|
|
{
|
|
BOOLEAN Ret1, Ret2, Ret3;
|
|
if (!(gSettings.ACPI.DSDT.FixDsdt & FIX_HEADERS) && !gSettings.ACPI.FixHeaders) {
|
|
return FALSE;
|
|
}
|
|
Ret1 = FixAsciiTableHeader((UINT8*)&Header->CreatorId, 4);
|
|
Ret2 = FixAsciiTableHeader((UINT8*)&Header->OemTableId, 8);
|
|
Ret3 = FixAsciiTableHeader((UINT8*)&Header->OemId, 6);
|
|
return (Ret1 || Ret2 || Ret3);
|
|
}
|
|
|
|
void PatchAllTables()
|
|
{
|
|
UINT32 Count = XsdtTableCount();
|
|
UINT64* Ptr = XsdtEntryPtrFromIndex(0);
|
|
UINT64* EndPtr = XsdtEntryPtrFromIndex(Count);
|
|
for (; Ptr < EndPtr; Ptr++) {
|
|
BOOLEAN Patched = FALSE;
|
|
EFI_ACPI_DESCRIPTION_HEADER* Table = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)ReadUnaligned64(Ptr);
|
|
if (!Table) {
|
|
// skip NULL entry
|
|
continue;
|
|
}
|
|
if (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE == Table->Signature) {
|
|
// may be also EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE?
|
|
continue; // will be patched elsewhere
|
|
}
|
|
|
|
//do new table with patched header
|
|
UINT32 Len = Table->Length;
|
|
EFI_PHYSICAL_ADDRESS BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
EFI_STATUS Status = gBS->AllocatePages(AllocateMaxAddress,
|
|
EfiACPIReclaimMemory,
|
|
EFI_SIZE_TO_PAGES(Len + 4096),
|
|
&BufferPtr);
|
|
if(EFI_ERROR(Status)) {
|
|
//DBG(" ... not patched\n");
|
|
continue;
|
|
}
|
|
EFI_ACPI_DESCRIPTION_HEADER* NewTable = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)BufferPtr;
|
|
CopyMem(NewTable, Table, Len);
|
|
if ((gSettings.ACPI.DSDT.FixDsdt & FIX_HEADERS) || gSettings.ACPI.FixHeaders) {
|
|
// Merged tables already have the header patched, so no need to do it again
|
|
if (!IsXsdtEntryMerged(IndexFromXsdtEntryPtr(Ptr))) {
|
|
// table header NOT already patched
|
|
Patched = PatchTableHeader(NewTable);
|
|
}
|
|
}
|
|
if (NewTable->Signature == EFI_ACPI_4_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
|
|
if (gSettings.ACPI.DSDT.DSDTPatchArray.size() > 0) {
|
|
DBG("Patching SSDTs: %zu patches each\n", gSettings.ACPI.DSDT.DSDTPatchArray.size());
|
|
|
|
// CHAR8 OTID[9];
|
|
// OTID[8] = 0;
|
|
// CopyMem(OTID, &NewTable->OemTableId, 8);
|
|
// DBG("Patching SSDT %s Length=%d\n", OTID, (INT32)Len);
|
|
|
|
for (UINT32 i = 0; i < gSettings.ACPI.DSDT.DSDTPatchArray.size(); i++) {
|
|
if ( gSettings.ACPI.DSDT.DSDTPatchArray[i].PatchDsdtFind.isEmpty() ) {
|
|
continue;
|
|
}
|
|
// DBG("%d. [%s]:", i, gSettings.PatchDsdtLabel[i]);
|
|
if (!gSettings.ACPI.DSDT.DSDTPatchArray[i].PatchDsdtMenuItem.BValue) {
|
|
// DBG(" disabled\n");
|
|
continue;
|
|
}
|
|
if ( gSettings.ACPI.DSDT.DSDTPatchArray[i].PatchDsdtTgt.isEmpty() ) {
|
|
Len = FixAny((UINT8*)NewTable, Len,
|
|
gSettings.ACPI.DSDT.DSDTPatchArray[i].PatchDsdtFind,
|
|
gSettings.ACPI.DSDT.DSDTPatchArray[i].PatchDsdtReplace);
|
|
//DBG(" OK\n");
|
|
}else{
|
|
//DBG("Patching: renaming in bridge\n");
|
|
Len = FixRenameByBridge2((UINT8*)NewTable, Len, gSettings.ACPI.DSDT.DSDTPatchArray[i].PatchDsdtTgt, gSettings.ACPI.DSDT.DSDTPatchArray[i].PatchDsdtFind, gSettings.ACPI.DSDT.DSDTPatchArray[i].PatchDsdtReplace);
|
|
}
|
|
}
|
|
}
|
|
// fixup length and checksum
|
|
NewTable->Length = Len;
|
|
RenameDevices((UINT8*)NewTable);
|
|
GetBiosRegions((UINT8*)NewTable); //take Regions from SSDT even if they will be dropped
|
|
Patched = TRUE;
|
|
}
|
|
if (NewTable->Signature == MCFG_SIGN && gSettings.ACPI.FixMCFG) {
|
|
INTN Len1 = ((Len + 4 - 1) / 16 + 1) * 16 - 4;
|
|
CopyMem(NewTable, Table, Len1); //Len increased but less than EFI_PAGE
|
|
NewTable->Length = (UINT32)(UINTN)Len1; Patched = TRUE;
|
|
}
|
|
if (Patched) {
|
|
WriteUnaligned64(Ptr, BufferPtr);
|
|
FixChecksum(NewTable);
|
|
}
|
|
else {
|
|
gBS->FreePages(BufferPtr, EFI_SIZE_TO_PAGES(Len + 4096));
|
|
}
|
|
}
|
|
}
|
|
|
|
EFI_STATUS InsertTable(void* TableEntry, UINTN Length)
|
|
{
|
|
if (!TableEntry) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
EFI_PHYSICAL_ADDRESS BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
EFI_STATUS Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiACPIReclaimMemory,
|
|
EFI_SIZE_TO_PAGES(Length),
|
|
&BufferPtr
|
|
);
|
|
//if success insert table pointer into ACPI tables
|
|
if(!EFI_ERROR(Status)) {
|
|
// DBG("page is allocated, write SSDT into\n");
|
|
EFI_ACPI_DESCRIPTION_HEADER* TableHeader = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)BufferPtr;
|
|
CopyMem(TableHeader, TableEntry, Length);
|
|
// Now is a good time to fix the table header and checksum
|
|
PatchTableHeader(TableHeader);
|
|
FixChecksum(TableHeader);
|
|
|
|
//insert into RSDT
|
|
if (Rsdt) {
|
|
UINT32* Ptr = RsdtEntryPtrFromIndex(RsdtTableCount());
|
|
*Ptr = (UINT32)(UINTN)BufferPtr;
|
|
Rsdt->Header.Length += sizeof(UINT32);
|
|
//DBG("Rsdt->Length = %d\n", Rsdt->Header.Length);
|
|
}
|
|
//insert into XSDT
|
|
if (Xsdt) {
|
|
UINT64* Ptr = XsdtEntryPtrFromIndex(XsdtTableCount());
|
|
WriteUnaligned64(Ptr, BufferPtr);
|
|
Xsdt->Header.Length += sizeof(UINT64);
|
|
//DBG("Xsdt->Length = %d\n", Xsdt->Header.Length);
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
UINTN IndexFromFileName(CONST CHAR16* FileName)
|
|
{
|
|
// FileName must be as "XXXX-number-..." or "XXXX-number.aml", such as "SSDT-9.aml", or "SSDT-11-SaSsdt.aml"
|
|
// But just checking for '-' or '.' following the number.
|
|
|
|
// search for '-'
|
|
UINTN Result = IGNORE_INDEX;
|
|
CONST CHAR16* temp = FileName;
|
|
for (; *temp != 0 && *temp != '-'; temp++);
|
|
if ('-' == *temp && 4 == temp-FileName) {
|
|
++temp;
|
|
if (*temp >= '0' && *temp <= '9') {
|
|
Result = 0;
|
|
for (; *temp >= '0' && *temp <= '9'; temp++) {
|
|
Result *= 10;
|
|
Result += *temp - '0';
|
|
}
|
|
// a FileName such as "SSDT-4x30s.aml" is not considered as "SSDT-4.aml"
|
|
if ('.' != *temp && '-' != *temp)
|
|
Result = IGNORE_INDEX;
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
EFI_STATUS ReplaceOrInsertTable(void* TableEntry, UINTN Length, UINTN MatchIndex, INTN Pass)
|
|
{
|
|
if (!TableEntry) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
EFI_PHYSICAL_ADDRESS BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
EFI_STATUS Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiACPIReclaimMemory,
|
|
EFI_SIZE_TO_PAGES(Length),
|
|
&BufferPtr
|
|
);
|
|
EFI_ACPI_DESCRIPTION_HEADER* hdr = (EFI_ACPI_DESCRIPTION_HEADER*)TableEntry;
|
|
|
|
//if success insert or replace table pointer into ACPI tables
|
|
if(!EFI_ERROR(Status)) {
|
|
Status = EFI_ABORTED;
|
|
//DBG("page is allocated, write SSDT into\n");
|
|
EFI_ACPI_DESCRIPTION_HEADER* TableHeader = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)BufferPtr;
|
|
CopyMem(TableHeader, TableEntry, Length);
|
|
#if 0 //REVIEW: seems as if Rsdt is always NULL for ReplaceOrInsertTable scenarios (macOS/OS X)
|
|
//insert/modify into RSDT
|
|
if (Rsdt) {
|
|
UINT32* Ptr = NULL;
|
|
if (hdr->Signature != EFI_ACPI_4_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE || MatchIndex != IGNORE_INDEX) {
|
|
// SSDT with target index or non-SSDT, try to find matching entry
|
|
Ptr = ScanRSDT2(hdr->Signature, hdr->OemTableId, MatchIndex);
|
|
}
|
|
if (Ptr) {
|
|
*Ptr = (UINT32)(UINTN)BufferPtr;
|
|
Status = EFI_SUCCESS;
|
|
} else if (AUTOMERGE_PASS2 == Pass) {
|
|
Ptr = RsdtEntryPtrFromIndex(RsdtTableCount());
|
|
*Ptr = (UINT32)(UINTN)BufferPtr;
|
|
Rsdt->Header.Length += sizeof(UINT32);
|
|
//DBG("Rsdt->Length = %d\n", Rsdt->Header.Length);
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
#endif
|
|
//insert/modify into XSDT
|
|
if (Xsdt) {
|
|
UINT64* Ptr = NULL;
|
|
if (hdr->Signature != EFI_ACPI_4_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE || MatchIndex != IGNORE_INDEX) {
|
|
// SSDT with target index or non-SSDT, try to find matching entry
|
|
Ptr = ScanXSDT2(hdr->Signature, hdr->OemTableId, MatchIndex);
|
|
}
|
|
// Now is a good time to fix the table header and checksum (*MUST* be done after matching)
|
|
PatchTableHeader(TableHeader);
|
|
FixChecksum(TableHeader);
|
|
if (Ptr) {
|
|
UINT32 Index = IndexFromXsdtEntryPtr(Ptr);
|
|
DBG("@%llu ", (UINT64)Index);
|
|
// keep track of new table size in case it needs to be freed later
|
|
SaveMergedXsdtEntrySize(Index, Length);
|
|
WriteUnaligned64(Ptr, BufferPtr);
|
|
Status = EFI_SUCCESS;
|
|
} else if (AUTOMERGE_PASS2 == Pass) {
|
|
Ptr = XsdtEntryPtrFromIndex(XsdtTableCount());
|
|
WriteUnaligned64(Ptr, BufferPtr);
|
|
Xsdt->Header.Length += sizeof(UINT64);
|
|
//DBG("Xsdt->Length = %d\n", Xsdt->Header.Length);
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
void PreCleanupRSDT()
|
|
{
|
|
if (!Rsdt) {
|
|
return;
|
|
}
|
|
|
|
//REVIEW: really?
|
|
// Если адрес RSDT < адреса XSDT и хвост RSDT наползает на XSDT, то подрезаем хвост RSDT до начала XSDT
|
|
// English: If the RSDT address of the XSDT address and the tail of the RSDT crawls onto the XSDT, then we
|
|
// trim the RSDT tail before the XSDT starts
|
|
if ((UINTN)Rsdt < (UINTN)Xsdt && (UINTN)Rsdt + Rsdt->Header.Length > (UINTN)Xsdt) {
|
|
UINTN v = ((UINTN)Xsdt - (UINTN)Rsdt) & ~3;
|
|
// if ( v > MAX_UINT32 ) panic("((UINTN)Xsdt - (UINTN)Rsdt) & ~3 > MAX_UINT32");
|
|
Rsdt->Header.Length = (UINT32)v;
|
|
DBG("Cropped Rsdt->Header.Length=%d\n", (UINT32)Rsdt->Header.Length);
|
|
}
|
|
|
|
//REVIEW: why?
|
|
// terminate RSDT table at first double zero, if present
|
|
UINT32 Count = RsdtTableCount();
|
|
if (Count <= 2) {
|
|
return;
|
|
}
|
|
|
|
DBG("PreCleanup RSDT: count=%d, length=%d\n", Count, (UINT32)Rsdt->Header.Length);
|
|
UINT32* Ptr = RsdtEntryPtrFromIndex(0);
|
|
UINT32* EndPtr = RsdtEntryPtrFromIndex(Count-1);
|
|
for (; Ptr < EndPtr; Ptr++) {
|
|
if (0 == Ptr[0] && 0 == Ptr[1]) {
|
|
// double zero found, terminate RSDT entry table here
|
|
DBG("DoubleZero in RSDT table\n");
|
|
Rsdt->Header.Length = (UINT32)((CHAR8*)Ptr - (CHAR8*)Rsdt);
|
|
break;
|
|
}
|
|
}
|
|
DBG("PreCleanup RSDT, corrected RSDT: count=%d, length=%d\n", Count, (UINT32)Rsdt->Header.Length);
|
|
}
|
|
|
|
void PostCleanupRSDT()
|
|
{
|
|
if (!Rsdt) {
|
|
return;
|
|
}
|
|
|
|
// remove NULL entries from RSDT table
|
|
UINT32 Count = RsdtTableCount();
|
|
DBG("Cleanup RSDT: count=%d, length=%d\n", Count, (UINT32)Rsdt->Header.Length);
|
|
UINT32* Source = RsdtEntryPtrFromIndex(0);
|
|
UINT32* Dest = Source;
|
|
UINT32* EndPtr = RsdtEntryPtrFromIndex(Count);
|
|
while (Source < EndPtr) {
|
|
if (0 == *Source) {
|
|
// skip NULL entry
|
|
Source++;
|
|
continue;
|
|
}
|
|
*Dest++ = *Source++;
|
|
}
|
|
// fix header length
|
|
Rsdt->Header.Length = (UINT32)((CHAR8*)Dest - (CHAR8*)Rsdt);
|
|
Count = RsdtTableCount();
|
|
DBG("corrected RSDT: count=%d, length=%d\n", Count, (UINT32)Rsdt->Header.Length);
|
|
FixChecksum(&Rsdt->Header);
|
|
}
|
|
|
|
void PreCleanupXSDT()
|
|
{
|
|
UINT64 *Ptr, *EndPtr;
|
|
if (!Xsdt) {
|
|
return;
|
|
}
|
|
|
|
//REVIEW: why?
|
|
// terminate RSDT table at first double zero, if present
|
|
UINT32 Count = XsdtTableCount();
|
|
if (Count <= 2) {
|
|
return;
|
|
}
|
|
DBG("PreCleanup XSDT: count=%d, length=%d\n", Count, (UINT32)Xsdt->Header.Length);
|
|
Ptr = XsdtEntryPtrFromIndex(0);
|
|
EndPtr = XsdtEntryPtrFromIndex(Count-1);
|
|
for (; Ptr < EndPtr; Ptr++) {
|
|
if (0 == ReadUnaligned64(Ptr+0) && 0 == ReadUnaligned64(Ptr+1)) {
|
|
// double zero found, terminate XSDT entry table here
|
|
DBG("DoubleZero in XSDT table\n");
|
|
Xsdt->Header.Length = (UINT32)((CHAR8*)Ptr - (CHAR8*)Xsdt);
|
|
break;
|
|
}
|
|
}
|
|
DBG("PreCleanup XSDT, corrected XSDT: count=%d, length=%d\n", Count, (UINT32)Xsdt->Header.Length);
|
|
}
|
|
|
|
void PostCleanupXSDT()
|
|
{
|
|
UINT64 *Dest, *EndPtr, *Source;
|
|
if (!Xsdt) {
|
|
return;
|
|
}
|
|
|
|
// remove NULL entries from XSDT table
|
|
UINT32 Count = XsdtTableCount();
|
|
DBG("Cleanup XSDT: count=%d, length=%d\n", Count, (UINT32)Xsdt->Header.Length);
|
|
Source = XsdtEntryPtrFromIndex(0);
|
|
Dest = Source;
|
|
EndPtr = XsdtEntryPtrFromIndex(Count);
|
|
while (Source < EndPtr) {
|
|
if (0 == *Source) {
|
|
// skip NULL entry
|
|
Source++;
|
|
continue;
|
|
}
|
|
WriteUnaligned64(Dest++, ReadUnaligned64(Source++));
|
|
}
|
|
// fix header length
|
|
Xsdt->Header.Length = (UINT32)((CHAR8*)Dest - (CHAR8*)Xsdt);
|
|
Count = XsdtTableCount();
|
|
DBG("corrected XSDT count=%d, length=%d\n", Count, (UINT32)Xsdt->Header.Length);
|
|
FixChecksum(&Xsdt->Header);
|
|
}
|
|
|
|
|
|
/** Saves Buffer of Length to disk as OemDir\\DirName\\FileName. */
|
|
EFI_STATUS SaveBufferToDisk(void *Buffer, UINTN Length, CONST CHAR16 *DirName, CONST CHAR16 *FileName)
|
|
{
|
|
if (DirName == NULL || FileName == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
XStringW PathName = SWPrintf("%ls\\%ls", DirName, FileName);
|
|
|
|
EFI_STATUS Status = egSaveFile(&selfOem.getConfigDir(), PathName.wc_str(), Buffer, Length);
|
|
// Do not write outside OemDir
|
|
// if (EFI_ERROR(Status)) {
|
|
// Status = egSaveFile(NULL, PathName.wc_str(), Buffer, Length);
|
|
// }
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Remembering saved tables
|
|
//
|
|
#define SAVED_TABLES_ALLOC_ENTRIES 64
|
|
void **mSavedTables = NULL;
|
|
UINTN mSavedTablesEntries = 0;
|
|
UINTN mSavedTablesNum = 0;
|
|
|
|
/** Returns TRUE is TableEntry is already saved. */
|
|
BOOLEAN IsTableSaved(void *TableEntry)
|
|
{
|
|
UINTN Index;
|
|
|
|
if (mSavedTables != NULL) {
|
|
for (Index = 0; Index < mSavedTablesNum; Index++) {
|
|
if (mSavedTables[Index] == TableEntry) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/** Adds TableEntry to mSavedTables if not already there. */
|
|
void MarkTableAsSaved(void *TableEntry)
|
|
{
|
|
//
|
|
// If mSavedTables does not exists yet - allocate it
|
|
//
|
|
if (mSavedTables == NULL) {
|
|
//DBG(" Allocaing mSavedTables");
|
|
mSavedTablesEntries = SAVED_TABLES_ALLOC_ENTRIES;
|
|
mSavedTablesNum = 0;
|
|
mSavedTables = (__typeof__(mSavedTables))AllocateZeroPool(sizeof(*mSavedTables) * mSavedTablesEntries);
|
|
if (mSavedTables == NULL) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If TableEntry is not in mSavedTables - add it
|
|
//
|
|
//DBG(" MarkTableAsSaved %llx", TableEntry);
|
|
if (IsTableSaved(TableEntry)) {
|
|
// already saved
|
|
//DBG(" - already saved\n");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If mSavedTables is full - extend it
|
|
//
|
|
if (mSavedTablesNum + 1 >= mSavedTablesEntries) {
|
|
// not enough space
|
|
//DBG(" - extending mSavedTables from %d", mSavedTablesEntries);
|
|
mSavedTables = (__typeof__(mSavedTables))ReallocatePool(
|
|
sizeof(*mSavedTables) * mSavedTablesEntries,
|
|
sizeof(*mSavedTables) * (mSavedTablesEntries + SAVED_TABLES_ALLOC_ENTRIES),
|
|
mSavedTables
|
|
);
|
|
if (mSavedTables == NULL) {
|
|
return;
|
|
}
|
|
mSavedTablesEntries = mSavedTablesEntries + SAVED_TABLES_ALLOC_ENTRIES;
|
|
//DBG(" to %d", mSavedTablesEntries);
|
|
}
|
|
|
|
//
|
|
// Add TableEntry to mSavedTables
|
|
//
|
|
mSavedTables[mSavedTablesNum] = TableEntry;
|
|
//DBG(" - added to index %d\n", mSavedTablesNum);
|
|
mSavedTablesNum++;
|
|
}
|
|
|
|
#define AML_OP_NAME 0x08
|
|
#define AML_OP_PACKAGE 0x12
|
|
|
|
STATIC CHAR8 NameSSDT[] = {AML_OP_NAME, 'S', 'S', 'D', 'T', AML_OP_PACKAGE};
|
|
STATIC CHAR8 NameCSDT[] = {AML_OP_NAME, 'C', 'S', 'D', 'T', AML_OP_PACKAGE};
|
|
STATIC CHAR8 NameTSDT[] = {AML_OP_NAME, 'T', 'S', 'D', 'T', AML_OP_PACKAGE};
|
|
|
|
// OperationRegion (SSDT, SystemMemory, 0xDF5DAC18, 0x038C)
|
|
STATIC UINT8 NameSSDT2[] = {0x80, 0x53, 0x53, 0x44, 0x54};
|
|
// OperationRegion (CSDT, SystemMemory, 0xDF5DBE18, 0x84)
|
|
STATIC UINT8 NameCSDT2[] = {0x80, 0x43, 0x53, 0x44, 0x54};
|
|
|
|
//UINT32 get_size(UINT8 * An, UINT32 ); // Let borrow from FixBiosDsdt.
|
|
|
|
static XStringW GenerateFileName(CONST CHAR16* FileNamePrefix, UINTN SsdtCount, UINTN ChildCount, CHAR8 OemTableId[9])
|
|
// ChildCount == IGNORE_INDEX indicates normal SSDT
|
|
// SsdtCount == IGNORE_INDEX indicates dynamic SSDT in DSDT
|
|
// otherwise is child SSDT from normal SSDT
|
|
{
|
|
XStringW FileName;
|
|
CHAR8 Suffix[10]; // "-" + OemTableId + NUL
|
|
if (gSettings.ACPI.SSDT.NoOemTableId || 0 == OemTableId[0]) {
|
|
Suffix[0] = 0;
|
|
} else {
|
|
Suffix[0] = '-';
|
|
CopyMem(Suffix+1, OemTableId, 9);
|
|
}
|
|
if (IGNORE_INDEX == ChildCount) {
|
|
// normal SSDT
|
|
FileName = SWPrintf("%lsSSDT-%llu%s.aml", FileNamePrefix, SsdtCount, Suffix);
|
|
} else if (IGNORE_INDEX == SsdtCount) {
|
|
// dynamic SSDT in DSDT
|
|
FileName = SWPrintf("%lsSSDT-xDSDT_%llu%s.aml", FileNamePrefix, ChildCount, Suffix);
|
|
} else {
|
|
// dynamic SSDT in static SSDT
|
|
FileName = SWPrintf("%lsSSDT-x%llu_%llu%s.aml", FileNamePrefix, SsdtCount, ChildCount, Suffix);
|
|
}
|
|
return FileName;
|
|
}
|
|
|
|
void DumpChildSsdt(EFI_ACPI_DESCRIPTION_HEADER *TableEntry, CONST CHAR16 *DirName, CONST CHAR16 *FileNamePrefix, UINTN SsdtCount)
|
|
{
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
INTN j, k, pacLen, pacCount;
|
|
CHAR8 Signature[5];
|
|
CHAR8 OemTableId[9];
|
|
UINTN adr, len;
|
|
UINT8 *Entry;
|
|
UINT8 *End;
|
|
UINT8 *pacBody;
|
|
INTN ChildCount = 0;
|
|
|
|
if (gSettings.ACPI.SSDT.NoDynamicExtract) {
|
|
return;
|
|
}
|
|
|
|
Entry = (UINT8*)TableEntry; //first entry is parent SSDT
|
|
End = Entry + TableEntry->Length;
|
|
while (Entry < End) {
|
|
|
|
if ((CompareMem(Entry, NameSSDT, sizeof (NameSSDT)) == 0) ||
|
|
(CompareMem(Entry, NameCSDT, sizeof (NameCSDT)) == 0) ||
|
|
(CompareMem(Entry, NameTSDT, sizeof (NameTSDT)) == 0)) {
|
|
pacLen = get_size(Entry, sizeof (NameSSDT));
|
|
|
|
pacBody = Entry + sizeof (NameSSDT) + (pacLen > 63 ? 2 : 1); // Our packages are not huge
|
|
pacCount = *pacBody++;
|
|
|
|
if (pacCount > 0 && pacCount % 3 == 0) {
|
|
pacCount /= 3;
|
|
DBG(" (Found hidden SSDT %lld pcs)\n", pacCount);
|
|
|
|
while (pacCount-- > 0) {
|
|
// Skip text marker and addr type tag
|
|
pacBody += 1 + 8 + 1 + 1;
|
|
|
|
adr = ReadUnaligned32((UINT32*)(pacBody));
|
|
len = 0;
|
|
pacBody += 4;
|
|
|
|
if (*pacBody == AML_CHUNK_DWORD) {
|
|
len = ReadUnaligned32((UINT32*)(pacBody + 1));
|
|
pacBody += 5;
|
|
} else if (*pacBody == AML_CHUNK_WORD) {
|
|
len = ReadUnaligned16((UINT16*)(pacBody + 1));
|
|
pacBody += 3;
|
|
}
|
|
|
|
// Take Signature and OemId for printing
|
|
CopyMem(&Signature[0], &((EFI_ACPI_DESCRIPTION_HEADER *)adr)->Signature, 4);
|
|
Signature[4] = 0;
|
|
CopyMem(&OemTableId[0], &((EFI_ACPI_DESCRIPTION_HEADER *)adr)->OemTableId, 8);
|
|
OemTableId[8] = 0;
|
|
stripTrailingSpaces(OemTableId);
|
|
DBG(" * %llu: '%s', '%s', Rev: %d, Len: %d ", adr, Signature, OemTableId,
|
|
((EFI_ACPI_DESCRIPTION_HEADER *)adr)->Revision, ((EFI_ACPI_DESCRIPTION_HEADER *)adr)->Length);
|
|
for (k = 0; k < 16; k++) {
|
|
DBG("%02hhX ", ((UINT8*)adr)[k]);
|
|
}
|
|
if ((AsciiStrCmp(Signature, "SSDT") == 0) && (len < 0x20000) && DirName != NULL && !IsTableSaved((void*)adr)) {
|
|
XStringW FileName = GenerateFileName(FileNamePrefix, SsdtCount, ChildCount, OemTableId);
|
|
len = ((UINT16*)adr)[2];
|
|
DBG("Internal length = %llu", len);
|
|
Status = SaveBufferToDisk((void*)adr, len, DirName, FileName.wc_str());
|
|
if (!EFI_ERROR(Status)) {
|
|
DBG(" -> %ls", FileName.wc_str());
|
|
MarkTableAsSaved((void*)adr);
|
|
ChildCount++;
|
|
} else {
|
|
DBG(" -> %s", efiStrError(Status));
|
|
}
|
|
}
|
|
DBG("\n");
|
|
}
|
|
}
|
|
Entry += sizeof (NameSSDT) + pacLen;
|
|
} else if (CompareMem(Entry, NameSSDT2, 5) == 0 ||
|
|
CompareMem(Entry, NameCSDT2, 5) == 0) {
|
|
|
|
adr = ReadUnaligned32((UINT32*)(Entry + 7));
|
|
len = 0;
|
|
j = *(Entry + 11);
|
|
if (j == 0x0b) {
|
|
len = ReadUnaligned16((UINT16*)(Entry + 12));
|
|
} else if (j == 0x0a) {
|
|
len = *(Entry + 12);
|
|
} else {
|
|
//not a number so skip for security
|
|
Entry += 5;
|
|
continue;
|
|
}
|
|
|
|
if (len > 0) {
|
|
// Take Signature and OemId for printing
|
|
CopyMem(&Signature, &((EFI_ACPI_DESCRIPTION_HEADER *)adr)->Signature, 4);
|
|
Signature[4] = 0;
|
|
CopyMem(&OemTableId, &((EFI_ACPI_DESCRIPTION_HEADER *)adr)->OemTableId, 8);
|
|
OemTableId[8] = 0;
|
|
stripTrailingSpaces(OemTableId);
|
|
DBG(" * %llu: '%s', '%s', Rev: %d, Len: %d ", adr, Signature, OemTableId,
|
|
((EFI_ACPI_DESCRIPTION_HEADER *)adr)->Revision, ((EFI_ACPI_DESCRIPTION_HEADER *)adr)->Length);
|
|
for(k=0; k<16; k++){
|
|
DBG("%02hhX ", ((UINT8*)adr)[k]);
|
|
}
|
|
if ((AsciiStrCmp(Signature, "SSDT") == 0) && (len < 0x20000) && DirName != NULL && !IsTableSaved((void*)adr)) {
|
|
XStringW FileName = GenerateFileName(FileNamePrefix, SsdtCount, ChildCount, OemTableId);
|
|
Status = SaveBufferToDisk((void*)adr, len, DirName, FileName.wc_str());
|
|
if (!EFI_ERROR(Status)) {
|
|
DBG(" -> %ls", FileName.wc_str());
|
|
MarkTableAsSaved((void*)adr);
|
|
ChildCount++;
|
|
} else {
|
|
DBG(" -> %s", efiStrError(Status));
|
|
}
|
|
}
|
|
DBG("\n");
|
|
}
|
|
Entry += 5;
|
|
} else {
|
|
Entry++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Saves Table to disk as DirName\\FileName (DirName != NULL)
|
|
* or just prints basic table data to log (DirName == NULL).
|
|
*/
|
|
EFI_STATUS DumpTable(EFI_ACPI_DESCRIPTION_HEADER *TableEntry, CONST CHAR8 *CheckSignature, CONST CHAR16 *DirName, const XStringW& FileName, CONST CHAR16 *FileNamePrefix, INTN *SsdtCount)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR8 Signature[5];
|
|
CHAR8 OemTableId[9];
|
|
|
|
// Take Signature and OemId for printing
|
|
CopyMem(&Signature[0], &TableEntry->Signature, 4);
|
|
Signature[4] = 0;
|
|
CopyMem(&OemTableId[0], &TableEntry->OemTableId, 8);
|
|
OemTableId[8] = 0;
|
|
stripTrailingSpaces(OemTableId);
|
|
|
|
DBG(" %llx: '%s', '%s', Rev: %d, Len: %d", (uintptr_t)TableEntry, Signature, OemTableId, TableEntry->Revision, TableEntry->Length);
|
|
|
|
//
|
|
// Additional checks
|
|
//
|
|
if (CheckSignature != NULL && AsciiStrCmp(Signature, CheckSignature) != 0) {
|
|
DBG(" -> invalid signature, expecting %s\n", CheckSignature);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
// XSDT checks
|
|
if (TableEntry->Signature == EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
|
|
if (TableEntry->Length < sizeof(XSDT_TABLE)) {
|
|
DBG(" -> invalid length\n");
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
// RSDT checks
|
|
if (TableEntry->Signature == EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
|
|
if (TableEntry->Length < sizeof(RSDT_TABLE)) {
|
|
DBG(" -> invalid length\n");
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
// FADT/FACP checks
|
|
if (TableEntry->Signature == EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
|
|
if (TableEntry->Length < sizeof(EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE)) {
|
|
DBG(" -> invalid length\n");
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
// DSDT checks
|
|
if (TableEntry->Signature == EFI_ACPI_1_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
|
|
if (TableEntry->Length < sizeof(EFI_ACPI_DESCRIPTION_HEADER)) {
|
|
DBG(" -> invalid length\n");
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
// SSDT checks
|
|
if (TableEntry->Signature == EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
|
|
if (TableEntry->Length < sizeof(EFI_ACPI_DESCRIPTION_HEADER)) {
|
|
DBG(" -> invalid length\n");
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if (DirName == NULL || IsTableSaved(TableEntry)) {
|
|
// just debug log dump
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (FileNamePrefix == NULL) {
|
|
FileNamePrefix = L"";
|
|
}
|
|
|
|
XStringW ReleaseFileName = FileName;
|
|
if (ReleaseFileName.isEmpty()) {
|
|
// take the name from the signature
|
|
if (TableEntry->Signature == EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE && SsdtCount != NULL) {
|
|
ReleaseFileName = GenerateFileName(FileNamePrefix, *SsdtCount, IGNORE_INDEX, OemTableId);
|
|
} else {
|
|
ReleaseFileName = SWPrintf("%ls%s.aml", FileNamePrefix, Signature);
|
|
}
|
|
}
|
|
DBG(" -> %ls", ReleaseFileName.wc_str());
|
|
|
|
// Save it
|
|
Status = SaveBufferToDisk(TableEntry, TableEntry->Length, DirName, ReleaseFileName.wc_str());
|
|
MarkTableAsSaved(TableEntry);
|
|
|
|
if (TableEntry->Signature == EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE && SsdtCount != NULL) {
|
|
DumpChildSsdt(TableEntry, DirName, FileNamePrefix, *SsdtCount);
|
|
*SsdtCount += 1;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Saves to disk (DirName != NULL) or prints to log (DirName == NULL) Fadt tables: Dsdt and Facs. */
|
|
EFI_STATUS DumpFadtTables(EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt, CONST CHAR16 *DirName, CONST CHAR16 *FileNamePrefix, INTN *SsdtCount)
|
|
{
|
|
EFI_ACPI_DESCRIPTION_HEADER *TableEntry;
|
|
EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
UINT64 DsdtAdr;
|
|
UINT64 FacsAdr;
|
|
CHAR8 Signature[5];
|
|
|
|
//
|
|
// if Fadt->Revision < 3 (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION), then it is Acpi 1.0
|
|
// and fields after Flags are not available
|
|
//
|
|
DBG(" (Dsdt: %X, Facs: %X", Fadt->Dsdt, Fadt->FirmwareCtrl);
|
|
// for Acpi 1.0
|
|
DsdtAdr = Fadt->Dsdt;
|
|
FacsAdr = Fadt->FirmwareCtrl;
|
|
|
|
if (Fadt->Header.Revision >= EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
|
|
// Acpi 2.0 or up
|
|
// may have it in XDsdt or XFirmwareCtrl
|
|
DBG(", XDsdt: %llx, XFacs: %llx", Fadt->XDsdt, Fadt->XFirmwareCtrl);
|
|
if (Fadt->XDsdt != 0) {
|
|
DsdtAdr = Fadt->XDsdt;
|
|
}
|
|
if (Fadt->XFirmwareCtrl != 0) {
|
|
FacsAdr = Fadt->XFirmwareCtrl;
|
|
}
|
|
}
|
|
DBG(")\n");
|
|
|
|
//
|
|
// Save Dsdt
|
|
//
|
|
if (DsdtAdr != 0) {
|
|
DBG(" ");
|
|
TableEntry = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)DsdtAdr;
|
|
Status = DumpTable(TableEntry, "DSDT", DirName, L""_XSW, FileNamePrefix, NULL);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG(" - %s\n", efiStrError(Status));
|
|
return Status;
|
|
}
|
|
DBG("\n");
|
|
DumpChildSsdt(TableEntry, DirName, FileNamePrefix, IGNORE_INDEX);
|
|
}
|
|
//
|
|
// Save Facs
|
|
//
|
|
if (FacsAdr != 0) {
|
|
// Taking it as structure from Acpi 2.0 just to get Version (it's reserved field in Acpi 1.0 and == 0)
|
|
Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE*)(UINTN)FacsAdr;
|
|
// Take Signature for printing
|
|
CopyMem(&Signature[0], &Facs->Signature, 4);
|
|
Signature[4] = 0;
|
|
DBG(" %llx: '%s', Ver: %d, Len: %d", (uintptr_t)Facs, Signature, Facs->Version, Facs->Length);
|
|
|
|
// FACS checks
|
|
if (Facs->Signature != EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) {
|
|
DBG(" -> invalid signature, expecting FACS\n");
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (Facs->Length < sizeof(EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) {
|
|
DBG(" -> invalid length\n");
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (DirName != NULL && !IsTableSaved(Facs)) {
|
|
XStringW FileName = SWPrintf("%lsFACS.aml", FileNamePrefix);
|
|
DBG(" -> %ls", FileName.wc_str());
|
|
Status = SaveBufferToDisk(Facs, Facs->Length, DirName, FileName.wc_str());
|
|
MarkTableAsSaved(Facs);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG(" - %s\n", efiStrError(Status));
|
|
return Status;
|
|
}
|
|
}
|
|
DBG("\n");
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE* GetFadt()
|
|
{
|
|
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *RsdPtr;
|
|
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer = NULL;
|
|
|
|
// EFI_STATUS Status;
|
|
|
|
RsdPtr = (__typeof__(RsdPtr))FindAcpiRsdPtr();
|
|
if (RsdPtr == NULL) {
|
|
/*Status = */EfiGetSystemConfigurationTable (&gEfiAcpi20TableGuid, (void **)&RsdPtr);
|
|
if (RsdPtr == NULL) {
|
|
/*Status = */EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (void **)&RsdPtr);
|
|
if (RsdPtr == NULL) {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
Rsdt = (RSDT_TABLE*)(UINTN)(RsdPtr->RsdtAddress);
|
|
if (RsdPtr->Revision > 0) {
|
|
if (Rsdt == NULL || Rsdt->Header.Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
|
|
Xsdt = (XSDT_TABLE *)(UINTN)(RsdPtr->XsdtAddress);
|
|
}
|
|
}
|
|
if (Rsdt == NULL && Xsdt == NULL) {
|
|
//
|
|
// Search Acpi 2.0 or newer in UEFI Sys.Tables
|
|
//
|
|
RsdPtr = NULL;
|
|
/*Status = */EfiGetSystemConfigurationTable (&gEfiAcpi20TableGuid, (void**)&RsdPtr);
|
|
if (RsdPtr != NULL) {
|
|
DBG("Found UEFI Acpi 2.0 RSDP at %llx\n", (uintptr_t)RsdPtr);
|
|
Rsdt = (RSDT_TABLE*)(UINTN)(RsdPtr->RsdtAddress);
|
|
if (RsdPtr->Revision > 0) {
|
|
if (Rsdt == NULL || Rsdt->Header.Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
|
|
Xsdt = (XSDT_TABLE *)(UINTN)(RsdPtr->XsdtAddress);
|
|
}
|
|
}
|
|
}
|
|
if (Rsdt == NULL && Xsdt == NULL) {
|
|
DBG("No RSDT or XSDT found!\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (Rsdt) {
|
|
FadtPointer = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE*)(UINTN)(Rsdt->Entry);
|
|
}
|
|
if (Xsdt) {
|
|
//overwrite previous find as xsdt priority
|
|
FadtPointer = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE*)(UINTN)(Xsdt->Entry);
|
|
}
|
|
return FadtPointer;
|
|
}
|
|
|
|
/** Saves to disk (DirName != NULL)
|
|
* or prints to debug log (DirName == NULL)
|
|
* ACPI tables given by RsdPtr.
|
|
* Takes tables from Xsdt if present or from Rsdt if Xsdt is not present.
|
|
*/
|
|
void DumpTables(void *RsdPtrVoid, CONST CHAR16 *DirName)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Length;
|
|
INTN SsdtCount;
|
|
CONST CHAR16 *FileNamePrefix;
|
|
//
|
|
// RSDP
|
|
// Take it as Acpi 2.0, but take care that if RsdPtr->Revision == 0
|
|
// then it is actually Acpi 1.0 and fields after RsdtAddress (like XsdtAddress)
|
|
// are not available
|
|
//
|
|
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER* RsdPtr = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER*)RsdPtrVoid;
|
|
if (DirName != NULL) {
|
|
DBG("Saving ACPI tables from RSDP %llx to %ls ...\n", (uintptr_t)RsdPtr, DirName);
|
|
} else {
|
|
DBG("Printing ACPI tables from RSDP %llx ...\n", (uintptr_t)RsdPtr);
|
|
}
|
|
|
|
if (RsdPtr->Signature != EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE) {
|
|
DBG(" RsdPrt at %llx has invaid signature 0x%llx - exiting.\n", (uintptr_t)RsdPtr, RsdPtr->Signature);
|
|
return;
|
|
}
|
|
|
|
// Take Signature for printing
|
|
CHAR8 Signature[9];
|
|
CopyMem(&Signature[0], &RsdPtr->Signature, 8);
|
|
Signature[8] = 0;
|
|
|
|
// Take Rsdt and Xsdt
|
|
Rsdt = NULL;
|
|
Xsdt = NULL;
|
|
|
|
DBG(" %llx: '%s', Rev: %d", (uintptr_t)RsdPtr, Signature, RsdPtr->Revision);
|
|
if (RsdPtr->Revision == 0) {
|
|
// Acpi 1.0
|
|
Length = sizeof(EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
|
|
DBG(" (Acpi 1.0)");
|
|
} else {
|
|
// Acpi 2.0 or newer
|
|
Length = RsdPtr->Length;
|
|
DBG(" (Acpi 2.0 or newer)");
|
|
}
|
|
DBG(", Len: %llu", Length);
|
|
|
|
//
|
|
// Save RsdPtr
|
|
//
|
|
if (DirName != NULL && !IsTableSaved(RsdPtr)) {
|
|
DBG(" -> RSDP.aml");
|
|
Status = SaveBufferToDisk(RsdPtr, Length, DirName, L"RSDP.aml");
|
|
MarkTableAsSaved(RsdPtr);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG(" - %s\n", efiStrError(Status));
|
|
return;
|
|
}
|
|
}
|
|
DBG("\n");
|
|
|
|
if (RsdPtr->Revision == 0) {
|
|
// Acpi 1.0 - no Xsdt
|
|
Rsdt = (RSDT_TABLE*)(UINTN)(RsdPtr->RsdtAddress);
|
|
DBG(" (Rsdt: %llx)\n", (UINTN)Rsdt);
|
|
} else {
|
|
// Acpi 2.0 or newer - may have Xsdt and/or Rsdt
|
|
Rsdt = (RSDT_TABLE*)(UINTN)(RsdPtr->RsdtAddress);
|
|
Xsdt = (XSDT_TABLE *)(UINTN)(RsdPtr->XsdtAddress);
|
|
DBG(" (Xsdt: %llx, Rsdt: %llx)\n", (UINTN)Xsdt, (UINTN)Rsdt);
|
|
}
|
|
|
|
if (Rsdt == NULL && Xsdt == NULL) {
|
|
DBG(" No Rsdt and Xsdt - exiting.\n");
|
|
return;
|
|
}
|
|
|
|
FileNamePrefix = L"";
|
|
//
|
|
// Save Xsdt
|
|
//
|
|
if (Xsdt != NULL) {
|
|
DBG(" ");
|
|
Status = DumpTable((EFI_ACPI_DESCRIPTION_HEADER *)Xsdt, "XSDT", DirName, L"XSDT.aml"_XSW, FileNamePrefix, NULL);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG(" - %s", efiStrError(Status));
|
|
Xsdt = NULL;
|
|
}
|
|
DBG("\n");
|
|
}
|
|
//
|
|
// Save Rsdt
|
|
//
|
|
if (Rsdt != NULL) {
|
|
DBG(" ");
|
|
Status = DumpTable((EFI_ACPI_DESCRIPTION_HEADER *)Rsdt, "RSDT", DirName, L"RSDT.aml"_XSW, FileNamePrefix, NULL);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG(" - %s", efiStrError(Status));
|
|
Rsdt = NULL;
|
|
}
|
|
DBG("\n");
|
|
}
|
|
//
|
|
// Check once more since they might be invalid
|
|
//
|
|
if (Rsdt == NULL && Xsdt == NULL) {
|
|
DBG(" No Rsdt and Xsdt - exiting.\n");
|
|
return;
|
|
}
|
|
if (Xsdt) {
|
|
UINT64 *Ptr, *EndPtr;
|
|
UINT32 Count = XsdtTableCount();
|
|
DBG(" Tables in Xsdt: %d\n", Count);
|
|
if (Count > 100) Count = 100; //it's enough
|
|
|
|
Ptr = XsdtEntryPtrFromIndex(0);
|
|
EndPtr = XsdtEntryPtrFromIndex(Count);
|
|
SsdtCount = 0;
|
|
for (; Ptr < EndPtr; Ptr++) {
|
|
DBG(" %d.", IndexFromXsdtEntryPtr(Ptr));
|
|
EFI_ACPI_DESCRIPTION_HEADER* Table = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)ReadUnaligned64(Ptr);
|
|
if (!Table) {
|
|
DBG(" = 0\n");
|
|
// skip NULL entry
|
|
continue;
|
|
}
|
|
if (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE == Table->Signature) {
|
|
// Fadt - save Dsdt and Facs
|
|
Status = DumpTable(Table, NULL, DirName, L""_XSW, FileNamePrefix, &SsdtCount);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG(" - %s\n", efiStrError(Status));
|
|
return;
|
|
}
|
|
DBG("\n");
|
|
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE* Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE*)Table;
|
|
Status = DumpFadtTables(Fadt, DirName, FileNamePrefix, &SsdtCount);
|
|
if (EFI_ERROR(Status)) {
|
|
return;
|
|
}
|
|
} else {
|
|
Status = DumpTable(Table, NULL, DirName, L""_XSW, FileNamePrefix, &SsdtCount);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG(" - %s\n", efiStrError(Status));
|
|
return;
|
|
}
|
|
DBG("\n");
|
|
}
|
|
}
|
|
} // if Xsdt
|
|
|
|
if (Rsdt) {
|
|
UINT32 *Ptr, *EndPtr;
|
|
// additional Rsdt tables which are not present in Xsdt will have "RSDT-" prefix, like RSDT-FACS.aml
|
|
FileNamePrefix = L"RSDT-";
|
|
// Take tables from Rsdt
|
|
// if saved from Xsdt already, then just print debug
|
|
UINT32 Count = RsdtTableCount();
|
|
DBG(" Tables in Rsdt: %d\n", Count);
|
|
if (Count > 100) Count = 100; //it's enough
|
|
Ptr = RsdtEntryPtrFromIndex(0);
|
|
EndPtr = RsdtEntryPtrFromIndex(Count);
|
|
for (; Ptr < EndPtr; Ptr++) {
|
|
DBG(" %d.", IndexFromRsdtEntryPtr(Ptr));
|
|
EFI_ACPI_DESCRIPTION_HEADER* Table = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)*Ptr;
|
|
if (!Table) {
|
|
DBG(" = 0\n");
|
|
// skip NULL entry
|
|
continue;
|
|
}
|
|
if (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE == Table->Signature) {
|
|
// Fadt - save Dsdt and Facs
|
|
Status = DumpTable(Table, NULL, DirName, L""_XSW, FileNamePrefix, &SsdtCount);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG(" - %s\n", efiStrError(Status));
|
|
return;
|
|
}
|
|
DBG("\n");
|
|
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE* Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE*)Table;
|
|
Status = DumpFadtTables(Fadt, DirName, FileNamePrefix, &SsdtCount);
|
|
if (EFI_ERROR(Status)) {
|
|
return;
|
|
}
|
|
} else {
|
|
Status = DumpTable(Table, NULL, DirName, L""_XSW, FileNamePrefix, &SsdtCount);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG(" - %s\n", efiStrError(Status));
|
|
return;
|
|
}
|
|
DBG("\n");
|
|
}
|
|
}
|
|
} // if Rsdt
|
|
}
|
|
|
|
/** Saves OEM ACPI tables to disk.
|
|
* Searches BIOS, then UEFI Sys.Tables for Acpi 2.0 or newer tables, then for Acpi 1.0 tables
|
|
* CloverEFI:
|
|
* - saves first one found, dump others to log
|
|
* UEFI:
|
|
* - saves first one found in UEFI Sys.Tables, dump others to log
|
|
*
|
|
* Dumping of other tables to log can be removed if it turns out that there is no value in doing it.
|
|
*/
|
|
void SaveOemTables()
|
|
{
|
|
// EFI_STATUS Status;
|
|
void *RsdPtr;
|
|
XStringW AcpiOriginPath = L"ACPI\\origin"_XSW;
|
|
BOOLEAN Saved = FALSE;
|
|
CHAR8 *MemLogStart;
|
|
UINTN MemLogStartLen;
|
|
|
|
MemLogStartLen = GetMemLogLen();
|
|
MemLogStart = GetMemLogBuffer() + MemLogStartLen;
|
|
//
|
|
// Search in BIOS
|
|
// CloverEFI - Save
|
|
// UEFI - just print to log
|
|
//
|
|
// RsdPtr = NULL;
|
|
RsdPtr = FindAcpiRsdPtr();
|
|
if (RsdPtr != NULL) {
|
|
DBG("Found BIOS RSDP at %llx\n", (UINTN)RsdPtr);
|
|
if (gFirmwareClover) {
|
|
// Save it
|
|
DumpTables(RsdPtr, AcpiOriginPath.wc_str());
|
|
Saved = TRUE;
|
|
} else {
|
|
// just print to log
|
|
DumpTables(RsdPtr, NULL);
|
|
}
|
|
}
|
|
//
|
|
// Search Acpi 2.0 or newer in UEFI Sys.Tables
|
|
//
|
|
RsdPtr = NULL;
|
|
/*Status = */EfiGetSystemConfigurationTable (&gEfiAcpi20TableGuid, &RsdPtr);
|
|
if (RsdPtr != NULL) { //it may be EFI_SUCCESS but null pointer
|
|
DBG("Found UEFI Acpi 2.0 RSDP at %llx\n", (UINTN)RsdPtr);
|
|
// if tables already saved, then just print to log
|
|
DumpTables(RsdPtr, Saved ? NULL : AcpiOriginPath.wc_str());
|
|
Saved = TRUE;
|
|
}
|
|
//
|
|
// Then search Acpi 1.0 UEFI Sys.Tables
|
|
//
|
|
RsdPtr = NULL;
|
|
/*Status = */EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, &RsdPtr);
|
|
if (RsdPtr != NULL) {
|
|
DBG("Found UEFI Acpi 1.0 RSDP at %llx\n", (UINTN)RsdPtr);
|
|
// if tables already saved, then just print to log
|
|
DumpTables(RsdPtr, Saved ? NULL : AcpiOriginPath.wc_str());
|
|
// Saved = TRUE;
|
|
}
|
|
SaveBufferToDisk(MemLogStart, GetMemLogLen() - MemLogStartLen, AcpiOriginPath.wc_str(), L"DumpLog.txt");
|
|
FreePool(mSavedTables);
|
|
}
|
|
|
|
void SaveOemDsdt(BOOLEAN FullPatch)
|
|
{
|
|
EFI_STATUS Status = EFI_NOT_FOUND;
|
|
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer = NULL;
|
|
EFI_PHYSICAL_ADDRESS dsdt = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
|
|
UINTN Pages;
|
|
UINT8 *buffer = NULL;
|
|
UINTN DsdtLen = 0;
|
|
XStringW OriginDsdt = SWPrintf("ACPI\\origin\\DSDT.aml");
|
|
XStringW OriginDsdtFixed = SWPrintf("ACPI\\origin\\DSDT-%x.aml", gSettings.ACPI.DSDT.FixDsdt);
|
|
// constexpr LStringW PathPatched = L"\\EFI\\CL OVER\\ACPI\\patched";
|
|
// XStringW PathDsdt;
|
|
// XStringW AcpiOemPath = SWPrintf("ACPI\\patched");
|
|
|
|
// PathDsdt.SWPrintf("\\%ls", gSettings.ACPI.DSDT.FixDsdt.wc_str());
|
|
|
|
if (FileExists(selfOem.getConfigDir(), SWPrintf("ACPI\\patched\\%ls", gSettings.ACPI.DSDT.DsdtName.wc_str()))) {
|
|
DBG("SaveOemDsdt: DSDT found in Clover volume OEM folder: \\%ls\\ACPI\\patched\\%ls\n", selfOem.getConfigDirFullPath().wc_str(), gSettings.ACPI.DSDT.DsdtName.wc_str());
|
|
Status = egLoadFile(&selfOem.getConfigDir(), SWPrintf("ACPI\\patched\\%ls", gSettings.ACPI.DSDT.DsdtName.wc_str()).wc_str(), &buffer, &DsdtLen);
|
|
}
|
|
|
|
// Jief : Do not write outside OemPath
|
|
// if (EFI_ERROR(Status) && FileExists(&self.getSelfRootDir(), SWPrintf("%ls%ls", PathPatched.wc_str(), PathDsdt.wc_str()))) {
|
|
// DBG("SaveOemDsdt: DSDT found in Clover volume common folder: %ls%ls\n", PathPatched.wc_str(), PathDsdt.wc_str());
|
|
// Status = egLoadFile(&self.getSelfRootDir(), SWPrintf("%ls%ls", PathPatched.wc_str(), PathDsdt.wc_str()).wc_str(), &buffer, &DsdtLen);
|
|
// }
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
FadtPointer = GetFadt();
|
|
if (FadtPointer == NULL) {
|
|
DBG("Cannot found FADT in BIOS or in UEFI!\n"); //really?!
|
|
return;
|
|
}
|
|
BiosDsdt = FadtPointer->Dsdt;
|
|
if (FadtPointer->Header.Revision >= EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION &&
|
|
FadtPointer->XDsdt != 0) {
|
|
BiosDsdt = FadtPointer->XDsdt;
|
|
}
|
|
buffer = (UINT8*)(UINTN)BiosDsdt;
|
|
}
|
|
|
|
if (!buffer) {
|
|
DBG("Cannot found DSDT in BIOS or in files!\n");
|
|
return;
|
|
}
|
|
|
|
DsdtLen = ((EFI_ACPI_DESCRIPTION_HEADER*)buffer)->Length;
|
|
Pages = EFI_SIZE_TO_PAGES(DsdtLen + DsdtLen / 8); // take some extra space for patches
|
|
Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiBootServicesData,
|
|
Pages,
|
|
&dsdt
|
|
);
|
|
//if success insert dsdt pointer into ACPI tables
|
|
if(!EFI_ERROR(Status))
|
|
{
|
|
CopyMem((void*)(UINTN)dsdt, buffer, DsdtLen);
|
|
buffer = (UINT8*)(UINTN)dsdt;
|
|
if (FullPatch) {
|
|
FixBiosDsdt(buffer, FadtPointer, NullXString8);
|
|
DsdtLen = ((EFI_ACPI_DESCRIPTION_HEADER*)buffer)->Length;
|
|
OriginDsdt = OriginDsdtFixed;
|
|
}
|
|
Status = egSaveFile(&selfOem.getConfigDir(), OriginDsdt.wc_str(), buffer, DsdtLen);
|
|
// Jief : do not write outside of OemDir
|
|
// if (EFI_ERROR(Status)) {
|
|
// Status = egSaveFile(NULL, OriginDsdt.wc_str(), buffer, DsdtLen);
|
|
// }
|
|
if (!EFI_ERROR(Status)) {
|
|
MsgLog("DSDT saved to %ls\\%ls\n", selfOem.getConfigDirFullPath().wc_str(), OriginDsdt.wc_str());
|
|
} else {
|
|
MsgLog("Saving DSDT to %ls\\%ls failed - %s\n", selfOem.getConfigDirFullPath().wc_str(), OriginDsdt.wc_str(), efiStrError(Status));
|
|
}
|
|
gBS->FreePages(dsdt, Pages);
|
|
}
|
|
}
|
|
|
|
BOOLEAN LoadPatchedAML(const EFI_FILE& dir, const XStringW& acpiOemPath, CONST CHAR16* PartName, UINTN Pass)
|
|
{
|
|
// pass1 prefilter based on file names (optimization that avoids loading same files twice)
|
|
UINTN Index = IGNORE_INDEX;
|
|
if (AUTOMERGE_PASS1 == Pass) {
|
|
Index = IndexFromFileName(PartName);
|
|
// gSettings.ACPI.AutoMerge always true in this case
|
|
// file names such as: ECDT.aml, SSDT-0.aml, SSDT-1-CpuPm.aml, attempt merge on pass1
|
|
// others: no attempt for merge
|
|
// special case for SSDT.aml: no attempt to merge
|
|
if (0 == StriCmp(PartName, L"SSDT.aml") || (8 != StrLen(PartName) && IGNORE_INDEX == Index)) {
|
|
DBG("ignore on pass 1\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
UINT8 *buffer = NULL;
|
|
UINTN bufferLen = 0;
|
|
EFI_STATUS Status = egLoadFile(&dir, SWPrintf("%ls\\%ls", acpiOemPath.wc_str(), PartName).wc_str(), &buffer, &bufferLen);
|
|
if (!EFI_ERROR(Status)) {
|
|
if (buffer) {
|
|
EFI_ACPI_DESCRIPTION_HEADER* TableHeader = (EFI_ACPI_DESCRIPTION_HEADER*)buffer;
|
|
if (TableHeader->Length > 500 * Kilo) {
|
|
DBG("wrong table\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
DBG("size=%lld ", (UINT64)bufferLen);
|
|
if (!gSettings.ACPI.AutoMerge) {
|
|
// Note: with AutoMerge=false, Pass is only AUTOMERGE_PASS2 here
|
|
Status = InsertTable(buffer, bufferLen);
|
|
} else {
|
|
Status = ReplaceOrInsertTable(buffer, bufferLen, Index, Pass);
|
|
}
|
|
FreePool(buffer);
|
|
}
|
|
DBG("... %s\n", efiStrError(Status));
|
|
return !EFI_ERROR(Status);
|
|
}
|
|
|
|
#define BVALUE_ATTEMPTED 2 // special value for MenuItem.BValue to avoid excessive log output
|
|
|
|
void LoadAllPatchedAML(const XStringW& acpiPathUnderOem, UINTN Pass)
|
|
{
|
|
if (!gSettings.ACPI.AutoMerge && AUTOMERGE_PASS1 == Pass) {
|
|
// nothing to do in this case, since AutoMerge=false -> no tables ever merged
|
|
return;
|
|
}
|
|
if ( ACPIPatchedAML.notEmpty() ) {
|
|
DbgHeader("ACPIPatchedAML");
|
|
if (gSettings.ACPI.AutoMerge) {
|
|
DBG("AutoMerge pass %llu\n", Pass);
|
|
}
|
|
//DBG("Start: Processing Patched AML(s): ");
|
|
if (gSettings.ACPI.SortedACPI.size()) {
|
|
UINTN Index;
|
|
DBG("Sorted\n");
|
|
for (Index = 0; Index < gSettings.ACPI.SortedACPI.size(); Index++) {
|
|
size_t idx;
|
|
for ( idx = 0 ; idx < ACPIPatchedAML.size() ; ++idx) {
|
|
ACPI_PATCHED_AML& ACPIPatchedAMLTmp = ACPIPatchedAML[idx];
|
|
if ( ACPIPatchedAMLTmp.FileName == gSettings.ACPI.SortedACPI[Index] && ACPIPatchedAMLTmp.MenuItem.BValue) {
|
|
if (BVALUE_ATTEMPTED != ACPIPatchedAMLTmp.MenuItem.BValue)
|
|
DBG("Disabled: %s, skip\n", ACPIPatchedAMLTmp.FileName.c_str());
|
|
ACPIPatchedAMLTmp.MenuItem.BValue = BVALUE_ATTEMPTED;
|
|
break;
|
|
}
|
|
}
|
|
if ( idx == ACPIPatchedAML.size() ) { // NULL when not disabled
|
|
DBG("Inserting table[%llu]:%s from %ls\\%ls: ", Index, gSettings.ACPI.SortedACPI[Index].c_str(), selfOem.getConfigDirFullPath().wc_str(), acpiPathUnderOem.wc_str());
|
|
if (LoadPatchedAML(selfOem.getConfigDir(), acpiPathUnderOem, XStringW(gSettings.ACPI.SortedACPI[Index]).wc_str(), Pass)) {
|
|
// avoid inserting table again on second pass
|
|
for ( idx = 0 ; idx < ACPIPatchedAML.size() ; ++idx) {
|
|
ACPI_PATCHED_AML& temp2 = ACPIPatchedAML[idx];
|
|
if ( temp2.FileName == gSettings.ACPI.SortedACPI[Index] ) {
|
|
temp2.MenuItem.BValue = BVALUE_ATTEMPTED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
DBG("Unsorted\n");
|
|
for ( size_t idx = 0 ; idx < ACPIPatchedAML.size() ; ++idx) {
|
|
ACPI_PATCHED_AML& ACPIPatchedAMLTmp = ACPIPatchedAML[idx];
|
|
if (!ACPIPatchedAMLTmp.MenuItem.BValue) {
|
|
DBG("Inserting %s from %ls\\%ls: ", ACPIPatchedAMLTmp.FileName.c_str(), selfOem.getConfigDirFullPath().wc_str(), acpiPathUnderOem.wc_str());
|
|
if (LoadPatchedAML(selfOem.getConfigDir(), acpiPathUnderOem, XStringW(ACPIPatchedAMLTmp.FileName).wc_str(), Pass)) {
|
|
// avoid inserting table again on second pass
|
|
ACPIPatchedAMLTmp.MenuItem.BValue = BVALUE_ATTEMPTED;
|
|
}
|
|
} else {
|
|
if (BVALUE_ATTEMPTED != ACPIPatchedAMLTmp.MenuItem.BValue)
|
|
DBG("Disabled: %s, skip\n", ACPIPatchedAMLTmp.FileName.c_str());
|
|
ACPIPatchedAMLTmp.MenuItem.BValue = BVALUE_ATTEMPTED;
|
|
}
|
|
}
|
|
}
|
|
//DBG("End: Processing Patched AML(s)\n");
|
|
}
|
|
}
|
|
|
|
EFI_STATUS PatchACPI(IN REFIT_VOLUME *Volume, const MacOsVersion& OSVersion)
|
|
{
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
UINTN Index;
|
|
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *RsdPointer = NULL;
|
|
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer = NULL;
|
|
EFI_ACPI_4_0_FIXED_ACPI_DESCRIPTION_TABLE *newFadt = NULL;
|
|
// EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *Hpet = NULL;
|
|
EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs = NULL;
|
|
EFI_PHYSICAL_ADDRESS dsdt = EFI_SYSTEM_TABLE_MAX_ADDRESS; //0xFE000000;
|
|
EFI_PHYSICAL_ADDRESS BufferPtr;
|
|
SSDT_TABLE *Ssdt = NULL;
|
|
UINT8 *buffer = NULL;
|
|
UINTN bufferLen = 0;
|
|
// constexpr LStringW PathPatched = L"\\EFI\\CL OVER\\ACPI\\patched";
|
|
// XStringW PathDsdt; // = L"\\DSDT.aml";
|
|
// CHAR16* PatchedAPIC = L"\\EFI\\CL OVER\\ACPI\\origin\\APIC-p.aml";
|
|
UINT32* rf = NULL;
|
|
UINT64* xf = NULL;
|
|
UINT64 XDsdt; //save values if present
|
|
UINT64 XFirmwareCtrl;
|
|
// EFI_FILE *RootDir;
|
|
UINT32 eCntR; //, eCntX;
|
|
UINT32 *pEntryR;
|
|
CHAR8 *pEntry;
|
|
EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
|
|
// -===== APIC =====-
|
|
EFI_ACPI_DESCRIPTION_HEADER *ApicTable;
|
|
// EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *ApicHeader;
|
|
EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE *ProcLocalApic;
|
|
EFI_ACPI_2_0_LOCAL_APIC_NMI_STRUCTURE *LocalApicNMI;
|
|
// UINTN ApicLen;
|
|
UINTN ApicCPUNum;
|
|
UINT8 *SubTable;
|
|
BOOLEAN DsdtLoaded = FALSE;
|
|
BOOLEAN NeedUpdate = FALSE;
|
|
OPER_REGION *tmpRegion;
|
|
// XStringW AcpiOemPath = SWPrintf("%ls\\ACPI\\patched", OEMPath.wc_str());
|
|
|
|
DbgHeader("PatchACPI");
|
|
|
|
//try to find in SystemTable
|
|
for(Index = 0; Index < gST->NumberOfTableEntries; Index++) {
|
|
if(CompareGuid (&gST->ConfigurationTable[Index].VendorGuid, &gEfiAcpi20TableGuid)) {
|
|
// Acpi 2.0
|
|
RsdPointer = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER*)gST->ConfigurationTable[Index].VendorTable;
|
|
break;
|
|
}
|
|
else if(CompareGuid (&gST->ConfigurationTable[Index].VendorGuid, &gEfiAcpi10TableGuid)) {
|
|
// Acpi 1.0 - RSDT only
|
|
RsdPointer = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER*)gST->ConfigurationTable[Index].VendorTable;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!RsdPointer) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
Rsdt = (RSDT_TABLE*)(UINTN)RsdPointer->RsdtAddress;
|
|
// DBG("RSDT 0x%llx\n", Rsdt);
|
|
rf = ScanRSDT(EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, 0);
|
|
if(rf) {
|
|
FadtPointer = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE*)(UINTN)(*rf);
|
|
// DBG("FADT from RSDT: 0x%llx\n", FadtPointer);
|
|
}
|
|
|
|
Xsdt = NULL;
|
|
if (RsdPointer->Revision >=2 && (RsdPointer->XsdtAddress < (UINT64)(UINTN)-1)) {
|
|
Xsdt = (XSDT_TABLE*)(UINTN)RsdPointer->XsdtAddress;
|
|
// DBG("XSDT 0x%llx\n", Xsdt);
|
|
xf = ScanXSDT(EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, 0);
|
|
if(xf) {
|
|
//Slice - change priority. First Xsdt, second Rsdt
|
|
if (*xf) {
|
|
FadtPointer = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE*)(UINTN)(*xf);
|
|
// DBG("FADT from XSDT: 0x%llx\n", FadtPointer);
|
|
} else {
|
|
*xf = (UINT64)(UINTN)FadtPointer;
|
|
// DBG("reuse FADT\n"); //never happens
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!xf && Rsdt) {
|
|
DBG("Xsdt is not found! Creating new one\n");
|
|
//We should make here ACPI20 RSDP with all needed subtables based on ACPI10
|
|
BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIReclaimMemory, 1, &BufferPtr);
|
|
if(!EFI_ERROR(Status)) {
|
|
if (RsdPointer->Revision == 0) {
|
|
// Acpi 1.0 RsdPtr, but we need Acpi 2.0
|
|
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *NewRsdPointer;
|
|
DBG("RsdPointer is Acpi 1.0 - creating new one Acpi 2.0\n");
|
|
|
|
// add new pointer to the beginning of a new buffer
|
|
NewRsdPointer = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER*)(UINTN)BufferPtr;
|
|
|
|
// and Xsdt will come after it
|
|
BufferPtr += 0x30;
|
|
// DBG("::pointers %llx %llx\n", NewRsdPointer, RsdPointer);
|
|
// Signature, Checksum, OemId, Reserved/Revision, RsdtAddress
|
|
CopyMem(NewRsdPointer, RsdPointer, sizeof(EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER));
|
|
NewRsdPointer->Revision = 2;
|
|
NewRsdPointer->Length = sizeof(EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
|
|
RsdPointer = NewRsdPointer;
|
|
NeedUpdate = TRUE;
|
|
// gBS->InstallConfigurationTable(&gEfiAcpiTableGuid, RsdPointer);
|
|
// DBG("first install success\n");
|
|
// gBS->InstallConfigurationTable(&gEfiAcpi10TableGuid, RsdPointer);
|
|
DBG("RsdPointer Acpi 2.0 installed\n");
|
|
}
|
|
Xsdt = (XSDT_TABLE*)(UINTN)BufferPtr;
|
|
// DBG("XSDT = 0x%llx\n", uintptr_t(Xsdt));
|
|
Xsdt->Header.Signature = 0x54445358; //EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
|
|
eCntR = (Rsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
|
|
Xsdt->Header.Length = eCntR * sizeof(UINT64) + sizeof (EFI_ACPI_DESCRIPTION_HEADER);
|
|
Xsdt->Header.Revision = 1;
|
|
CopyMem(&Xsdt->Header.OemId, &FadtPointer->Header.OemId, 6);
|
|
// Xsdt->Header.OemTableId = Rsdt->Header.OemTableId;
|
|
CopyMem(&Xsdt->Header.OemTableId, &Rsdt->Header.OemTableId, 8);
|
|
Xsdt->Header.OemRevision = Rsdt->Header.OemRevision;
|
|
Xsdt->Header.CreatorId = Rsdt->Header.CreatorId;
|
|
Xsdt->Header.CreatorRevision = Rsdt->Header.CreatorRevision;
|
|
pEntryR = (UINT32*)(&(Rsdt->Entry));
|
|
pEntry = (CHAR8*)(&(Xsdt->Entry));
|
|
DBG("RSDT entries = %d\n", eCntR);
|
|
for (Index = 0; Index < eCntR; Index ++)
|
|
{
|
|
UINT64 *pEntryX = (UINT64 *)pEntry;
|
|
// DBG("RSDT entry = 0x%X\n", *pEntryR);
|
|
if (*pEntryR != 0) {
|
|
*pEntryX = 0;
|
|
CopyMem(pEntryX, pEntryR, sizeof(UINT32));
|
|
pEntryR++;
|
|
pEntry += sizeof(UINT64);
|
|
} else {
|
|
DBG("RSDT entry %llu = 0 ... skip it\n", Index);
|
|
Xsdt->Header.Length -= sizeof(UINT64);
|
|
pEntryR++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (Xsdt) {
|
|
//Now we need no more Rsdt
|
|
Rsdt = NULL;
|
|
RsdPointer->RsdtAddress = 0;
|
|
//and we want to reallocate Xsdt
|
|
BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIReclaimMemory, 1, &BufferPtr);
|
|
if(!EFI_ERROR(Status))
|
|
{
|
|
CopyMem((void*)(UINTN)BufferPtr, Xsdt, Xsdt->Header.Length);
|
|
Xsdt = (XSDT_TABLE*)(UINTN)BufferPtr;
|
|
}
|
|
// DBG("Finishing RsdPointer\n");
|
|
RsdPointer->XsdtAddress = (UINT64)(UINTN)Xsdt;
|
|
RsdPointer->Checksum = 0;
|
|
RsdPointer->Checksum = (UINT8)(256-Checksum8((CHAR8*)RsdPointer, 20));
|
|
RsdPointer->ExtendedChecksum = 0;
|
|
RsdPointer->ExtendedChecksum = (UINT8)(256-Checksum8((CHAR8*)RsdPointer, RsdPointer->Length));
|
|
DBG("Xsdt reallocation done\n");
|
|
}
|
|
// DBG("FADT pointer = %X\n", (UINTN)FadtPointer);
|
|
if(!FadtPointer) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
//Slice - then we do FADT patch no matter if we don't have DSDT.aml
|
|
BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIReclaimMemory, 1, &BufferPtr);
|
|
if(!EFI_ERROR(Status))
|
|
{
|
|
UINT32 oldLength = ((EFI_ACPI_DESCRIPTION_HEADER*)FadtPointer)->Length;
|
|
newFadt = (EFI_ACPI_4_0_FIXED_ACPI_DESCRIPTION_TABLE*)(UINTN)BufferPtr;
|
|
DBG("old FADT length=%X\n", oldLength);
|
|
CopyMem(newFadt, FadtPointer, oldLength); //old data
|
|
newFadt->Header.Length = 0xF4;
|
|
CopyMem(newFadt->Header.OemId, AppleBiosVendor.c_str(), 6);
|
|
if (newFadt->Header.Revision < EFI_ACPI_4_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
|
|
newFadt->Header.Revision = EFI_ACPI_4_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION;
|
|
}
|
|
newFadt->Reserved0 = 0; //ACPIspec said it should be 0, while 1 is possible, but no more
|
|
|
|
//should correct headers if needed and if asked
|
|
PatchTableHeader((EFI_ACPI_DESCRIPTION_HEADER*)newFadt);
|
|
|
|
if (gSettings.ACPI.smartUPS==TRUE) {
|
|
newFadt->PreferredPmProfile = 3;
|
|
} else {
|
|
newFadt->PreferredPmProfile = gMobile?2:1; //as calculated before
|
|
}
|
|
if (GlobalConfig.EnableC6 || gSettings.ACPI.SSDT.EnableISS) {
|
|
newFadt->CstCnt = 0x85; //as in Mac
|
|
}
|
|
if (GlobalConfig.EnableC2) newFadt->PLvl2Lat = 0x65;
|
|
if (GlobalConfig.C3Latency > 0) {
|
|
newFadt->PLvl3Lat = GlobalConfig.C3Latency;
|
|
} else if (GlobalConfig.EnableC4) {
|
|
newFadt->PLvl3Lat = 0x3E9;
|
|
}
|
|
if (GlobalConfig.C3Latency == 0) {
|
|
GlobalConfig.C3Latency = newFadt->PLvl3Lat;
|
|
}
|
|
|
|
newFadt->IaPcBootArch = 0x3;
|
|
if (gSettings.ACPI.NoASPM) {
|
|
newFadt->IaPcBootArch |= 0x10; // disable ASPM
|
|
}
|
|
newFadt->Flags |= 0x420; //Reset Register Supported and SleepButton active
|
|
newFadt->Flags &= ~0x10010; //RTC_STS not valid and PowerButton disable
|
|
XDsdt = newFadt->XDsdt; //save values if present
|
|
XFirmwareCtrl = newFadt->XFirmwareCtrl;
|
|
CopyMem(&newFadt->ResetReg, pmBlock, 0x80);
|
|
//but these common values are not specific, so adjust
|
|
//ACPIspec said that if Xdsdt !=0 then Dsdt must be =0. But real Mac no! Both values present
|
|
if (BiosDsdt) {
|
|
newFadt->XDsdt = BiosDsdt;
|
|
newFadt->Dsdt = (UINT32)BiosDsdt;
|
|
} else if (newFadt->Dsdt) {
|
|
newFadt->XDsdt = (UINT64)(newFadt->Dsdt);
|
|
} else if (XDsdt) {
|
|
newFadt->Dsdt = (UINT32)XDsdt;
|
|
}
|
|
if (newFadt->FirmwareCtrl) {
|
|
Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE*)(UINTN)newFadt->FirmwareCtrl;
|
|
newFadt->XFirmwareCtrl = (UINT64)(UINTN)(Facs);
|
|
} else if (newFadt->XFirmwareCtrl) {
|
|
newFadt->FirmwareCtrl = (UINT32)XFirmwareCtrl;
|
|
Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE*)(UINTN)XFirmwareCtrl;
|
|
}
|
|
|
|
//patch for FACS included here
|
|
Facs->Version = EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION;
|
|
if (gSettings.Boot.SignatureFixup) {
|
|
DBG(" SignatureFixup: 0x%X -> 0x%llX\n", Facs->HardwareSignature, machineSignature);
|
|
Facs->HardwareSignature = (UINT32)machineSignature;
|
|
} else {
|
|
DBG(" SignatureFixup: 0x%X -> 0x0\n", Facs->HardwareSignature);
|
|
Facs->HardwareSignature = 0x0;
|
|
}
|
|
Facs->Flags = 0; //dont' support S4BIOS, as well as 64bit wake
|
|
//
|
|
|
|
if ((gSettings.ACPI.ResetAddr == 0) && ((oldLength < 0x80) || (newFadt->ResetReg.Address == 0))) {
|
|
newFadt->ResetReg.Address = 0x64;
|
|
newFadt->ResetValue = 0xFE;
|
|
gSettings.ACPI.ResetAddr = 0x64;
|
|
gSettings.ACPI.ResetVal = 0xFE;
|
|
} else if (gSettings.ACPI.ResetAddr != 0) {
|
|
newFadt->ResetReg.Address = gSettings.ACPI.ResetAddr;
|
|
newFadt->ResetValue = gSettings.ACPI.ResetVal;
|
|
}
|
|
newFadt->XPm1aEvtBlk.Address = (UINT64)(newFadt->Pm1aEvtBlk);
|
|
newFadt->XPm1bEvtBlk.Address = (UINT64)(newFadt->Pm1bEvtBlk);
|
|
newFadt->XPm1aCntBlk.Address = (UINT64)(newFadt->Pm1aCntBlk);
|
|
newFadt->XPm1bCntBlk.Address = (UINT64)(newFadt->Pm1bCntBlk);
|
|
newFadt->XPm2CntBlk.Address = (UINT64)(newFadt->Pm2CntBlk);
|
|
newFadt->XPmTmrBlk.Address = (UINT64)(newFadt->PmTmrBlk);
|
|
newFadt->XGpe0Blk.Address = (UINT64)(newFadt->Gpe0Blk);
|
|
newFadt->XGpe1Blk.Address = (UINT64)(newFadt->Gpe1Blk);
|
|
FadtPointer = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE*)newFadt;
|
|
//We are sure that Fadt is the first entry in RSDT/XSDT table
|
|
if (Rsdt!=NULL) {
|
|
Rsdt->Entry = (UINT32)(UINTN)newFadt;
|
|
}
|
|
if (Xsdt!=NULL) {
|
|
Xsdt->Entry = (UINT64)((UINT32)(UINTN)newFadt);
|
|
}
|
|
FixChecksum(&FadtPointer->Header);
|
|
if (gSettings.ACPI.SlpSmiEnable) {
|
|
UINT32 *SlpSmiEn = (UINT32*)((UINTN)(newFadt->Pm1aEvtBlk) + 0x30);
|
|
UINT32 Value = *SlpSmiEn;
|
|
Value &= ~ bit(4);
|
|
*SlpSmiEn = Value;
|
|
}
|
|
}
|
|
|
|
//Get regions from BIOS DSDT
|
|
if ((gSettings.ACPI.DSDT.FixDsdt & FIX_REGIONS) != 0) {
|
|
GetBiosRegions((UINT8*)(UINTN)(newFadt->Dsdt));
|
|
}
|
|
// DBG("DSDT finding\n");
|
|
if (!Volume) {
|
|
DBG("Volume not found!\n");
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
// RootDir = Volume->RootDir;
|
|
Status = EFI_NOT_FOUND;
|
|
|
|
|
|
XStringW acpiPath = SWPrintf("ACPI\\patched\\%ls", gSettings.ACPI.DSDT.DsdtName.wc_str());
|
|
|
|
if ( selfOem.oemDirExists() ) {
|
|
if ( FileExists(&selfOem.getOemDir(), acpiPath) ) {
|
|
DBG("DSDT found in Clover volume OEM folder: %ls\\%ls\n", selfOem.getOemFullPath().wc_str(), acpiPath.wc_str());
|
|
Status = egLoadFile(&selfOem.getOemDir(), acpiPath.wc_str(), &buffer, &bufferLen);
|
|
//REVIEW: memory leak... buffer
|
|
}
|
|
}
|
|
|
|
//Slice: the idea was from past
|
|
// first priority DSDT.aml from the root of booted volume. It allows to keep different DSDT for different systems
|
|
// second priority is DSDT from OEM folder
|
|
// third priority is /EFI/CLOVER/ACPI/patched/DSDT*.aml choosen from GUI.
|
|
|
|
XStringW PathDsdt = SWPrintf("\\%ls", gSettings.ACPI.DSDT.DsdtName.wc_str());
|
|
if (EFI_ERROR(Status) && FileExists(Volume->RootDir, PathDsdt)) {
|
|
DBG("DSDT found in booted volume\n");
|
|
Status = egLoadFile(Volume->RootDir, PathDsdt.wc_str(), &buffer, &bufferLen);
|
|
}
|
|
|
|
// Jief : may I suggest to remove that. Loading from outside of OemPath might be confusing
|
|
if ( EFI_ERROR(Status) && FileExists(&self.getCloverDir(), acpiPath) ) {
|
|
DBG("DSDT found in Clover volume: %ls\\%ls\n", self.getCloverDirFullPath().wc_str(), acpiPath.wc_str());
|
|
Status = egLoadFile(&self.getCloverDir(), acpiPath.wc_str(), &buffer, &bufferLen);
|
|
}
|
|
//
|
|
//apply DSDT loaded from a file into buffer
|
|
//else FADT will contain old BIOS DSDT
|
|
//
|
|
DsdtLoaded = FALSE;
|
|
if (!EFI_ERROR(Status)) {
|
|
// if we will apply fixes, allocate additional space
|
|
bufferLen = bufferLen + bufferLen / 8;
|
|
dsdt = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiACPIReclaimMemory,
|
|
EFI_SIZE_TO_PAGES(bufferLen),
|
|
&dsdt
|
|
);
|
|
|
|
//if success insert dsdt pointer into ACPI tables
|
|
if(!EFI_ERROR(Status)) {
|
|
// DBG("page is allocated, write DSDT into\n");
|
|
CopyMem((void*)(UINTN)dsdt, buffer, bufferLen);
|
|
//once we copied buffer to other place we can free the buffer
|
|
FadtPointer->Dsdt = (UINT32)dsdt;
|
|
FadtPointer->XDsdt = dsdt;
|
|
FixChecksum(&FadtPointer->Header);
|
|
DsdtLoaded = TRUE;
|
|
}
|
|
}
|
|
if(buffer) FreePool(buffer); //the buffer is allocated if egLoadFile() is success. Else the pointer must be nullptr
|
|
|
|
if (!DsdtLoaded) {
|
|
// allocate space for fixes
|
|
TableHeader = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)FadtPointer->Dsdt;
|
|
bufferLen = TableHeader->Length;
|
|
// DBG("DSDT len = 0x%X", bufferLen);
|
|
// bufferLen = bufferLen + bufferLen / 8;
|
|
// DBG(" new len = 0x%X\n", bufferLen);
|
|
|
|
//Slice: new buffer is greater then origin by 12.5%. It is dirty hack but we live with it
|
|
// there will be the sense reallocate buffer if one patch requires increasing the buffer
|
|
// this is headache to predict how many new bytes we need.
|
|
dsdt = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
Status = gBS->AllocatePages(AllocateMaxAddress,
|
|
EfiACPIReclaimMemory,
|
|
EFI_SIZE_TO_PAGES(bufferLen + bufferLen / 8),
|
|
&dsdt);
|
|
|
|
//if success insert dsdt pointer into ACPI tables
|
|
if(!EFI_ERROR(Status)) {
|
|
CopyMem((void*)(UINTN)dsdt, TableHeader, bufferLen); //can't free TableHeader because we are not allocate it
|
|
|
|
FadtPointer->Dsdt = (UINT32)dsdt;
|
|
FadtPointer->XDsdt = dsdt;
|
|
FixChecksum(&FadtPointer->Header);
|
|
}
|
|
}
|
|
// dropDSM = 0xFFFF; //by default we drop all OEM _DSM. They have no sense for us.
|
|
// if (defDSM) {
|
|
// dropDSM = gSettings.DropOEM_DSM; //if set by user
|
|
// }
|
|
|
|
if (gSettings.ACPI.DSDT.DebugDSDT) {
|
|
TableHeader = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)FadtPointer->XDsdt;
|
|
bufferLen = TableHeader->Length;
|
|
|
|
DBG("Output DSDT before patch to %ls\\ACPI\\origin\\DSDT-or.aml\n", selfOem.getConfigDirFullPath().wc_str());
|
|
Status = egSaveFile(&selfOem.getConfigDir(), L"ACPI\\origin\\DSDT-or.aml", (UINT8*)(UINTN)FadtPointer->XDsdt, bufferLen);
|
|
}
|
|
//native DSDT or loaded we want to apply autoFix to this
|
|
// if (gSettings.ACPI.DSDT.FixDsdt) { //fix even with zero mask because we want to know PCIRootUID and count(?)
|
|
DBG("Apply DsdtFixMask=0x%08X\n", gSettings.ACPI.DSDT.FixDsdt);
|
|
// DBG(" drop _DSM mask=0x%04hX\n", dropDSM);
|
|
FixBiosDsdt((UINT8*)(UINTN)FadtPointer->XDsdt, FadtPointer, OSVersion);
|
|
if (gSettings.ACPI.DSDT.DebugDSDT) {
|
|
for (Index=0; Index < 60; Index++) {
|
|
XStringW DsdtPatchedName = SWPrintf("ACPI\\origin\\DSDT-pa%llu.aml", Index);
|
|
if(!FileExists(&selfOem.getConfigDir(), DsdtPatchedName)){
|
|
Status = egSaveFile(&selfOem.getConfigDir(), DsdtPatchedName.wc_str(), (UINT8*)(UINTN)FadtPointer->XDsdt, bufferLen);
|
|
if (!EFI_ERROR(Status)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (EFI_ERROR(Status)) {
|
|
DBG("...saving DSDT failed with status=%s\n", efiStrError(Status));
|
|
}
|
|
}
|
|
|
|
// handle unusual situations with XSDT and RSDT
|
|
PreCleanupRSDT();
|
|
PreCleanupXSDT();
|
|
|
|
// XsdtReplaceSizes array is used to keep track of allocations for the merged tables,
|
|
// as those tables may need to be freed if patched later.
|
|
XsdtReplaceSizes = (__typeof__(XsdtReplaceSizes))AllocateZeroPool(XsdtTableCount() * sizeof(*XsdtReplaceSizes));
|
|
|
|
// Load merged ACPI files from ACPI/patched
|
|
LoadAllPatchedAML(L"ACPI\\patched"_XSW, AUTOMERGE_PASS1);
|
|
|
|
// Drop tables
|
|
if (GlobalConfig.ACPIDropTables) {
|
|
ACPI_DROP_TABLE *DropTable;
|
|
DbgHeader("ACPIDropTables");
|
|
for (DropTable = GlobalConfig.ACPIDropTables; DropTable; DropTable = DropTable->Next) {
|
|
if (DropTable->MenuItem.BValue) {
|
|
//DBG("Attempting to drop \"%4.4a\" (%8.8X) \"%8.8a\" (%16.16lX) L=%d\n", &(DropTable->Signature), DropTable->Signature, &(DropTable->TableId), DropTable->TableId, DropTable->Length);
|
|
DropTableFromXSDT(DropTable->Signature, DropTable->TableId, DropTable->Length);
|
|
DropTableFromRSDT(DropTable->Signature, DropTable->TableId, DropTable->Length);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GlobalConfig.DropSSDT) {
|
|
DbgHeader("DropSSDT");
|
|
//special case if we set into menu drop all SSDT
|
|
DropTableFromXSDT(EFI_ACPI_4_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, 0, 0);
|
|
DropTableFromRSDT(EFI_ACPI_4_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, 0, 0);
|
|
}
|
|
//It's time to fix headers of all remaining ACPI tables.
|
|
// The bug reported by TheRacerMaster and https://alextjam.es/debugging-appleacpiplatform/
|
|
// Workaround proposed by cecekpawon, revised by Slice
|
|
PatchAllTables();
|
|
|
|
// Load add-on ACPI files from ACPI/patched
|
|
LoadAllPatchedAML(L"ACPI\\patched"_XSW, AUTOMERGE_PASS2);
|
|
|
|
if (XsdtReplaceSizes) {
|
|
FreePool(XsdtReplaceSizes);
|
|
XsdtReplaceSizes = NULL;
|
|
}
|
|
|
|
//Slice - this is a time to patch MADT table.
|
|
// DBG("Fool proof: size of APIC NMI = %d\n", sizeof(EFI_ACPI_2_0_LOCAL_APIC_NMI_STRUCTURE));
|
|
// DBG("----------- size of APIC DESC = %d\n", sizeof(EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER));
|
|
// DBG("----------- size of APIC PROC = %d\n", sizeof(EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE));
|
|
|
|
ApicCPUNum = 0;
|
|
// 2. For absent NMI subtable
|
|
xf = ScanXSDT(APIC_SIGN, 0);
|
|
if (xf) {
|
|
ApicTable = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)(*xf);
|
|
// ApicLen = ApicTable->Length;
|
|
ProcLocalApic = (EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE *)(UINTN)(*xf + sizeof(EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER));
|
|
|
|
while ((ProcLocalApic->Type == EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC) && (ProcLocalApic->Length == 8)) {
|
|
if (ProcLocalApic->Flags & EFI_ACPI_4_0_LOCAL_APIC_ENABLED) {
|
|
ApicCPUNum++;
|
|
}
|
|
ProcLocalApic++;
|
|
if (ApicCPUNum > 16) {
|
|
DBG("Out of control with CPU numbers\n");
|
|
break;
|
|
}
|
|
}
|
|
//fool proof
|
|
if ((ApicCPUNum == 0) || (ApicCPUNum > 16)) {
|
|
ApicCPUNum = gCPUStructure.Threads;
|
|
}
|
|
|
|
DBG("ApicCPUNum=%llu\n", ApicCPUNum);
|
|
//reallocate table
|
|
if (gSettings.ACPI.PatchNMI) {
|
|
BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
Status=gBS->AllocatePages(AllocateMaxAddress, EfiACPIReclaimMemory, 1, &BufferPtr);
|
|
if(!EFI_ERROR(Status)) {
|
|
//save old table and drop it from XSDT
|
|
CopyMem((void*)(UINTN)BufferPtr, ApicTable, ApicTable->Length);
|
|
DropTableFromXSDT(APIC_SIGN, 0, 0);
|
|
ApicTable = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)BufferPtr;
|
|
ApicTable->Revision = EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION;
|
|
CopyMem(&ApicTable->OemId, oemID, 6);
|
|
CopyMem(&ApicTable->OemTableId, oemTableID, 8);
|
|
ApicTable->OemRevision = 0x00000001;
|
|
CopyMem(&ApicTable->CreatorId, creatorID, 4);
|
|
|
|
SubTable = (UINT8*)((UINTN)BufferPtr + sizeof(EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER));
|
|
Index = 0;
|
|
while (*SubTable != EFI_ACPI_4_0_LOCAL_APIC_NMI) {
|
|
DBG("Found subtable in MADT: type=%d\n", *SubTable);
|
|
if (*SubTable == EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC) {
|
|
ProcLocalApic = (EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE *)SubTable;
|
|
// macOS assumes that the first processor from DSDT is always enabled, without checking MADT table
|
|
// here we're trying to assign first IDs found in DSDT to enabled processors in MADT, such that macOS assumption to be true
|
|
if (ProcLocalApic->Flags & EFI_ACPI_4_0_LOCAL_APIC_ENABLED) {
|
|
if (ProcLocalApic->AcpiProcessorId != acpi_cpu_processor_id[Index]) {
|
|
DBG("AcpiProcessorId changed: 0x%02hhX to 0x%02hhX\n", ProcLocalApic->AcpiProcessorId, acpi_cpu_processor_id[Index]);
|
|
ProcLocalApic->AcpiProcessorId = acpi_cpu_processor_id[Index];
|
|
} else {
|
|
DBG("AcpiProcessorId: 0x%02hhX\n", ProcLocalApic->AcpiProcessorId);
|
|
}
|
|
Index++;
|
|
}
|
|
}
|
|
bufferLen = (UINTN)SubTable[1];
|
|
SubTable += bufferLen;
|
|
if (((UINTN)SubTable - (UINTN)BufferPtr) >= ApicTable->Length) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*SubTable == EFI_ACPI_4_0_LOCAL_APIC_NMI) {
|
|
DBG("LocalApicNMI is already present, no patch needed\n");
|
|
} else {
|
|
LocalApicNMI = (EFI_ACPI_2_0_LOCAL_APIC_NMI_STRUCTURE*)((UINTN)ApicTable + ApicTable->Length);
|
|
for (Index = 0; Index < ApicCPUNum; Index++) {
|
|
LocalApicNMI->Type = EFI_ACPI_4_0_LOCAL_APIC_NMI;
|
|
LocalApicNMI->Length = sizeof(EFI_ACPI_4_0_LOCAL_APIC_NMI_STRUCTURE);
|
|
LocalApicNMI->AcpiProcessorId = acpi_cpu_processor_id[Index];
|
|
LocalApicNMI->Flags = 5;
|
|
LocalApicNMI->LocalApicLint = 1;
|
|
LocalApicNMI++;
|
|
ApicTable->Length += sizeof(EFI_ACPI_4_0_LOCAL_APIC_NMI_STRUCTURE);
|
|
}
|
|
DBG("ApicTable new Length=%d\n", ApicTable->Length);
|
|
// insert corrected MADT
|
|
}
|
|
|
|
Status = InsertTable(ApicTable, ApicTable->Length);
|
|
if (!EFI_ERROR(Status)) {
|
|
DBG("New APIC table successfully inserted\n");
|
|
}
|
|
/*
|
|
Status = egSaveFile(&self.getSelfRootDir(), PatchedAPIC, (UINT8 *)ApicTable, ApicTable->Length);
|
|
if (EFI_ERROR(Status)) {
|
|
Status = egSaveFile(NULL, PatchedAPIC, (UINT8 *)ApicTable, ApicTable->Length);
|
|
}
|
|
if (!EFI_ERROR(Status)) {
|
|
DBG("Patched APIC table saved into efi/clover/acpi/origin/APIC-p.aml \n");
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DBG("No APIC table Found !!!\n");
|
|
}
|
|
|
|
if (gCPUStructure.Threads >= gCPUStructure.Cores) {
|
|
ApicCPUNum = gCPUStructure.Threads;
|
|
} else {
|
|
ApicCPUNum = gCPUStructure.Cores;
|
|
}
|
|
// }
|
|
/*
|
|
At this moment we have CPU numbers from DSDT - acpi_cpu_num
|
|
and from CPU characteristics gCPUStructure
|
|
Also we had the number from APIC table ApicCPUNum
|
|
What to choose?
|
|
Since rev745 I will return to acpi_cpu_count global variable
|
|
*/
|
|
if (acpi_cpu_count) {
|
|
ApicCPUNum = acpi_cpu_count;
|
|
}
|
|
|
|
if (gSettings.ACPI.SSDT.Generate.GeneratePStates || gSettings.ACPI.SSDT.Generate.GeneratePluginType) {
|
|
Status = EFI_NOT_FOUND;
|
|
Ssdt = generate_pss_ssdt(ApicCPUNum);
|
|
if (Ssdt) {
|
|
Status = InsertTable(Ssdt, Ssdt->Length);
|
|
}
|
|
if(EFI_ERROR(Status)){
|
|
DBG("GeneratePStates failed: Status=%s\n", efiStrError(Status));
|
|
}
|
|
}
|
|
|
|
if (gSettings.ACPI.SSDT.Generate.GenerateCStates) {
|
|
Status = EFI_NOT_FOUND;
|
|
Ssdt = generate_cst_ssdt(FadtPointer, ApicCPUNum);
|
|
if (Ssdt) {
|
|
Status = InsertTable(Ssdt, Ssdt->Length);
|
|
}
|
|
if(EFI_ERROR(Status)){
|
|
DBG("GenerateCStates failed Status=%s\n", efiStrError(Status));
|
|
}
|
|
}
|
|
|
|
// remove NULL entries from RSDT and XSDT
|
|
PostCleanupRSDT();
|
|
PostCleanupXSDT();
|
|
|
|
if (NeedUpdate) {
|
|
gBS->InstallConfigurationTable(&gEfiAcpiTableGuid, RsdPointer);
|
|
gBS->InstallConfigurationTable(&gEfiAcpi10TableGuid, RsdPointer);
|
|
}
|
|
|
|
//free regions?
|
|
while (gRegions) {
|
|
tmpRegion = gRegions->next;
|
|
FreePool(gRegions);
|
|
gRegions = tmpRegion;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Searches for TableName in PathPatched dirs and loads it
|
|
* to Buffer if found. Buffer is allocated here and should be released
|
|
* by caller.
|
|
*/
|
|
EFI_STATUS LoadAcpiTable (
|
|
CONST CHAR16 *PathPatched,
|
|
CONST CHAR16 *TableName,
|
|
UINT8 **Buffer,
|
|
UINTN *BufferLen
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
|
|
// checking \EFI\ACPI\patched dir
|
|
XStringW TmpStr = SWPrintf("%ls\\%ls", PathPatched, TableName);
|
|
if (FileExists(&self.getCloverDir(), TmpStr)) {
|
|
DBG("found %ls\n", TmpStr.wc_str());
|
|
Status = egLoadFile(&self.getCloverDir(), TmpStr.wc_str(), Buffer, BufferLen);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
* Searches for DSDT in AcpiOemPath or PathPatched dirs and inserts it
|
|
* to FadtPointer if found.
|
|
*/
|
|
EFI_STATUS LoadAndInjectDSDT(CONST CHAR16 *PathPatched,
|
|
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *Buffer = NULL;
|
|
UINTN BufferLen = 0;
|
|
EFI_PHYSICAL_ADDRESS Dsdt;
|
|
|
|
// load if exists
|
|
Status = LoadAcpiTable(PathPatched, gSettings.ACPI.DSDT.DsdtName.wc_str(), &Buffer, &BufferLen);
|
|
|
|
if (!EFI_ERROR(Status)) {
|
|
// loaded - allocate EfiACPIReclaim
|
|
DBG("Loaded DSDT at \\%ls\\%ls\\%ls\n", self.getCloverDirFullPath().wc_str(), PathPatched, gSettings.ACPI.DSDT.DsdtName.wc_str());
|
|
Dsdt = EFI_SYSTEM_TABLE_MAX_ADDRESS; //0xFE000000;
|
|
Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiACPIReclaimMemory,
|
|
EFI_SIZE_TO_PAGES(BufferLen),
|
|
&Dsdt
|
|
);
|
|
|
|
if(!EFI_ERROR(Status)) {
|
|
// copy DSDT into EfiACPIReclaim block
|
|
CopyMem((void*)(UINTN)Dsdt, Buffer, BufferLen);
|
|
|
|
// update FADT
|
|
FadtPointer->Dsdt = (UINT32)Dsdt;
|
|
FadtPointer->XDsdt = Dsdt;
|
|
FixChecksum(&FadtPointer->Header);
|
|
DBG("DSDT at 0x%llX injected to FADT 0x%llx\n", Dsdt, (UINTN)FadtPointer);
|
|
}
|
|
|
|
if(Buffer) FreePool(Buffer);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
* Searches for TableName in AcpiOemPath or PathPatched dirs and inserts it
|
|
* to Rsdt and/or Xsdt (globals) if found.
|
|
*/
|
|
EFI_STATUS LoadAndInjectAcpiTable(CONST CHAR16 *PathPatched,
|
|
CONST CHAR16 *TableName)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *Buffer = NULL;
|
|
UINTN BufferLen = 0;
|
|
EFI_ACPI_DESCRIPTION_HEADER *TableHeader = NULL;
|
|
|
|
|
|
// load if exists
|
|
Status = LoadAcpiTable(PathPatched, TableName, &Buffer, &BufferLen);
|
|
|
|
if(!EFI_ERROR(Status)) {
|
|
if (Buffer) {
|
|
// if this is SLIC, then remove previous SLIC if it is there
|
|
TableHeader = (EFI_ACPI_DESCRIPTION_HEADER*)Buffer;
|
|
if (TableHeader->Signature == SLIC_SIGN) {
|
|
DropTableFromXSDT(SLIC_SIGN, 0, 0);
|
|
DropTableFromRSDT(SLIC_SIGN, 0, 0);
|
|
}
|
|
}
|
|
|
|
// loaded - insert it into XSDT/RSDT
|
|
Status = InsertTable(Buffer, BufferLen);
|
|
|
|
if(!EFI_ERROR(Status)) {
|
|
DBG("Table %ls inserted.\n", TableName);
|
|
|
|
// if this was SLIC, then update IDs in XSDT/RSDT
|
|
|
|
if (TableHeader->Signature == SLIC_SIGN) {
|
|
if (Rsdt) {
|
|
DBG("SLIC: Rsdt OEMid '%6.6s', TabId '%8.8s'", (CHAR8*)&Rsdt->Header.OemId, (CHAR8*)&Rsdt->Header.OemTableId);
|
|
CopyMem(&Rsdt->Header.OemId, &TableHeader->OemId, 6);
|
|
Rsdt->Header.OemTableId = TableHeader->OemTableId;
|
|
DBG(" to OEMid '%6.6s', TabId '%8.8s'\n", (CHAR8*)&Rsdt->Header.OemId, (CHAR8*)&Rsdt->Header.OemTableId);
|
|
}
|
|
if (Xsdt) {
|
|
DBG("SLIC: Xsdt OEMid '%6.6s', TabId '%8.8s'", (CHAR8*)&Xsdt->Header.OemId, (CHAR8*)&Xsdt->Header.OemTableId);
|
|
CopyMem(&Xsdt->Header.OemId, &TableHeader->OemId, 6);
|
|
Xsdt->Header.OemTableId = TableHeader->OemTableId;
|
|
DBG(" to OEMid '%6.6s', TabId '%8.8s'\n", (CHAR8*)&Xsdt->Header.OemId, (CHAR8*)&Xsdt->Header.OemTableId);
|
|
}
|
|
}
|
|
} else {
|
|
DBG("Insert return status %s\n", efiStrError(Status));
|
|
}
|
|
|
|
FreePool(Buffer);
|
|
} // if table loaded
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
* Patches UEFI ACPI tables with tables found in OsSubdir.
|
|
*/
|
|
EFI_STATUS PatchACPI_OtherOS(CONST CHAR16* OsSubdir, BOOLEAN DropSSDT)
|
|
{
|
|
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *RsdPointer;
|
|
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer;
|
|
|
|
EFI_STATUS Status; // = EFI_SUCCESS;
|
|
// UINTN Index;
|
|
REFIT_DIR_ITER DirIter;
|
|
EFI_FILE_INFO *DirEntry;
|
|
|
|
//
|
|
// Search for RSDP in UEFI SystemTable/ConfigTable (first Acpi 2.0, then 1.0)
|
|
//
|
|
RsdPointer = NULL;
|
|
|
|
Status = EfiGetSystemConfigurationTable (&gEfiAcpi20TableGuid, (void **) &RsdPointer);
|
|
if (RsdPointer != NULL) {
|
|
DBG("OtherOS: Found Acpi 2.0 RSDP 0x%llX\n", (uintptr_t)RsdPointer);
|
|
} else {
|
|
Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (void **) &RsdPointer);
|
|
if (RsdPointer != NULL) {
|
|
DBG("Found Acpi 1.0 RSDP 0x%llX\n", (uintptr_t)RsdPointer);
|
|
}
|
|
}
|
|
// if RSDP not found - quit
|
|
if (!RsdPointer) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Find RSDT and/or XSDT
|
|
//
|
|
Rsdt = (RSDT_TABLE*)(UINTN)(RsdPointer->RsdtAddress);
|
|
if (Rsdt != NULL && Rsdt->Header.Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
|
|
Rsdt = NULL;
|
|
}
|
|
DBG("RSDT at 0x%llX\n", (UINTN)Rsdt);
|
|
|
|
// check for XSDT
|
|
Xsdt = NULL;
|
|
if (RsdPointer->Revision >=2 && (RsdPointer->XsdtAddress < (UINT64)((UINTN)(-1)))) {
|
|
Xsdt = (XSDT_TABLE*)(UINTN)RsdPointer->XsdtAddress;
|
|
if (Xsdt != NULL && Xsdt->Header.Signature != EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
|
|
Xsdt = NULL;
|
|
}
|
|
}
|
|
DBG("XSDT at 0x%llX\n", (UINTN)Xsdt);
|
|
|
|
// if RSDT and XSDT not found - quit
|
|
if (Rsdt == NULL && Xsdt == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Take FADT (FACP) from XSDT or RSDT (always first entry)
|
|
//
|
|
FadtPointer = NULL;
|
|
if (Xsdt) {
|
|
FadtPointer = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE*)(UINTN)(Xsdt->Entry);
|
|
} else if (Rsdt) {
|
|
FadtPointer = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE*)(UINTN)(Rsdt->Entry);
|
|
}
|
|
DBG("FADT pointer = 0x%llX\n", (UINTN)FadtPointer);
|
|
|
|
// if not found - quit
|
|
if(FadtPointer == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Inject/drop tables
|
|
//
|
|
|
|
// prepare dirs that will be searched for custom ACPI tables
|
|
XStringW PathPatched;
|
|
if ( selfOem.oemDirExists() ) {
|
|
PathPatched = SWPrintf("%ls\\ACPI\\%ls", selfOem.getOemPathRelToSelfDir().wc_str(), OsSubdir);
|
|
if ( !FileExists(&self.getCloverDir(), PathPatched) ) {
|
|
PathPatched.setEmpty();
|
|
}
|
|
}
|
|
if ( PathPatched.isEmpty() ) {
|
|
PathPatched = SWPrintf("ACPI\\%ls", OsSubdir);
|
|
if (!FileExists(&self.getCloverDir(), PathPatched)) {
|
|
DBG("Dir '\\%ls\\%ls' not found. No patching will be done.\n", self.getCloverDirFullPath().wc_str(), PathPatched.wc_str());
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Inject DSDT
|
|
//
|
|
/* Status = */LoadAndInjectDSDT(PathPatched.wc_str(), FadtPointer);
|
|
|
|
//
|
|
// Drop SSDT if requested. Not until now
|
|
//
|
|
/*
|
|
if (DropSSDT) {
|
|
DropTableFromXSDT(EFI_ACPI_4_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, 0, 0);
|
|
DropTableFromRSDT(EFI_ACPI_4_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, 0, 0);
|
|
}
|
|
*/
|
|
if (GlobalConfig.ACPIDropTables) {
|
|
ACPI_DROP_TABLE *DropTable;
|
|
DbgHeader("ACPIDropTables");
|
|
for (DropTable = GlobalConfig.ACPIDropTables; DropTable; DropTable = DropTable->Next) {
|
|
// only for tables that have OtherOS true
|
|
if (DropTable->OtherOS && DropTable->MenuItem.BValue) {
|
|
//DBG("Attempting to drop \"%4.4a\" (%8.8X) \"%8.8a\" (%16.16lX) L=%d\n", &(DropTable->Signature), DropTable->Signature, &(DropTable->TableId), DropTable->TableId, DropTable->Length);
|
|
DropTableFromXSDT(DropTable->Signature, DropTable->TableId, DropTable->Length);
|
|
DropTableFromRSDT(DropTable->Signature, DropTable->TableId, DropTable->Length);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// find and inject other ACPI tables
|
|
//
|
|
|
|
DirIterOpen(&self.getCloverDir(), PathPatched.wc_str(), &DirIter);
|
|
while (DirIterNext(&DirIter, 2, L"*.aml", &DirEntry)) {
|
|
|
|
if (DirEntry->FileName[0] == L'.') {
|
|
continue;
|
|
}
|
|
if (StrStr(DirEntry->FileName, L"DSDT")) {
|
|
continue;
|
|
}
|
|
|
|
LoadAndInjectAcpiTable(PathPatched.wc_str(), DirEntry->FileName);
|
|
}
|
|
/*Status = */DirIterClose(&DirIter);
|
|
|
|
// remove NULL entries from RSDT and XSDT
|
|
PostCleanupRSDT();
|
|
PostCleanupXSDT();
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|