| /**@file | |
| Xen Platform PEI support | |
| Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> | |
| Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com> | |
| 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. | |
| **/ | |
| // | |
| // The package level header files this module uses | |
| // | |
| #include <PiPei.h> | |
| // | |
| // The Library classes this module consumes | |
| // | |
| #include <Library/DebugLib.h> | |
| #include <Library/HobLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/PcdLib.h> | |
| #include <Guid/XenInfo.h> | |
| #include <IndustryStandard/E820.h> | |
| #include <Library/ResourcePublicationLib.h> | |
| #include <Library/MtrrLib.h> | |
| #include "Platform.h" | |
| #include "Xen.h" | |
| BOOLEAN mXen = FALSE; | |
| STATIC UINT32 mXenLeaf = 0; | |
| EFI_XEN_INFO mXenInfo; | |
| /** | |
| Returns E820 map provided by Xen | |
| @param Entries Pointer to E820 map | |
| @param Count Number of entries | |
| @return EFI_STATUS | |
| **/ | |
| EFI_STATUS | |
| XenGetE820Map ( | |
| EFI_E820_ENTRY64 **Entries, | |
| UINT32 *Count | |
| ) | |
| { | |
| EFI_XEN_OVMF_INFO *Info = | |
| (EFI_XEN_OVMF_INFO *)(UINTN) OVMF_INFO_PHYSICAL_ADDRESS; | |
| if (AsciiStrCmp ((CHAR8 *) Info->Signature, "XenHVMOVMF")) { | |
| return EFI_NOT_FOUND; | |
| } | |
| ASSERT (Info->E820 < MAX_ADDRESS); | |
| *Entries = (EFI_E820_ENTRY64 *)(UINTN) Info->E820; | |
| *Count = Info->E820EntriesCount; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Connects to the Hypervisor. | |
| @param XenLeaf CPUID index used to connect. | |
| @return EFI_STATUS | |
| **/ | |
| EFI_STATUS | |
| XenConnect ( | |
| UINT32 XenLeaf | |
| ) | |
| { | |
| UINT32 Index; | |
| UINT32 TransferReg; | |
| UINT32 TransferPages; | |
| UINT32 XenVersion; | |
| AsmCpuid (XenLeaf + 2, &TransferPages, &TransferReg, NULL, NULL); | |
| mXenInfo.HyperPages = AllocatePages (TransferPages); | |
| if (!mXenInfo.HyperPages) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| for (Index = 0; Index < TransferPages; Index++) { | |
| AsmWriteMsr64 (TransferReg, | |
| (UINTN) mXenInfo.HyperPages + | |
| (Index << EFI_PAGE_SHIFT) + Index); | |
| } | |
| AsmCpuid (XenLeaf + 1, &XenVersion, NULL, NULL, NULL); | |
| DEBUG ((EFI_D_ERROR, "Detected Xen version %d.%d\n", | |
| XenVersion >> 16, XenVersion & 0xFFFF)); | |
| mXenInfo.VersionMajor = (UINT16)(XenVersion >> 16); | |
| mXenInfo.VersionMinor = (UINT16)(XenVersion & 0xFFFF); | |
| /* TBD: Locate hvm_info and reserve it away. */ | |
| mXenInfo.HvmInfo = NULL; | |
| BuildGuidDataHob ( | |
| &gEfiXenInfoGuid, | |
| &mXenInfo, | |
| sizeof(mXenInfo) | |
| ); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Figures out if we are running inside Xen HVM. | |
| @retval TRUE Xen was detected | |
| @retval FALSE Xen was not detected | |
| **/ | |
| BOOLEAN | |
| XenDetect ( | |
| VOID | |
| ) | |
| { | |
| UINT8 Signature[13]; | |
| if (mXenLeaf != 0) { | |
| return TRUE; | |
| } | |
| Signature[12] = '\0'; | |
| for (mXenLeaf = 0x40000000; mXenLeaf < 0x40010000; mXenLeaf += 0x100) { | |
| AsmCpuid (mXenLeaf, | |
| NULL, | |
| (UINT32 *) &Signature[0], | |
| (UINT32 *) &Signature[4], | |
| (UINT32 *) &Signature[8]); | |
| if (!AsciiStrCmp ((CHAR8 *) Signature, "XenVMMXenVMM")) { | |
| mXen = TRUE; | |
| return TRUE; | |
| } | |
| } | |
| mXenLeaf = 0; | |
| return FALSE; | |
| } | |
| VOID | |
| XenPublishRamRegions ( | |
| VOID | |
| ) | |
| { | |
| EFI_E820_ENTRY64 *E820Map; | |
| UINT32 E820EntriesCount; | |
| EFI_STATUS Status; | |
| if (!mXen) { | |
| return; | |
| } | |
| DEBUG ((EFI_D_INFO, "Using memory map provided by Xen\n")); | |
| // | |
| // Parse RAM in E820 map | |
| // | |
| E820EntriesCount = 0; | |
| Status = XenGetE820Map (&E820Map, &E820EntriesCount); | |
| ASSERT_EFI_ERROR (Status); | |
| if (E820EntriesCount > 0) { | |
| EFI_E820_ENTRY64 *Entry; | |
| UINT32 Loop; | |
| for (Loop = 0; Loop < E820EntriesCount; Loop++) { | |
| Entry = E820Map + Loop; | |
| // | |
| // Only care about RAM | |
| // | |
| if (Entry->Type != EfiAcpiAddressRangeMemory) { | |
| continue; | |
| } | |
| AddMemoryBaseSizeHob (Entry->BaseAddr, Entry->Length); | |
| MtrrSetMemoryAttribute (Entry->BaseAddr, Entry->Length, CacheWriteBack); | |
| } | |
| } | |
| } | |
| /** | |
| Perform Xen PEI initialization. | |
| @return EFI_SUCCESS Xen initialized successfully | |
| @return EFI_NOT_FOUND Not running under Xen | |
| **/ | |
| EFI_STATUS | |
| InitializeXen ( | |
| VOID | |
| ) | |
| { | |
| RETURN_STATUS PcdStatus; | |
| if (mXenLeaf == 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| XenConnect (mXenLeaf); | |
| // | |
| // Reserve away HVMLOADER reserved memory [0xFC000000,0xFD000000). | |
| // This needs to match HVMLOADER RESERVED_MEMBASE/RESERVED_MEMSIZE. | |
| // | |
| AddReservedMemoryBaseSizeHob (0xFC000000, 0x1000000, FALSE); | |
| PcdStatus = PcdSetBoolS (PcdPciDisableBusEnumeration, TRUE); | |
| ASSERT_RETURN_ERROR (PcdStatus); | |
| return EFI_SUCCESS; | |
| } |