Skip to content

Commit

Permalink
config.plist/ACPI/AutoMerge, allows individual patched OEM SSDTs to r…
Browse files Browse the repository at this point in the history
…eplace OEM SSDTs in original position in XSDT
  • Loading branch information
RehabMan committed Oct 20, 2017
1 parent 72a1ae8 commit def1969
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 17 deletions.
165 changes: 149 additions & 16 deletions rEFIt_UEFI/Platform/AcpiPatcher.c
Expand Up @@ -33,6 +33,7 @@ Re-Work by Slice 2011.
#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 SSDT_SIGN SIGNATURE_32('S','S','D','T')
#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' }
Expand All @@ -44,6 +45,8 @@ CONST CHAR8 creatorID[4] = APPLE_CREATOR_ID;
//Global pointers
RSDT_TABLE *Rsdt = NULL;
XSDT_TABLE *Xsdt = NULL;
UINT32 XsdtOriginalEntryCount;
UINTN *XsdtReplaceSizes;

UINT64 BiosDsdt;
UINT32 BiosDsdtLen;
Expand Down Expand Up @@ -193,12 +196,14 @@ UINT8 Checksum8(VOID * startPtr, UINT32 len)
return Value;
}

UINT32* ScanRSDT (UINT32 Signature, UINT64 TableId)
UINT32* ScanRSDT2(UINT32 Signature, UINT64 TableId, INTN MatchIndex)
{
EFI_ACPI_DESCRIPTION_HEADER *TableEntry;
UINTN Index;
UINT32 EntryCount;
UINT32 *EntryPtr;
INTN Count = 0;

if (!Rsdt) {
return NULL;
}
Expand All @@ -208,25 +213,33 @@ UINT32* ScanRSDT (UINT32 Signature, UINT64 TableId)
}

EntryCount = (Rsdt->Header.Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);

EntryPtr = &Rsdt->Entry;
for (Index = 0; Index < EntryCount; Index++, EntryPtr++) {
TableEntry = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(*EntryPtr));
if (((Signature == 0) || (TableEntry->Signature == Signature)) &&
((TableId == 0) || (TableEntry->OemTableId == TableId))) {
return EntryPtr; //point to TableEntry entry
if (-1 == MatchIndex || Count == MatchIndex) {
return EntryPtr; //point to TableEntry entry
}
++Count;
}
}
return NULL;
}

UINT64* ScanXSDT (UINT32 Signature, UINT64 TableId)
UINT32* ScanRSDT(UINT32 Signature, UINT64 TableId)
{
return ScanRSDT2(Signature, TableId, -1);
}

UINT64* ScanXSDT2(UINT32 Signature, UINT64 TableId, INTN MatchIndex)
{
EFI_ACPI_DESCRIPTION_HEADER *TableEntry;
UINTN Index;
UINT32 EntryCount;
CHAR8 *BasePtr;
UINT64 Entry64;
INTN Count = 0;

if ((Signature == 0) && (TableId == 0)) {
return NULL;
Expand All @@ -239,12 +252,20 @@ UINT64* ScanXSDT (UINT32 Signature, UINT64 TableId)
TableEntry = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(Entry64));
if (((Signature == 0) || (TableEntry->Signature == Signature)) &&
((TableId == 0) || (TableEntry->OemTableId == TableId))) {
return (UINT64 *)BasePtr; //pointer to the TableEntry entry
if (-1 == MatchIndex || Count == MatchIndex) {
return (UINT64 *)BasePtr; //pointer to the TableEntry entry
}
++Count;
}
}
return NULL;
}

UINT64* ScanXSDT(UINT32 Signature, UINT64 TableId)
{
return ScanXSDT2(Signature, TableId, -1);
}

VOID GetAcpiTablesList()
{
EFI_ACPI_DESCRIPTION_HEADER *TableEntry;
Expand Down Expand Up @@ -565,7 +586,11 @@ VOID PatchAllSSDT()

sign[4] = 0;
OTID[8] = 0;
EntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);

// RehabMan: we want to patch only the SSDTs that were original or were loaded and merged
EntryCount = XsdtOriginalEntryCount;
//EntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);

BasePtr = (CHAR8*)(UINTN)(&(Xsdt->Entry));
for (Index = 0; Index < EntryCount; Index++, BasePtr += sizeof(UINT64)) {
CopyMem (&Entry64, (VOID*)BasePtr, sizeof(UINT64)); //value from BasePtr->
Expand Down Expand Up @@ -605,6 +630,12 @@ VOID PatchAllSSDT()
}
}
}
// Note: Index is always less than XsdtOriginalEntryCount (size of XsdtReplaceSizes array)
if (XsdtReplaceSizes && XsdtReplaceSizes[Index]) {
// came from patched table in ACPI/patched, so free original pages
gBS->FreePages(Entry64, EFI_SIZE_TO_PAGES(XsdtReplaceSizes[Index]));
XsdtReplaceSizes[Index] = 0;
}
CopyMem ((VOID*)BasePtr, &ssdt, sizeof(UINT64));
if ((gSettings.FixDsdt & FIX_HEADERS)) {
PatchTableHeader((EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)ssdt);
Expand Down Expand Up @@ -657,6 +688,91 @@ EFI_STATUS InsertTable(VOID* TableEntry, UINTN Length)
return Status;
}

INTN IndexFromFileName(CHAR16* FileName)
{
// FileName must start as "XXXX-number...", such as "SSDT-9.aml", or "SSDT-11-SaSsdt.aml"

// search for '-'
INTN Result = -1;
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';
}
}
}
return Result;
}

EFI_STATUS ReplaceOrInsertTable(VOID* TableEntry, UINTN Length, INTN MatchIndex)
{
EFI_STATUS Status; // = EFI_SUCCESS;
EFI_PHYSICAL_ADDRESS BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
EFI_ACPI_DESCRIPTION_HEADER* hdr = (EFI_ACPI_DESCRIPTION_HEADER*)TableEntry;

if (!TableEntry) {
return EFI_NOT_FOUND;
}

Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiACPIReclaimMemory,
EFI_SIZE_TO_PAGES(Length),
&BufferPtr
);
//if success insert or replace table pointer into ACPI tables
if(!EFI_ERROR(Status)) {
// DBG("page is allocated, write SSDT into\n");
CopyMem((VOID*)(UINTN)BufferPtr, (VOID*)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* entry = NULL;
if (hdr->Signature != SSDT_SIGN || MatchIndex != -1) {
// SSDT with target index or non-SSDT, try to find matching entry
entry = ScanRSDT2(hdr->Signature, hdr->OemTableId, MatchIndex);
}
if (entry) {
*entry = (UINT32)(UINTN)BufferPtr;
} else {
UINT32* Ptr = (UINT32*)((UINTN)Rsdt + Rsdt->Header.Length);
*Ptr = (UINT32)(UINTN)BufferPtr;
Rsdt->Header.Length += sizeof(UINT32);
// DBG("Rsdt->Length = %d\n", Rsdt->Header.Length);
}
}
#endif
//insert/modify into XSDT
if (Xsdt) {
UINT64* entry = NULL;
if (hdr->Signature != SSDT_SIGN || MatchIndex != -1) {
// SSDT with target index or non-SSDT, try to find matching entry
entry = ScanXSDT2(hdr->Signature, hdr->OemTableId, MatchIndex);
}
if (entry) {
WriteUnaligned64(entry, (UINT64)BufferPtr);
UINTN Index = entry - &Xsdt->Entry;
if (XsdtReplaceSizes && Index < XsdtOriginalEntryCount) {
XsdtReplaceSizes[Index] = Length; // mark as replaced, as it should be freed if patched later
}
} else {
UINT64* XPtr = (UINT64*)((UINTN)Xsdt + Xsdt->Header.Length);
// *XPtr = (UINT64)(UINTN)BufferPtr;
WriteUnaligned64(XPtr, (UINT64)BufferPtr);
Xsdt->Header.Length += sizeof(UINT64);
// DBG("Xsdt->Length = %d\n", Xsdt->Header.Length);
}
}
}

return Status;
}

/** Saves Buffer of Length to disk as DirName\\FileName. */
EFI_STATUS SaveBufferToDisk(VOID *Buffer, UINTN Length, CHAR16 *DirName, CHAR16 *FileName)
{
Expand Down Expand Up @@ -1960,7 +2076,6 @@ EFI_STATUS PatchACPI(IN REFIT_VOLUME *Volume, CHAR8 *OSVersion)
DBG("...saving DSDT failed with status=%r\n", Status);
}
}

// Drop tables
if (gSettings.ACPIDropTables) {
ACPI_DROP_TABLE *DropTable = gSettings.ACPIDropTables;
Expand All @@ -1975,18 +2090,18 @@ EFI_STATUS PatchACPI(IN REFIT_VOLUME *Volume, CHAR8 *OSVersion)
}
}

// RehabMan: Save current Xsdt entry count, as PatchAllSSDT operates on only
// original SSDTs or SSDTs that were loaded/merged.
// XsdtReplaceSizes array is used to keep track of allocations for the merged tables,
// as those tables may need to be freed if patched later.
XsdtOriginalEntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
XsdtReplaceSizes = AllocateZeroPool(XsdtOriginalEntryCount * sizeof(*XsdtReplaceSizes));

if (gSettings.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);
} else {
DbgHeader("PatchAllSSDT");
//all remaining SSDT tables will be patched
PatchAllSSDT();
//do the empty drop to clean xsdt
DropTableFromXSDT(XXXX_SIGN, 0, 0);
DropTableFromRSDT(XXXX_SIGN, 0, 0);
}

if (ACPIPatchedAML) {
Expand Down Expand Up @@ -2020,7 +2135,10 @@ EFI_STATUS PatchACPI(IN REFIT_VOLUME *Volume, CHAR8 *OSVersion)
TableHeader->Checksum = 0;
TableHeader->Checksum = (UINT8)(256-Checksum8((CHAR8*)buffer, TableHeader->Length));
}
Status = InsertTable((VOID*)buffer, bufferLen);
if (!gSettings.AutoMerge)
Status = InsertTable(buffer, bufferLen);
else
Status = ReplaceOrInsertTable(buffer, bufferLen, IndexFromFileName(gSettings.SortedACPI[Index]));
}
DBG("%r\n", Status);
}
Expand All @@ -2044,7 +2162,10 @@ EFI_STATUS PatchACPI(IN REFIT_VOLUME *Volume, CHAR8 *OSVersion)
TableHeader->Checksum = 0;
TableHeader->Checksum = (UINT8)(256-Checksum8((CHAR8*)buffer, TableHeader->Length));
}
Status = InsertTable((VOID*)buffer, bufferLen);
if (!gSettings.AutoMerge)
Status = InsertTable(buffer, bufferLen);
else
Status = ReplaceOrInsertTable(buffer, bufferLen, IndexFromFileName(ACPIPatchedAMLTmp->FileName));
}
DBG("%r\n", Status);
} else {
Expand All @@ -2056,6 +2177,18 @@ EFI_STATUS PatchACPI(IN REFIT_VOLUME *Volume, CHAR8 *OSVersion)
// DBG("End: Processing Patched AML(s)\n");
}

if (!gSettings.DropSSDT) {
DbgHeader("PatchAllSSDT");
PatchAllSSDT();
//do the empty drop to clean xsdt
DropTableFromXSDT(XXXX_SIGN, 0, 0);
DropTableFromRSDT(XXXX_SIGN, 0, 0);
}
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));
Expand Down
1 change: 1 addition & 0 deletions rEFIt_UEFI/Platform/Platform.h
Expand Up @@ -942,6 +942,7 @@ typedef struct {
BOOLEAN NoASPM;
BOOLEAN DropSSDT;
BOOLEAN NoOemTableId;
BOOLEAN AutoMerge;
BOOLEAN GeneratePStates;
BOOLEAN GenerateCStates;
BOOLEAN GenerateAPSN;
Expand Down
3 changes: 3 additions & 0 deletions rEFIt_UEFI/Platform/Settings.c
Expand Up @@ -5529,6 +5529,9 @@ GetUserSettings(
}
}

Prop = GetProperty (DictPointer, "AutoMerge");
gSettings.AutoMerge = IsPropertyTrue (Prop);

Prop = GetProperty (DictPointer, "DisabledAML");
if (Prop) {
INTN i, Count = GetTagCount (Prop);
Expand Down
8 changes: 7 additions & 1 deletion rEFIt_UEFI/refit/menu.c
Expand Up @@ -674,6 +674,8 @@ VOID FillInputs(BOOLEAN New)
}
UnicodeSPrint(InputItems[InputItemsCount++].SValue, 16, L"%04d", gSettings.IntelMaxValue);

InputItems[InputItemsCount].ItemType = BoolValue; //113
InputItems[InputItemsCount++].BValue = gSettings.AutoMerge;

//menu for drop table
if (gSettings.ACPIDropTables) {
Expand Down Expand Up @@ -1257,7 +1259,10 @@ VOID ApplyInputs(VOID)
if (InputItems[i].Valid) {
gSettings.IntelMaxValue = InputItems[i].BValue;
}

i++; //113
if (InputItems[i].Valid) {
gSettings.AutoMerge = InputItems[i].BValue;
}

if (NeedSave) {
SaveSettings();
Expand Down Expand Up @@ -4415,6 +4420,7 @@ REFIT_MENU_ENTRY *SubMenuDropTables()
}

AddMenuItem(SubScreen, 4, "Drop all OEM SSDT", TAG_INPUT, FALSE);
AddMenuItem(SubScreen, 113, "Automatic smart merge", TAG_INPUT, FALSE);

//AddMenuInfoLine(SubScreen, L"PATCHED AML:");
if (ACPIPatchedAML) {
Expand Down

0 comments on commit def1969

Please sign in to comment.