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