/** @file Xen ARM ACPI Platform Driver using Xen ARM multiboot protocol Copyright (C) 2016, Linaro Ltd. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include /** 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 (( DEBUG_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 *)(UINTN)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 ((DEBUG_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; }