未验证 提交 dd251266 编写于 作者: J John Davis 提交者: GitHub

OcAcpiLib: Relocate ACPI tables if they are not writeable (#152)

上级 9a2c6696
......@@ -263,6 +263,170 @@ AcpiFindName (
return 0;
}
STATIC
VOID
AcpiRefreshTableChecksum (
IN EFI_ACPI_DESCRIPTION_HEADER *Table
)
{
UINT32 TablePrintSignature;
TablePrintSignature = AcpiReadSignature ((EFI_ACPI_COMMON_HEADER *) Table);
Table->Checksum = 0;
Table->Checksum = CalculateCheckSum8 ((UINT8 *) Table, Table->Length);
DEBUG ((
DEBUG_INFO,
"OCA: Refreshed %.4a checksum to %02x\n",
(CHAR8 *) &TablePrintSignature,
Table->Checksum
));
}
STATIC
BOOLEAN
AcpiIsTableWritable (
IN EFI_ACPI_COMMON_HEADER *Table
)
{
UINT32 LengthOriginal;
LengthOriginal = Table->Length;
(*(volatile UINT32 *)&Table->Length)++;
if (LengthOriginal == *(volatile UINT32 *)&Table->Length) {
return FALSE;
}
Table->Length = LengthOriginal;
return TRUE;
}
STATIC
EFI_STATUS
AcpiAllocateCopyTable (
IN EFI_ACPI_COMMON_HEADER *Table,
IN UINT32 NewSize OPTIONAL,
OUT EFI_ACPI_COMMON_HEADER **NewTable
)
{
EFI_STATUS Status;
UINT32 TablePrintSignature;
EFI_PHYSICAL_ADDRESS NewTableAddress;
if (NewSize < Table->Length) {
NewSize = Table->Length;
}
TablePrintSignature = AcpiReadSignature (Table);
NewTableAddress = BASE_4GB - 1;
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiACPIMemoryNVS,
EFI_SIZE_TO_PAGES (NewSize),
&NewTableAddress
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_WARN,
"OCA: Failed to allocate %u bytes for table %.4a\n",
NewSize,
(CHAR8 *) &TablePrintSignature
));
return Status;
}
*NewTable = (EFI_ACPI_COMMON_HEADER *)(UINTN) NewTableAddress;
DEBUG ((
DEBUG_INFO,
"OCA: Allocated new table %.4a at %p\n",
(CHAR8 *) &TablePrintSignature,
*NewTable
));
CopyMem (*NewTable, Table, Table->Length);
ZeroMem (((UINT8 *) *NewTable) + Table->Length, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewSize)) - Table->Length);
(*NewTable)->Length = NewSize;
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
AcpiAllocateCopyFadt (
IN OUT OC_ACPI_CONTEXT *Context,
IN UINT32 NewSize
)
{
EFI_STATUS Status;
EFI_ACPI_COMMON_HEADER *NewFadt;
UINT32 Index;
Status = AcpiAllocateCopyTable (
(EFI_ACPI_COMMON_HEADER *) Context->Fadt,
NewSize,
&NewFadt
);
if (EFI_ERROR (Status)) {
return Status;
}
for (Index = 0; Index < Context->NumberOfTables; ++Index) {
//
// There is a possibility for multiple FADT tables.
//
if (Context->Tables[Index]->Signature == EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
Context->Tables[Index] = NewFadt;
}
}
Context->Fadt = (EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE *) NewFadt;
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
AcpiAllocateCopyDsdt (
IN OUT OC_ACPI_CONTEXT *Context,
IN EFI_ACPI_DESCRIPTION_HEADER *NewDsdt OPTIONAL
)
{
EFI_STATUS Status;
EFI_ACPI_COMMON_HEADER *AllocatedDsdt;
Status = AcpiAllocateCopyTable (
(EFI_ACPI_COMMON_HEADER *) (NewDsdt != NULL ? NewDsdt : Context->Dsdt),
0,
&AllocatedDsdt
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Reallocate FADT if needed.
//
if (!AcpiIsTableWritable ((EFI_ACPI_COMMON_HEADER *) Context->Fadt)) {
Status = AcpiAllocateCopyFadt (Context, 0);
if (EFI_ERROR (Status)) {
FreePool (AllocatedDsdt);
return Status;
}
}
if (Context->Fadt->Header.Length >= OFFSET_OF (EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE, XDsdt) + sizeof (Context->Fadt->XDsdt)) {
Context->Fadt->XDsdt = (UINT64)(UINTN) AllocatedDsdt;
}
Context->Fadt->Dsdt = (UINT32)(UINTN) AllocatedDsdt;
AcpiRefreshTableChecksum ((EFI_ACPI_DESCRIPTION_HEADER *) Context->Fadt);
Context->Dsdt = (EFI_ACPI_DESCRIPTION_HEADER *) AllocatedDsdt;
return EFI_SUCCESS;
}
/**
Load ACPI table regions.
......@@ -624,6 +788,15 @@ AcpiInitContext (
Context->Dsdt->Length,
Index
));
if ((UINTN)Context->Dsdt < BASE_1MB) {
DEBUG ((
DEBUG_INFO,
"OCA: Unlocking DSDT at %p\n",
Context->Dsdt
));
LegacyRegionUnlock ((UINT32)(UINTN)Context->Tables[DstIndex], Context->Tables[DstIndex]->Length);
}
}
++DstIndex;
......@@ -850,7 +1023,7 @@ AcpiInsertTable (
{
EFI_ACPI_COMMON_HEADER *Common;
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS Table;
EFI_ACPI_COMMON_HEADER *NewTable;
EFI_ACPI_COMMON_HEADER **NewTables;
BOOLEAN ReplaceDsdt;
UINT32 TablePrintSignature;
......@@ -887,54 +1060,37 @@ AcpiInsertTable (
Context->AllocatedTables += 2;
}
Table = BASE_4GB - 1;
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiACPIMemoryNVS,
EFI_SIZE_TO_PAGES (Length),
&Table
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "OCA: Failed to allocate %u bytes for inserted ACPI table\n", Length));
return Status;
}
CopyMem ((UINT8 *)(UINTN)Table, Data, Length);
ZeroMem ((UINT8 *)(UINTN)Table + Length, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length)) - Length);
if (ReplaceDsdt) {
DEBUG ((
DEBUG_INFO,
"OCA: Replaced DSDT of %u bytes into ACPI\n",
Common->Length
));
Context->Dsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Table;
if (Context->Fadt->Header.Length >= OFFSET_OF (EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE, XDsdt) + sizeof (Context->Fadt->XDsdt)) {
Context->Fadt->XDsdt = (UINT64)(UINTN) Context->Dsdt;
}
Context->Fadt->Dsdt = (UINT32)(UINTN) Context->Dsdt;
Context->Fadt->Header.Checksum = 0;
Context->Fadt->Header.Checksum = CalculateCheckSum8 (
(UINT8 *) Context->Fadt,
Context->Fadt->Header.Length
);
Status = AcpiAllocateCopyDsdt (Context, (EFI_ACPI_DESCRIPTION_HEADER *) Data);
if (EFI_ERROR (Status)) {
return Status;
}
} else {
TablePrintSignature = AcpiReadSignature (Common);
Status = AcpiAllocateCopyTable ((EFI_ACPI_COMMON_HEADER *) Data, 0, &NewTable);
if (EFI_ERROR (Status)) {
return Status;
}
TablePrintSignature = AcpiReadSignature (NewTable);
DEBUG ((
DEBUG_INFO,
"OCA: Inserted table %.4a (%08x) (OEM %016Lx) of %u bytes into ACPI at index %u\n",
(CHAR8 *) &TablePrintSignature,
Common->Signature,
AcpiReadOemTableId (Common),
Common->Length,
NewTable->Signature,
AcpiReadOemTableId (NewTable),
NewTable->Length,
Context->NumberOfTables
));
Context->Tables[Context->NumberOfTables] = (EFI_ACPI_COMMON_HEADER *)(UINTN)Table;
Context->Tables[Context->NumberOfTables] = NewTable;
++Context->NumberOfTables;
}
......@@ -946,16 +1102,33 @@ AcpiNormalizeHeaders (
IN OUT OC_ACPI_CONTEXT *Context
)
{
UINT32 Index;
UINT32 TablePrintSignature;
EFI_STATUS Status;
UINT32 Index;
EFI_ACPI_COMMON_HEADER *NewTable;
UINT32 TablePrintSignature;
if (Context->Dsdt != NULL) {
if (!AcpiIsTableWritable ((EFI_ACPI_COMMON_HEADER *) Context->Dsdt)) {
Status = AcpiAllocateCopyDsdt (Context, NULL);
if (EFI_ERROR (Status)) {
return;
}
}
if (AcpiNormalizeTableHeaders (Context->Dsdt)) {
DEBUG ((DEBUG_INFO, "OCA: Normalized DSDT of %u bytes headers\n", Context->Dsdt->Length));
}
}
for (Index = 0; Index < Context->NumberOfTables; ++Index) {
if (!AcpiIsTableWritable (Context->Tables[Index])) {
Status = AcpiAllocateCopyTable (Context->Tables[Index], 0, &NewTable);
if (EFI_ERROR (Status)) {
return;
}
Context->Tables[Index] = NewTable;
}
if (AcpiNormalizeTableHeaders ((EFI_ACPI_DESCRIPTION_HEADER *) Context->Tables[Index])) {
TablePrintSignature = AcpiReadSignature (Context->Tables[Index]);
......@@ -978,11 +1151,13 @@ AcpiApplyPatch (
IN OC_ACPI_PATCH *Patch
)
{
UINT32 Index;
UINT64 CurrOemTableId;
UINT32 ReplaceCount;
UINT32 ReplaceLimit;
UINT32 TablePrintSignature;
EFI_STATUS Status;
UINT32 Index;
UINT64 CurrOemTableId;
UINT32 ReplaceCount;
UINT32 ReplaceLimit;
UINT32 TablePrintSignature;
EFI_ACPI_COMMON_HEADER *NewTable;
DEBUG ((DEBUG_INFO, "OCA: Applying %u byte ACPI patch skip %u, count %u\n", Patch->Size, Patch->Skip, Patch->Count));
......@@ -995,6 +1170,13 @@ AcpiApplyPatch (
ReplaceLimit = Context->Dsdt->Length;
}
if (!AcpiIsTableWritable ((EFI_ACPI_COMMON_HEADER *) Context->Dsdt)) {
Status = AcpiAllocateCopyDsdt (Context, NULL);
if (EFI_ERROR (Status)) {
return Status;
}
}
ReplaceCount = ApplyPatch (
Patch->Find,
Patch->Mask,
......@@ -1017,17 +1199,9 @@ AcpiApplyPatch (
));
if (ReplaceCount > 0) {
Context->Dsdt->Checksum = 0;
Context->Dsdt->Checksum = CalculateCheckSum8 (
(UINT8 *) Context->Dsdt,
Context->Dsdt->Length
);
AcpiRefreshTableChecksum (Context->Dsdt);
DEBUG ((
DEBUG_INFO,
"OCA: Refreshed DSDT checksum to %02x\n",
Context->Dsdt->Checksum
));
}
}
......@@ -1050,6 +1224,14 @@ AcpiApplyPatch (
ReplaceLimit = Context->Tables[Index]->Length;
}
if (!AcpiIsTableWritable (Context->Tables[Index])) {
Status = AcpiAllocateCopyTable (Context->Tables[Index], 0, &NewTable);
if (EFI_ERROR (Status)) {
return Status;
}
Context->Tables[Index] = NewTable;
}
ReplaceCount = ApplyPatch (
Patch->Find,
Patch->Mask,
......@@ -1078,17 +1260,7 @@ AcpiApplyPatch (
));
if (ReplaceCount > 0 && Context->Tables[Index]->Length >= sizeof (EFI_ACPI_DESCRIPTION_HEADER)) {
((EFI_ACPI_DESCRIPTION_HEADER *)Context->Tables[Index])->Checksum = 0;
((EFI_ACPI_DESCRIPTION_HEADER *)Context->Tables[Index])->Checksum = CalculateCheckSum8 (
(UINT8 *) Context->Tables[Index],
Context->Tables[Index]->Length
);
DEBUG ((
DEBUG_INFO,
"OCA: Refreshed checksum to %02x\n",
((EFI_ACPI_DESCRIPTION_HEADER *)Context->Tables[Index])->Checksum
));
AcpiRefreshTableChecksum ((EFI_ACPI_DESCRIPTION_HEADER *) Context->Tables[Index]);
}
}
}
......@@ -1145,7 +1317,9 @@ AcpiRelocateRegions (
IN OUT OC_ACPI_CONTEXT *Context
)
{
UINT32 Index;
EFI_STATUS Status;
UINT32 Index;
EFI_ACPI_COMMON_HEADER *NewTable;
//
// Should not be called before AcpiLoadRegions, but just in case.
......@@ -1157,11 +1331,26 @@ AcpiRelocateRegions (
}
if (Context->Dsdt != NULL) {
if (!AcpiIsTableWritable ((EFI_ACPI_COMMON_HEADER *) Context->Dsdt)) {
Status = AcpiAllocateCopyDsdt (Context, NULL);
if (EFI_ERROR (Status)) {
return;
}
}
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) {
if (!AcpiIsTableWritable (Context->Tables[Index])) {
Status = AcpiAllocateCopyTable (Context->Tables[Index], 0, &NewTable);
if (EFI_ERROR (Status)) {
return;
}
Context->Tables[Index] = NewTable;
}
AcpiRelocateTableRegions (Context, Context->Tables[Index]);
}
}
......@@ -1172,12 +1361,9 @@ AcpiFadtEnableReset (
IN OUT OC_ACPI_CONTEXT *Context
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS Table;
UINT32 OldSize;
UINT32 RequiredSize;
EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
UINT32 Index;
EFI_STATUS Status;
UINT32 OldSize;
UINT32 RequiredSize;
if (Context->Fadt == NULL) {
return EFI_NOT_FOUND;
......@@ -1196,39 +1382,17 @@ AcpiFadtEnableReset (
// REF: https://github.com/acidanthera/bugtracker/issues/897
//
if (OldSize < RequiredSize) {
Table = BASE_4GB - 1;
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiACPIMemoryNVS,
EFI_SIZE_TO_PAGES (RequiredSize),
&Table
);
if (OldSize < RequiredSize || !AcpiIsTableWritable ((EFI_ACPI_COMMON_HEADER *) Context->Fadt)) {
Status = AcpiAllocateCopyFadt (Context, OldSize < RequiredSize ? RequiredSize : 0);
if (EFI_ERROR (Status)) {
return Status;
}
Fadt = (EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE *)(UINTN) Table;
CopyMem (Fadt, Context->Fadt, OldSize);
ZeroMem (((UINT8 *) Context->Fadt) + OldSize, RequiredSize - OldSize);
Fadt->Header.Length = RequiredSize;
for (Index = 0; Index < Context->NumberOfTables; ++Index) {
//
// I think sometimes there are multiple FADT tables.
//
if (Context->Tables[Index]->Signature == EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
Context->Tables[Index] = (EFI_ACPI_COMMON_HEADER *) Fadt;
}
}
} else if ((Context->Fadt->Flags & EFI_ACPI_6_2_RESET_REG_SUP) == 0
} else if (!((Context->Fadt->Flags & EFI_ACPI_6_2_RESET_REG_SUP) == 0
|| (Context->Fadt->Flags & EFI_ACPI_6_2_SLP_BUTTON) == 0
|| (Context->Fadt->Flags & EFI_ACPI_6_2_PWR_BUTTON) != 0
|| Context->Fadt->ResetReg.Address == 0
|| Context->Fadt->ResetReg.RegisterBitWidth != 8) {
Fadt = Context->Fadt;
} else {
|| Context->Fadt->ResetReg.RegisterBitWidth != 8)) {
return EFI_SUCCESS;
}
......@@ -1236,24 +1400,23 @@ AcpiFadtEnableReset (
// Enable sleep button, but disable power button actions.
// This resolves power button action in macOS on some models.
//
Fadt->Flags |= EFI_ACPI_6_2_SLP_BUTTON | EFI_ACPI_6_2_RESET_REG_SUP;
Fadt->Flags &= ~EFI_ACPI_6_2_PWR_BUTTON;
Context->Fadt->Flags |= EFI_ACPI_6_2_SLP_BUTTON | EFI_ACPI_6_2_RESET_REG_SUP;
Context->Fadt->Flags &= ~EFI_ACPI_6_2_PWR_BUTTON;
if (Fadt->ResetReg.Address == 0 || Fadt->ResetReg.RegisterBitWidth != 8) {
if (Context->Fadt->ResetReg.Address == 0 || Context->Fadt->ResetReg.RegisterBitWidth != 8) {
//
// Resetting through port 0xCF9 is universal on Intel and AMD.
// But may not be the case on some laptops, which use 0xB2.
//
Fadt->ResetReg.AddressSpaceId = EFI_ACPI_6_2_SYSTEM_IO;
Fadt->ResetReg.RegisterBitWidth = 8;
Fadt->ResetReg.RegisterBitOffset = 0;
Fadt->ResetReg.AccessSize = EFI_ACPI_6_2_BYTE;
Fadt->ResetReg.Address = 0xCF9;
Fadt->ResetValue = 6;
Context->Fadt->ResetReg.AddressSpaceId = EFI_ACPI_6_2_SYSTEM_IO;
Context->Fadt->ResetReg.RegisterBitWidth = 8;
Context->Fadt->ResetReg.RegisterBitOffset = 0;
Context->Fadt->ResetReg.AccessSize = EFI_ACPI_6_2_BYTE;
Context->Fadt->ResetReg.Address = 0xCF9;
Context->Fadt->ResetValue = 6;
}
Fadt->Header.Checksum = 0;
Fadt->Header.Checksum = CalculateCheckSum8 ((UINT8 *) Fadt, Fadt->Header.Length);
AcpiRefreshTableChecksum ((EFI_ACPI_DESCRIPTION_HEADER *) Context->Fadt);
return EFI_SUCCESS;
}
......@@ -1263,13 +1426,32 @@ AcpiResetLogoStatus (
IN OUT OC_ACPI_CONTEXT *Context
)
{
UINT32 Index;
EFI_STATUS Status;
UINT32 Index;
EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE *Bgrt;
EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE *BgrtNew;
for (Index = 0; Index < Context->NumberOfTables; ++Index) {
if (Context->Tables[Index]->Signature == EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE) {
if (Context->Tables[Index]->Length >= sizeof (EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE)) {
EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE *Bgrt =
(EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE *)Context->Tables[Index];
Bgrt = (EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE *) Context->Tables[Index];
if (!AcpiIsTableWritable ((EFI_ACPI_COMMON_HEADER *) Bgrt)) {
Status = AcpiAllocateCopyTable (
(EFI_ACPI_COMMON_HEADER *) Bgrt,
0,
(EFI_ACPI_COMMON_HEADER **) &BgrtNew
);
if (EFI_ERROR (Status)) {
return;
}
Context->Tables[Index] = (EFI_ACPI_COMMON_HEADER *) BgrtNew;
Bgrt = BgrtNew;
}
Bgrt->Status &= ~EFI_ACPI_6_2_BGRT_STATUS_DISPLAYED;
Bgrt->Header.Checksum = 0;
Bgrt->Header.Checksum = CalculateCheckSum8 (
......@@ -1288,7 +1470,11 @@ AcpiHandleHardwareSignature (
IN BOOLEAN Reset
)
{
EFI_STATUS Status;
BOOLEAN IsXFirmwareCtrl;
EFI_ACPI_6_2_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
EFI_ACPI_6_2_FIRMWARE_ACPI_CONTROL_STRUCTURE *FacsNew;
if (Context->Fadt == NULL) {
return;
......@@ -1296,8 +1482,10 @@ AcpiHandleHardwareSignature (
if (Context->Fadt->Header.Length >= OFFSET_OF (EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE, XFirmwareCtrl) + sizeof (Context->Fadt->XFirmwareCtrl)) {
Facs = (EFI_ACPI_6_2_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN) Context->Fadt->XFirmwareCtrl;
IsXFirmwareCtrl = TRUE;
} else {
Facs = NULL;
IsXFirmwareCtrl = FALSE;
}
if (Facs == NULL && Context->Fadt->Header.Length >= OFFSET_OF (EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE, FirmwareCtrl) + sizeof (Context->Fadt->FirmwareCtrl)) {
......@@ -1308,6 +1496,37 @@ AcpiHandleHardwareSignature (
DEBUG ((DEBUG_INFO, "OCA: FACS signature is %X (%d)\n", Facs->Flags, Reset));
if (Reset) {
if (!AcpiIsTableWritable ((EFI_ACPI_COMMON_HEADER *) Facs)) {
Status = AcpiAllocateCopyTable (
(EFI_ACPI_COMMON_HEADER *) Facs,
0,
(EFI_ACPI_COMMON_HEADER **) &FacsNew
);
if (EFI_ERROR (Status)) {
return;
}
//
// Reallocate FADT if needed.
//
if (!AcpiIsTableWritable ((EFI_ACPI_COMMON_HEADER *) Context->Fadt)) {
Status = AcpiAllocateCopyFadt (Context, 0);
if (EFI_ERROR (Status)) {
FreePool (FacsNew);
return;
}
}
if (IsXFirmwareCtrl) {
Context->Fadt->XFirmwareCtrl = (UINT64)(UINTN) FacsNew;
} else {
Context->Fadt->FirmwareCtrl = (UINT32)(UINTN) FacsNew;
}
AcpiRefreshTableChecksum ((EFI_ACPI_DESCRIPTION_HEADER *) Context->Fadt);
Facs = FacsNew;
}
//
// TODO: We might also want to unset S4BIOS_F flag in Facs->Flags.
//
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册