mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
Fix DSDT injection and implement region relocation, thx Clover
This commit is contained in:
parent
02bf038446
commit
29354b8f62
@ -17,6 +17,8 @@
|
||||
|
||||
#include <IndustryStandard/Acpi62.h>
|
||||
|
||||
#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
|
||||
|
||||
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user