Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Anthony Perard <anthony.perard@citrix.com> Cc: Julien Grall <julien.grall@arm.com> Cc: David Woodhouse <dwmw2@infradead.org> Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>
		
			
				
	
	
		
			313 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			313 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   OVMF ACPI Xen support
 | |
| 
 | |
|   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 "AcpiPlatform.h"
 | |
| #include <Library/BaseLib.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;
 | |
| }
 | |
| 
 |