/** @file OVMF ACPI Xen support Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.
Copyright (c) 2012, Bei Guan SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "AcpiPlatform.h" #include #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; }