]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/XenPlatformPei/Xen.c
OvmfPkg: Apply uncrustify changes
[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
c75c6405 24#include <Library/LocalApicLib.h>\r
3b96221f
AP
25#include <Library/MemoryAllocationLib.h>\r
26#include <Library/PcdLib.h>\r
c75c6405 27#include <Library/SafeIntLib.h>\r
3b96221f
AP
28#include <Guid/XenInfo.h>\r
29#include <IndustryStandard/E820.h>\r
30#include <Library/ResourcePublicationLib.h>\r
31#include <Library/MtrrLib.h>\r
51e0bd28 32#include <IndustryStandard/PageTable.h>\r
60d26545 33#include <IndustryStandard/Xen/arch-x86/hvm/start_info.h>\r
80b619d5 34#include <Library/XenHypercallLib.h>\r
a749e1f9 35#include <IndustryStandard/Xen/memory.h>\r
3b96221f
AP
36\r
37#include "Platform.h"\r
38#include "Xen.h"\r
39\r
ac0a286f 40STATIC UINT32 mXenLeaf = 0;\r
3b96221f 41\r
ac0a286f 42EFI_XEN_INFO mXenInfo;\r
3b96221f 43\r
8651e1ce
AP
44//\r
45// Location of the firmware info struct setup by hvmloader.\r
46// Only the E820 table is used by OVMF.\r
47//\r
ac0a286f
MK
48EFI_XEN_OVMF_INFO *mXenHvmloaderInfo;\r
49STATIC EFI_E820_ENTRY64 mE820Entries[128];\r
50STATIC UINT32 mE820EntriesCount;\r
8651e1ce 51\r
3b96221f
AP
52/**\r
53 Returns E820 map provided by Xen\r
54\r
55 @param Entries Pointer to E820 map\r
56 @param Count Number of entries\r
57\r
58 @return EFI_STATUS\r
59**/\r
60EFI_STATUS\r
61XenGetE820Map (\r
ac0a286f
MK
62 EFI_E820_ENTRY64 **Entries,\r
63 UINT32 *Count\r
3b96221f
AP
64 )\r
65{\r
ac0a286f
MK
66 INTN ReturnCode;\r
67 xen_memory_map_t Parameters;\r
68 UINTN LoopIndex;\r
69 UINTN Index;\r
70 EFI_E820_ENTRY64 TmpEntry;\r
a749e1f9 71\r
594b5002
AP
72 //\r
73 // Get E820 produced by hvmloader\r
74 //\r
75 if (mXenHvmloaderInfo != NULL) {\r
76 ASSERT (mXenHvmloaderInfo->E820 < MAX_ADDRESS);\r
ac0a286f
MK
77 *Entries = (EFI_E820_ENTRY64 *)(UINTN)mXenHvmloaderInfo->E820;\r
78 *Count = mXenHvmloaderInfo->E820EntriesCount;\r
594b5002
AP
79\r
80 return EFI_SUCCESS;\r
3b96221f
AP
81 }\r
82\r
a749e1f9
AP
83 //\r
84 // Otherwise, get the E820 table from the Xen hypervisor\r
85 //\r
86\r
87 if (mE820EntriesCount > 0) {\r
88 *Entries = mE820Entries;\r
ac0a286f 89 *Count = mE820EntriesCount;\r
a749e1f9
AP
90 return EFI_SUCCESS;\r
91 }\r
92\r
93 Parameters.nr_entries = 128;\r
94 set_xen_guest_handle (Parameters.buffer, mE820Entries);\r
95\r
96 // Returns a errno\r
97 ReturnCode = XenHypercallMemoryOp (XENMEM_memory_map, &Parameters);\r
98 ASSERT (ReturnCode == 0);\r
99\r
100 mE820EntriesCount = Parameters.nr_entries;\r
101\r
102 //\r
103 // Sort E820 entries\r
104 //\r
105 for (LoopIndex = 1; LoopIndex < mE820EntriesCount; LoopIndex++) {\r
106 for (Index = LoopIndex; Index < mE820EntriesCount; Index++) {\r
107 if (mE820Entries[Index - 1].BaseAddr > mE820Entries[Index].BaseAddr) {\r
ac0a286f
MK
108 TmpEntry = mE820Entries[Index];\r
109 mE820Entries[Index] = mE820Entries[Index - 1];\r
a749e1f9
AP
110 mE820Entries[Index - 1] = TmpEntry;\r
111 }\r
112 }\r
113 }\r
114\r
ac0a286f 115 *Count = mE820EntriesCount;\r
a749e1f9
AP
116 *Entries = mE820Entries;\r
117\r
118 return EFI_SUCCESS;\r
3b96221f
AP
119}\r
120\r
121/**\r
122 Connects to the Hypervisor.\r
123\r
3b96221f
AP
124 @return EFI_STATUS\r
125\r
126**/\r
127EFI_STATUS\r
128XenConnect (\r
3b96221f
AP
129 )\r
130{\r
ac0a286f
MK
131 UINT32 Index;\r
132 UINT32 TransferReg;\r
133 UINT32 TransferPages;\r
134 UINT32 XenVersion;\r
135 EFI_XEN_OVMF_INFO *Info;\r
136 CHAR8 Sig[sizeof (Info->Signature) + 1];\r
137 UINT32 *PVHResetVectorData;\r
138 RETURN_STATUS Status;\r
3b96221f 139\r
12998837
AP
140 ASSERT (mXenLeaf != 0);\r
141\r
142 //\r
143 // Prepare HyperPages to be able to make hypercalls\r
144 //\r
145\r
146 AsmCpuid (mXenLeaf + 2, &TransferPages, &TransferReg, NULL, NULL);\r
3b96221f
AP
147 mXenInfo.HyperPages = AllocatePages (TransferPages);\r
148 if (!mXenInfo.HyperPages) {\r
149 return EFI_OUT_OF_RESOURCES;\r
150 }\r
151\r
152 for (Index = 0; Index < TransferPages; Index++) {\r
ac0a286f
MK
153 AsmWriteMsr64 (\r
154 TransferReg,\r
155 (UINTN)mXenInfo.HyperPages +\r
156 (Index << EFI_PAGE_SHIFT) + Index\r
157 );\r
3b96221f
AP
158 }\r
159\r
12998837
AP
160 //\r
161 // Find out the Xen version\r
162 //\r
163\r
164 AsmCpuid (mXenLeaf + 1, &XenVersion, NULL, NULL, NULL);\r
ac0a286f
MK
165 DEBUG ((\r
166 DEBUG_ERROR,\r
167 "Detected Xen version %d.%d\n",\r
168 XenVersion >> 16,\r
169 XenVersion & 0xFFFF\r
170 ));\r
3b96221f
AP
171 mXenInfo.VersionMajor = (UINT16)(XenVersion >> 16);\r
172 mXenInfo.VersionMinor = (UINT16)(XenVersion & 0xFFFF);\r
173\r
8651e1ce
AP
174 //\r
175 // Check if there are information left by hvmloader\r
176 //\r
177\r
ac0a286f 178 Info = (EFI_XEN_OVMF_INFO *)(UINTN)OVMF_INFO_PHYSICAL_ADDRESS;\r
8651e1ce
AP
179 //\r
180 // Copy the signature, and make it null-terminated.\r
181 //\r
ac0a286f
MK
182 AsciiStrnCpyS (\r
183 Sig,\r
184 sizeof (Sig),\r
185 (CHAR8 *)&Info->Signature,\r
186 sizeof (Info->Signature)\r
187 );\r
8651e1ce
AP
188 if (AsciiStrCmp (Sig, "XenHVMOVMF") == 0) {\r
189 mXenHvmloaderInfo = Info;\r
190 } else {\r
191 mXenHvmloaderInfo = NULL;\r
192 }\r
3b96221f 193\r
60d26545
AP
194 mXenInfo.RsdpPvh = NULL;\r
195\r
196 //\r
197 // Locate and use information from the start of day structure if we have\r
198 // booted via the PVH entry point.\r
199 //\r
200\r
ac0a286f 201 PVHResetVectorData = (VOID *)(UINTN)PcdGet32 (PcdXenPvhStartOfDayStructPtr);\r
60d26545
AP
202 //\r
203 // That magic value is written in XenResetVector/Ia32/XenPVHMain.asm\r
204 //\r
205 if (PVHResetVectorData[1] == SIGNATURE_32 ('X', 'P', 'V', 'H')) {\r
ac0a286f 206 struct hvm_start_info *HVMStartInfo;\r
60d26545 207\r
ac0a286f 208 HVMStartInfo = (VOID *)(UINTN)PVHResetVectorData[0];\r
60d26545
AP
209 if (HVMStartInfo->magic == XEN_HVM_START_MAGIC_VALUE) {\r
210 ASSERT (HVMStartInfo->rsdp_paddr != 0);\r
211 if (HVMStartInfo->rsdp_paddr != 0) {\r
212 mXenInfo.RsdpPvh = (VOID *)(UINTN)HVMStartInfo->rsdp_paddr;\r
213 }\r
214 }\r
215 }\r
216\r
3b96221f
AP
217 BuildGuidDataHob (\r
218 &gEfiXenInfoGuid,\r
219 &mXenInfo,\r
ac0a286f 220 sizeof (mXenInfo)\r
3b96221f
AP
221 );\r
222\r
80b619d5
AP
223 //\r
224 // Initialize the XenHypercall library, now that the XenInfo HOB is\r
225 // available\r
226 //\r
227 Status = XenHypercallLibInit ();\r
228 ASSERT_RETURN_ERROR (Status);\r
229\r
3b96221f
AP
230 return EFI_SUCCESS;\r
231}\r
232\r
233/**\r
234 Figures out if we are running inside Xen HVM.\r
235\r
236 @retval TRUE Xen was detected\r
237 @retval FALSE Xen was not detected\r
238\r
239**/\r
240BOOLEAN\r
241XenDetect (\r
242 VOID\r
243 )\r
244{\r
ac0a286f 245 UINT8 Signature[13];\r
3b96221f
AP
246\r
247 if (mXenLeaf != 0) {\r
248 return TRUE;\r
249 }\r
250\r
251 Signature[12] = '\0';\r
252 for (mXenLeaf = 0x40000000; mXenLeaf < 0x40010000; mXenLeaf += 0x100) {\r
ac0a286f
MK
253 AsmCpuid (\r
254 mXenLeaf,\r
255 NULL,\r
256 (UINT32 *)&Signature[0],\r
257 (UINT32 *)&Signature[4],\r
258 (UINT32 *)&Signature[8]\r
259 );\r
260\r
261 if (!AsciiStrCmp ((CHAR8 *)Signature, "XenVMMXenVMM")) {\r
3b96221f
AP
262 return TRUE;\r
263 }\r
264 }\r
265\r
266 mXenLeaf = 0;\r
267 return FALSE;\r
268}\r
269\r
4022f7fa
AP
270BOOLEAN\r
271XenHvmloaderDetected (\r
272 VOID\r
273 )\r
274{\r
275 return (mXenHvmloaderInfo != NULL);\r
276}\r
3b96221f 277\r
64eac295
AP
278BOOLEAN\r
279XenPvhDetected (\r
280 VOID\r
281 )\r
282{\r
283 //\r
284 // This function should only be used after XenConnect\r
285 //\r
286 ASSERT (mXenInfo.HyperPages != NULL);\r
287\r
288 return mXenHvmloaderInfo == NULL;\r
289}\r
290\r
3b96221f
AP
291VOID\r
292XenPublishRamRegions (\r
293 VOID\r
294 )\r
295{\r
ac0a286f
MK
296 EFI_E820_ENTRY64 *E820Map;\r
297 UINT32 E820EntriesCount;\r
298 EFI_STATUS Status;\r
299 EFI_E820_ENTRY64 *Entry;\r
300 UINTN Index;\r
301 UINT64 LapicBase;\r
302 UINT64 LapicEnd;\r
3b96221f
AP
303\r
304 DEBUG ((DEBUG_INFO, "Using memory map provided by Xen\n"));\r
305\r
306 //\r
307 // Parse RAM in E820 map\r
308 //\r
309 E820EntriesCount = 0;\r
ac0a286f 310 Status = XenGetE820Map (&E820Map, &E820EntriesCount);\r
3b96221f
AP
311 ASSERT_EFI_ERROR (Status);\r
312\r
77d35f50
AP
313 AddMemoryBaseSizeHob (0, 0xA0000);\r
314 //\r
315 // Video memory + Legacy BIOS region, to allow Linux to boot.\r
316 //\r
317 AddReservedMemoryBaseSizeHob (0xA0000, BASE_1MB - 0xA0000, TRUE);\r
318\r
24465c38 319 LapicBase = PcdGet32 (PcdCpuLocalApicBaseAddress);\r
ac0a286f 320 LapicEnd = LapicBase + SIZE_1MB;\r
24465c38
AP
321 AddIoMemoryRangeHob (LapicBase, LapicEnd);\r
322\r
323 for (Index = 0; Index < E820EntriesCount; Index++) {\r
ac0a286f
MK
324 UINT64 Base;\r
325 UINT64 End;\r
326 UINT64 ReservedBase;\r
327 UINT64 ReservedEnd;\r
24465c38
AP
328\r
329 Entry = &E820Map[Index];\r
330\r
331 //\r
332 // Round up the start address, and round down the end address.\r
333 //\r
334 Base = ALIGN_VALUE (Entry->BaseAddr, (UINT64)EFI_PAGE_SIZE);\r
ac0a286f 335 End = (Entry->BaseAddr + Entry->Length) & ~(UINT64)EFI_PAGE_MASK;\r
24465c38 336\r
77d35f50
AP
337 //\r
338 // Ignore the first 1MB, this is handled before the loop.\r
339 //\r
340 if (Base < BASE_1MB) {\r
341 Base = BASE_1MB;\r
342 }\r
ac0a286f 343\r
77d35f50
AP
344 if (Base >= End) {\r
345 continue;\r
346 }\r
347\r
24465c38 348 switch (Entry->Type) {\r
ac0a286f
MK
349 case EfiAcpiAddressRangeMemory:\r
350 AddMemoryRangeHob (Base, End);\r
351 break;\r
352 case EfiAcpiAddressRangeACPI:\r
353 AddReservedMemoryRangeHob (Base, End, FALSE);\r
354 break;\r
355 case EfiAcpiAddressRangeReserved:\r
356 //\r
357 // hvmloader marks a range that overlaps with the local APIC memory\r
358 // mapped region as reserved, but CpuDxe wants it as mapped IO. We\r
359 // have already added it as mapped IO, so skip it here.\r
360 //\r
361\r
362 //\r
363 // add LAPIC predecessor range, if any\r
364 //\r
365 ReservedBase = Base;\r
366 ReservedEnd = MIN (End, LapicBase);\r
367 if (ReservedBase < ReservedEnd) {\r
368 AddReservedMemoryRangeHob (ReservedBase, ReservedEnd, FALSE);\r
369 }\r
370\r
371 //\r
372 // add LAPIC successor range, if any\r
373 //\r
374 ReservedBase = MAX (Base, LapicEnd);\r
375 ReservedEnd = End;\r
376 if (ReservedBase < ReservedEnd) {\r
377 AddReservedMemoryRangeHob (ReservedBase, ReservedEnd, FALSE);\r
378 }\r
379\r
380 break;\r
381 default:\r
382 break;\r
3b96221f
AP
383 }\r
384 }\r
385}\r
386\r
51e0bd28
AP
387EFI_STATUS\r
388PhysicalAddressIdentityMapping (\r
ac0a286f 389 IN EFI_PHYSICAL_ADDRESS AddressToMap\r
51e0bd28
AP
390 )\r
391{\r
392 INTN Index;\r
393 PAGE_MAP_AND_DIRECTORY_POINTER *L4, *L3;\r
394 PAGE_TABLE_ENTRY *PageTable;\r
395\r
396 DEBUG ((DEBUG_INFO, "Mapping 1:1 of address 0x%lx\n", (UINT64)AddressToMap));\r
397\r
398 // L4 / Top level Page Directory Pointers\r
399\r
ac0a286f 400 L4 = (VOID *)(UINTN)PcdGet32 (PcdOvmfSecPageTablesBase);\r
51e0bd28
AP
401 Index = PML4_OFFSET (AddressToMap);\r
402\r
403 if (!L4[Index].Bits.Present) {\r
404 L3 = AllocatePages (1);\r
405 if (L3 == NULL) {\r
406 return EFI_OUT_OF_RESOURCES;\r
407 }\r
408\r
409 ZeroMem (L3, EFI_PAGE_SIZE);\r
410\r
ac0a286f
MK
411 L4[Index].Bits.ReadWrite = 1;\r
412 L4[Index].Bits.Accessed = 1;\r
51e0bd28 413 L4[Index].Bits.PageTableBaseAddress = (EFI_PHYSICAL_ADDRESS)L3 >> 12;\r
ac0a286f 414 L4[Index].Bits.Present = 1;\r
51e0bd28
AP
415 }\r
416\r
417 // L3 / Next level Page Directory Pointers\r
418\r
ac0a286f 419 L3 = (VOID *)(EFI_PHYSICAL_ADDRESS)(L4[Index].Bits.PageTableBaseAddress << 12);\r
51e0bd28
AP
420 Index = PDP_OFFSET (AddressToMap);\r
421\r
422 if (!L3[Index].Bits.Present) {\r
423 PageTable = AllocatePages (1);\r
424 if (PageTable == NULL) {\r
425 return EFI_OUT_OF_RESOURCES;\r
426 }\r
427\r
428 ZeroMem (PageTable, EFI_PAGE_SIZE);\r
429\r
ac0a286f
MK
430 L3[Index].Bits.ReadWrite = 1;\r
431 L3[Index].Bits.Accessed = 1;\r
51e0bd28 432 L3[Index].Bits.PageTableBaseAddress = (EFI_PHYSICAL_ADDRESS)PageTable >> 12;\r
ac0a286f 433 L3[Index].Bits.Present = 1;\r
51e0bd28
AP
434 }\r
435\r
436 // L2 / Page Table Entries\r
437\r
ac0a286f
MK
438 PageTable = (VOID *)(EFI_PHYSICAL_ADDRESS)(L3[Index].Bits.PageTableBaseAddress << 12);\r
439 Index = PDE_OFFSET (AddressToMap);\r
51e0bd28
AP
440\r
441 if (!PageTable[Index].Bits.Present) {\r
ac0a286f
MK
442 PageTable[Index].Bits.ReadWrite = 1;\r
443 PageTable[Index].Bits.Accessed = 1;\r
444 PageTable[Index].Bits.Dirty = 1;\r
445 PageTable[Index].Bits.MustBe1 = 1;\r
51e0bd28 446 PageTable[Index].Bits.PageTableBaseAddress = AddressToMap >> 21;\r
ac0a286f 447 PageTable[Index].Bits.Present = 1;\r
51e0bd28
AP
448 }\r
449\r
450 CpuFlushTlb ();\r
451\r
452 return EFI_SUCCESS;\r
453}\r
c75c6405
AP
454\r
455STATIC\r
456EFI_STATUS\r
457MapSharedInfoPage (\r
ac0a286f 458 IN VOID *PagePtr\r
c75c6405
AP
459 )\r
460{\r
461 xen_add_to_physmap_t Parameters;\r
462 INTN ReturnCode;\r
463\r
464 Parameters.domid = DOMID_SELF;\r
465 Parameters.space = XENMAPSPACE_shared_info;\r
ac0a286f
MK
466 Parameters.idx = 0;\r
467 Parameters.gpfn = (UINTN)PagePtr >> EFI_PAGE_SHIFT;\r
468 ReturnCode = XenHypercallMemoryOp (XENMEM_add_to_physmap, &Parameters);\r
c75c6405
AP
469 if (ReturnCode != 0) {\r
470 return EFI_NO_MAPPING;\r
471 }\r
ac0a286f 472\r
c75c6405
AP
473 return EFI_SUCCESS;\r
474}\r
475\r
476STATIC\r
477VOID\r
478UnmapXenPage (\r
ac0a286f 479 IN VOID *PagePtr\r
c75c6405
AP
480 )\r
481{\r
ac0a286f
MK
482 xen_remove_from_physmap_t Parameters;\r
483 INTN ReturnCode;\r
c75c6405
AP
484\r
485 Parameters.domid = DOMID_SELF;\r
ac0a286f
MK
486 Parameters.gpfn = (UINTN)PagePtr >> EFI_PAGE_SHIFT;\r
487 ReturnCode = XenHypercallMemoryOp (XENMEM_remove_from_physmap, &Parameters);\r
c75c6405
AP
488 ASSERT (ReturnCode == 0);\r
489}\r
490\r
c75c6405
AP
491STATIC\r
492UINT64\r
493GetCpuFreq (\r
ac0a286f 494 IN XEN_VCPU_TIME_INFO *VcpuTime\r
c75c6405
AP
495 )\r
496{\r
ac0a286f
MK
497 UINT32 Version;\r
498 UINT32 TscToSystemMultiplier;\r
499 INT8 TscShift;\r
500 UINT64 CpuFreq;\r
c75c6405
AP
501\r
502 do {\r
503 Version = VcpuTime->Version;\r
504 MemoryFence ();\r
505 TscToSystemMultiplier = VcpuTime->TscToSystemMultiplier;\r
ac0a286f 506 TscShift = VcpuTime->TscShift;\r
c75c6405
AP
507 MemoryFence ();\r
508 } while (((Version & 1) != 0) && (Version != VcpuTime->Version));\r
509\r
510 CpuFreq = DivU64x32 (LShiftU64 (1000000000ULL, 32), TscToSystemMultiplier);\r
511 if (TscShift >= 0) {\r
ac0a286f 512 CpuFreq = RShiftU64 (CpuFreq, TscShift);\r
c75c6405 513 } else {\r
ac0a286f 514 CpuFreq = LShiftU64 (CpuFreq, -TscShift);\r
c75c6405 515 }\r
ac0a286f 516\r
c75c6405
AP
517 return CpuFreq;\r
518}\r
519\r
520STATIC\r
521VOID\r
522XenDelay (\r
ac0a286f
MK
523 IN XEN_VCPU_TIME_INFO *VcpuTimeInfo,\r
524 IN UINT64 DelayNs\r
c75c6405
AP
525 )\r
526{\r
ac0a286f
MK
527 UINT64 Tick;\r
528 UINT64 CpuFreq;\r
529 UINT64 Delay;\r
530 UINT64 DelayTick;\r
531 UINT64 NewTick;\r
532 RETURN_STATUS Status;\r
c75c6405
AP
533\r
534 Tick = AsmReadTsc ();\r
535\r
536 CpuFreq = GetCpuFreq (VcpuTimeInfo);\r
ac0a286f 537 Status = SafeUint64Mult (DelayNs, CpuFreq, &Delay);\r
c75c6405 538 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
539 DEBUG ((\r
540 DEBUG_ERROR,\r
c75c6405 541 "XenDelay (%lu ns): delay too big in relation to CPU freq %lu Hz\n",\r
ac0a286f
MK
542 DelayNs,\r
543 CpuFreq\r
544 ));\r
c75c6405
AP
545 ASSERT_EFI_ERROR (Status);\r
546 CpuDeadLoop ();\r
547 }\r
548\r
549 DelayTick = DivU64x32 (Delay, 1000000000);\r
550\r
551 NewTick = Tick + DelayTick;\r
552\r
553 //\r
554 // Check for overflow\r
555 //\r
556 if (NewTick < Tick) {\r
557 //\r
558 // Overflow, wait for TSC to also overflow\r
559 //\r
560 while (AsmReadTsc () >= Tick) {\r
561 CpuPause ();\r
562 }\r
563 }\r
564\r
565 while (AsmReadTsc () <= NewTick) {\r
566 CpuPause ();\r
567 }\r
568}\r
569\r
c75c6405
AP
570/**\r
571 Calculate the frequency of the Local Apic Timer\r
572**/\r
573VOID\r
574CalibrateLapicTimer (\r
575 VOID\r
576 )\r
577{\r
ac0a286f
MK
578 XEN_SHARED_INFO *SharedInfo;\r
579 XEN_VCPU_TIME_INFO *VcpuTimeInfo;\r
580 UINT32 TimerTick, TimerTick2, DiffTimer;\r
581 UINT64 TscTick, TscTick2;\r
582 UINT64 Freq;\r
583 UINT64 Dividend;\r
584 EFI_STATUS Status;\r
585\r
586 SharedInfo = (VOID *)((UINTN)PcdGet32 (PcdCpuLocalApicBaseAddress) + SIZE_1MB);\r
587 Status = PhysicalAddressIdentityMapping ((EFI_PHYSICAL_ADDRESS)SharedInfo);\r
c75c6405 588 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
589 DEBUG ((\r
590 DEBUG_ERROR,\r
c75c6405 591 "Failed to add page table entry for Xen shared info page: %r\n",\r
ac0a286f
MK
592 Status\r
593 ));\r
c75c6405
AP
594 ASSERT_EFI_ERROR (Status);\r
595 return;\r
596 }\r
597\r
598 Status = MapSharedInfoPage (SharedInfo);\r
599 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
600 DEBUG ((\r
601 DEBUG_ERROR,\r
602 "Failed to map Xen's shared info page: %r\n",\r
603 Status\r
604 ));\r
c75c6405
AP
605 ASSERT_EFI_ERROR (Status);\r
606 return;\r
607 }\r
608\r
609 VcpuTimeInfo = &SharedInfo->VcpuInfo[0].Time;\r
610\r
611 InitializeApicTimer (1, MAX_UINT32, TRUE, 0);\r
612 DisableApicTimerInterrupt ();\r
613\r
614 TimerTick = GetApicTimerCurrentCount ();\r
ac0a286f 615 TscTick = AsmReadTsc ();\r
c75c6405
AP
616 XenDelay (VcpuTimeInfo, 1000000ULL);\r
617 TimerTick2 = GetApicTimerCurrentCount ();\r
ac0a286f 618 TscTick2 = AsmReadTsc ();\r
c75c6405
AP
619\r
620 DiffTimer = TimerTick - TimerTick2;\r
ac0a286f 621 Status = SafeUint64Mult (GetCpuFreq (VcpuTimeInfo), DiffTimer, &Dividend);\r
c75c6405
AP
622 if (EFI_ERROR (Status)) {\r
623 DEBUG ((DEBUG_ERROR, "overflow while calculating APIC frequency\n"));\r
ac0a286f
MK
624 DEBUG ((\r
625 DEBUG_ERROR,\r
626 "CPU freq: %lu Hz; APIC timer tick count for 1 ms: %u\n",\r
627 GetCpuFreq (VcpuTimeInfo),\r
628 DiffTimer\r
629 ));\r
c75c6405
AP
630 ASSERT_EFI_ERROR (Status);\r
631 CpuDeadLoop ();\r
632 }\r
633\r
634 Freq = DivU64x64Remainder (Dividend, TscTick2 - TscTick, NULL);\r
635 DEBUG ((DEBUG_INFO, "APIC Freq % 8lu Hz\n", Freq));\r
636\r
71cdb91f
AP
637 ASSERT (Freq <= MAX_UINT32);\r
638 Status = PcdSet32S (PcdFSBClock, (UINT32)Freq);\r
639 ASSERT_EFI_ERROR (Status);\r
640\r
c75c6405
AP
641 UnmapXenPage (SharedInfo);\r
642}\r