From 29354b8f621df350b0818ed01dcedd6407f55eb4 Mon Sep 17 00:00:00 2001 From: vit9696 Date: Sat, 9 Mar 2019 06:15:53 +0300 Subject: [PATCH] Fix DSDT injection and implement region relocation, thx Clover --- Include/Library/OcAcpiLib.h | 19 ++- Library/OcAcpiLib/OcAcpiLib.c | 305 +++++++++++++++++++++++++++++++++- Tests/AcpiTest/AcpiTest.c | 4 + TestsUser/Include/Base.h | 2 + 4 files changed, 323 insertions(+), 7 deletions(-) diff --git a/Include/Library/OcAcpiLib.h b/Include/Library/OcAcpiLib.h index 11ca9dba..8c8416e6 100755 --- a/Include/Library/OcAcpiLib.h +++ b/Include/Library/OcAcpiLib.h @@ -17,6 +17,8 @@ #include +#define OC_ACPI_NAME_SIZE 4 + // // RSDP and XSDT table definitions not provided by EDK2 due to no // flexible array support. @@ -40,14 +42,14 @@ typedef struct { // Operation region structure. // typedef struct { - // - // Region name, not guaranteed to be null-terminated. - // - CHAR8 Name[8]; // // Region address. // UINT32 Address; + // + // Region name, not guaranteed to be null-terminated. + // + CHAR8 Name[OC_ACPI_NAME_SIZE+1]; } OC_ACPI_REGION; // @@ -228,4 +230,13 @@ AcpiLoadRegions ( IN OUT OC_ACPI_CONTEXT *Context ); +/** Attempt to relocate ACPI regions based on loaded ones. + + @param Context ACPI library context. +**/ +VOID +AcpiRelocateRegions ( + IN OUT OC_ACPI_CONTEXT *Context + ); + #endif // OC_ACPI_LIB_H diff --git a/Library/OcAcpiLib/OcAcpiLib.c b/Library/OcAcpiLib/OcAcpiLib.c index 73781e32..afeb7238 100755 --- a/Library/OcAcpiLib/OcAcpiLib.c +++ b/Library/OcAcpiLib/OcAcpiLib.c @@ -128,6 +128,261 @@ AcpiFindRsdp ( return Rsdp; } +/** Extract and verify ACPI name from data. + + @param Data Data of at least OC_ACPI_NAME_SIZE+1 bytes to read name from. + @param Name Name buffer of at least OC_ACPI_NAME_SIZE+1 bytes. + @param NameOffset Name offset from original data (1 if '\\' and 0 otherwise). + + @return TRUE for valid names. +**/ +STATIC +BOOLEAN +AcpiReadName ( + IN CONST UINT8 *Data, + OUT CHAR8 *Name, + OUT UINT32 *NameOffset OPTIONAL + ) +{ + UINT32 Index; + UINT32 Off; + + // + // Skip \ in \NAME. + // + Off = Data[0] == '\\' ? 1 : 0; + + for (Index = Off; Index < Off + OC_ACPI_NAME_SIZE; ++Index) { + if (Data[Index] < '/' + || ((Data[Index] > '9') && (Data[Index] < 'A')) + || ((Data[Index] > 'Z') && (Data[Index] != '_'))) { + return FALSE; + } + + Name[Index - Off] = Data[Index]; + } + + Name[OC_ACPI_NAME_SIZE] = 0; + + if (NameOffset != NULL) { + *NameOffset = Off; + } + + return TRUE; +} + +/** Find ACPI name declaration in data. + + @param Data ACPI table data. + @param Length ACPI table data length. + @param Name ACPI name of at least OC_ACPI_NAME_SIZE bytes. + + @return offset > 0 for valid names. +**/ +STATIC +UINT32 +AcpiFindName ( + IN CONST UINT8 *Data, + IN UINT32 Length, + IN CONST CHAR8 *Name + ) +{ + UINT32 Index; + + // + // Lookup from offset 1 and after. + // + if (Length < OC_ACPI_NAME_SIZE + 1) { + return 0; + } + + for (Index = 0; Index < Length - OC_ACPI_NAME_SIZE; ++Index) { + if (Data[Index] == AML_NAME_OP + && Data[Index+1] == Name[0] + && Data[Index+2] == Name[1] + && Data[Index+3] == Name[2] + && Data[Index+4] == Name[3]) { + return Index+1; + } + } + + return 0; +} + +/** Load ACPI table regions. + + @param Context ACPI library context. + @param Table ACPI table. + + @return EFI_SUCCESS unless memory allocation failure. +**/ +STATIC +EFI_STATUS +AcpiLoadTableRegions ( + IN OUT OC_ACPI_CONTEXT *Context, + IN EFI_ACPI_COMMON_HEADER *Table + ) +{ + UINT32 Index; + UINT32 Index2; + UINT32 NameOffset; + UINT8 *Buffer; + UINT32 BufferLen; + CHAR8 Name[OC_ACPI_NAME_SIZE+1]; + CHAR8 NameAddr[OC_ACPI_NAME_SIZE+1]; + OC_ACPI_REGION *NewRegions; + UINT32 Address; + + Buffer = (UINT8 *) Table; + BufferLen = Table->Length; + + if (BufferLen < sizeof (EFI_ACPI_DESCRIPTION_HEADER)) { + return EFI_SUCCESS; + } + + for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < BufferLen - 0xF; ++Index) { + if (Buffer[Index] == AML_EXT_OP + && Buffer[Index+1] == AML_EXT_REGION_OP + && AcpiReadName (&Buffer[Index+2], &Name[0], &NameOffset) + && Buffer[Index+OC_ACPI_NAME_SIZE+2+NameOffset] == 0) { + // + // This is SystemMemory region. Try to save it. + // + Address = 0; + if (Buffer[Index+OC_ACPI_NAME_SIZE+3+NameOffset] == AML_DWORD_PREFIX) { + CopyMem (&Address, &Buffer[Index+OC_ACPI_NAME_SIZE+4+NameOffset], sizeof (UINT32)); + } else if (Buffer[Index+OC_ACPI_NAME_SIZE+3+NameOffset] == AML_WORD_PREFIX) { + CopyMem (&Address, &Buffer[Index+OC_ACPI_NAME_SIZE+4+NameOffset], sizeof (UINT16)); + } else if (AcpiReadName (&Buffer[Index+OC_ACPI_NAME_SIZE+3+NameOffset], &NameAddr[0], NULL)) { + Index2 = AcpiFindName (Buffer, BufferLen, &NameAddr[0]); + if (Index2 > 0 && Index2 < BufferLen - 0xF) { + if (Buffer[Index2+OC_ACPI_NAME_SIZE] == AML_DWORD_PREFIX) { + CopyMem (&Address, &Buffer[Index2+OC_ACPI_NAME_SIZE+1], sizeof (UINT32)); + } else if (Buffer[Index2+OC_ACPI_NAME_SIZE] == AML_WORD_PREFIX) { + CopyMem (&Address, &Buffer[Index2+OC_ACPI_NAME_SIZE+1], sizeof (UINT16)); + } + } + } + + if (Address != 0) { + if (Context->AllocatedRegions == Context->NumberOfRegions) { + NewRegions = AllocatePool ((Context->AllocatedRegions + 2) * sizeof (Context->Regions[0])); + if (NewRegions == NULL) { + DEBUG ((DEBUG_WARN, "Failed to allocate memory for %u regions\n", Context->NumberOfRegions+2)); + return EFI_OUT_OF_RESOURCES; + } + CopyMem (NewRegions, Context->Regions, Context->NumberOfRegions * sizeof (Context->Regions[0])); + FreePool (Context->Regions); + + Context->Regions = NewRegions; + Context->AllocatedRegions += 2; + } + + DEBUG ((DEBUG_INFO, "Found OperationRegion %a at %08X\n", Name, Address)); + Context->Regions[Context->NumberOfRegions].Address = Address; + CopyMem (&Context->Regions[Context->NumberOfRegions].Name[0], &Name[0], sizeof (Name)); + Context->NumberOfRegions++; + } + } + } + + return EFI_SUCCESS; +} + +/** Relocate ACPI table regions. + + @param Context ACPI library context. + @param Table ACPI table. +**/ +STATIC +VOID +AcpiRelocateTableRegions ( + IN OUT OC_ACPI_CONTEXT *Context, + IN EFI_ACPI_COMMON_HEADER *Table + ) +{ + UINT32 Index; + UINT32 Index2; + UINT32 RegionIndex; + UINT32 NameOffset; + UINT8 *Buffer; + UINT32 BufferLen; + CHAR8 Name[OC_ACPI_NAME_SIZE+1]; + CHAR8 NameAddr[OC_ACPI_NAME_SIZE+1]; + UINT32 OldAddress; + BOOLEAN Modified; + + Buffer = (UINT8 *) Table; + BufferLen = Table->Length; + Modified = FALSE; + + if (BufferLen < sizeof (EFI_ACPI_DESCRIPTION_HEADER)) { + return; + } + + for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < BufferLen - 0xF; ++Index) { + if (Buffer[Index] == AML_EXT_OP + && Buffer[Index+1] == AML_EXT_REGION_OP + && AcpiReadName (&Buffer[Index+2], &Name[0], &NameOffset) + && Buffer[Index+OC_ACPI_NAME_SIZE+2+NameOffset] == 0) { + // + // This is region. Compare to current BIOS tables and relocate. + // + + for (RegionIndex = 0; RegionIndex < Context->NumberOfRegions; ++RegionIndex) { + if (AsciiStrCmp (Context->Regions[RegionIndex].Name, Name) == 0) { + OldAddress = 0; + if (Buffer[Index+OC_ACPI_NAME_SIZE+3+NameOffset] == AML_DWORD_PREFIX) { + CopyMem (&OldAddress, &Buffer[Index+OC_ACPI_NAME_SIZE+4+NameOffset], sizeof (UINT32)); + CopyMem (&Buffer[Index+OC_ACPI_NAME_SIZE+4+NameOffset], &Context->Regions[RegionIndex].Address, sizeof (UINT32)); + Modified = TRUE; + } else if (Buffer[Index+OC_ACPI_NAME_SIZE+3+NameOffset] == AML_WORD_PREFIX) { + CopyMem (&OldAddress, &Buffer[Index+OC_ACPI_NAME_SIZE+4+NameOffset], sizeof (UINT16)); + CopyMem (&Buffer[Index+OC_ACPI_NAME_SIZE+4+NameOffset], &Context->Regions[RegionIndex].Address, sizeof (UINT16)); + Modified = TRUE; + } else if (AcpiReadName (&Buffer[Index+OC_ACPI_NAME_SIZE+3+NameOffset], &NameAddr[0], NULL)) { + Index2 = AcpiFindName (Buffer, BufferLen, &NameAddr[0]); + if (Index2 > 0 && Index2 < BufferLen - 0xF) { + if (Buffer[Index2+OC_ACPI_NAME_SIZE] == AML_DWORD_PREFIX) { + CopyMem (&OldAddress, &Buffer[Index2+OC_ACPI_NAME_SIZE+1], sizeof (UINT32)); + CopyMem (&Buffer[Index2+OC_ACPI_NAME_SIZE+1], &Context->Regions[RegionIndex].Address, sizeof (UINT32)); + Modified = TRUE; + } else if (Buffer[Index2+OC_ACPI_NAME_SIZE] == AML_WORD_PREFIX) { + CopyMem (&OldAddress, &Buffer[Index2+OC_ACPI_NAME_SIZE+1], sizeof (UINT16)); + CopyMem (&Buffer[Index2+OC_ACPI_NAME_SIZE+1], &Context->Regions[RegionIndex].Address, sizeof (UINT16)); + Modified = TRUE; + } + } + } + + if (Modified && OldAddress != Context->Regions[RegionIndex].Address) { + DEBUG (( + DEBUG_INFO, + "Region %a address relocated from %08X to %08X\n", + Context->Regions[RegionIndex].Name, + OldAddress, + Context->Regions[RegionIndex].Address + )); + } + + break; + } + } + } + } + + // + // Update checksum + // + if (Modified) { + ((EFI_ACPI_DESCRIPTION_HEADER *)Table)->Checksum = 0; + ((EFI_ACPI_DESCRIPTION_HEADER *)Table)->Checksum = CalculateCheckSum8 ( + (UINT8 *) Table, + Table->Length + ); + } +} + EFI_STATUS AcpiInitContext ( IN OUT OC_ACPI_CONTEXT *Context @@ -398,7 +653,7 @@ AcpiInsertTable ( return EFI_INVALID_PARAMETER; } - ReplaceDsdt = Common->Signature != EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE; + ReplaceDsdt = Common->Signature == EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE; if (ReplaceDsdt && Context->Dsdt == NULL) { DEBUG ((DEBUG_WARN, "We do not have DSDT to replace\n")); @@ -594,6 +849,9 @@ AcpiLoadRegions ( IN OUT OC_ACPI_CONTEXT *Context ) { + EFI_STATUS Status; + UINT32 Index; + // // Should not be called twice, but just in case. // @@ -611,7 +869,48 @@ AcpiLoadRegions ( return EFI_OUT_OF_RESOURCES; } - //TODO: Implement. + if (Context->Dsdt != NULL) { + Status = AcpiLoadTableRegions (Context, (EFI_ACPI_COMMON_HEADER *) Context->Dsdt); + if (EFI_ERROR (Status)) { + return Status; + } + } - return EFI_UNSUPPORTED; + for (Index = 0; Index < Context->NumberOfTables; ++Index) { + if (Context->Tables[Index]->Signature == EFI_ACPI_6_2_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { + Status = AcpiLoadTableRegions (Context, Context->Tables[Index]); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + return EFI_SUCCESS; +} + +VOID +AcpiRelocateRegions ( + IN OUT OC_ACPI_CONTEXT *Context + ) +{ + UINT32 Index; + + // + // Should not be called before AcpiLoadRegions, but just in case. + // + ASSERT (Context->Regions != NULL); + + if (Context->NumberOfRegions == 0) { + return; + } + + if (Context->Dsdt != NULL) { + AcpiRelocateTableRegions (Context, (EFI_ACPI_COMMON_HEADER *) Context->Dsdt); + } + + for (Index = 0; Index < Context->NumberOfTables; ++Index) { + if (Context->Tables[Index]->Signature == EFI_ACPI_6_2_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { + AcpiRelocateTableRegions (Context, Context->Tables[Index]); + } + } } diff --git a/Tests/AcpiTest/AcpiTest.c b/Tests/AcpiTest/AcpiTest.c index ed2890dd..b1868a39 100644 --- a/Tests/AcpiTest/AcpiTest.c +++ b/Tests/AcpiTest/AcpiTest.c @@ -101,6 +101,8 @@ TestAcpi ( Status = AcpiInitContext (&Context); if (!EFI_ERROR (Status)) { + AcpiLoadRegions (&Context); + AcpiDropTable (&Context, EFI_ACPI_6_2_DMA_REMAPPING_TABLE_SIGNATURE, 0, 0); AcpiDropTable (&Context, EFI_ACPI_6_2_WINDOWS_SMM_SECURITY_MITIGATION_TABLE_SIGNATURE, 0, 0); AcpiDropTable (&Context, EFI_ACPI_6_2_WINDOWS_ACPI_EMULATED_DEVICES_TABLE_SIGNATURE, 0, 0); @@ -109,6 +111,8 @@ TestAcpi ( AcpiApplyPatch (&Context, &HpetPatch); + AcpiRelocateRegions (&Context); + AcpiApplyContext (&Context); AcpiFreeContext (&Context); diff --git a/TestsUser/Include/Base.h b/TestsUser/Include/Base.h index 3ac306b9..91990f6c 100644 --- a/TestsUser/Include/Base.h +++ b/TestsUser/Include/Base.h @@ -934,6 +934,7 @@ InsertTailList ( _ListHead->BackLink = Entry; } +STATIC VOID RemoveEntryList ( LIST_ENTRY *Entry @@ -967,6 +968,7 @@ IsNull ( return (BOOLEAN)(Node == List); } +STATIC BOOLEAN IsListEmpty ( LIST_ENTRY *List