| /** @file | |
| Xen ARM ACPI Platform Driver using Xen ARM multiboot protocol | |
| Copyright (C) 2016, Linaro Ltd. All rights reserved. | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <Library/BaseLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/UefiDriverEntryPoint.h> | |
| #include <Protocol/AcpiTable.h> | |
| #include <Protocol/FdtClient.h> | |
| #include <IndustryStandard/Acpi.h> | |
| /** | |
| 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. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| GetXenArmAcpiRsdp ( | |
| OUT EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER **RsdpPtr | |
| ) | |
| { | |
| EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *RsdpStructurePtr; | |
| EFI_STATUS Status; | |
| FDT_CLIENT_PROTOCOL *FdtClient; | |
| CONST UINT64 *Reg; | |
| UINT32 RegSize; | |
| UINTN AddressCells, SizeCells; | |
| UINT64 RegBase; | |
| UINT8 Sum; | |
| RsdpStructurePtr = NULL; | |
| FdtClient = NULL; | |
| // | |
| // Get the RSDP structure address from DeviceTree | |
| // | |
| Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL, | |
| (VOID **)&FdtClient); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = FdtClient->FindCompatibleNodeReg (FdtClient, "xen,guest-acpi", | |
| (CONST VOID **)&Reg, &AddressCells, &SizeCells, | |
| &RegSize); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_WARN, "%a: No 'xen,guest-acpi' compatible DT node found\n", | |
| __FUNCTION__)); | |
| return EFI_NOT_FOUND; | |
| } | |
| ASSERT (AddressCells == 2); | |
| ASSERT (SizeCells == 2); | |
| ASSERT (RegSize == 2 * sizeof (UINT64)); | |
| RegBase = SwapBytes64(Reg[0]); | |
| RsdpStructurePtr = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)RegBase; | |
| if (RsdpStructurePtr && RsdpStructurePtr->Revision >= 2) { | |
| 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; | |
| } | |
| /** | |
| 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, GTDT, 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. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| InstallXenArmTables ( | |
| IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN TableHandle; | |
| VOID *CurrentTableEntry; | |
| UINTN CurrentTablePointer; | |
| EFI_ACPI_DESCRIPTION_HEADER *CurrentTable; | |
| UINTN Index; | |
| UINTN NumberOfTableEntries; | |
| EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *XenAcpiRsdpStructurePtr; | |
| EFI_ACPI_DESCRIPTION_HEADER *Xsdt; | |
| EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtTable; | |
| EFI_ACPI_DESCRIPTION_HEADER *DsdtTable; | |
| XenAcpiRsdpStructurePtr = NULL; | |
| FadtTable = NULL; | |
| DsdtTable = NULL; | |
| TableHandle = 0; | |
| NumberOfTableEntries = 0; | |
| // | |
| // Try to find Xen ARM ACPI tables | |
| // | |
| Status = GetXenArmAcpiRsdp (&XenAcpiRsdpStructurePtr); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_INFO, "%a: No RSDP table found\n", __FUNCTION__)); | |
| return Status; | |
| } | |
| // | |
| // If XSDT table is find, just install its 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 = AcpiProtocol->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)) { | |
| FadtTable = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) | |
| (UINTN) CurrentTablePointer; | |
| DsdtTable = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) FadtTable->Dsdt; | |
| } | |
| } | |
| } | |
| // | |
| // Install DSDT table. | |
| // | |
| Status = AcpiProtocol->InstallAcpiTable ( | |
| AcpiProtocol, | |
| DsdtTable, | |
| DsdtTable->Length, | |
| &TableHandle | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| STATIC | |
| EFI_ACPI_TABLE_PROTOCOL * | |
| FindAcpiTableProtocol ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_ACPI_TABLE_PROTOCOL *AcpiTable; | |
| AcpiTable = NULL; | |
| Status = gBS->LocateProtocol ( | |
| &gEfiAcpiTableProtocolGuid, | |
| NULL, | |
| (VOID**)&AcpiTable | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return AcpiTable; | |
| } | |
| /** | |
| Entrypoint of Xen ARM Acpi Platform driver. | |
| @param ImageHandle | |
| @param SystemTable | |
| @return EFI_SUCCESS | |
| @return EFI_LOAD_ERROR | |
| @return EFI_OUT_OF_RESOURCES | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| XenAcpiPlatformEntryPoint ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = InstallXenArmTables (FindAcpiTableProtocol ()); | |
| return Status; | |
| } |