]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/XenPlatformPei/Xen.c
OvmfPkg/XenPlatformPei: Map extra physical address
[mirror_edk2.git] / OvmfPkg / XenPlatformPei / Xen.c
CommitLineData
3b96221f
AP
1/**@file\r
2 Xen Platform PEI support\r
3\r
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
5 Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>\r
6 Copyright (c) 2019, Citrix Systems, Inc.\r
7\r
8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9\r
10**/\r
11\r
12//\r
13// The package level header files this module uses\r
14//\r
15#include <PiPei.h>\r
16\r
17//\r
18// The Library classes this module consumes\r
19//\r
51e0bd28
AP
20#include <Library/BaseMemoryLib.h>\r
21#include <Library/CpuLib.h>\r
3b96221f
AP
22#include <Library/DebugLib.h>\r
23#include <Library/HobLib.h>\r
24#include <Library/MemoryAllocationLib.h>\r
25#include <Library/PcdLib.h>\r
26#include <Guid/XenInfo.h>\r
27#include <IndustryStandard/E820.h>\r
28#include <Library/ResourcePublicationLib.h>\r
29#include <Library/MtrrLib.h>\r
51e0bd28 30#include <IndustryStandard/PageTable.h>\r
60d26545 31#include <IndustryStandard/Xen/arch-x86/hvm/start_info.h>\r
80b619d5 32#include <Library/XenHypercallLib.h>\r
a749e1f9 33#include <IndustryStandard/Xen/memory.h>\r
3b96221f
AP
34\r
35#include "Platform.h"\r
36#include "Xen.h"\r
37\r
38STATIC UINT32 mXenLeaf = 0;\r
39\r
40EFI_XEN_INFO mXenInfo;\r
41\r
8651e1ce
AP
42//\r
43// Location of the firmware info struct setup by hvmloader.\r
44// Only the E820 table is used by OVMF.\r
45//\r
46EFI_XEN_OVMF_INFO *mXenHvmloaderInfo;\r
a749e1f9
AP
47STATIC EFI_E820_ENTRY64 mE820Entries[128];\r
48STATIC UINT32 mE820EntriesCount;\r
8651e1ce 49\r
3b96221f
AP
50/**\r
51 Returns E820 map provided by Xen\r
52\r
53 @param Entries Pointer to E820 map\r
54 @param Count Number of entries\r
55\r
56 @return EFI_STATUS\r
57**/\r
58EFI_STATUS\r
59XenGetE820Map (\r
60 EFI_E820_ENTRY64 **Entries,\r
61 UINT32 *Count\r
62 )\r
63{\r
a749e1f9
AP
64 INTN ReturnCode;\r
65 xen_memory_map_t Parameters;\r
66 UINTN LoopIndex;\r
67 UINTN Index;\r
68 EFI_E820_ENTRY64 TmpEntry;\r
69\r
594b5002
AP
70 //\r
71 // Get E820 produced by hvmloader\r
72 //\r
73 if (mXenHvmloaderInfo != NULL) {\r
74 ASSERT (mXenHvmloaderInfo->E820 < MAX_ADDRESS);\r
75 *Entries = (EFI_E820_ENTRY64 *)(UINTN) mXenHvmloaderInfo->E820;\r
76 *Count = mXenHvmloaderInfo->E820EntriesCount;\r
77\r
78 return EFI_SUCCESS;\r
3b96221f
AP
79 }\r
80\r
a749e1f9
AP
81 //\r
82 // Otherwise, get the E820 table from the Xen hypervisor\r
83 //\r
84\r
85 if (mE820EntriesCount > 0) {\r
86 *Entries = mE820Entries;\r
87 *Count = mE820EntriesCount;\r
88 return EFI_SUCCESS;\r
89 }\r
90\r
91 Parameters.nr_entries = 128;\r
92 set_xen_guest_handle (Parameters.buffer, mE820Entries);\r
93\r
94 // Returns a errno\r
95 ReturnCode = XenHypercallMemoryOp (XENMEM_memory_map, &Parameters);\r
96 ASSERT (ReturnCode == 0);\r
97\r
98 mE820EntriesCount = Parameters.nr_entries;\r
99\r
100 //\r
101 // Sort E820 entries\r
102 //\r
103 for (LoopIndex = 1; LoopIndex < mE820EntriesCount; LoopIndex++) {\r
104 for (Index = LoopIndex; Index < mE820EntriesCount; Index++) {\r
105 if (mE820Entries[Index - 1].BaseAddr > mE820Entries[Index].BaseAddr) {\r
106 TmpEntry = mE820Entries[Index];\r
107 mE820Entries[Index] = mE820Entries[Index - 1];\r
108 mE820Entries[Index - 1] = TmpEntry;\r
109 }\r
110 }\r
111 }\r
112\r
113 *Count = mE820EntriesCount;\r
114 *Entries = mE820Entries;\r
115\r
116 return EFI_SUCCESS;\r
3b96221f
AP
117}\r
118\r
119/**\r
120 Connects to the Hypervisor.\r
121\r
3b96221f
AP
122 @return EFI_STATUS\r
123\r
124**/\r
125EFI_STATUS\r
126XenConnect (\r
3b96221f
AP
127 )\r
128{\r
129 UINT32 Index;\r
130 UINT32 TransferReg;\r
131 UINT32 TransferPages;\r
132 UINT32 XenVersion;\r
8651e1ce
AP
133 EFI_XEN_OVMF_INFO *Info;\r
134 CHAR8 Sig[sizeof (Info->Signature) + 1];\r
60d26545 135 UINT32 *PVHResetVectorData;\r
80b619d5 136 RETURN_STATUS Status;\r
3b96221f 137\r
12998837
AP
138 ASSERT (mXenLeaf != 0);\r
139\r
140 //\r
141 // Prepare HyperPages to be able to make hypercalls\r
142 //\r
143\r
144 AsmCpuid (mXenLeaf + 2, &TransferPages, &TransferReg, NULL, NULL);\r
3b96221f
AP
145 mXenInfo.HyperPages = AllocatePages (TransferPages);\r
146 if (!mXenInfo.HyperPages) {\r
147 return EFI_OUT_OF_RESOURCES;\r
148 }\r
149\r
150 for (Index = 0; Index < TransferPages; Index++) {\r
151 AsmWriteMsr64 (TransferReg,\r
152 (UINTN) mXenInfo.HyperPages +\r
153 (Index << EFI_PAGE_SHIFT) + Index);\r
154 }\r
155\r
12998837
AP
156 //\r
157 // Find out the Xen version\r
158 //\r
159\r
160 AsmCpuid (mXenLeaf + 1, &XenVersion, NULL, NULL, NULL);\r
3b96221f
AP
161 DEBUG ((DEBUG_ERROR, "Detected Xen version %d.%d\n",\r
162 XenVersion >> 16, XenVersion & 0xFFFF));\r
163 mXenInfo.VersionMajor = (UINT16)(XenVersion >> 16);\r
164 mXenInfo.VersionMinor = (UINT16)(XenVersion & 0xFFFF);\r
165\r
8651e1ce
AP
166 //\r
167 // Check if there are information left by hvmloader\r
168 //\r
169\r
170 Info = (EFI_XEN_OVMF_INFO *)(UINTN) OVMF_INFO_PHYSICAL_ADDRESS;\r
171 //\r
172 // Copy the signature, and make it null-terminated.\r
173 //\r
174 AsciiStrnCpyS (Sig, sizeof (Sig), (CHAR8 *) &Info->Signature,\r
175 sizeof (Info->Signature));\r
176 if (AsciiStrCmp (Sig, "XenHVMOVMF") == 0) {\r
177 mXenHvmloaderInfo = Info;\r
178 } else {\r
179 mXenHvmloaderInfo = NULL;\r
180 }\r
3b96221f 181\r
60d26545
AP
182 mXenInfo.RsdpPvh = NULL;\r
183\r
184 //\r
185 // Locate and use information from the start of day structure if we have\r
186 // booted via the PVH entry point.\r
187 //\r
188\r
189 PVHResetVectorData = (VOID *)(UINTN) PcdGet32 (PcdXenPvhStartOfDayStructPtr);\r
190 //\r
191 // That magic value is written in XenResetVector/Ia32/XenPVHMain.asm\r
192 //\r
193 if (PVHResetVectorData[1] == SIGNATURE_32 ('X', 'P', 'V', 'H')) {\r
194 struct hvm_start_info *HVMStartInfo;\r
195\r
196 HVMStartInfo = (VOID *)(UINTN) PVHResetVectorData[0];\r
197 if (HVMStartInfo->magic == XEN_HVM_START_MAGIC_VALUE) {\r
198 ASSERT (HVMStartInfo->rsdp_paddr != 0);\r
199 if (HVMStartInfo->rsdp_paddr != 0) {\r
200 mXenInfo.RsdpPvh = (VOID *)(UINTN)HVMStartInfo->rsdp_paddr;\r
201 }\r
202 }\r
203 }\r
204\r
3b96221f
AP
205 BuildGuidDataHob (\r
206 &gEfiXenInfoGuid,\r
207 &mXenInfo,\r
208 sizeof(mXenInfo)\r
209 );\r
210\r
80b619d5
AP
211 //\r
212 // Initialize the XenHypercall library, now that the XenInfo HOB is\r
213 // available\r
214 //\r
215 Status = XenHypercallLibInit ();\r
216 ASSERT_RETURN_ERROR (Status);\r
217\r
3b96221f
AP
218 return EFI_SUCCESS;\r
219}\r
220\r
221/**\r
222 Figures out if we are running inside Xen HVM.\r
223\r
224 @retval TRUE Xen was detected\r
225 @retval FALSE Xen was not detected\r
226\r
227**/\r
228BOOLEAN\r
229XenDetect (\r
230 VOID\r
231 )\r
232{\r
233 UINT8 Signature[13];\r
234\r
235 if (mXenLeaf != 0) {\r
236 return TRUE;\r
237 }\r
238\r
239 Signature[12] = '\0';\r
240 for (mXenLeaf = 0x40000000; mXenLeaf < 0x40010000; mXenLeaf += 0x100) {\r
241 AsmCpuid (mXenLeaf,\r
242 NULL,\r
243 (UINT32 *) &Signature[0],\r
244 (UINT32 *) &Signature[4],\r
245 (UINT32 *) &Signature[8]);\r
246\r
247 if (!AsciiStrCmp ((CHAR8 *) Signature, "XenVMMXenVMM")) {\r
248 return TRUE;\r
249 }\r
250 }\r
251\r
252 mXenLeaf = 0;\r
253 return FALSE;\r
254}\r
255\r
4022f7fa
AP
256BOOLEAN\r
257XenHvmloaderDetected (\r
258 VOID\r
259 )\r
260{\r
261 return (mXenHvmloaderInfo != NULL);\r
262}\r
3b96221f 263\r
64eac295
AP
264BOOLEAN\r
265XenPvhDetected (\r
266 VOID\r
267 )\r
268{\r
269 //\r
270 // This function should only be used after XenConnect\r
271 //\r
272 ASSERT (mXenInfo.HyperPages != NULL);\r
273\r
274 return mXenHvmloaderInfo == NULL;\r
275}\r
276\r
3b96221f
AP
277VOID\r
278XenPublishRamRegions (\r
279 VOID\r
280 )\r
281{\r
24465c38
AP
282 EFI_E820_ENTRY64 *E820Map;\r
283 UINT32 E820EntriesCount;\r
284 EFI_STATUS Status;\r
285 EFI_E820_ENTRY64 *Entry;\r
286 UINTN Index;\r
287 UINT64 LapicBase;\r
288 UINT64 LapicEnd;\r
289\r
3b96221f
AP
290\r
291 DEBUG ((DEBUG_INFO, "Using memory map provided by Xen\n"));\r
292\r
293 //\r
294 // Parse RAM in E820 map\r
295 //\r
296 E820EntriesCount = 0;\r
297 Status = XenGetE820Map (&E820Map, &E820EntriesCount);\r
3b96221f
AP
298 ASSERT_EFI_ERROR (Status);\r
299\r
77d35f50
AP
300 AddMemoryBaseSizeHob (0, 0xA0000);\r
301 //\r
302 // Video memory + Legacy BIOS region, to allow Linux to boot.\r
303 //\r
304 AddReservedMemoryBaseSizeHob (0xA0000, BASE_1MB - 0xA0000, TRUE);\r
305\r
24465c38
AP
306 LapicBase = PcdGet32 (PcdCpuLocalApicBaseAddress);\r
307 LapicEnd = LapicBase + SIZE_1MB;\r
308 AddIoMemoryRangeHob (LapicBase, LapicEnd);\r
309\r
310 for (Index = 0; Index < E820EntriesCount; Index++) {\r
311 UINT64 Base;\r
312 UINT64 End;\r
313 UINT64 ReservedBase;\r
314 UINT64 ReservedEnd;\r
315\r
316 Entry = &E820Map[Index];\r
317\r
318 //\r
319 // Round up the start address, and round down the end address.\r
320 //\r
321 Base = ALIGN_VALUE (Entry->BaseAddr, (UINT64)EFI_PAGE_SIZE);\r
322 End = (Entry->BaseAddr + Entry->Length) & ~(UINT64)EFI_PAGE_MASK;\r
323\r
77d35f50
AP
324 //\r
325 // Ignore the first 1MB, this is handled before the loop.\r
326 //\r
327 if (Base < BASE_1MB) {\r
328 Base = BASE_1MB;\r
329 }\r
330 if (Base >= End) {\r
331 continue;\r
332 }\r
333\r
24465c38
AP
334 switch (Entry->Type) {\r
335 case EfiAcpiAddressRangeMemory:\r
336 AddMemoryRangeHob (Base, End);\r
337 break;\r
338 case EfiAcpiAddressRangeACPI:\r
339 AddReservedMemoryRangeHob (Base, End, FALSE);\r
340 break;\r
341 case EfiAcpiAddressRangeReserved:\r
342 //\r
343 // hvmloader marks a range that overlaps with the local APIC memory\r
344 // mapped region as reserved, but CpuDxe wants it as mapped IO. We\r
345 // have already added it as mapped IO, so skip it here.\r
346 //\r
3b96221f
AP
347\r
348 //\r
24465c38 349 // add LAPIC predecessor range, if any\r
3b96221f 350 //\r
24465c38
AP
351 ReservedBase = Base;\r
352 ReservedEnd = MIN (End, LapicBase);\r
353 if (ReservedBase < ReservedEnd) {\r
354 AddReservedMemoryRangeHob (ReservedBase, ReservedEnd, FALSE);\r
3b96221f
AP
355 }\r
356\r
24465c38
AP
357 //\r
358 // add LAPIC successor range, if any\r
359 //\r
360 ReservedBase = MAX (Base, LapicEnd);\r
361 ReservedEnd = End;\r
362 if (ReservedBase < ReservedEnd) {\r
363 AddReservedMemoryRangeHob (ReservedBase, ReservedEnd, FALSE);\r
364 }\r
365 break;\r
366 default:\r
367 break;\r
3b96221f
AP
368 }\r
369 }\r
370}\r
371\r
372\r
373/**\r
374 Perform Xen PEI initialization.\r
375\r
376 @return EFI_SUCCESS Xen initialized successfully\r
377 @return EFI_NOT_FOUND Not running under Xen\r
378\r
379**/\r
380EFI_STATUS\r
381InitializeXen (\r
382 VOID\r
383 )\r
384{\r
385 RETURN_STATUS PcdStatus;\r
386\r
3b96221f
AP
387 PcdStatus = PcdSetBoolS (PcdPciDisableBusEnumeration, TRUE);\r
388 ASSERT_RETURN_ERROR (PcdStatus);\r
389\r
390 return EFI_SUCCESS;\r
391}\r
51e0bd28
AP
392\r
393EFI_STATUS\r
394PhysicalAddressIdentityMapping (\r
395 IN EFI_PHYSICAL_ADDRESS AddressToMap\r
396 )\r
397{\r
398 INTN Index;\r
399 PAGE_MAP_AND_DIRECTORY_POINTER *L4, *L3;\r
400 PAGE_TABLE_ENTRY *PageTable;\r
401\r
402 DEBUG ((DEBUG_INFO, "Mapping 1:1 of address 0x%lx\n", (UINT64)AddressToMap));\r
403\r
404 // L4 / Top level Page Directory Pointers\r
405\r
406 L4 = (VOID*)(UINTN)PcdGet32 (PcdOvmfSecPageTablesBase);\r
407 Index = PML4_OFFSET (AddressToMap);\r
408\r
409 if (!L4[Index].Bits.Present) {\r
410 L3 = AllocatePages (1);\r
411 if (L3 == NULL) {\r
412 return EFI_OUT_OF_RESOURCES;\r
413 }\r
414\r
415 ZeroMem (L3, EFI_PAGE_SIZE);\r
416\r
417 L4[Index].Bits.ReadWrite = 1;\r
418 L4[Index].Bits.Accessed = 1;\r
419 L4[Index].Bits.PageTableBaseAddress = (EFI_PHYSICAL_ADDRESS)L3 >> 12;\r
420 L4[Index].Bits.Present = 1;\r
421 }\r
422\r
423 // L3 / Next level Page Directory Pointers\r
424\r
425 L3 = (VOID*)(EFI_PHYSICAL_ADDRESS)(L4[Index].Bits.PageTableBaseAddress << 12);\r
426 Index = PDP_OFFSET (AddressToMap);\r
427\r
428 if (!L3[Index].Bits.Present) {\r
429 PageTable = AllocatePages (1);\r
430 if (PageTable == NULL) {\r
431 return EFI_OUT_OF_RESOURCES;\r
432 }\r
433\r
434 ZeroMem (PageTable, EFI_PAGE_SIZE);\r
435\r
436 L3[Index].Bits.ReadWrite = 1;\r
437 L3[Index].Bits.Accessed = 1;\r
438 L3[Index].Bits.PageTableBaseAddress = (EFI_PHYSICAL_ADDRESS)PageTable >> 12;\r
439 L3[Index].Bits.Present = 1;\r
440 }\r
441\r
442 // L2 / Page Table Entries\r
443\r
444 PageTable = (VOID*)(EFI_PHYSICAL_ADDRESS)(L3[Index].Bits.PageTableBaseAddress << 12);\r
445 Index = PDE_OFFSET (AddressToMap);\r
446\r
447 if (!PageTable[Index].Bits.Present) {\r
448 PageTable[Index].Bits.ReadWrite = 1;\r
449 PageTable[Index].Bits.Accessed = 1;\r
450 PageTable[Index].Bits.Dirty = 1;\r
451 PageTable[Index].Bits.MustBe1 = 1;\r
452 PageTable[Index].Bits.PageTableBaseAddress = AddressToMap >> 21;\r
453 PageTable[Index].Bits.Present = 1;\r
454 }\r
455\r
456 CpuFlushTlb ();\r
457\r
458 return EFI_SUCCESS;\r
459}\r