]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/XenPlatformPei/Xen.c
BaseTools: Add YAML files with path env and tool extdeps
[mirror_edk2.git] / OvmfPkg / XenPlatformPei / Xen.c
1 /**@file
2 Xen Platform PEI support
3
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.
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 //
13 // The package level header files this module uses
14 //
15 #include <PiPei.h>
16
17 //
18 // The Library classes this module consumes
19 //
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>
31
32 #include "Platform.h"
33 #include "Xen.h"
34
35 STATIC UINT32 mXenLeaf = 0;
36
37 EFI_XEN_INFO mXenInfo;
38
39 //
40 // Location of the firmware info struct setup by hvmloader.
41 // Only the E820 table is used by OVMF.
42 //
43 EFI_XEN_OVMF_INFO *mXenHvmloaderInfo;
44 STATIC EFI_E820_ENTRY64 mE820Entries[128];
45 STATIC UINT32 mE820EntriesCount;
46
47 /**
48 Returns E820 map provided by Xen
49
50 @param Entries Pointer to E820 map
51 @param Count Number of entries
52
53 @return EFI_STATUS
54 **/
55 EFI_STATUS
56 XenGetE820Map (
57 EFI_E820_ENTRY64 **Entries,
58 UINT32 *Count
59 )
60 {
61 INTN ReturnCode;
62 xen_memory_map_t Parameters;
63 UINTN LoopIndex;
64 UINTN Index;
65 EFI_E820_ENTRY64 TmpEntry;
66
67 //
68 // Get E820 produced by hvmloader
69 //
70 if (mXenHvmloaderInfo != NULL) {
71 ASSERT (mXenHvmloaderInfo->E820 < MAX_ADDRESS);
72 *Entries = (EFI_E820_ENTRY64 *)(UINTN) mXenHvmloaderInfo->E820;
73 *Count = mXenHvmloaderInfo->E820EntriesCount;
74
75 return EFI_SUCCESS;
76 }
77
78 //
79 // Otherwise, get the E820 table from the Xen hypervisor
80 //
81
82 if (mE820EntriesCount > 0) {
83 *Entries = mE820Entries;
84 *Count = mE820EntriesCount;
85 return EFI_SUCCESS;
86 }
87
88 Parameters.nr_entries = 128;
89 set_xen_guest_handle (Parameters.buffer, mE820Entries);
90
91 // Returns a errno
92 ReturnCode = XenHypercallMemoryOp (XENMEM_memory_map, &Parameters);
93 ASSERT (ReturnCode == 0);
94
95 mE820EntriesCount = Parameters.nr_entries;
96
97 //
98 // Sort E820 entries
99 //
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;
106 }
107 }
108 }
109
110 *Count = mE820EntriesCount;
111 *Entries = mE820Entries;
112
113 return EFI_SUCCESS;
114 }
115
116 /**
117 Connects to the Hypervisor.
118
119 @return EFI_STATUS
120
121 **/
122 EFI_STATUS
123 XenConnect (
124 )
125 {
126 UINT32 Index;
127 UINT32 TransferReg;
128 UINT32 TransferPages;
129 UINT32 XenVersion;
130 EFI_XEN_OVMF_INFO *Info;
131 CHAR8 Sig[sizeof (Info->Signature) + 1];
132 UINT32 *PVHResetVectorData;
133 RETURN_STATUS Status;
134
135 ASSERT (mXenLeaf != 0);
136
137 //
138 // Prepare HyperPages to be able to make hypercalls
139 //
140
141 AsmCpuid (mXenLeaf + 2, &TransferPages, &TransferReg, NULL, NULL);
142 mXenInfo.HyperPages = AllocatePages (TransferPages);
143 if (!mXenInfo.HyperPages) {
144 return EFI_OUT_OF_RESOURCES;
145 }
146
147 for (Index = 0; Index < TransferPages; Index++) {
148 AsmWriteMsr64 (TransferReg,
149 (UINTN) mXenInfo.HyperPages +
150 (Index << EFI_PAGE_SHIFT) + Index);
151 }
152
153 //
154 // Find out the Xen version
155 //
156
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);
162
163 //
164 // Check if there are information left by hvmloader
165 //
166
167 Info = (EFI_XEN_OVMF_INFO *)(UINTN) OVMF_INFO_PHYSICAL_ADDRESS;
168 //
169 // Copy the signature, and make it null-terminated.
170 //
171 AsciiStrnCpyS (Sig, sizeof (Sig), (CHAR8 *) &Info->Signature,
172 sizeof (Info->Signature));
173 if (AsciiStrCmp (Sig, "XenHVMOVMF") == 0) {
174 mXenHvmloaderInfo = Info;
175 } else {
176 mXenHvmloaderInfo = NULL;
177 }
178
179 mXenInfo.RsdpPvh = NULL;
180
181 //
182 // Locate and use information from the start of day structure if we have
183 // booted via the PVH entry point.
184 //
185
186 PVHResetVectorData = (VOID *)(UINTN) PcdGet32 (PcdXenPvhStartOfDayStructPtr);
187 //
188 // That magic value is written in XenResetVector/Ia32/XenPVHMain.asm
189 //
190 if (PVHResetVectorData[1] == SIGNATURE_32 ('X', 'P', 'V', 'H')) {
191 struct hvm_start_info *HVMStartInfo;
192
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;
198 }
199 }
200 }
201
202 BuildGuidDataHob (
203 &gEfiXenInfoGuid,
204 &mXenInfo,
205 sizeof(mXenInfo)
206 );
207
208 //
209 // Initialize the XenHypercall library, now that the XenInfo HOB is
210 // available
211 //
212 Status = XenHypercallLibInit ();
213 ASSERT_RETURN_ERROR (Status);
214
215 return EFI_SUCCESS;
216 }
217
218 /**
219 Figures out if we are running inside Xen HVM.
220
221 @retval TRUE Xen was detected
222 @retval FALSE Xen was not detected
223
224 **/
225 BOOLEAN
226 XenDetect (
227 VOID
228 )
229 {
230 UINT8 Signature[13];
231
232 if (mXenLeaf != 0) {
233 return TRUE;
234 }
235
236 Signature[12] = '\0';
237 for (mXenLeaf = 0x40000000; mXenLeaf < 0x40010000; mXenLeaf += 0x100) {
238 AsmCpuid (mXenLeaf,
239 NULL,
240 (UINT32 *) &Signature[0],
241 (UINT32 *) &Signature[4],
242 (UINT32 *) &Signature[8]);
243
244 if (!AsciiStrCmp ((CHAR8 *) Signature, "XenVMMXenVMM")) {
245 return TRUE;
246 }
247 }
248
249 mXenLeaf = 0;
250 return FALSE;
251 }
252
253 BOOLEAN
254 XenHvmloaderDetected (
255 VOID
256 )
257 {
258 return (mXenHvmloaderInfo != NULL);
259 }
260
261 BOOLEAN
262 XenPvhDetected (
263 VOID
264 )
265 {
266 //
267 // This function should only be used after XenConnect
268 //
269 ASSERT (mXenInfo.HyperPages != NULL);
270
271 return mXenHvmloaderInfo == NULL;
272 }
273
274 VOID
275 XenPublishRamRegions (
276 VOID
277 )
278 {
279 EFI_E820_ENTRY64 *E820Map;
280 UINT32 E820EntriesCount;
281 EFI_STATUS Status;
282 EFI_E820_ENTRY64 *Entry;
283 UINTN Index;
284 UINT64 LapicBase;
285 UINT64 LapicEnd;
286
287
288 DEBUG ((DEBUG_INFO, "Using memory map provided by Xen\n"));
289
290 //
291 // Parse RAM in E820 map
292 //
293 E820EntriesCount = 0;
294 Status = XenGetE820Map (&E820Map, &E820EntriesCount);
295 ASSERT_EFI_ERROR (Status);
296
297 AddMemoryBaseSizeHob (0, 0xA0000);
298 //
299 // Video memory + Legacy BIOS region, to allow Linux to boot.
300 //
301 AddReservedMemoryBaseSizeHob (0xA0000, BASE_1MB - 0xA0000, TRUE);
302
303 LapicBase = PcdGet32 (PcdCpuLocalApicBaseAddress);
304 LapicEnd = LapicBase + SIZE_1MB;
305 AddIoMemoryRangeHob (LapicBase, LapicEnd);
306
307 for (Index = 0; Index < E820EntriesCount; Index++) {
308 UINT64 Base;
309 UINT64 End;
310 UINT64 ReservedBase;
311 UINT64 ReservedEnd;
312
313 Entry = &E820Map[Index];
314
315 //
316 // Round up the start address, and round down the end address.
317 //
318 Base = ALIGN_VALUE (Entry->BaseAddr, (UINT64)EFI_PAGE_SIZE);
319 End = (Entry->BaseAddr + Entry->Length) & ~(UINT64)EFI_PAGE_MASK;
320
321 //
322 // Ignore the first 1MB, this is handled before the loop.
323 //
324 if (Base < BASE_1MB) {
325 Base = BASE_1MB;
326 }
327 if (Base >= End) {
328 continue;
329 }
330
331 switch (Entry->Type) {
332 case EfiAcpiAddressRangeMemory:
333 AddMemoryRangeHob (Base, End);
334 break;
335 case EfiAcpiAddressRangeACPI:
336 AddReservedMemoryRangeHob (Base, End, FALSE);
337 break;
338 case EfiAcpiAddressRangeReserved:
339 //
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.
343 //
344
345 //
346 // add LAPIC predecessor range, if any
347 //
348 ReservedBase = Base;
349 ReservedEnd = MIN (End, LapicBase);
350 if (ReservedBase < ReservedEnd) {
351 AddReservedMemoryRangeHob (ReservedBase, ReservedEnd, FALSE);
352 }
353
354 //
355 // add LAPIC successor range, if any
356 //
357 ReservedBase = MAX (Base, LapicEnd);
358 ReservedEnd = End;
359 if (ReservedBase < ReservedEnd) {
360 AddReservedMemoryRangeHob (ReservedBase, ReservedEnd, FALSE);
361 }
362 break;
363 default:
364 break;
365 }
366 }
367 }
368
369
370 /**
371 Perform Xen PEI initialization.
372
373 @return EFI_SUCCESS Xen initialized successfully
374 @return EFI_NOT_FOUND Not running under Xen
375
376 **/
377 EFI_STATUS
378 InitializeXen (
379 VOID
380 )
381 {
382 RETURN_STATUS PcdStatus;
383
384 PcdStatus = PcdSetBoolS (PcdPciDisableBusEnumeration, TRUE);
385 ASSERT_RETURN_ERROR (PcdStatus);
386
387 return EFI_SUCCESS;
388 }