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