From def196926469cb65fe5e8050368d5228d213d720 Mon Sep 17 00:00:00 2001 From: RehabMan Date: Fri, 20 Oct 2017 14:01:46 -0700 Subject: [PATCH] config.plist/ACPI/AutoMerge, allows individual patched OEM SSDTs to replace OEM SSDTs in original position in XSDT --- rEFIt_UEFI/Platform/AcpiPatcher.c | 165 +++++++++++++++++++++++++++--- rEFIt_UEFI/Platform/Platform.h | 1 + rEFIt_UEFI/Platform/Settings.c | 3 + rEFIt_UEFI/refit/menu.c | 8 +- 4 files changed, 160 insertions(+), 17 deletions(-) diff --git a/rEFIt_UEFI/Platform/AcpiPatcher.c b/rEFIt_UEFI/Platform/AcpiPatcher.c index a0aeb0ee8..0cecf87f6 100644 --- a/rEFIt_UEFI/Platform/AcpiPatcher.c +++ b/rEFIt_UEFI/Platform/AcpiPatcher.c @@ -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' } @@ -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; @@ -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; } @@ -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; @@ -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; @@ -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-> @@ -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); @@ -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) { @@ -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; @@ -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) { @@ -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); } @@ -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 { @@ -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)); diff --git a/rEFIt_UEFI/Platform/Platform.h b/rEFIt_UEFI/Platform/Platform.h index b22e3f34f..7f3a7e393 100644 --- a/rEFIt_UEFI/Platform/Platform.h +++ b/rEFIt_UEFI/Platform/Platform.h @@ -942,6 +942,7 @@ typedef struct { BOOLEAN NoASPM; BOOLEAN DropSSDT; BOOLEAN NoOemTableId; + BOOLEAN AutoMerge; BOOLEAN GeneratePStates; BOOLEAN GenerateCStates; BOOLEAN GenerateAPSN; diff --git a/rEFIt_UEFI/Platform/Settings.c b/rEFIt_UEFI/Platform/Settings.c index c08774542..42c559ffb 100644 --- a/rEFIt_UEFI/Platform/Settings.c +++ b/rEFIt_UEFI/Platform/Settings.c @@ -5529,6 +5529,9 @@ GetUserSettings( } } + Prop = GetProperty (DictPointer, "AutoMerge"); + gSettings.AutoMerge = IsPropertyTrue (Prop); + Prop = GetProperty (DictPointer, "DisabledAML"); if (Prop) { INTN i, Count = GetTagCount (Prop); diff --git a/rEFIt_UEFI/refit/menu.c b/rEFIt_UEFI/refit/menu.c index 59e984308..f80487c6f 100644 --- a/rEFIt_UEFI/refit/menu.c +++ b/rEFIt_UEFI/refit/menu.c @@ -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) { @@ -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(); @@ -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) {