mirror of
https://github.com/reactos/reactos.git
synced 2024-07-06 20:55:16 +00:00
[BOOTMGFW]
- Fix some heap bugs. It (works?) now, at least for one allocation. - Fix GCC support for Phase 1 Architectural Initialization. - Implement Time measurement for Hyper-V compatible hypervisors (tested with Virtual Box 5.0!) as well as non-hypervisors (also tested) svn path=/trunk/; revision=69071
This commit is contained in:
parent
d8b6cfc7f3
commit
3e997c870b
|
@ -17,7 +17,8 @@ list(APPEND BOOTLIB_SOURCE
|
||||||
lib/mm/pagealloc.c
|
lib/mm/pagealloc.c
|
||||||
lib/mm/heapalloc.c
|
lib/mm/heapalloc.c
|
||||||
lib/mm/blkalloc.c
|
lib/mm/blkalloc.c
|
||||||
lib/mm/descriptor.c)
|
lib/mm/descriptor.c
|
||||||
|
lib/platform/time.c)
|
||||||
|
|
||||||
if(ARCH STREQUAL "i386")
|
if(ARCH STREQUAL "i386")
|
||||||
list(APPEND BOOTLIB_ASM_SOURCE
|
list(APPEND BOOTLIB_ASM_SOURCE
|
||||||
|
|
|
@ -522,6 +522,18 @@ EfiAllocatePages (
|
||||||
_Inout_ EFI_PHYSICAL_ADDRESS* Memory
|
_Inout_ EFI_PHYSICAL_ADDRESS* Memory
|
||||||
);
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
EfiStall (
|
||||||
|
_In_ ULONG StallTime
|
||||||
|
);
|
||||||
|
|
||||||
|
/* PLATFORM TIMER ROUTINES ***************************************************/
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
BlpTimeCalibratePerformanceCounter (
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
/* UTILITY ROUTINES **********************************************************/
|
/* UTILITY ROUTINES **********************************************************/
|
||||||
|
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
|
|
|
@ -19,13 +19,20 @@ PBL_ARCH_CONTEXT CurrentExecutionContext;
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
//__declspec(naked) fixme: gcc
|
DECLSPEC_NORETURN
|
||||||
ArchTrapNoProcess (
|
ArchTrapNoProcess (
|
||||||
VOID
|
VOID
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
/* Do nothing, this is an unsupported debugging interrupt */
|
/* Do nothing, this is an unsupported debugging interrupt */
|
||||||
// _asm { iret } FIXME: GCC
|
#if defined(__GNUC__)
|
||||||
|
__asm__ __volatile__ ("iret");
|
||||||
|
#elif defined (_MSC_VER)
|
||||||
|
_asm { iret };
|
||||||
|
#else
|
||||||
|
#error wtf are you using
|
||||||
|
#endif
|
||||||
|
__assume(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
|
@ -208,8 +215,13 @@ BlpArchInitialize (
|
||||||
IdtBase = (PKIDTENTRY)Idtr.Base;
|
IdtBase = (PKIDTENTRY)Idtr.Base;
|
||||||
|
|
||||||
/* Get the Code Segment */
|
/* Get the Code Segment */
|
||||||
// _asm { mov CodeSegment, cs } FIXME: GCC
|
#if defined(__GNUC__)
|
||||||
CodeSegment = 8; // fix fix
|
__asm__ __volatile__ ("mov %%cs,%0\n\t" :"=r" (CodeSegment));
|
||||||
|
#elif defined (_MSC_VER)
|
||||||
|
_asm { mov CodeSegment, cs };
|
||||||
|
#else
|
||||||
|
#error wtf are you using
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Set up INT 3, ASSERT, and SECURITY_ASSERT to be no-op (for Rtl) */
|
/* Set up INT 3, ASSERT, and SECURITY_ASSERT to be no-op (for Rtl) */
|
||||||
IdtBase[3].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess;
|
IdtBase[3].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess;
|
||||||
|
@ -230,7 +242,13 @@ BlpArchInitialize (
|
||||||
__lidt(&Idtr);
|
__lidt(&Idtr);
|
||||||
|
|
||||||
/* Reset FPU state */
|
/* Reset FPU state */
|
||||||
// __asm { fninit } FIXME: GCC
|
#if defined(__GNUC__)
|
||||||
|
__asm__ __volatile__ ("fninit");
|
||||||
|
#elif defined (_MSC_VER)
|
||||||
|
_asm { fninit };
|
||||||
|
#else
|
||||||
|
#error wtf are you using
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -132,6 +132,50 @@ InitializeLibrary (
|
||||||
goto Quickie;
|
goto Quickie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize firmware now that the heap, etc works */
|
||||||
|
Status = BlpFwInitialize(1, FirmwareDescriptor);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Destroy memory manager in phase 1 */
|
||||||
|
//BlpMmDestroy(1);
|
||||||
|
EarlyPrint(L"Firmware2 init failed!\n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Modern systems have an undocumented BCD system for the boot frequency */
|
||||||
|
Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
|
||||||
|
0x15000075,
|
||||||
|
&BootFrequency);
|
||||||
|
if (NT_SUCCESS(Status) && (BootFrequency))
|
||||||
|
{
|
||||||
|
/* Use it if present */
|
||||||
|
BlpTimePerformanceFrequency = BootFrequency;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* Use the TSC for calibration */
|
||||||
|
Status = BlpTimeCalibratePerformanceCounter();
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Destroy memory manager in phase 1 */
|
||||||
|
EarlyPrint(L"TSC calibration failed\n");
|
||||||
|
//BlpMmDestroy(1);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now setup the rest of the architecture (IDT, etc) */
|
||||||
|
Status = BlpArchInitialize(1);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Destroy memory manager in phase 1 */
|
||||||
|
EarlyPrint(L"Arch2 init failed\n");
|
||||||
|
//BlpMmDestroy(1);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
EarlyPrint(L"TODO!\n");
|
EarlyPrint(L"TODO!\n");
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
Status = STATUS_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
|
|
|
@ -218,6 +218,35 @@ EfiFreePages (
|
||||||
return EfiGetNtStatusCode(EfiStatus);
|
return EfiGetNtStatusCode(EfiStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
EfiStall (
|
||||||
|
_In_ ULONG StallTime
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BL_ARCH_MODE OldMode;
|
||||||
|
EFI_STATUS EfiStatus;
|
||||||
|
|
||||||
|
/* Are we in protected mode? */
|
||||||
|
OldMode = CurrentExecutionContext->Mode;
|
||||||
|
if (OldMode != BlRealMode)
|
||||||
|
{
|
||||||
|
/* FIXME: Not yet implemented */
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make the EFI call */
|
||||||
|
EfiStatus = EfiBS->Stall(StallTime);
|
||||||
|
|
||||||
|
/* Switch back to protected mode if we came from there */
|
||||||
|
if (OldMode != BlRealMode)
|
||||||
|
{
|
||||||
|
BlpArchSwitchContext(OldMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the error to an NTSTATUS */
|
||||||
|
return EfiGetNtStatusCode(EfiStatus);
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
EfiAllocatePages (
|
EfiAllocatePages (
|
||||||
_In_ ULONG Type,
|
_In_ ULONG Type,
|
||||||
|
@ -749,7 +778,7 @@ BlpFwInitialize (
|
||||||
{
|
{
|
||||||
/* Set the initial key toggle state */
|
/* Set the initial key toggle state */
|
||||||
KeyToggleState = EFI_TOGGLE_STATE_VALID | 40;
|
KeyToggleState = EFI_TOGGLE_STATE_VALID | 40;
|
||||||
EfiConInExSetState(EfiST->ConsoleInHandle, &KeyToggleState);
|
EfiConInExSetState(EfiConInEx, &KeyToggleState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup the watchdog timer */
|
/* Setup the watchdog timer */
|
||||||
|
|
|
@ -47,10 +47,10 @@ typedef struct _BL_BUSY_HEAP_ENTRY
|
||||||
typedef struct _BL_HEAP_BOUNDARIES
|
typedef struct _BL_HEAP_BOUNDARIES
|
||||||
{
|
{
|
||||||
LIST_ENTRY ListEntry;
|
LIST_ENTRY ListEntry;
|
||||||
ULONG_PTR HeapHigh;
|
ULONG_PTR HeapEnd;
|
||||||
ULONG_PTR HeapLimit;
|
ULONG_PTR HeapLimit;
|
||||||
ULONG_PTR HeapBottom;
|
ULONG_PTR HeapBase;
|
||||||
PBL_BUSY_HEAP_ENTRY HeapTop;
|
PBL_BUSY_HEAP_ENTRY HeapStart;
|
||||||
} BL_HEAP_BOUNDARIES, *PBL_HEAP_BOUNDARIES;
|
} BL_HEAP_BOUNDARIES, *PBL_HEAP_BOUNDARIES;
|
||||||
|
|
||||||
ULONG HapInitializationStatus;
|
ULONG HapInitializationStatus;
|
||||||
|
@ -125,7 +125,7 @@ MmHapHeapAllocatorExtend (
|
||||||
|
|
||||||
/* Check if we have a page free above the heap */
|
/* Check if we have a page free above the heap */
|
||||||
HeapLimit = Heap->HeapLimit + PAGE_SIZE;
|
HeapLimit = Heap->HeapLimit + PAGE_SIZE;
|
||||||
if (HeapLimit <= Heap->HeapHigh)
|
if (HeapLimit <= Heap->HeapEnd)
|
||||||
{
|
{
|
||||||
EarlyPrint(L"Heap extension TODO\n");
|
EarlyPrint(L"Heap extension TODO\n");
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
@ -147,32 +147,32 @@ MmHapHeapAllocatorExtend (
|
||||||
|
|
||||||
/* Set the heap bottom, limit, and top */
|
/* Set the heap bottom, limit, and top */
|
||||||
NewHeap = (PBL_HEAP_BOUNDARIES)HeapBase->Buffer;
|
NewHeap = (PBL_HEAP_BOUNDARIES)HeapBase->Buffer;
|
||||||
NewHeap->HeapBottom = (ULONG_PTR)HeapBase;
|
NewHeap->HeapBase = (ULONG_PTR)HeapBase;
|
||||||
NewHeap->HeapLimit = (ULONG_PTR)HeapBase + AlignedSize;
|
NewHeap->HeapLimit = (ULONG_PTR)HeapBase + AlignedSize;
|
||||||
NewHeap->HeapTop = (PBL_BUSY_HEAP_ENTRY)(NewHeap + 1);
|
NewHeap->HeapStart = (PBL_BUSY_HEAP_ENTRY)(NewHeap + 1);
|
||||||
|
|
||||||
/* Set the buffer links */
|
/* Set the buffer links */
|
||||||
HeapBase->BufferPrevious.P = NULL;
|
HeapBase->BufferPrevious.P = NULL;
|
||||||
HeapBase->BufferNext.P = NewHeap->HeapTop;
|
HeapBase->BufferNext.P = NewHeap->HeapStart;
|
||||||
|
|
||||||
/* Set the buffer at the top of the heap and mark it as being free */
|
/* Set the buffer at the top of the heap and mark it as being free */
|
||||||
NewHeap->HeapTop->BufferPrevious.P = HeapBase;
|
NewHeap->HeapStart->BufferPrevious.P = HeapBase;
|
||||||
NewHeap->HeapTop->BufferNext.P = NewHeap->HeapTop;
|
NewHeap->HeapStart->BufferNext.P = NewHeap->HeapStart;
|
||||||
NewHeap->HeapTop->BufferNext.BufferFree = 1;
|
NewHeap->HeapStart->BufferNext.BufferFree = 1;
|
||||||
NewHeap->HeapTop->BufferNext.BufferOnHeap = 1;
|
NewHeap->HeapStart->BufferNext.BufferOnHeap = 1;
|
||||||
|
|
||||||
/* Is this the first heap ever? */
|
/* Is this the first heap ever? */
|
||||||
if (IsListEmpty(&MmHeapBoundaries))
|
if (IsListEmpty(&MmHeapBoundaries))
|
||||||
{
|
{
|
||||||
/* We will host the free list at the top of the heap */
|
/* We will host the free list at the top of the heap */
|
||||||
MmFreeList = (PBL_FREE_HEAP_ENTRY*)((ULONG_PTR)NewHeap->HeapLimit - sizeof(BL_HEAP_BOUNDARIES));
|
MmFreeList = (PBL_FREE_HEAP_ENTRY*)((ULONG_PTR)NewHeap->HeapLimit - 8 * sizeof(PBL_FREE_HEAP_ENTRY));
|
||||||
NewHeap->HeapLimit = (ULONG_PTR)MmFreeList;
|
NewHeap->HeapLimit = (ULONG_PTR)MmFreeList;
|
||||||
RtlZeroMemory(MmFreeList, 8 * sizeof(PBL_FREE_HEAP_ENTRY));
|
RtlZeroMemory(MmFreeList, 8 * sizeof(PBL_FREE_HEAP_ENTRY));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove a page on top */
|
/* Remove a page on top */
|
||||||
HeapLimit = NewHeap->HeapLimit;
|
HeapLimit = NewHeap->HeapLimit;
|
||||||
NewHeap->HeapHigh = NewHeap->HeapLimit;
|
NewHeap->HeapEnd = NewHeap->HeapLimit;
|
||||||
NewHeap->HeapLimit -= PAGE_SIZE;
|
NewHeap->HeapLimit -= PAGE_SIZE;
|
||||||
|
|
||||||
/* Add us into the heap list */
|
/* Add us into the heap list */
|
||||||
|
@ -595,29 +595,24 @@ BlMmAllocateHeap (
|
||||||
ListEntry);
|
ListEntry);
|
||||||
|
|
||||||
/* Check if we have space in the heap page for this allocation? */
|
/* Check if we have space in the heap page for this allocation? */
|
||||||
FreeEntry = Heap->HeapTop;
|
FreeEntry = Heap->HeapStart;
|
||||||
NextEntry = (PBL_BUSY_HEAP_ENTRY)((ULONG_PTR)FreeEntry + BufferSize);
|
NextEntry = (PBL_BUSY_HEAP_ENTRY)((ULONG_PTR)FreeEntry + BufferSize);
|
||||||
|
|
||||||
EarlyPrint(L"Free Entry: %p Size: %lx Next: %p\n", FreeEntry, BufferSize, NextEntry);
|
|
||||||
|
|
||||||
EarlyPrint(L"Heap Limit: %p\n", Heap->HeapLimit);
|
|
||||||
EarlyPrint(L"Minus one busy entry: %p\n", Heap->HeapLimit - sizeof(BL_BUSY_HEAP_ENTRY));
|
|
||||||
|
|
||||||
if ((NextEntry >= FreeEntry) &&
|
if ((NextEntry >= FreeEntry) &&
|
||||||
((ULONG_PTR)NextEntry <= Heap->HeapLimit - sizeof(BL_BUSY_HEAP_ENTRY)))
|
((ULONG_PTR)NextEntry <= Heap->HeapLimit - sizeof(BL_BUSY_HEAP_ENTRY)))
|
||||||
{
|
{
|
||||||
/* Update the heap top pointer past this allocation */
|
/* Update the heap top pointer past this allocation */
|
||||||
Heap->HeapTop = NextEntry;
|
Heap->HeapStart = NextEntry;
|
||||||
|
|
||||||
/* Make this allocation point to the slot */
|
/* Make this allocation point to the slot */
|
||||||
FreeEntry->BufferNext.P = Heap->HeapTop;
|
FreeEntry->BufferNext.P = Heap->HeapStart;
|
||||||
|
|
||||||
/* And make the free heap entry point back to us */
|
/* And make the free heap entry point back to us */
|
||||||
Heap->HeapTop->BufferNext.P = FreeEntry;
|
Heap->HeapStart->BufferNext.P = FreeEntry;
|
||||||
|
|
||||||
/* Mark the heap entry as being free and on the heap */
|
/* Mark the heap entry as being free and on the heap */
|
||||||
Heap->HeapTop->BufferNext.BufferFree = 1;
|
Heap->HeapStart->BufferNext.BufferFree = 1;
|
||||||
Heap->HeapTop->BufferNext.BufferOnHeap = 1;
|
Heap->HeapStart->BufferNext.BufferOnHeap = 1;
|
||||||
|
|
||||||
/* The previously freed entry on the heap page is now ours */
|
/* The previously freed entry on the heap page is now ours */
|
||||||
BusyEntry = FreeEntry;
|
BusyEntry = FreeEntry;
|
||||||
|
@ -639,6 +634,7 @@ BlMmAllocateHeap (
|
||||||
BusyEntry->BufferNext.P = MmHapDecodeLink(BusyEntry->BufferNext);
|
BusyEntry->BufferNext.P = MmHapDecodeLink(BusyEntry->BufferNext);
|
||||||
|
|
||||||
/* Return the entry's data buffer */
|
/* Return the entry's data buffer */
|
||||||
|
EarlyPrint(L"Returning buffer at 0x%p\n", &BusyEntry->Buffer);
|
||||||
return &BusyEntry->Buffer;
|
return &BusyEntry->Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,8 +664,8 @@ BlMmFreeHeap (
|
||||||
Heap = CONTAINING_RECORD(NextEntry, BL_HEAP_BOUNDARIES, ListEntry);
|
Heap = CONTAINING_RECORD(NextEntry, BL_HEAP_BOUNDARIES, ListEntry);
|
||||||
|
|
||||||
/* Is this entry part of this heap? */
|
/* Is this entry part of this heap? */
|
||||||
if (((ULONG_PTR)Heap->HeapBottom <= (ULONG_PTR)BusyEntry) &&
|
if (((ULONG_PTR)Heap->HeapBase <= (ULONG_PTR)BusyEntry) &&
|
||||||
((ULONG_PTR)BusyEntry < (ULONG_PTR)Heap->HeapTop))
|
((ULONG_PTR)BusyEntry < (ULONG_PTR)Heap->HeapStart))
|
||||||
{
|
{
|
||||||
/* Ignore double-free */
|
/* Ignore double-free */
|
||||||
if (BusyEntry->BufferNext.BufferFree)
|
if (BusyEntry->BufferNext.BufferFree)
|
||||||
|
|
88
reactos/boot/environ/lib/platform/time.c
Normal file
88
reactos/boot/environ/lib/platform/time.c
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING.ARM in the top level directory
|
||||||
|
* PROJECT: ReactOS UEFI Boot Library
|
||||||
|
* FILE: boot/environ/lib/platform/time.c
|
||||||
|
* PURPOSE: Boot Library Time Management Routines
|
||||||
|
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
|
#include "bl.h"
|
||||||
|
|
||||||
|
/* DATA VARIABLES ************************************************************/
|
||||||
|
|
||||||
|
ULONGLONG BlpTimePerformanceFrequency;
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
BlpTimeMeasureTscFrequency (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ULONG Count;
|
||||||
|
INT CpuInfo[4];
|
||||||
|
ULONGLONG TimeStamp1, TimeStamp2, Delta;
|
||||||
|
|
||||||
|
/* Check if the ISVM bit it set, meaning we're in a hypervisor */
|
||||||
|
__cpuid(CpuInfo, 1);
|
||||||
|
Count = CpuInfo[2] & 0x80000000 ? 10 : 1;
|
||||||
|
|
||||||
|
/* Loop trying to get an accurate TSC */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Stall for 1us and get count 1 */
|
||||||
|
EfiStall(1);
|
||||||
|
TimeStamp1 = __rdtsc();
|
||||||
|
|
||||||
|
/* Stall for 1000us and get count 2*/
|
||||||
|
EfiStall(1000);
|
||||||
|
TimeStamp2 = __rdtsc();
|
||||||
|
|
||||||
|
/* Stall for 9000us and get the difference */
|
||||||
|
EfiStall(9000);
|
||||||
|
Delta = __rdtsc() - TimeStamp2;
|
||||||
|
|
||||||
|
/* Keep going as long as the TSC is fluctuating */
|
||||||
|
--Count;
|
||||||
|
} while (((TimeStamp2 - TimeStamp1) > Delta) && (Count));
|
||||||
|
|
||||||
|
/* Set the frequency based on the two measurements we took */
|
||||||
|
BlpTimePerformanceFrequency = 125 * (Delta - (TimeStamp2 - TimeStamp1)) & 0x1FFFFFFFFFFFFFF;
|
||||||
|
EarlyPrint(L"Computed frequency as: %I64d\n", BlpTimePerformanceFrequency);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
BlpTimeCalibratePerformanceCounter (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
INT CpuInfo[4];
|
||||||
|
|
||||||
|
/* Check if the ISVM bit it set, meaning we're in a hypervisor */
|
||||||
|
__cpuid(CpuInfo, 1);
|
||||||
|
if (CpuInfo[2] & 0x80000000)
|
||||||
|
{
|
||||||
|
/* Get the Hypervisor Identification Leaf */
|
||||||
|
__cpuid(CpuInfo, 0x40000001);
|
||||||
|
|
||||||
|
/* Is this Hyper-V? */
|
||||||
|
if (CpuInfo[0] == '1#vH')
|
||||||
|
{
|
||||||
|
/* Get the Hypervisor Feature Identification Leaf */
|
||||||
|
__cpuid(CpuInfo, 0x40000003);
|
||||||
|
|
||||||
|
/* Check if HV_X64_MSR_REFERENCE_TSC is present */
|
||||||
|
if (CpuInfo[3] & 0x100)
|
||||||
|
{
|
||||||
|
/* Read the TSC frequency from the MSR */
|
||||||
|
BlpTimePerformanceFrequency = __readmsr(0x40000022);
|
||||||
|
EarlyPrint(L"Using frequency as: %I64d\n", BlpTimePerformanceFrequency);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* On other systems, compute it */
|
||||||
|
return BlpTimeMeasureTscFrequency();
|
||||||
|
}
|
Loading…
Reference in a new issue