CloverBootloader/rEFIt_UEFI/Platform/AcpiPatcher.cpp
jief666 6ff5bab8a5 Create section Smbios and BootGraphics.
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.
2021-04-03 17:42:49 +03:00

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;
}