2 Xen Platform PEI support
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
6 Copyright (c) 2019, Citrix Systems, Inc.
8 SPDX-License-Identifier: BSD-2-Clause-Patent
13 // The package level header files this module uses
18 // The Library classes this module consumes
20 #include <Library/DebugLib.h>
21 #include <Library/HobLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/PcdLib.h>
24 #include <Guid/XenInfo.h>
25 #include <IndustryStandard/E820.h>
26 #include <Library/ResourcePublicationLib.h>
27 #include <Library/MtrrLib.h>
28 #include <IndustryStandard/Xen/arch-x86/hvm/start_info.h>
29 #include <Library/XenHypercallLib.h>
30 #include <IndustryStandard/Xen/memory.h>
35 STATIC UINT32 mXenLeaf
= 0;
37 EFI_XEN_INFO mXenInfo
;
40 // Location of the firmware info struct setup by hvmloader.
41 // Only the E820 table is used by OVMF.
43 EFI_XEN_OVMF_INFO
*mXenHvmloaderInfo
;
44 STATIC EFI_E820_ENTRY64 mE820Entries
[128];
45 STATIC UINT32 mE820EntriesCount
;
48 Returns E820 map provided by Xen
50 @param Entries Pointer to E820 map
51 @param Count Number of entries
57 EFI_E820_ENTRY64
**Entries
,
62 xen_memory_map_t Parameters
;
65 EFI_E820_ENTRY64 TmpEntry
;
68 // Get E820 produced by hvmloader
70 if (mXenHvmloaderInfo
!= NULL
) {
71 ASSERT (mXenHvmloaderInfo
->E820
< MAX_ADDRESS
);
72 *Entries
= (EFI_E820_ENTRY64
*)(UINTN
) mXenHvmloaderInfo
->E820
;
73 *Count
= mXenHvmloaderInfo
->E820EntriesCount
;
79 // Otherwise, get the E820 table from the Xen hypervisor
82 if (mE820EntriesCount
> 0) {
83 *Entries
= mE820Entries
;
84 *Count
= mE820EntriesCount
;
88 Parameters
.nr_entries
= 128;
89 set_xen_guest_handle (Parameters
.buffer
, mE820Entries
);
92 ReturnCode
= XenHypercallMemoryOp (XENMEM_memory_map
, &Parameters
);
93 ASSERT (ReturnCode
== 0);
95 mE820EntriesCount
= Parameters
.nr_entries
;
100 for (LoopIndex
= 1; LoopIndex
< mE820EntriesCount
; LoopIndex
++) {
101 for (Index
= LoopIndex
; Index
< mE820EntriesCount
; Index
++) {
102 if (mE820Entries
[Index
- 1].BaseAddr
> mE820Entries
[Index
].BaseAddr
) {
103 TmpEntry
= mE820Entries
[Index
];
104 mE820Entries
[Index
] = mE820Entries
[Index
- 1];
105 mE820Entries
[Index
- 1] = TmpEntry
;
110 *Count
= mE820EntriesCount
;
111 *Entries
= mE820Entries
;
117 Connects to the Hypervisor.
128 UINT32 TransferPages
;
130 EFI_XEN_OVMF_INFO
*Info
;
131 CHAR8 Sig
[sizeof (Info
->Signature
) + 1];
132 UINT32
*PVHResetVectorData
;
133 RETURN_STATUS Status
;
135 ASSERT (mXenLeaf
!= 0);
138 // Prepare HyperPages to be able to make hypercalls
141 AsmCpuid (mXenLeaf
+ 2, &TransferPages
, &TransferReg
, NULL
, NULL
);
142 mXenInfo
.HyperPages
= AllocatePages (TransferPages
);
143 if (!mXenInfo
.HyperPages
) {
144 return EFI_OUT_OF_RESOURCES
;
147 for (Index
= 0; Index
< TransferPages
; Index
++) {
148 AsmWriteMsr64 (TransferReg
,
149 (UINTN
) mXenInfo
.HyperPages
+
150 (Index
<< EFI_PAGE_SHIFT
) + Index
);
154 // Find out the Xen version
157 AsmCpuid (mXenLeaf
+ 1, &XenVersion
, NULL
, NULL
, NULL
);
158 DEBUG ((DEBUG_ERROR
, "Detected Xen version %d.%d\n",
159 XenVersion
>> 16, XenVersion
& 0xFFFF));
160 mXenInfo
.VersionMajor
= (UINT16
)(XenVersion
>> 16);
161 mXenInfo
.VersionMinor
= (UINT16
)(XenVersion
& 0xFFFF);
164 // Check if there are information left by hvmloader
167 Info
= (EFI_XEN_OVMF_INFO
*)(UINTN
) OVMF_INFO_PHYSICAL_ADDRESS
;
169 // Copy the signature, and make it null-terminated.
171 AsciiStrnCpyS (Sig
, sizeof (Sig
), (CHAR8
*) &Info
->Signature
,
172 sizeof (Info
->Signature
));
173 if (AsciiStrCmp (Sig
, "XenHVMOVMF") == 0) {
174 mXenHvmloaderInfo
= Info
;
176 mXenHvmloaderInfo
= NULL
;
179 mXenInfo
.RsdpPvh
= NULL
;
182 // Locate and use information from the start of day structure if we have
183 // booted via the PVH entry point.
186 PVHResetVectorData
= (VOID
*)(UINTN
) PcdGet32 (PcdXenPvhStartOfDayStructPtr
);
188 // That magic value is written in XenResetVector/Ia32/XenPVHMain.asm
190 if (PVHResetVectorData
[1] == SIGNATURE_32 ('X', 'P', 'V', 'H')) {
191 struct hvm_start_info
*HVMStartInfo
;
193 HVMStartInfo
= (VOID
*)(UINTN
) PVHResetVectorData
[0];
194 if (HVMStartInfo
->magic
== XEN_HVM_START_MAGIC_VALUE
) {
195 ASSERT (HVMStartInfo
->rsdp_paddr
!= 0);
196 if (HVMStartInfo
->rsdp_paddr
!= 0) {
197 mXenInfo
.RsdpPvh
= (VOID
*)(UINTN
)HVMStartInfo
->rsdp_paddr
;
209 // Initialize the XenHypercall library, now that the XenInfo HOB is
212 Status
= XenHypercallLibInit ();
213 ASSERT_RETURN_ERROR (Status
);
219 Figures out if we are running inside Xen HVM.
221 @retval TRUE Xen was detected
222 @retval FALSE Xen was not detected
236 Signature
[12] = '\0';
237 for (mXenLeaf
= 0x40000000; mXenLeaf
< 0x40010000; mXenLeaf
+= 0x100) {
240 (UINT32
*) &Signature
[0],
241 (UINT32
*) &Signature
[4],
242 (UINT32
*) &Signature
[8]);
244 if (!AsciiStrCmp ((CHAR8
*) Signature
, "XenVMMXenVMM")) {
254 XenHvmloaderDetected (
258 return (mXenHvmloaderInfo
!= NULL
);
267 // This function should only be used after XenConnect
269 ASSERT (mXenInfo
.HyperPages
!= NULL
);
271 return mXenHvmloaderInfo
== NULL
;
275 XenPublishRamRegions (
279 EFI_E820_ENTRY64
*E820Map
;
280 UINT32 E820EntriesCount
;
282 EFI_E820_ENTRY64
*Entry
;
288 DEBUG ((DEBUG_INFO
, "Using memory map provided by Xen\n"));
291 // Parse RAM in E820 map
293 E820EntriesCount
= 0;
294 Status
= XenGetE820Map (&E820Map
, &E820EntriesCount
);
295 ASSERT_EFI_ERROR (Status
);
297 AddMemoryBaseSizeHob (0, 0xA0000);
299 // Video memory + Legacy BIOS region, to allow Linux to boot.
301 AddReservedMemoryBaseSizeHob (0xA0000, BASE_1MB
- 0xA0000, TRUE
);
303 LapicBase
= PcdGet32 (PcdCpuLocalApicBaseAddress
);
304 LapicEnd
= LapicBase
+ SIZE_1MB
;
305 AddIoMemoryRangeHob (LapicBase
, LapicEnd
);
307 for (Index
= 0; Index
< E820EntriesCount
; Index
++) {
313 Entry
= &E820Map
[Index
];
316 // Round up the start address, and round down the end address.
318 Base
= ALIGN_VALUE (Entry
->BaseAddr
, (UINT64
)EFI_PAGE_SIZE
);
319 End
= (Entry
->BaseAddr
+ Entry
->Length
) & ~(UINT64
)EFI_PAGE_MASK
;
322 // Ignore the first 1MB, this is handled before the loop.
324 if (Base
< BASE_1MB
) {
331 switch (Entry
->Type
) {
332 case EfiAcpiAddressRangeMemory
:
333 AddMemoryRangeHob (Base
, End
);
335 case EfiAcpiAddressRangeACPI
:
336 AddReservedMemoryRangeHob (Base
, End
, FALSE
);
338 case EfiAcpiAddressRangeReserved
:
340 // hvmloader marks a range that overlaps with the local APIC memory
341 // mapped region as reserved, but CpuDxe wants it as mapped IO. We
342 // have already added it as mapped IO, so skip it here.
346 // add LAPIC predecessor range, if any
349 ReservedEnd
= MIN (End
, LapicBase
);
350 if (ReservedBase
< ReservedEnd
) {
351 AddReservedMemoryRangeHob (ReservedBase
, ReservedEnd
, FALSE
);
355 // add LAPIC successor range, if any
357 ReservedBase
= MAX (Base
, LapicEnd
);
359 if (ReservedBase
< ReservedEnd
) {
360 AddReservedMemoryRangeHob (ReservedBase
, ReservedEnd
, FALSE
);
371 Perform Xen PEI initialization.
373 @return EFI_SUCCESS Xen initialized successfully
374 @return EFI_NOT_FOUND Not running under Xen
382 RETURN_STATUS PcdStatus
;
384 PcdStatus
= PcdSetBoolS (PcdPciDisableBusEnumeration
, TRUE
);
385 ASSERT_RETURN_ERROR (PcdStatus
);