mirror of https://github.com/acidanthera/audk.git
OvmfPkg/XenAcpiPlatformDxe: create from AcpiPlatformDxe
Create an almost verbatim copy of the "OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf" driver for the OvmfXen platform. We're going to trim the driver in subsequent patches. Ultimately, the XenAcpiPlatformDxe driver will duplicate a negligible amount of code that is currently present in the QemuFwCfgAcpiPlatformDxe driver. List the new driver in "Maintainers.txt", in the "OvmfPkg: Xen-related modules" section. Switch the OvmfXen platform to the new driver at once. This patch should be reviewed with "git show --find-copies-harder". Cc: Andrew Fish <afish@apple.com> Cc: Anthony Perard <anthony.perard@citrix.com> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Julien Grall <julien@xen.org> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Philippe Mathieu-Daudé <philmd@redhat.com> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2122 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Message-Id: <20210526201446.12554-12-lersek@redhat.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Reviewed-by: Leif Lindholm <leif@nuviainc.com>
This commit is contained in:
parent
cc302b799e
commit
c9bba52fc7
|
@ -497,6 +497,7 @@ F: OvmfPkg/PlatformPei/MemDetect.c
|
|||
F: OvmfPkg/PlatformPei/Platform.*
|
||||
F: OvmfPkg/PlatformPei/Xen.*
|
||||
F: OvmfPkg/SmbiosPlatformDxe/*Xen.c
|
||||
F: OvmfPkg/XenAcpiPlatformDxe/
|
||||
F: OvmfPkg/XenBusDxe/
|
||||
F: OvmfPkg/XenIoPciDxe/
|
||||
F: OvmfPkg/XenIoPvhDxe/
|
||||
|
|
|
@ -652,7 +652,7 @@
|
|||
# ACPI Support
|
||||
#
|
||||
MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
|
||||
OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
|
||||
OvmfPkg/XenAcpiPlatformDxe/XenAcpiPlatformDxe.inf
|
||||
OvmfPkg/AcpiTables/AcpiTables.inf
|
||||
MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf
|
||||
MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf
|
||||
|
|
|
@ -352,7 +352,7 @@ INF MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
|
|||
INF OvmfPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.inf
|
||||
|
||||
INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
|
||||
INF OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
|
||||
INF OvmfPkg/XenAcpiPlatformDxe/XenAcpiPlatformDxe.inf
|
||||
INF RuleOverride=ACPITABLE OvmfPkg/AcpiTables/AcpiTables.inf
|
||||
INF MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf
|
||||
INF MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
/** @file
|
||||
OVMF ACPI Platform Driver for Xen guests
|
||||
|
||||
Copyright (C) 2021, Red Hat, Inc.
|
||||
Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <Library/DebugLib.h> // ASSERT_EFI_ERROR()
|
||||
#include <Library/UefiBootServicesTableLib.h> // gBS
|
||||
#include <Library/XenPlatformLib.h> // XenDetected()
|
||||
#include <Protocol/FirmwareVolume2.h> // gEfiFirmwareVolume2Protocol...
|
||||
|
||||
#include "AcpiPlatform.h"
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InstallAcpiTable (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
|
||||
IN VOID *AcpiTableBuffer,
|
||||
IN UINTN AcpiTableBufferSize,
|
||||
OUT UINTN *TableKey
|
||||
)
|
||||
{
|
||||
return AcpiProtocol->InstallAcpiTable (
|
||||
AcpiProtocol,
|
||||
AcpiTableBuffer,
|
||||
AcpiTableBufferSize,
|
||||
TableKey
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Locate the first instance of a protocol. If the protocol requested is an
|
||||
FV protocol, then it will return the first FV that contains the ACPI table
|
||||
storage file.
|
||||
|
||||
@param Instance Return pointer to the first instance of the protocol
|
||||
|
||||
@return EFI_SUCCESS The function completed successfully.
|
||||
@return EFI_NOT_FOUND The protocol could not be located.
|
||||
@return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
LocateFvInstanceWithTables (
|
||||
OUT EFI_FIRMWARE_VOLUME2_PROTOCOL **Instance
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_HANDLE *HandleBuffer;
|
||||
UINTN NumberOfHandles;
|
||||
EFI_FV_FILETYPE FileType;
|
||||
UINT32 FvStatus;
|
||||
EFI_FV_FILE_ATTRIBUTES Attributes;
|
||||
UINTN Size;
|
||||
UINTN Index;
|
||||
EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
|
||||
|
||||
FvStatus = 0;
|
||||
|
||||
//
|
||||
// Locate protocol.
|
||||
//
|
||||
Status = gBS->LocateHandleBuffer (
|
||||
ByProtocol,
|
||||
&gEfiFirmwareVolume2ProtocolGuid,
|
||||
NULL,
|
||||
&NumberOfHandles,
|
||||
&HandleBuffer
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// Defined errors at this time are not found and out of resources.
|
||||
//
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Looking for FV with ACPI storage file
|
||||
//
|
||||
for (Index = 0; Index < NumberOfHandles; Index++) {
|
||||
//
|
||||
// Get the protocol on this handle
|
||||
// This should not fail because of LocateHandleBuffer
|
||||
//
|
||||
Status = gBS->HandleProtocol (
|
||||
HandleBuffer[Index],
|
||||
&gEfiFirmwareVolume2ProtocolGuid,
|
||||
(VOID**) &FvInstance
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
//
|
||||
// See if it has the ACPI storage file
|
||||
//
|
||||
Status = FvInstance->ReadFile (
|
||||
FvInstance,
|
||||
(EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
|
||||
NULL,
|
||||
&Size,
|
||||
&FileType,
|
||||
&Attributes,
|
||||
&FvStatus
|
||||
);
|
||||
|
||||
//
|
||||
// If we found it, then we are done
|
||||
//
|
||||
if (Status == EFI_SUCCESS) {
|
||||
*Instance = FvInstance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Our exit status is determined by the success of the previous operations
|
||||
// If the protocol was found, Instance already points to it.
|
||||
//
|
||||
|
||||
//
|
||||
// Free any allocated buffers
|
||||
//
|
||||
gBS->FreePool (HandleBuffer);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Find ACPI tables in an FV and install them.
|
||||
|
||||
This is now a fall-back path. Normally, we will search for tables provided
|
||||
by the VMM first.
|
||||
|
||||
If that fails, we use this function to load the ACPI tables from an FV. The
|
||||
sources for the FV based tables is located under OvmfPkg/AcpiTables.
|
||||
|
||||
@param AcpiTable Protocol instance pointer
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InstallOvmfFvTables (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
|
||||
INTN Instance;
|
||||
EFI_ACPI_COMMON_HEADER *CurrentTable;
|
||||
UINTN TableHandle;
|
||||
UINT32 FvStatus;
|
||||
UINTN TableSize;
|
||||
UINTN Size;
|
||||
EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction;
|
||||
|
||||
Instance = 0;
|
||||
CurrentTable = NULL;
|
||||
TableHandle = 0;
|
||||
|
||||
if (QemuDetected ()) {
|
||||
TableInstallFunction = QemuInstallAcpiTable;
|
||||
} else {
|
||||
TableInstallFunction = InstallAcpiTable;
|
||||
}
|
||||
|
||||
//
|
||||
// set FwVol (and use an ASSERT() below) to suppress incorrect
|
||||
// compiler/analyzer warnings
|
||||
//
|
||||
FwVol = NULL;
|
||||
//
|
||||
// Locate the firmware volume protocol
|
||||
//
|
||||
Status = LocateFvInstanceWithTables (&FwVol);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
ASSERT (FwVol != NULL);
|
||||
|
||||
//
|
||||
// Read tables from the storage file.
|
||||
//
|
||||
while (Status == EFI_SUCCESS) {
|
||||
|
||||
Status = FwVol->ReadSection (
|
||||
FwVol,
|
||||
(EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
|
||||
EFI_SECTION_RAW,
|
||||
Instance,
|
||||
(VOID**) &CurrentTable,
|
||||
&Size,
|
||||
&FvStatus
|
||||
);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
//
|
||||
// Add the table
|
||||
//
|
||||
TableHandle = 0;
|
||||
|
||||
TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Length;
|
||||
ASSERT (Size >= TableSize);
|
||||
|
||||
//
|
||||
// Install ACPI table
|
||||
//
|
||||
Status = TableInstallFunction (
|
||||
AcpiTable,
|
||||
CurrentTable,
|
||||
TableSize,
|
||||
&TableHandle
|
||||
);
|
||||
|
||||
//
|
||||
// Free memory allocated by ReadSection
|
||||
//
|
||||
gBS->FreePool (CurrentTable);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// Increment the instance
|
||||
//
|
||||
Instance++;
|
||||
CurrentTable = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Effective entrypoint of Acpi Platform driver.
|
||||
|
||||
@param ImageHandle
|
||||
@param SystemTable
|
||||
|
||||
@return EFI_SUCCESS
|
||||
@return EFI_LOAD_ERROR
|
||||
@return EFI_OUT_OF_RESOURCES
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InstallAcpiTables (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (XenDetected ()) {
|
||||
Status = InstallXenTables (AcpiTable);
|
||||
} else {
|
||||
Status = InstallQemuFwCfgTables (AcpiTable);
|
||||
}
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
Status = InstallOvmfFvTables (AcpiTable);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/** @file
|
||||
OVMF ACPI Platform Driver for Xen guests
|
||||
|
||||
Copyright (C) 2021, Red Hat, Inc.
|
||||
Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef ACPI_PLATFORM_H_
|
||||
#define ACPI_PLATFORM_H_
|
||||
|
||||
#include <Protocol/AcpiTable.h> // EFI_ACPI_TABLE_PROTOCOL
|
||||
#include <Protocol/PciIo.h> // EFI_PCI_IO_PROTOCOL
|
||||
|
||||
typedef struct {
|
||||
EFI_PCI_IO_PROTOCOL *PciIo;
|
||||
UINT64 PciAttributes;
|
||||
} ORIGINAL_ATTRIBUTES;
|
||||
|
||||
typedef struct S3_CONTEXT S3_CONTEXT;
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InstallAcpiTable (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
|
||||
IN VOID *AcpiTableBuffer,
|
||||
IN UINTN AcpiTableBufferSize,
|
||||
OUT UINTN *TableKey
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
QemuDetected (
|
||||
VOID
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
QemuInstallAcpiTable (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
|
||||
IN VOID *AcpiTableBuffer,
|
||||
IN UINTN AcpiTableBufferSize,
|
||||
OUT UINTN *TableKey
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InstallXenTables (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InstallQemuFwCfgTables (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InstallAcpiTables (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiTable
|
||||
);
|
||||
|
||||
VOID
|
||||
EnablePciDecoding (
|
||||
OUT ORIGINAL_ATTRIBUTES **OriginalAttributes,
|
||||
OUT UINTN *Count
|
||||
);
|
||||
|
||||
VOID
|
||||
RestorePciDecoding (
|
||||
IN ORIGINAL_ATTRIBUTES *OriginalAttributes,
|
||||
IN UINTN Count
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
AllocateS3Context (
|
||||
OUT S3_CONTEXT **S3Context,
|
||||
IN UINTN WritePointerCount
|
||||
);
|
||||
|
||||
VOID
|
||||
ReleaseS3Context (
|
||||
IN S3_CONTEXT *S3Context
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
SaveCondensedWritePointerToS3Context (
|
||||
IN OUT S3_CONTEXT *S3Context,
|
||||
IN UINT16 PointerItem,
|
||||
IN UINT8 PointerSize,
|
||||
IN UINT32 PointerOffset,
|
||||
IN UINT64 PointerValue
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
TransferS3ContextToBootScript (
|
||||
IN S3_CONTEXT *S3Context
|
||||
);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,269 @@
|
|||
/** @file
|
||||
Append an ACPI S3 Boot Script fragment from the QEMU_LOADER_WRITE_POINTER
|
||||
commands of QEMU's fully processed table linker/loader script.
|
||||
|
||||
Copyright (C) 2017-2021, Red Hat, Inc.
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <Library/BaseLib.h> // CpuDeadLoop()
|
||||
#include <Library/DebugLib.h> // DEBUG()
|
||||
#include <Library/MemoryAllocationLib.h> // AllocatePool()
|
||||
#include <Library/QemuFwCfgS3Lib.h> // QemuFwCfgS3ScriptSkipBytes()
|
||||
|
||||
#include "AcpiPlatform.h"
|
||||
|
||||
|
||||
//
|
||||
// Condensed structure for capturing the fw_cfg operations -- select, skip,
|
||||
// write -- inherent in executing a QEMU_LOADER_WRITE_POINTER command.
|
||||
//
|
||||
typedef struct {
|
||||
UINT16 PointerItem; // resolved from QEMU_LOADER_WRITE_POINTER.PointerFile
|
||||
UINT8 PointerSize; // copied as-is from QEMU_LOADER_WRITE_POINTER
|
||||
UINT32 PointerOffset; // copied as-is from QEMU_LOADER_WRITE_POINTER
|
||||
UINT64 PointerValue; // resolved from QEMU_LOADER_WRITE_POINTER.PointeeFile
|
||||
// and QEMU_LOADER_WRITE_POINTER.PointeeOffset
|
||||
} CONDENSED_WRITE_POINTER;
|
||||
|
||||
|
||||
//
|
||||
// Context structure to accumulate CONDENSED_WRITE_POINTER objects from
|
||||
// QEMU_LOADER_WRITE_POINTER commands.
|
||||
//
|
||||
// Any pointers in this structure own the pointed-to objects; that is, when the
|
||||
// context structure is released, all pointed-to objects must be released too.
|
||||
//
|
||||
struct S3_CONTEXT {
|
||||
CONDENSED_WRITE_POINTER *WritePointers; // one array element per processed
|
||||
// QEMU_LOADER_WRITE_POINTER
|
||||
// command
|
||||
UINTN Allocated; // number of elements allocated for
|
||||
// WritePointers
|
||||
UINTN Used; // number of elements populated in
|
||||
// WritePointers
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Scratch buffer, allocated in EfiReservedMemoryType type memory, for the ACPI
|
||||
// S3 Boot Script opcodes to work on.
|
||||
//
|
||||
#pragma pack (1)
|
||||
typedef union {
|
||||
UINT64 PointerValue; // filled in from CONDENSED_WRITE_POINTER.PointerValue
|
||||
} SCRATCH_BUFFER;
|
||||
#pragma pack ()
|
||||
|
||||
|
||||
/**
|
||||
Allocate an S3_CONTEXT object.
|
||||
|
||||
@param[out] S3Context The allocated S3_CONTEXT object is returned
|
||||
through this parameter.
|
||||
|
||||
@param[in] WritePointerCount Number of CONDENSED_WRITE_POINTER elements to
|
||||
allocate room for. WritePointerCount must be
|
||||
positive.
|
||||
|
||||
@retval EFI_SUCCESS Allocation successful.
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Out of memory.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER WritePointerCount is zero.
|
||||
**/
|
||||
EFI_STATUS
|
||||
AllocateS3Context (
|
||||
OUT S3_CONTEXT **S3Context,
|
||||
IN UINTN WritePointerCount
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
S3_CONTEXT *Context;
|
||||
|
||||
if (WritePointerCount == 0) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Context = AllocateZeroPool (sizeof *Context);
|
||||
if (Context == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Context->WritePointers = AllocatePool (WritePointerCount *
|
||||
sizeof *Context->WritePointers);
|
||||
if (Context->WritePointers == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto FreeContext;
|
||||
}
|
||||
|
||||
Context->Allocated = WritePointerCount;
|
||||
*S3Context = Context;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
FreeContext:
|
||||
FreePool (Context);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Release an S3_CONTEXT object.
|
||||
|
||||
@param[in] S3Context The object to release.
|
||||
**/
|
||||
VOID
|
||||
ReleaseS3Context (
|
||||
IN S3_CONTEXT *S3Context
|
||||
)
|
||||
{
|
||||
FreePool (S3Context->WritePointers);
|
||||
FreePool (S3Context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Save the information necessary to replicate a QEMU_LOADER_WRITE_POINTER
|
||||
command during S3 resume, in condensed format.
|
||||
|
||||
This function is to be called from ProcessCmdWritePointer(), after all the
|
||||
sanity checks have passed, and before the fw_cfg operations are performed.
|
||||
|
||||
@param[in,out] S3Context The S3_CONTEXT object into which the caller wants
|
||||
to save the information that was derived from
|
||||
QEMU_LOADER_WRITE_POINTER.
|
||||
|
||||
@param[in] PointerItem The FIRMWARE_CONFIG_ITEM that
|
||||
QEMU_LOADER_WRITE_POINTER.PointerFile was resolved
|
||||
to, expressed as a UINT16 value.
|
||||
|
||||
@param[in] PointerSize Copied directly from
|
||||
QEMU_LOADER_WRITE_POINTER.PointerSize.
|
||||
|
||||
@param[in] PointerOffset Copied directly from
|
||||
QEMU_LOADER_WRITE_POINTER.PointerOffset.
|
||||
|
||||
@param[in] PointerValue The base address of the allocated / downloaded
|
||||
fw_cfg blob that is identified by
|
||||
QEMU_LOADER_WRITE_POINTER.PointeeFile, plus
|
||||
QEMU_LOADER_WRITE_POINTER.PointeeOffset.
|
||||
|
||||
@retval EFI_SUCCESS The information derived from
|
||||
QEMU_LOADER_WRITE_POINTER has been successfully
|
||||
absorbed into S3Context.
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES No room available in S3Context.
|
||||
**/
|
||||
EFI_STATUS
|
||||
SaveCondensedWritePointerToS3Context (
|
||||
IN OUT S3_CONTEXT *S3Context,
|
||||
IN UINT16 PointerItem,
|
||||
IN UINT8 PointerSize,
|
||||
IN UINT32 PointerOffset,
|
||||
IN UINT64 PointerValue
|
||||
)
|
||||
{
|
||||
CONDENSED_WRITE_POINTER *Condensed;
|
||||
|
||||
if (S3Context->Used == S3Context->Allocated) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
Condensed = S3Context->WritePointers + S3Context->Used;
|
||||
Condensed->PointerItem = PointerItem;
|
||||
Condensed->PointerSize = PointerSize;
|
||||
Condensed->PointerOffset = PointerOffset;
|
||||
Condensed->PointerValue = PointerValue;
|
||||
DEBUG ((DEBUG_VERBOSE, "%a: 0x%04x/[0x%08x+%d] := 0x%Lx (%Lu)\n",
|
||||
__FUNCTION__, PointerItem, PointerOffset, PointerSize, PointerValue,
|
||||
(UINT64)S3Context->Used));
|
||||
++S3Context->Used;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION provided to QemuFwCfgS3Lib.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
EFIAPI
|
||||
AppendFwCfgBootScript (
|
||||
IN OUT VOID *Context, OPTIONAL
|
||||
IN OUT VOID *ExternalScratchBuffer
|
||||
)
|
||||
{
|
||||
S3_CONTEXT *S3Context;
|
||||
SCRATCH_BUFFER *ScratchBuffer;
|
||||
UINTN Index;
|
||||
|
||||
S3Context = Context;
|
||||
ScratchBuffer = ExternalScratchBuffer;
|
||||
|
||||
for (Index = 0; Index < S3Context->Used; ++Index) {
|
||||
CONST CONDENSED_WRITE_POINTER *Condensed;
|
||||
RETURN_STATUS Status;
|
||||
|
||||
Condensed = &S3Context->WritePointers[Index];
|
||||
|
||||
Status = QemuFwCfgS3ScriptSkipBytes (Condensed->PointerItem,
|
||||
Condensed->PointerOffset);
|
||||
if (RETURN_ERROR (Status)) {
|
||||
goto FatalError;
|
||||
}
|
||||
|
||||
ScratchBuffer->PointerValue = Condensed->PointerValue;
|
||||
Status = QemuFwCfgS3ScriptWriteBytes (-1, Condensed->PointerSize);
|
||||
if (RETURN_ERROR (Status)) {
|
||||
goto FatalError;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG ((DEBUG_VERBOSE, "%a: boot script fragment saved\n", __FUNCTION__));
|
||||
|
||||
ReleaseS3Context (S3Context);
|
||||
return;
|
||||
|
||||
FatalError:
|
||||
ASSERT (FALSE);
|
||||
CpuDeadLoop ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Translate and append the information from an S3_CONTEXT object to the ACPI S3
|
||||
Boot Script.
|
||||
|
||||
The effects of a successful call to this function cannot be undone.
|
||||
|
||||
@param[in] S3Context The S3_CONTEXT object to translate to ACPI S3 Boot
|
||||
Script opcodes. If the function returns successfully,
|
||||
the caller must set the S3Context pointer -- originally
|
||||
returned by AllocateS3Context() -- immediately to NULL,
|
||||
because the ownership of S3Context has been transferred.
|
||||
|
||||
@retval EFI_SUCCESS The translation of S3Context to ACPI S3 Boot Script
|
||||
opcodes has been successfully executed or queued. (This
|
||||
includes the case when S3Context was empty on input and
|
||||
no ACPI S3 Boot Script opcodes have been necessary to
|
||||
produce.)
|
||||
|
||||
@return Error codes from underlying functions.
|
||||
**/
|
||||
EFI_STATUS
|
||||
TransferS3ContextToBootScript (
|
||||
IN S3_CONTEXT *S3Context
|
||||
)
|
||||
{
|
||||
RETURN_STATUS Status;
|
||||
|
||||
if (S3Context->Used == 0) {
|
||||
ReleaseS3Context (S3Context);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Status = QemuFwCfgS3CallWhenBootScriptReady (AppendFwCfgBootScript,
|
||||
S3Context, sizeof (SCRATCH_BUFFER));
|
||||
return (EFI_STATUS)Status;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/** @file
|
||||
Entry point of OVMF ACPI Platform Driver for Xen guests
|
||||
|
||||
Copyright (C) 2015-2021, Red Hat, Inc.
|
||||
Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <Guid/RootBridgesConnectedEventGroup.h> // gRootBridgesConnectedEve...
|
||||
#include <Library/DebugLib.h> // DEBUG()
|
||||
#include <Library/PcdLib.h> // PcdGetBool()
|
||||
#include <Library/UefiBootServicesTableLib.h> // gBS
|
||||
#include <Protocol/AcpiTable.h> // EFI_ACPI_TABLE_PROTOCOL
|
||||
|
||||
#include "AcpiPlatform.h"
|
||||
|
||||
STATIC
|
||||
EFI_ACPI_TABLE_PROTOCOL *
|
||||
FindAcpiTableProtocol (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
|
||||
|
||||
Status = gBS->LocateProtocol (
|
||||
&gEfiAcpiTableProtocolGuid,
|
||||
NULL,
|
||||
(VOID**)&AcpiTable
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
return AcpiTable;
|
||||
}
|
||||
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
EFIAPI
|
||||
OnRootBridgesConnected (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
DEBUG ((DEBUG_INFO,
|
||||
"%a: root bridges have been connected, installing ACPI tables\n",
|
||||
__FUNCTION__));
|
||||
Status = InstallAcpiTables (FindAcpiTableProtocol ());
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "%a: InstallAcpiTables: %r\n", __FUNCTION__, Status));
|
||||
}
|
||||
gBS->CloseEvent (Event);
|
||||
}
|
||||
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AcpiPlatformEntryPoint (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_EVENT RootBridgesConnected;
|
||||
|
||||
//
|
||||
// If the platform doesn't support PCI, or PCI enumeration has been disabled,
|
||||
// install the tables at once, and let the entry point's return code reflect
|
||||
// the full functionality.
|
||||
//
|
||||
if (PcdGetBool (PcdPciDisableBusEnumeration)) {
|
||||
DEBUG ((DEBUG_INFO, "%a: PCI or its enumeration disabled, installing "
|
||||
"ACPI tables\n", __FUNCTION__));
|
||||
return InstallAcpiTables (FindAcpiTableProtocol ());
|
||||
}
|
||||
|
||||
//
|
||||
// Otherwise, delay installing the ACPI tables until root bridges are
|
||||
// connected. The entry point's return status will only reflect the callback
|
||||
// setup. (Note that we're a DXE_DRIVER; our entry point function is invoked
|
||||
// strictly before BDS is entered and can connect the root bridges.)
|
||||
//
|
||||
Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
|
||||
OnRootBridgesConnected, NULL /* Context */,
|
||||
&gRootBridgesConnectedEventGroupGuid, &RootBridgesConnected);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_INFO,
|
||||
"%a: waiting for root bridges to be connected, registered callback\n",
|
||||
__FUNCTION__));
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
/** @file
|
||||
Temporarily enable IO and MMIO decoding for all PCI devices while QEMU
|
||||
regenerates the ACPI tables.
|
||||
|
||||
Copyright (C) 2016-2021, Red Hat, Inc.
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <Library/DebugLib.h> // DEBUG()
|
||||
#include <Library/MemoryAllocationLib.h> // AllocatePool()
|
||||
#include <Library/UefiBootServicesTableLib.h> // gBS
|
||||
|
||||
#include "AcpiPlatform.h"
|
||||
|
||||
|
||||
/**
|
||||
Collect all PciIo protocol instances in the system. Save their original
|
||||
attributes, and enable IO and MMIO decoding for each.
|
||||
|
||||
This is a best effort function; it doesn't return status codes. Its
|
||||
caller is supposed to proceed even if this function fails.
|
||||
|
||||
@param[out] OriginalAttributes On output, a dynamically allocated array of
|
||||
ORIGINAL_ATTRIBUTES elements. The array lists
|
||||
the PciIo protocol instances found in the
|
||||
system at the time of the call, plus the
|
||||
original PCI attributes for each.
|
||||
|
||||
Before returning, the function enables IO and
|
||||
MMIO decoding for each PciIo instance it
|
||||
finds.
|
||||
|
||||
On error, or when no such instances are
|
||||
found, OriginalAttributes is set to NULL.
|
||||
|
||||
@param[out] Count On output, the number of elements in
|
||||
OriginalAttributes. On error it is set to
|
||||
zero.
|
||||
**/
|
||||
VOID
|
||||
EnablePciDecoding (
|
||||
OUT ORIGINAL_ATTRIBUTES **OriginalAttributes,
|
||||
OUT UINTN *Count
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN NoHandles;
|
||||
EFI_HANDLE *Handles;
|
||||
ORIGINAL_ATTRIBUTES *OrigAttrs;
|
||||
UINTN Idx;
|
||||
|
||||
*OriginalAttributes = NULL;
|
||||
*Count = 0;
|
||||
|
||||
if (PcdGetBool (PcdPciDisableBusEnumeration)) {
|
||||
//
|
||||
// The platform downloads ACPI tables from QEMU in general, but there are
|
||||
// no root bridges in this execution. We're done.
|
||||
//
|
||||
return;
|
||||
}
|
||||
|
||||
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPciIoProtocolGuid,
|
||||
NULL /* SearchKey */, &NoHandles, &Handles);
|
||||
if (Status == EFI_NOT_FOUND) {
|
||||
//
|
||||
// No PCI devices were found on either of the root bridges. We're done.
|
||||
//
|
||||
return;
|
||||
}
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_WARN, "%a: LocateHandleBuffer(): %r\n", __FUNCTION__,
|
||||
Status));
|
||||
return;
|
||||
}
|
||||
|
||||
OrigAttrs = AllocatePool (NoHandles * sizeof *OrigAttrs);
|
||||
if (OrigAttrs == NULL) {
|
||||
DEBUG ((DEBUG_WARN, "%a: AllocatePool(): out of resources\n",
|
||||
__FUNCTION__));
|
||||
goto FreeHandles;
|
||||
}
|
||||
|
||||
for (Idx = 0; Idx < NoHandles; ++Idx) {
|
||||
EFI_PCI_IO_PROTOCOL *PciIo;
|
||||
UINT64 Attributes;
|
||||
|
||||
//
|
||||
// Look up PciIo on the handle and stash it
|
||||
//
|
||||
Status = gBS->HandleProtocol (Handles[Idx], &gEfiPciIoProtocolGuid,
|
||||
(VOID**)&PciIo);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
OrigAttrs[Idx].PciIo = PciIo;
|
||||
|
||||
//
|
||||
// Stash the current attributes
|
||||
//
|
||||
Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationGet, 0,
|
||||
&OrigAttrs[Idx].PciAttributes);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_WARN, "%a: EfiPciIoAttributeOperationGet: %r\n",
|
||||
__FUNCTION__, Status));
|
||||
goto RestoreAttributes;
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve supported attributes
|
||||
//
|
||||
Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationSupported, 0,
|
||||
&Attributes);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_WARN, "%a: EfiPciIoAttributeOperationSupported: %r\n",
|
||||
__FUNCTION__, Status));
|
||||
goto RestoreAttributes;
|
||||
}
|
||||
|
||||
//
|
||||
// Enable IO and MMIO decoding
|
||||
//
|
||||
Attributes &= EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY;
|
||||
Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationEnable,
|
||||
Attributes, NULL);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_WARN, "%a: EfiPciIoAttributeOperationEnable: %r\n",
|
||||
__FUNCTION__, Status));
|
||||
goto RestoreAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Success
|
||||
//
|
||||
FreePool (Handles);
|
||||
*OriginalAttributes = OrigAttrs;
|
||||
*Count = NoHandles;
|
||||
return;
|
||||
|
||||
RestoreAttributes:
|
||||
while (Idx > 0) {
|
||||
--Idx;
|
||||
OrigAttrs[Idx].PciIo->Attributes (OrigAttrs[Idx].PciIo,
|
||||
EfiPciIoAttributeOperationSet,
|
||||
OrigAttrs[Idx].PciAttributes,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
FreePool (OrigAttrs);
|
||||
|
||||
FreeHandles:
|
||||
FreePool (Handles);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Restore the original PCI attributes saved with EnablePciDecoding().
|
||||
|
||||
@param[in] OriginalAttributes The array allocated and populated by
|
||||
EnablePciDecoding(). This parameter may be
|
||||
NULL. If OriginalAttributes is NULL, then the
|
||||
function is a no-op; otherwise the PciIo
|
||||
attributes will be restored, and the
|
||||
OriginalAttributes array will be freed.
|
||||
|
||||
@param[in] Count The Count value stored by EnablePciDecoding(),
|
||||
the number of elements in OriginalAttributes.
|
||||
Count may be zero if and only if
|
||||
OriginalAttributes is NULL.
|
||||
**/
|
||||
VOID
|
||||
RestorePciDecoding (
|
||||
IN ORIGINAL_ATTRIBUTES *OriginalAttributes,
|
||||
IN UINTN Count
|
||||
)
|
||||
{
|
||||
UINTN Idx;
|
||||
|
||||
ASSERT ((OriginalAttributes == NULL) == (Count == 0));
|
||||
if (OriginalAttributes == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Idx = 0; Idx < Count; ++Idx) {
|
||||
OriginalAttributes[Idx].PciIo->Attributes (
|
||||
OriginalAttributes[Idx].PciIo,
|
||||
EfiPciIoAttributeOperationSet,
|
||||
OriginalAttributes[Idx].PciAttributes,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
FreePool (OriginalAttributes);
|
||||
}
|
|
@ -0,0 +1,511 @@
|
|||
/** @file
|
||||
OVMF ACPI QEMU support
|
||||
|
||||
Copyright (C) 2012-2021, Red Hat, Inc.
|
||||
Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <IndustryStandard/Acpi.h> // EFI_ACPI_1_0_IO_APIC_STRUCTURE
|
||||
#include <Library/BaseMemoryLib.h> // CopyMem()
|
||||
#include <Library/DebugLib.h> // DEBUG()
|
||||
#include <Library/DxeServicesTableLib.h> // gDS
|
||||
#include <Library/MemoryAllocationLib.h> // AllocatePool()
|
||||
#include <Library/PcdLib.h> // PcdGet16()
|
||||
#include <Library/QemuFwCfgLib.h> // QemuFwCfgIsAvailable()
|
||||
|
||||
#include "AcpiPlatform.h"
|
||||
|
||||
BOOLEAN
|
||||
QemuDetected (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if (!QemuFwCfgIsAvailable ()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
STATIC
|
||||
UINTN
|
||||
CountBits16 (
|
||||
UINT16 Mask
|
||||
)
|
||||
{
|
||||
//
|
||||
// For all N >= 1, N bits are enough to represent the number of bits set
|
||||
// among N bits. It's true for N == 1. When adding a new bit (N := N+1),
|
||||
// the maximum number of possibly set bits increases by one, while the
|
||||
// representable maximum doubles.
|
||||
//
|
||||
Mask = ((Mask & 0xAAAA) >> 1) + (Mask & 0x5555);
|
||||
Mask = ((Mask & 0xCCCC) >> 2) + (Mask & 0x3333);
|
||||
Mask = ((Mask & 0xF0F0) >> 4) + (Mask & 0x0F0F);
|
||||
Mask = ((Mask & 0xFF00) >> 8) + (Mask & 0x00FF);
|
||||
|
||||
return Mask;
|
||||
}
|
||||
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
QemuInstallAcpiMadtTable (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
|
||||
IN VOID *AcpiTableBuffer,
|
||||
IN UINTN AcpiTableBufferSize,
|
||||
OUT UINTN *TableKey
|
||||
)
|
||||
{
|
||||
UINTN CpuCount;
|
||||
UINTN PciLinkIsoCount;
|
||||
UINTN NewBufferSize;
|
||||
EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
|
||||
EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic;
|
||||
EFI_ACPI_1_0_IO_APIC_STRUCTURE *IoApic;
|
||||
EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *Iso;
|
||||
EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE *LocalApicNmi;
|
||||
VOID *Ptr;
|
||||
UINTN Loop;
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
||||
|
||||
QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
|
||||
CpuCount = QemuFwCfgRead16 ();
|
||||
ASSERT (CpuCount >= 1);
|
||||
|
||||
//
|
||||
// Set Level-tiggered, Active High for these identity mapped IRQs. The bitset
|
||||
// corresponds to the union of all possible interrupt assignments for the LNKA,
|
||||
// LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT.
|
||||
//
|
||||
PciLinkIsoCount = CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel));
|
||||
|
||||
NewBufferSize = 1 * sizeof (*Madt) +
|
||||
CpuCount * sizeof (*LocalApic) +
|
||||
1 * sizeof (*IoApic) +
|
||||
(1 + PciLinkIsoCount) * sizeof (*Iso) +
|
||||
1 * sizeof (*LocalApicNmi);
|
||||
|
||||
Madt = AllocatePool (NewBufferSize);
|
||||
if (Madt == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
||||
Madt->Header.Length = (UINT32) NewBufferSize;
|
||||
Madt->LocalApicAddress = PcdGet32 (PcdCpuLocalApicBaseAddress);
|
||||
Madt->Flags = EFI_ACPI_1_0_PCAT_COMPAT;
|
||||
Ptr = Madt + 1;
|
||||
|
||||
LocalApic = Ptr;
|
||||
for (Loop = 0; Loop < CpuCount; ++Loop) {
|
||||
LocalApic->Type = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC;
|
||||
LocalApic->Length = sizeof (*LocalApic);
|
||||
LocalApic->AcpiProcessorId = (UINT8) Loop;
|
||||
LocalApic->ApicId = (UINT8) Loop;
|
||||
LocalApic->Flags = 1; // enabled
|
||||
++LocalApic;
|
||||
}
|
||||
Ptr = LocalApic;
|
||||
|
||||
IoApic = Ptr;
|
||||
IoApic->Type = EFI_ACPI_1_0_IO_APIC;
|
||||
IoApic->Length = sizeof (*IoApic);
|
||||
IoApic->IoApicId = (UINT8) CpuCount;
|
||||
IoApic->Reserved = EFI_ACPI_RESERVED_BYTE;
|
||||
IoApic->IoApicAddress = 0xFEC00000;
|
||||
IoApic->SystemVectorBase = 0x00000000;
|
||||
Ptr = IoApic + 1;
|
||||
|
||||
//
|
||||
// IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
|
||||
//
|
||||
Iso = Ptr;
|
||||
Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
|
||||
Iso->Length = sizeof (*Iso);
|
||||
Iso->Bus = 0x00; // ISA
|
||||
Iso->Source = 0x00; // IRQ0
|
||||
Iso->GlobalSystemInterruptVector = 0x00000002;
|
||||
Iso->Flags = 0x0000; // Conforms to specs of the bus
|
||||
++Iso;
|
||||
|
||||
//
|
||||
// Set Level-triggered, Active High for all possible PCI link targets.
|
||||
//
|
||||
for (Loop = 0; Loop < 16; ++Loop) {
|
||||
if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel) & (1 << Loop)) == 0) {
|
||||
continue;
|
||||
}
|
||||
Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
|
||||
Iso->Length = sizeof (*Iso);
|
||||
Iso->Bus = 0x00; // ISA
|
||||
Iso->Source = (UINT8) Loop;
|
||||
Iso->GlobalSystemInterruptVector = (UINT32) Loop;
|
||||
Iso->Flags = 0x000D; // Level-triggered, Active High
|
||||
++Iso;
|
||||
}
|
||||
ASSERT (
|
||||
(UINTN) (Iso - (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)Ptr) ==
|
||||
1 + PciLinkIsoCount
|
||||
);
|
||||
Ptr = Iso;
|
||||
|
||||
LocalApicNmi = Ptr;
|
||||
LocalApicNmi->Type = EFI_ACPI_1_0_LOCAL_APIC_NMI;
|
||||
LocalApicNmi->Length = sizeof (*LocalApicNmi);
|
||||
LocalApicNmi->AcpiProcessorId = 0xFF; // applies to all processors
|
||||
//
|
||||
// polarity and trigger mode of the APIC I/O input signals conform to the
|
||||
// specifications of the bus
|
||||
//
|
||||
LocalApicNmi->Flags = 0x0000;
|
||||
//
|
||||
// Local APIC interrupt input LINTn to which NMI is connected.
|
||||
//
|
||||
LocalApicNmi->LocalApicInti = 0x01;
|
||||
Ptr = LocalApicNmi + 1;
|
||||
|
||||
ASSERT ((UINTN) ((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize);
|
||||
Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
|
||||
|
||||
FreePool (Madt);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct {
|
||||
UINT64 Base;
|
||||
UINT64 End;
|
||||
UINT64 Length;
|
||||
} PCI_WINDOW;
|
||||
|
||||
typedef struct {
|
||||
PCI_WINDOW PciWindow32;
|
||||
PCI_WINDOW PciWindow64;
|
||||
} FIRMWARE_DATA;
|
||||
|
||||
typedef struct {
|
||||
UINT8 BytePrefix;
|
||||
UINT8 ByteValue;
|
||||
} AML_BYTE;
|
||||
|
||||
typedef struct {
|
||||
UINT8 NameOp;
|
||||
UINT8 RootChar;
|
||||
UINT8 NameChar[4];
|
||||
UINT8 PackageOp;
|
||||
UINT8 PkgLength;
|
||||
UINT8 NumElements;
|
||||
AML_BYTE Pm1aCntSlpTyp;
|
||||
AML_BYTE Pm1bCntSlpTyp;
|
||||
AML_BYTE Reserved[2];
|
||||
} SYSTEM_STATE_PACKAGE;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
PopulateFwData(
|
||||
OUT FIRMWARE_DATA *FwData
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN NumDesc;
|
||||
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDesc;
|
||||
|
||||
Status = gDS->GetMemorySpaceMap (&NumDesc, &AllDesc);
|
||||
if (Status == EFI_SUCCESS) {
|
||||
UINT64 NonMmio32MaxExclTop;
|
||||
UINT64 Mmio32MinBase;
|
||||
UINT64 Mmio32MaxExclTop;
|
||||
UINTN CurDesc;
|
||||
|
||||
Status = EFI_UNSUPPORTED;
|
||||
|
||||
NonMmio32MaxExclTop = 0;
|
||||
Mmio32MinBase = BASE_4GB;
|
||||
Mmio32MaxExclTop = 0;
|
||||
|
||||
for (CurDesc = 0; CurDesc < NumDesc; ++CurDesc) {
|
||||
CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
|
||||
UINT64 ExclTop;
|
||||
|
||||
Desc = &AllDesc[CurDesc];
|
||||
ExclTop = Desc->BaseAddress + Desc->Length;
|
||||
|
||||
if (ExclTop <= (UINT64) PcdGet32 (PcdOvmfFdBaseAddress)) {
|
||||
switch (Desc->GcdMemoryType) {
|
||||
case EfiGcdMemoryTypeNonExistent:
|
||||
break;
|
||||
|
||||
case EfiGcdMemoryTypeReserved:
|
||||
case EfiGcdMemoryTypeSystemMemory:
|
||||
if (NonMmio32MaxExclTop < ExclTop) {
|
||||
NonMmio32MaxExclTop = ExclTop;
|
||||
}
|
||||
break;
|
||||
|
||||
case EfiGcdMemoryTypeMemoryMappedIo:
|
||||
if (Mmio32MinBase > Desc->BaseAddress) {
|
||||
Mmio32MinBase = Desc->BaseAddress;
|
||||
}
|
||||
if (Mmio32MaxExclTop < ExclTop) {
|
||||
Mmio32MaxExclTop = ExclTop;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Mmio32MinBase < NonMmio32MaxExclTop) {
|
||||
Mmio32MinBase = NonMmio32MaxExclTop;
|
||||
}
|
||||
|
||||
if (Mmio32MinBase < Mmio32MaxExclTop) {
|
||||
FwData->PciWindow32.Base = Mmio32MinBase;
|
||||
FwData->PciWindow32.End = Mmio32MaxExclTop - 1;
|
||||
FwData->PciWindow32.Length = Mmio32MaxExclTop - Mmio32MinBase;
|
||||
|
||||
FwData->PciWindow64.Base = 0;
|
||||
FwData->PciWindow64.End = 0;
|
||||
FwData->PciWindow64.Length = 0;
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
}
|
||||
|
||||
FreePool (AllDesc);
|
||||
}
|
||||
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
|
||||
FwData->PciWindow32.Base,
|
||||
FwData->PciWindow32.End,
|
||||
FwData->PciWindow32.Length
|
||||
));
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
|
||||
FwData->PciWindow64.Base,
|
||||
FwData->PciWindow64.End,
|
||||
FwData->PciWindow64.Length
|
||||
));
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
EFIAPI
|
||||
GetSuspendStates (
|
||||
UINTN *SuspendToRamSize,
|
||||
SYSTEM_STATE_PACKAGE *SuspendToRam,
|
||||
UINTN *SuspendToDiskSize,
|
||||
SYSTEM_STATE_PACKAGE *SuspendToDisk
|
||||
)
|
||||
{
|
||||
STATIC CONST SYSTEM_STATE_PACKAGE Template = {
|
||||
0x08, // NameOp
|
||||
'\\', // RootChar
|
||||
{ '_', 'S', 'x', '_' }, // NameChar[4]
|
||||
0x12, // PackageOp
|
||||
0x0A, // PkgLength
|
||||
0x04, // NumElements
|
||||
{ 0x0A, 0x00 }, // Pm1aCntSlpTyp
|
||||
{ 0x0A, 0x00 }, // Pm1bCntSlpTyp -- we don't support it
|
||||
{ // Reserved[2]
|
||||
{ 0x0A, 0x00 },
|
||||
{ 0x0A, 0x00 }
|
||||
}
|
||||
};
|
||||
RETURN_STATUS Status;
|
||||
FIRMWARE_CONFIG_ITEM FwCfgItem;
|
||||
UINTN FwCfgSize;
|
||||
UINT8 SystemStates[6];
|
||||
|
||||
//
|
||||
// configure defaults
|
||||
//
|
||||
*SuspendToRamSize = sizeof Template;
|
||||
CopyMem (SuspendToRam, &Template, sizeof Template);
|
||||
SuspendToRam->NameChar[2] = '3'; // S3
|
||||
SuspendToRam->Pm1aCntSlpTyp.ByteValue = 1; // PIIX4: STR
|
||||
|
||||
*SuspendToDiskSize = sizeof Template;
|
||||
CopyMem (SuspendToDisk, &Template, sizeof Template);
|
||||
SuspendToDisk->NameChar[2] = '4'; // S4
|
||||
SuspendToDisk->Pm1aCntSlpTyp.ByteValue = 2; // PIIX4: POSCL
|
||||
|
||||
//
|
||||
// check for overrides
|
||||
//
|
||||
Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
|
||||
if (Status != RETURN_SUCCESS || FwCfgSize != sizeof SystemStates) {
|
||||
DEBUG ((DEBUG_INFO, "ACPI using S3/S4 defaults\n"));
|
||||
return;
|
||||
}
|
||||
QemuFwCfgSelectItem (FwCfgItem);
|
||||
QemuFwCfgReadBytes (sizeof SystemStates, SystemStates);
|
||||
|
||||
//
|
||||
// Each byte corresponds to a system state. In each byte, the MSB tells us
|
||||
// whether the given state is enabled. If so, the three LSBs specify the
|
||||
// value to be written to the PM control register's SUS_TYP bits.
|
||||
//
|
||||
if (SystemStates[3] & BIT7) {
|
||||
SuspendToRam->Pm1aCntSlpTyp.ByteValue =
|
||||
SystemStates[3] & (BIT2 | BIT1 | BIT0);
|
||||
DEBUG ((DEBUG_INFO, "ACPI S3 value: %d\n",
|
||||
SuspendToRam->Pm1aCntSlpTyp.ByteValue));
|
||||
} else {
|
||||
*SuspendToRamSize = 0;
|
||||
DEBUG ((DEBUG_INFO, "ACPI S3 disabled\n"));
|
||||
}
|
||||
|
||||
if (SystemStates[4] & BIT7) {
|
||||
SuspendToDisk->Pm1aCntSlpTyp.ByteValue =
|
||||
SystemStates[4] & (BIT2 | BIT1 | BIT0);
|
||||
DEBUG ((DEBUG_INFO, "ACPI S4 value: %d\n",
|
||||
SuspendToDisk->Pm1aCntSlpTyp.ByteValue));
|
||||
} else {
|
||||
*SuspendToDiskSize = 0;
|
||||
DEBUG ((DEBUG_INFO, "ACPI S4 disabled\n"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
QemuInstallAcpiSsdtTable (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
|
||||
IN VOID *AcpiTableBuffer,
|
||||
IN UINTN AcpiTableBufferSize,
|
||||
OUT UINTN *TableKey
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
FIRMWARE_DATA *FwData;
|
||||
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
|
||||
FwData = AllocateReservedPool (sizeof (*FwData));
|
||||
if (FwData != NULL) {
|
||||
UINTN SuspendToRamSize;
|
||||
SYSTEM_STATE_PACKAGE SuspendToRam;
|
||||
UINTN SuspendToDiskSize;
|
||||
SYSTEM_STATE_PACKAGE SuspendToDisk;
|
||||
UINTN SsdtSize;
|
||||
UINT8 *Ssdt;
|
||||
|
||||
GetSuspendStates (&SuspendToRamSize, &SuspendToRam,
|
||||
&SuspendToDiskSize, &SuspendToDisk);
|
||||
SsdtSize = AcpiTableBufferSize + 17 + SuspendToRamSize + SuspendToDiskSize;
|
||||
Ssdt = AllocatePool (SsdtSize);
|
||||
|
||||
if (Ssdt != NULL) {
|
||||
Status = PopulateFwData (FwData);
|
||||
|
||||
if (Status == EFI_SUCCESS) {
|
||||
UINT8 *SsdtPtr;
|
||||
|
||||
SsdtPtr = Ssdt;
|
||||
|
||||
CopyMem (SsdtPtr, AcpiTableBuffer, AcpiTableBufferSize);
|
||||
SsdtPtr += AcpiTableBufferSize;
|
||||
|
||||
//
|
||||
// build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
|
||||
//
|
||||
*(SsdtPtr++) = 0x5B; // ExtOpPrefix
|
||||
*(SsdtPtr++) = 0x80; // OpRegionOp
|
||||
*(SsdtPtr++) = 'F';
|
||||
*(SsdtPtr++) = 'W';
|
||||
*(SsdtPtr++) = 'D';
|
||||
*(SsdtPtr++) = 'T';
|
||||
*(SsdtPtr++) = 0x00; // SystemMemory
|
||||
*(SsdtPtr++) = 0x0C; // DWordPrefix
|
||||
|
||||
//
|
||||
// no virtual addressing yet, take the four least significant bytes
|
||||
//
|
||||
CopyMem(SsdtPtr, &FwData, 4);
|
||||
SsdtPtr += 4;
|
||||
|
||||
*(SsdtPtr++) = 0x0C; // DWordPrefix
|
||||
|
||||
*(UINT32*) SsdtPtr = sizeof (*FwData);
|
||||
SsdtPtr += 4;
|
||||
|
||||
//
|
||||
// add suspend system states
|
||||
//
|
||||
CopyMem (SsdtPtr, &SuspendToRam, SuspendToRamSize);
|
||||
SsdtPtr += SuspendToRamSize;
|
||||
CopyMem (SsdtPtr, &SuspendToDisk, SuspendToDiskSize);
|
||||
SsdtPtr += SuspendToDiskSize;
|
||||
|
||||
ASSERT((UINTN) (SsdtPtr - Ssdt) == SsdtSize);
|
||||
((EFI_ACPI_DESCRIPTION_HEADER *) Ssdt)->Length = (UINT32) SsdtSize;
|
||||
Status = InstallAcpiTable (AcpiProtocol, Ssdt, SsdtSize, TableKey);
|
||||
}
|
||||
|
||||
FreePool(Ssdt);
|
||||
}
|
||||
|
||||
if (Status != EFI_SUCCESS) {
|
||||
FreePool(FwData);
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
QemuInstallAcpiTable (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
|
||||
IN VOID *AcpiTableBuffer,
|
||||
IN UINTN AcpiTableBufferSize,
|
||||
OUT UINTN *TableKey
|
||||
)
|
||||
{
|
||||
EFI_ACPI_DESCRIPTION_HEADER *Hdr;
|
||||
EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction;
|
||||
|
||||
Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer;
|
||||
switch (Hdr->Signature) {
|
||||
case EFI_ACPI_1_0_APIC_SIGNATURE:
|
||||
TableInstallFunction = QemuInstallAcpiMadtTable;
|
||||
break;
|
||||
case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
|
||||
TableInstallFunction = QemuInstallAcpiSsdtTable;
|
||||
break;
|
||||
default:
|
||||
TableInstallFunction = InstallAcpiTable;
|
||||
}
|
||||
|
||||
return TableInstallFunction (
|
||||
AcpiProtocol,
|
||||
AcpiTableBuffer,
|
||||
AcpiTableBufferSize,
|
||||
TableKey
|
||||
);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,316 @@
|
|||
/** @file
|
||||
OVMF ACPI Xen support
|
||||
|
||||
Copyright (C) 2021, Red Hat, Inc.
|
||||
Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2012, Bei Guan <gbtju85@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <Library/BaseLib.h> // CpuDeadLoop()
|
||||
#include <Library/DebugLib.h> // DEBUG()
|
||||
#include <Library/XenPlatformLib.h> // XenGetInfoHOB()
|
||||
|
||||
#include "AcpiPlatform.h"
|
||||
|
||||
#define XEN_ACPI_PHYSICAL_ADDRESS 0x000EA020
|
||||
#define XEN_BIOS_PHYSICAL_END 0x000FFFFF
|
||||
|
||||
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *XenAcpiRsdpStructurePtr = NULL;
|
||||
|
||||
/**
|
||||
Get the address of Xen ACPI Root System Description Pointer (RSDP)
|
||||
structure.
|
||||
|
||||
@param RsdpStructurePtr Return pointer to RSDP structure
|
||||
|
||||
@return EFI_SUCCESS Find Xen RSDP structure successfully.
|
||||
@return EFI_NOT_FOUND Don't find Xen RSDP structure.
|
||||
@return EFI_ABORTED Find Xen RSDP structure, but it's not integrated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
GetXenAcpiRsdp (
|
||||
OUT EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER **RsdpPtr
|
||||
)
|
||||
{
|
||||
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *RsdpStructurePtr;
|
||||
UINT8 *XenAcpiPtr;
|
||||
UINT8 Sum;
|
||||
EFI_XEN_INFO *XenInfo;
|
||||
|
||||
//
|
||||
// Detect the RSDP structure
|
||||
//
|
||||
|
||||
//
|
||||
// First look for PVH one
|
||||
//
|
||||
XenInfo = XenGetInfoHOB ();
|
||||
ASSERT (XenInfo != NULL);
|
||||
if (XenInfo->RsdpPvh != NULL) {
|
||||
DEBUG ((DEBUG_INFO, "%a: Use ACPI RSDP table at 0x%p\n",
|
||||
gEfiCallerBaseName, XenInfo->RsdpPvh));
|
||||
*RsdpPtr = XenInfo->RsdpPvh;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Otherwise, look for the HVM one
|
||||
//
|
||||
for (XenAcpiPtr = (UINT8*)(UINTN) XEN_ACPI_PHYSICAL_ADDRESS;
|
||||
XenAcpiPtr < (UINT8*)(UINTN) XEN_BIOS_PHYSICAL_END;
|
||||
XenAcpiPtr += 0x10) {
|
||||
|
||||
RsdpStructurePtr = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)
|
||||
(UINTN) XenAcpiPtr;
|
||||
|
||||
if (!AsciiStrnCmp ((CHAR8 *) &RsdpStructurePtr->Signature, "RSD PTR ", 8)) {
|
||||
//
|
||||
// RSDP ACPI 1.0 checksum for 1.0/2.0/3.0 table.
|
||||
// This is only the first 20 bytes of the structure
|
||||
//
|
||||
Sum = CalculateSum8 (
|
||||
(CONST UINT8 *)RsdpStructurePtr,
|
||||
sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER)
|
||||
);
|
||||
if (Sum != 0) {
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
if (RsdpStructurePtr->Revision >= 2) {
|
||||
//
|
||||
// RSDP ACPI 2.0/3.0 checksum, this is the entire table
|
||||
//
|
||||
Sum = CalculateSum8 (
|
||||
(CONST UINT8 *)RsdpStructurePtr,
|
||||
sizeof (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER)
|
||||
);
|
||||
if (Sum != 0) {
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
}
|
||||
*RsdpPtr = RsdpStructurePtr;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
Get Xen Acpi tables from the RSDP structure. And installs Xen ACPI tables
|
||||
into the RSDT/XSDT using InstallAcpiTable. Some signature of the installed
|
||||
ACPI tables are: FACP, APIC, HPET, WAET, SSDT, FACS, DSDT.
|
||||
|
||||
@param AcpiProtocol Protocol instance pointer.
|
||||
|
||||
@return EFI_SUCCESS The table was successfully inserted.
|
||||
@return EFI_INVALID_PARAMETER Either AcpiTableBuffer is NULL, TableHandle is
|
||||
NULL, or AcpiTableBufferSize and the size
|
||||
field embedded in the ACPI table pointed to
|
||||
by AcpiTableBuffer are not in sync.
|
||||
@return EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the request.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InstallXenTables (
|
||||
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN TableHandle;
|
||||
|
||||
EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
|
||||
EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
|
||||
VOID *CurrentTableEntry;
|
||||
UINTN CurrentTablePointer;
|
||||
EFI_ACPI_DESCRIPTION_HEADER *CurrentTable;
|
||||
UINTN Index;
|
||||
UINTN NumberOfTableEntries;
|
||||
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt2Table;
|
||||
EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt1Table;
|
||||
EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs2Table;
|
||||
EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs1Table;
|
||||
EFI_ACPI_DESCRIPTION_HEADER *DsdtTable;
|
||||
|
||||
Fadt2Table = NULL;
|
||||
Fadt1Table = NULL;
|
||||
Facs2Table = NULL;
|
||||
Facs1Table = NULL;
|
||||
DsdtTable = NULL;
|
||||
TableHandle = 0;
|
||||
NumberOfTableEntries = 0;
|
||||
|
||||
//
|
||||
// Try to find Xen ACPI tables
|
||||
//
|
||||
Status = GetXenAcpiRsdp (&XenAcpiRsdpStructurePtr);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// If XSDT table is find, just install its tables.
|
||||
// Otherwise, try to find and install the RSDT tables.
|
||||
//
|
||||
if (XenAcpiRsdpStructurePtr->XsdtAddress) {
|
||||
//
|
||||
// Retrieve the addresses of XSDT and
|
||||
// calculate the number of its table entries.
|
||||
//
|
||||
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN)
|
||||
XenAcpiRsdpStructurePtr->XsdtAddress;
|
||||
NumberOfTableEntries = (Xsdt->Length -
|
||||
sizeof (EFI_ACPI_DESCRIPTION_HEADER)) /
|
||||
sizeof (UINT64);
|
||||
|
||||
//
|
||||
// Install ACPI tables found in XSDT.
|
||||
//
|
||||
for (Index = 0; Index < NumberOfTableEntries; Index++) {
|
||||
//
|
||||
// Get the table entry from XSDT
|
||||
//
|
||||
CurrentTableEntry = (VOID *) ((UINT8 *) Xsdt +
|
||||
sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
|
||||
Index * sizeof (UINT64));
|
||||
CurrentTablePointer = (UINTN) *(UINT64 *)CurrentTableEntry;
|
||||
CurrentTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTablePointer;
|
||||
|
||||
//
|
||||
// Install the XSDT tables
|
||||
//
|
||||
Status = InstallAcpiTable (
|
||||
AcpiProtocol,
|
||||
CurrentTable,
|
||||
CurrentTable->Length,
|
||||
&TableHandle
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the FACS and DSDT table address from the table FADT
|
||||
//
|
||||
if (!AsciiStrnCmp ((CHAR8 *) &CurrentTable->Signature, "FACP", 4)) {
|
||||
Fadt2Table = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *)
|
||||
(UINTN) CurrentTablePointer;
|
||||
Facs2Table = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)
|
||||
(UINTN) Fadt2Table->FirmwareCtrl;
|
||||
DsdtTable = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Fadt2Table->Dsdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (XenAcpiRsdpStructurePtr->RsdtAddress) {
|
||||
//
|
||||
// Retrieve the addresses of RSDT and
|
||||
// calculate the number of its table entries.
|
||||
//
|
||||
Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN)
|
||||
XenAcpiRsdpStructurePtr->RsdtAddress;
|
||||
NumberOfTableEntries = (Rsdt->Length -
|
||||
sizeof (EFI_ACPI_DESCRIPTION_HEADER)) /
|
||||
sizeof (UINT32);
|
||||
|
||||
//
|
||||
// Install ACPI tables found in XSDT.
|
||||
//
|
||||
for (Index = 0; Index < NumberOfTableEntries; Index++) {
|
||||
//
|
||||
// Get the table entry from RSDT
|
||||
//
|
||||
CurrentTableEntry = (UINT32 *) ((UINT8 *) Rsdt +
|
||||
sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
|
||||
Index * sizeof (UINT32));
|
||||
CurrentTablePointer = *(UINT32 *)CurrentTableEntry;
|
||||
CurrentTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTablePointer;
|
||||
|
||||
//
|
||||
// Install the RSDT tables
|
||||
//
|
||||
Status = InstallAcpiTable (
|
||||
AcpiProtocol,
|
||||
CurrentTable,
|
||||
CurrentTable->Length,
|
||||
&TableHandle
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the FACS and DSDT table address from the table FADT
|
||||
//
|
||||
if (!AsciiStrnCmp ((CHAR8 *) &CurrentTable->Signature, "FACP", 4)) {
|
||||
Fadt1Table = (EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE *)
|
||||
(UINTN) CurrentTablePointer;
|
||||
Facs1Table = (EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)
|
||||
(UINTN) Fadt1Table->FirmwareCtrl;
|
||||
DsdtTable = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Fadt1Table->Dsdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Install the FACS table.
|
||||
//
|
||||
if (Fadt2Table) {
|
||||
//
|
||||
// FACS 2.0
|
||||
//
|
||||
Status = InstallAcpiTable (
|
||||
AcpiProtocol,
|
||||
Facs2Table,
|
||||
Facs2Table->Length,
|
||||
&TableHandle
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
else if (Fadt1Table) {
|
||||
//
|
||||
// FACS 1.0
|
||||
//
|
||||
Status = InstallAcpiTable (
|
||||
AcpiProtocol,
|
||||
Facs1Table,
|
||||
Facs1Table->Length,
|
||||
&TableHandle
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Install DSDT table. If we reached this point without finding the DSDT,
|
||||
// then we're out of sync with the hypervisor, and cannot continue.
|
||||
//
|
||||
if (DsdtTable == NULL) {
|
||||
DEBUG ((DEBUG_ERROR, "%a: no DSDT found\n", __FUNCTION__));
|
||||
ASSERT (FALSE);
|
||||
CpuDeadLoop ();
|
||||
}
|
||||
|
||||
Status = InstallAcpiTable (
|
||||
AcpiProtocol,
|
||||
DsdtTable,
|
||||
DsdtTable->Length,
|
||||
&TableHandle
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
## @file
|
||||
# OVMF ACPI Platform Driver for Xen guests
|
||||
#
|
||||
# Copyright (C) 2021, Red Hat, Inc.
|
||||
# Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = XenAcpiPlatform
|
||||
FILE_GUID = fa0a48ac-767d-4c88-b70c-ec54c8b900c4
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = AcpiPlatformEntryPoint
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 EBC
|
||||
#
|
||||
|
||||
[Sources]
|
||||
AcpiPlatform.c
|
||||
AcpiPlatform.h
|
||||
BootScript.c
|
||||
EntryPoint.c
|
||||
PciDecoding.c
|
||||
Qemu.c
|
||||
QemuFwCfgAcpi.c
|
||||
Xen.c
|
||||
|
||||
[Packages]
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
MdePkg/MdePkg.dec
|
||||
OvmfPkg/OvmfPkg.dec
|
||||
UefiCpuPkg/UefiCpuPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
BaseMemoryLib
|
||||
DebugLib
|
||||
DxeServicesTableLib
|
||||
MemoryAllocationLib
|
||||
OrderedCollectionLib
|
||||
PcdLib
|
||||
QemuFwCfgLib
|
||||
QemuFwCfgS3Lib
|
||||
UefiBootServicesTableLib
|
||||
UefiDriverEntryPoint
|
||||
XenPlatformLib
|
||||
|
||||
[Protocols]
|
||||
gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED
|
||||
gEfiFirmwareVolume2ProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
|
||||
gEfiPciIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
|
||||
|
||||
[Guids]
|
||||
gRootBridgesConnectedEventGroupGuid
|
||||
|
||||
[Pcd]
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiTableStorageFile
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration
|
||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
|
||||
gUefiOvmfPkgTokenSpaceGuid.Pcd8259LegacyModeEdgeLevel
|
||||
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress
|
||||
|
||||
[Depex]
|
||||
gEfiAcpiTableProtocolGuid
|
Loading…
Reference in New Issue