#include <Library/CpuLib.h>\r
#include <Library/DebugLib.h>\r
#include <Library/HobLib.h>\r
+#include <Library/LocalApicLib.h>\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/PcdLib.h>\r
+#include <Library/SafeIntLib.h>\r
#include <Guid/XenInfo.h>\r
#include <IndustryStandard/E820.h>\r
#include <Library/ResourcePublicationLib.h>\r
\r
return EFI_SUCCESS;\r
}\r
+\r
+STATIC\r
+EFI_STATUS\r
+MapSharedInfoPage (\r
+ IN VOID *PagePtr\r
+ )\r
+{\r
+ xen_add_to_physmap_t Parameters;\r
+ INTN ReturnCode;\r
+\r
+ Parameters.domid = DOMID_SELF;\r
+ Parameters.space = XENMAPSPACE_shared_info;\r
+ Parameters.idx = 0;\r
+ Parameters.gpfn = (UINTN)PagePtr >> EFI_PAGE_SHIFT;\r
+ ReturnCode = XenHypercallMemoryOp (XENMEM_add_to_physmap, &Parameters);\r
+ if (ReturnCode != 0) {\r
+ return EFI_NO_MAPPING;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+VOID\r
+UnmapXenPage (\r
+ IN VOID *PagePtr\r
+ )\r
+{\r
+ xen_remove_from_physmap_t Parameters;\r
+ INTN ReturnCode;\r
+\r
+ Parameters.domid = DOMID_SELF;\r
+ Parameters.gpfn = (UINTN)PagePtr >> EFI_PAGE_SHIFT;\r
+ ReturnCode = XenHypercallMemoryOp (XENMEM_remove_from_physmap, &Parameters);\r
+ ASSERT (ReturnCode == 0);\r
+}\r
+\r
+\r
+STATIC\r
+UINT64\r
+GetCpuFreq (\r
+ IN XEN_VCPU_TIME_INFO *VcpuTime\r
+ )\r
+{\r
+ UINT32 Version;\r
+ UINT32 TscToSystemMultiplier;\r
+ INT8 TscShift;\r
+ UINT64 CpuFreq;\r
+\r
+ do {\r
+ Version = VcpuTime->Version;\r
+ MemoryFence ();\r
+ TscToSystemMultiplier = VcpuTime->TscToSystemMultiplier;\r
+ TscShift = VcpuTime->TscShift;\r
+ MemoryFence ();\r
+ } while (((Version & 1) != 0) && (Version != VcpuTime->Version));\r
+\r
+ CpuFreq = DivU64x32 (LShiftU64 (1000000000ULL, 32), TscToSystemMultiplier);\r
+ if (TscShift >= 0) {\r
+ CpuFreq = RShiftU64 (CpuFreq, TscShift);\r
+ } else {\r
+ CpuFreq = LShiftU64 (CpuFreq, -TscShift);\r
+ }\r
+ return CpuFreq;\r
+}\r
+\r
+STATIC\r
+VOID\r
+XenDelay (\r
+ IN XEN_VCPU_TIME_INFO *VcpuTimeInfo,\r
+ IN UINT64 DelayNs\r
+ )\r
+{\r
+ UINT64 Tick;\r
+ UINT64 CpuFreq;\r
+ UINT64 Delay;\r
+ UINT64 DelayTick;\r
+ UINT64 NewTick;\r
+ RETURN_STATUS Status;\r
+\r
+ Tick = AsmReadTsc ();\r
+\r
+ CpuFreq = GetCpuFreq (VcpuTimeInfo);\r
+ Status = SafeUint64Mult (DelayNs, CpuFreq, &Delay);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR,\r
+ "XenDelay (%lu ns): delay too big in relation to CPU freq %lu Hz\n",\r
+ DelayNs, CpuFreq));\r
+ ASSERT_EFI_ERROR (Status);\r
+ CpuDeadLoop ();\r
+ }\r
+\r
+ DelayTick = DivU64x32 (Delay, 1000000000);\r
+\r
+ NewTick = Tick + DelayTick;\r
+\r
+ //\r
+ // Check for overflow\r
+ //\r
+ if (NewTick < Tick) {\r
+ //\r
+ // Overflow, wait for TSC to also overflow\r
+ //\r
+ while (AsmReadTsc () >= Tick) {\r
+ CpuPause ();\r
+ }\r
+ }\r
+\r
+ while (AsmReadTsc () <= NewTick) {\r
+ CpuPause ();\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Calculate the frequency of the Local Apic Timer\r
+**/\r
+VOID\r
+CalibrateLapicTimer (\r
+ VOID\r
+ )\r
+{\r
+ XEN_SHARED_INFO *SharedInfo;\r
+ XEN_VCPU_TIME_INFO *VcpuTimeInfo;\r
+ UINT32 TimerTick, TimerTick2, DiffTimer;\r
+ UINT64 TscTick, TscTick2;\r
+ UINT64 Freq;\r
+ UINT64 Dividend;\r
+ EFI_STATUS Status;\r
+\r
+\r
+ SharedInfo = (VOID*)((1ULL << mPhysMemAddressWidth) - EFI_PAGE_SIZE);\r
+ Status = PhysicalAddressIdentityMapping ((EFI_PHYSICAL_ADDRESS)SharedInfo);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR,\r
+ "Failed to add page table entry for Xen shared info page: %r\n",\r
+ Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ return;\r
+ }\r
+\r
+ Status = MapSharedInfoPage (SharedInfo);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Failed to map Xen's shared info page: %r\n",\r
+ Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ return;\r
+ }\r
+\r
+ VcpuTimeInfo = &SharedInfo->VcpuInfo[0].Time;\r
+\r
+ InitializeApicTimer (1, MAX_UINT32, TRUE, 0);\r
+ DisableApicTimerInterrupt ();\r
+\r
+ TimerTick = GetApicTimerCurrentCount ();\r
+ TscTick = AsmReadTsc ();\r
+ XenDelay (VcpuTimeInfo, 1000000ULL);\r
+ TimerTick2 = GetApicTimerCurrentCount ();\r
+ TscTick2 = AsmReadTsc ();\r
+\r
+\r
+ DiffTimer = TimerTick - TimerTick2;\r
+ Status = SafeUint64Mult (GetCpuFreq (VcpuTimeInfo), DiffTimer, &Dividend);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "overflow while calculating APIC frequency\n"));\r
+ DEBUG ((DEBUG_ERROR, "CPU freq: %lu Hz; APIC timer tick count for 1 ms: %u\n",\r
+ GetCpuFreq (VcpuTimeInfo), DiffTimer));\r
+ ASSERT_EFI_ERROR (Status);\r
+ CpuDeadLoop ();\r
+ }\r
+\r
+ Freq = DivU64x64Remainder (Dividend, TscTick2 - TscTick, NULL);\r
+ DEBUG ((DEBUG_INFO, "APIC Freq % 8lu Hz\n", Freq));\r
+\r
+ UnmapXenPage (SharedInfo);\r
+}\r