From 3e997c870bb309af58269a3bc296188f5e78eb13 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Sun, 6 Sep 2015 20:55:50 +0000 Subject: [PATCH] [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 --- reactos/boot/environ/CMakeLists.txt | 3 +- reactos/boot/environ/include/bl.h | 12 +++ reactos/boot/environ/lib/arch/i386/arch.c | 28 ++++-- reactos/boot/environ/lib/bootlib.c | 44 ++++++++++ .../boot/environ/lib/firmware/efi/firmware.c | 31 ++++++- reactos/boot/environ/lib/mm/heapalloc.c | 48 +++++----- reactos/boot/environ/lib/platform/time.c | 88 +++++++++++++++++++ 7 files changed, 221 insertions(+), 33 deletions(-) create mode 100644 reactos/boot/environ/lib/platform/time.c diff --git a/reactos/boot/environ/CMakeLists.txt b/reactos/boot/environ/CMakeLists.txt index bd42217b078..ffb112ae751 100644 --- a/reactos/boot/environ/CMakeLists.txt +++ b/reactos/boot/environ/CMakeLists.txt @@ -17,7 +17,8 @@ list(APPEND BOOTLIB_SOURCE lib/mm/pagealloc.c lib/mm/heapalloc.c lib/mm/blkalloc.c - lib/mm/descriptor.c) + lib/mm/descriptor.c + lib/platform/time.c) if(ARCH STREQUAL "i386") list(APPEND BOOTLIB_ASM_SOURCE diff --git a/reactos/boot/environ/include/bl.h b/reactos/boot/environ/include/bl.h index 60bb243f5cb..74e87d3ce0b 100644 --- a/reactos/boot/environ/include/bl.h +++ b/reactos/boot/environ/include/bl.h @@ -522,6 +522,18 @@ EfiAllocatePages ( _Inout_ EFI_PHYSICAL_ADDRESS* Memory ); +NTSTATUS +EfiStall ( + _In_ ULONG StallTime + ); + +/* PLATFORM TIMER ROUTINES ***************************************************/ + +NTSTATUS +BlpTimeCalibratePerformanceCounter ( + VOID + ); + /* UTILITY ROUTINES **********************************************************/ EFI_STATUS diff --git a/reactos/boot/environ/lib/arch/i386/arch.c b/reactos/boot/environ/lib/arch/i386/arch.c index 6cab2bb144f..1a5778a6983 100644 --- a/reactos/boot/environ/lib/arch/i386/arch.c +++ b/reactos/boot/environ/lib/arch/i386/arch.c @@ -19,13 +19,20 @@ PBL_ARCH_CONTEXT CurrentExecutionContext; /* FUNCTIONS *****************************************************************/ VOID -//__declspec(naked) fixme: gcc +DECLSPEC_NORETURN ArchTrapNoProcess ( VOID ) { /* 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 @@ -208,8 +215,13 @@ BlpArchInitialize ( IdtBase = (PKIDTENTRY)Idtr.Base; /* Get the Code Segment */ - // _asm { mov CodeSegment, cs } FIXME: GCC - CodeSegment = 8; // fix fix +#if defined(__GNUC__) + __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) */ IdtBase[3].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess; @@ -230,7 +242,13 @@ BlpArchInitialize ( __lidt(&Idtr); /* 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 { diff --git a/reactos/boot/environ/lib/bootlib.c b/reactos/boot/environ/lib/bootlib.c index 93ede145377..a6daf135670 100644 --- a/reactos/boot/environ/lib/bootlib.c +++ b/reactos/boot/environ/lib/bootlib.c @@ -132,6 +132,50 @@ InitializeLibrary ( 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"); Status = STATUS_NOT_IMPLEMENTED; diff --git a/reactos/boot/environ/lib/firmware/efi/firmware.c b/reactos/boot/environ/lib/firmware/efi/firmware.c index a69e6f3132c..147e4a87a52 100644 --- a/reactos/boot/environ/lib/firmware/efi/firmware.c +++ b/reactos/boot/environ/lib/firmware/efi/firmware.c @@ -218,6 +218,35 @@ EfiFreePages ( 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 EfiAllocatePages ( _In_ ULONG Type, @@ -749,7 +778,7 @@ BlpFwInitialize ( { /* Set the initial key toggle state */ KeyToggleState = EFI_TOGGLE_STATE_VALID | 40; - EfiConInExSetState(EfiST->ConsoleInHandle, &KeyToggleState); + EfiConInExSetState(EfiConInEx, &KeyToggleState); } /* Setup the watchdog timer */ diff --git a/reactos/boot/environ/lib/mm/heapalloc.c b/reactos/boot/environ/lib/mm/heapalloc.c index be0d0e9b06d..fbcaa2be00b 100644 --- a/reactos/boot/environ/lib/mm/heapalloc.c +++ b/reactos/boot/environ/lib/mm/heapalloc.c @@ -47,10 +47,10 @@ typedef struct _BL_BUSY_HEAP_ENTRY typedef struct _BL_HEAP_BOUNDARIES { LIST_ENTRY ListEntry; - ULONG_PTR HeapHigh; + ULONG_PTR HeapEnd; ULONG_PTR HeapLimit; - ULONG_PTR HeapBottom; - PBL_BUSY_HEAP_ENTRY HeapTop; + ULONG_PTR HeapBase; + PBL_BUSY_HEAP_ENTRY HeapStart; } BL_HEAP_BOUNDARIES, *PBL_HEAP_BOUNDARIES; ULONG HapInitializationStatus; @@ -125,7 +125,7 @@ MmHapHeapAllocatorExtend ( /* Check if we have a page free above the heap */ HeapLimit = Heap->HeapLimit + PAGE_SIZE; - if (HeapLimit <= Heap->HeapHigh) + if (HeapLimit <= Heap->HeapEnd) { EarlyPrint(L"Heap extension TODO\n"); return STATUS_INSUFFICIENT_RESOURCES; @@ -147,32 +147,32 @@ MmHapHeapAllocatorExtend ( /* Set the heap bottom, limit, and top */ NewHeap = (PBL_HEAP_BOUNDARIES)HeapBase->Buffer; - NewHeap->HeapBottom = (ULONG_PTR)HeapBase; + NewHeap->HeapBase = (ULONG_PTR)HeapBase; 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 */ 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 */ - NewHeap->HeapTop->BufferPrevious.P = HeapBase; - NewHeap->HeapTop->BufferNext.P = NewHeap->HeapTop; - NewHeap->HeapTop->BufferNext.BufferFree = 1; - NewHeap->HeapTop->BufferNext.BufferOnHeap = 1; + NewHeap->HeapStart->BufferPrevious.P = HeapBase; + NewHeap->HeapStart->BufferNext.P = NewHeap->HeapStart; + NewHeap->HeapStart->BufferNext.BufferFree = 1; + NewHeap->HeapStart->BufferNext.BufferOnHeap = 1; /* Is this the first heap ever? */ if (IsListEmpty(&MmHeapBoundaries)) { /* 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; RtlZeroMemory(MmFreeList, 8 * sizeof(PBL_FREE_HEAP_ENTRY)); } /* Remove a page on top */ HeapLimit = NewHeap->HeapLimit; - NewHeap->HeapHigh = NewHeap->HeapLimit; + NewHeap->HeapEnd = NewHeap->HeapLimit; NewHeap->HeapLimit -= PAGE_SIZE; /* Add us into the heap list */ @@ -595,29 +595,24 @@ BlMmAllocateHeap ( ListEntry); /* 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); - 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) && ((ULONG_PTR)NextEntry <= Heap->HeapLimit - sizeof(BL_BUSY_HEAP_ENTRY))) { /* Update the heap top pointer past this allocation */ - Heap->HeapTop = NextEntry; + Heap->HeapStart = NextEntry; /* 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 */ - Heap->HeapTop->BufferNext.P = FreeEntry; + Heap->HeapStart->BufferNext.P = FreeEntry; /* Mark the heap entry as being free and on the heap */ - Heap->HeapTop->BufferNext.BufferFree = 1; - Heap->HeapTop->BufferNext.BufferOnHeap = 1; + Heap->HeapStart->BufferNext.BufferFree = 1; + Heap->HeapStart->BufferNext.BufferOnHeap = 1; /* The previously freed entry on the heap page is now ours */ BusyEntry = FreeEntry; @@ -639,6 +634,7 @@ BlMmAllocateHeap ( BusyEntry->BufferNext.P = MmHapDecodeLink(BusyEntry->BufferNext); /* Return the entry's data buffer */ + EarlyPrint(L"Returning buffer at 0x%p\n", &BusyEntry->Buffer); return &BusyEntry->Buffer; } @@ -668,8 +664,8 @@ BlMmFreeHeap ( Heap = CONTAINING_RECORD(NextEntry, BL_HEAP_BOUNDARIES, ListEntry); /* Is this entry part of this heap? */ - if (((ULONG_PTR)Heap->HeapBottom <= (ULONG_PTR)BusyEntry) && - ((ULONG_PTR)BusyEntry < (ULONG_PTR)Heap->HeapTop)) + if (((ULONG_PTR)Heap->HeapBase <= (ULONG_PTR)BusyEntry) && + ((ULONG_PTR)BusyEntry < (ULONG_PTR)Heap->HeapStart)) { /* Ignore double-free */ if (BusyEntry->BufferNext.BufferFree) diff --git a/reactos/boot/environ/lib/platform/time.c b/reactos/boot/environ/lib/platform/time.c new file mode 100644 index 00000000000..c012dc22c96 --- /dev/null +++ b/reactos/boot/environ/lib/platform/time.c @@ -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(); +}