Author: ion Date: Wed May 10 14:38:34 2017 New Revision: 74519
URL: http://svn.reactos.org/svn/reactos?rev=74519&view=rev Log: Fully working x86 paging support! [BOOTLIB]: Fix a critical bug in BlpArchSwitchContext which was not switching to Firmware mode once paging was enabled. [BOOTLIB]: Fix a critical bug in OslMain which was incorrectly setting BL_LIBRARY_INITIALIZATION_COMPLETED instead of BL_LIBRARY_FLAG_REINITIALIZE_ALL and causing all sorts of failure paths. [BOOTLIB]: MmDefInitializeTranslation now turns on paging. [BOOTLIB]: Implement TrpGenerateMappingTracker and BlpArchEnableTranslation [BOOTLIB]: BlMmMapPhysicalAddressEx now works with paging enabled, and correctly finds mapped memory to use from the virtual MDLs. [BOOTLIB]: MmPapAllocateRegionFromMdl now handles virtual allocations from MmMdlMappedUnallocated. [BOOTLIB]: MmPapAllocatePagesInRange now handles BlMemoryKernelRange (KSEG0) allocations. [BOOTLIB]: MmMdFindSatisfyingRegion now handles virtual descriptors as well, and handles alignment better.
Modified: trunk/reactos/boot/environ/app/rosload/rosload.c trunk/reactos/boot/environ/include/bl.h trunk/reactos/boot/environ/lib/arch/i386/arch.c trunk/reactos/boot/environ/lib/mm/descriptor.c trunk/reactos/boot/environ/lib/mm/i386/mmx86.c trunk/reactos/boot/environ/lib/mm/mm.c trunk/reactos/boot/environ/lib/mm/pagealloc.c
Modified: trunk/reactos/boot/environ/app/rosload/rosload.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/environ/app/rosload/ro... ============================================================================== --- trunk/reactos/boot/environ/app/rosload/rosload.c [iso-8859-1] (original) +++ trunk/reactos/boot/environ/app/rosload/rosload.c [iso-8859-1] Wed May 10 14:38:34 2017 @@ -39,10 +39,11 @@ /* Setup the boot library parameters for this application */ BlSetupDefaultParameters(&LibraryParameters); LibraryParameters.TranslationType = BlVirtual; - LibraryParameters.LibraryFlags = BL_LIBRARY_FLAG_INITIALIZATION_COMPLETED; + LibraryParameters.LibraryFlags = BL_LIBRARY_FLAG_ZERO_HEAP_ALLOCATIONS_ON_FREE | + BL_LIBRARY_FLAG_REINITIALIZE_ALL; LibraryParameters.MinimumAllocationCount = 1024; LibraryParameters.MinimumHeapSize = 2 * 1024 * 1024; - LibraryParameters.HeapAllocationAttributes = 0x20000; + LibraryParameters.HeapAllocationAttributes = BlMemoryKernelRange; LibraryParameters.FontBaseDirectory = L"\Reactos\Boot\Fonts"; LibraryParameters.DescriptorCount = 512; Status = BlInitializeLibrary(BootParameters, &LibraryParameters);
Modified: trunk/reactos/boot/environ/include/bl.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/environ/include/bl.h?r... ============================================================================== --- trunk/reactos/boot/environ/include/bl.h [iso-8859-1] (original) +++ trunk/reactos/boot/environ/include/bl.h [iso-8859-1] Wed May 10 14:38:34 2017 @@ -2005,6 +2005,11 @@ VOID BlpArchSwitchContext ( _In_ BL_ARCH_MODE NewMode + ); + +VOID +BlpArchEnableTranslation ( + VOID );
VOID
Modified: trunk/reactos/boot/environ/lib/arch/i386/arch.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/environ/lib/arch/i386/... ============================================================================== --- trunk/reactos/boot/environ/lib/arch/i386/arch.c [iso-8859-1] (original) +++ trunk/reactos/boot/environ/lib/arch/i386/arch.c [iso-8859-1] Wed May 10 14:38:34 2017 @@ -171,7 +171,10 @@
/* In real mode, use EFI, otherwise, use the application mode */ Context = &FirmwareExecutionContext; - if (NewMode != BlProtectedMode) Context = &ApplicationExecutionContext; + if (NewMode != BlRealMode) + { + Context = &ApplicationExecutionContext; + }
/* Are we in a different mode? */ if (CurrentExecutionContext->Mode != NewMode) @@ -179,6 +182,40 @@ /* Switch to the new one */ ArchSwitchContext(Context, CurrentExecutionContext); CurrentExecutionContext = Context; + } +} + +VOID +BlpArchEnableTranslation ( + VOID + ) +{ + PBL_ARCH_CONTEXT Context; + + /* Does the current execution context already have paging enabled? */ + Context = CurrentExecutionContext; + if (!(Context->ContextFlags & BL_CONTEXT_PAGING_ON)) + { + /* No -- does it have interrupts enabled? */ + if (Context->ContextFlags & BL_CONTEXT_INTERRUPTS_ON) + { + /* Disable them */ + _disable(); + Context->ContextFlags &= ~BL_CONTEXT_INTERRUPTS_ON; + } + + /* Are we enabling PAE? */ + if (Context->TranslationType == BlPae) + { + /* Make sure CR4 reflects this */ + __writecr4(__readcr4() | CR4_PAE); + } + + /* Enable paging in the CPU */ + __writecr0(__readcr0() | CR0_PG); + + /* Reflect that paging is enabled */ + Context->ContextFlags |= BL_CONTEXT_PAGING_ON; } }
Modified: trunk/reactos/boot/environ/lib/mm/descriptor.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/environ/lib/mm/descrip... ============================================================================== --- trunk/reactos/boot/environ/lib/mm/descriptor.c [iso-8859-1] (original) +++ trunk/reactos/boot/environ/lib/mm/descriptor.c [iso-8859-1] Wed May 10 14:38:34 2017 @@ -1022,8 +1022,10 @@ _In_ ULONG Alignment ) { - ULONGLONG BaseMin, BaseMax; + ULONGLONG BaseMin, BaseMax, AlignedMin; ULONGLONG VirtualPage, BasePage; + ULONGLONG BaseDelta, AlignedBase; + ULONGLONG VirtualMin, VirtualMax;
/* Extract the minimum and maximum range */ BaseMin = BaseRange->Minimum; @@ -1050,11 +1052,15 @@ /* Align the base as required */ if (Alignment != 1) { - BaseMin = ALIGN_UP_BY(BaseMin, Alignment); + AlignedMin = ALIGN_UP_BY(BaseMin, Alignment); + } + else + { + AlignedMin = BaseMin; }
/* Check for range overflow */ - if (((BaseMin + Pages - 1) < BaseMin) || ((BaseMin + Pages - 1) > BaseMax)) + if (((AlignedMin + Pages - 1) < AlignedMin) || ((AlignedMin + Pages - 1) > BaseMax)) { return FALSE; } @@ -1067,13 +1073,22 @@ if (Alignment != 1) { /* Align it as needed */ - BasePage = ALIGN_DOWN_BY(BasePage, Alignment); - } + AlignedBase = ALIGN_DOWN_BY(BasePage, Alignment); + } + else + { + AlignedBase = BasePage; + } + + /* Calculate the delta between max address and our aligned base */ + BaseDelta = BasePage - AlignedBase; + BasePage -= BaseDelta; } else { /* Otherwise, get the lowest page possible */ - BasePage = BaseMin; + BasePage = AlignedMin; + BaseDelta = 0; }
/* If a virtual address range was passed in, this must be a virtual descriptor */ @@ -1086,8 +1101,49 @@ /* Any mapped page already? */ if (Descriptor->VirtualPage) { - EfiPrintf(L"Virtual memory not yet supported\r\n"); - return FALSE; + /* Get virtual min/max */ + VirtualMin = VirtualRange->Minimum; + VirtualMax = VirtualRange->Maximum; + + /* Don't go below where the descriptor maps */ + if (VirtualMin <= Descriptor->VirtualPage) + { + VirtualMin = Descriptor->VirtualPage; + } + + /* Don't go above where the descriptor maps */ + if (VirtualMax >= (Descriptor->VirtualPage + Descriptor->PageCount - 1)) + { + VirtualMax = Descriptor->VirtualPage + Descriptor->PageCount - 1; + } + + /* Don't let the base overflow */ + if (VirtualMin > VirtualMax) + { + return 0; + } + + /* Adjust the base by the alignment delta */ + VirtualMin += AlignedMin - BaseMin; + + /* Check that the bounds don't overflow or underflow */ + if (((VirtualMin + Pages - 1) < VirtualMin) || + ((VirtualMin + Pages - 1) > VirtualMax)) + { + return 0; + } + + /* Finally, pick the correct address based on direction */ + if (TopDown) + { + /* Highest possible base address, aligned */ + VirtualPage = VirtualMax - Pages + 1 - BaseDelta; + } + else + { + /* Lowest possible base address, aligned */ + VirtualPage = VirtualMin; + } } else {
Modified: trunk/reactos/boot/environ/lib/mm/i386/mmx86.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/environ/lib/mm/i386/mm... ============================================================================== --- trunk/reactos/boot/environ/lib/mm/i386/mmx86.c [iso-8859-1] (original) +++ trunk/reactos/boot/environ/lib/mm/i386/mmx86.c [iso-8859-1] Wed May 10 14:38:34 2017 @@ -1042,8 +1042,10 @@ goto Quickie; }
- EfiPrintf(L"Ready to turn on motherfucking paging, brah!\r\n"); - Status = STATUS_NOT_IMPLEMENTED; + /* Turn on paging with the new CR3 */ + __writecr3((ULONG_PTR)MmPdpt); + BlpArchEnableTranslation(); + EfiPrintf(L"Paging... ON\r\n");
Quickie: /* Free reference page if we allocated it */
Modified: trunk/reactos/boot/environ/lib/mm/mm.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/environ/lib/mm/mm.c?re... ============================================================================== --- trunk/reactos/boot/environ/lib/mm/mm.c [iso-8859-1] (original) +++ trunk/reactos/boot/environ/lib/mm/mm.c [iso-8859-1] Wed May 10 14:38:34 2017 @@ -19,6 +19,66 @@ ULONG MmDescriptorCallTreeCount;
/* FUNCTIONS *****************************************************************/ + +NTSTATUS +TrpGenerateMappingTracker ( + _In_ PVOID VirtualAddress, + _In_ ULONG Flags, + _In_ LARGE_INTEGER PhysicalAddress, + _In_ ULONGLONG Size + ) +{ + PBL_MEMORY_DESCRIPTOR Descriptor, NextDescriptor; + PLIST_ENTRY ListHead, NextEntry; + + /* Increment descriptor call count */ + MmDescriptorCallTreeCount++; + + /* Initialize a descriptor for this allocation */ + Descriptor = MmMdInitByteGranularDescriptor(Flags, + 0, + PhysicalAddress.QuadPart, + (ULONG_PTR)VirtualAddress, + Size); + + /* Loop the current tracker list */ + ListHead = MmMdlMappingTrackers.First; + NextEntry = ListHead->Flink; + if (IsListEmpty(ListHead)) + { + /* If it's empty, just add the descriptor at the end */ + InsertTailList(ListHead, &Descriptor->ListEntry); + goto Quickie; + } + + /* Otherwise, go to the last descriptor */ + NextDescriptor = CONTAINING_RECORD(NextEntry, + BL_MEMORY_DESCRIPTOR, + ListEntry); + while (NextDescriptor->VirtualPage < Descriptor->VirtualPage) + { + /* Keep going... */ + NextEntry = NextEntry->Flink; + NextDescriptor = CONTAINING_RECORD(NextEntry, + BL_MEMORY_DESCRIPTOR, + ListEntry); + + /* If we hit the end of the list, just add it at the end */ + if (NextEntry == ListHead) + { + goto Quickie; + } + + /* Otherwise, add it right after this descriptor */ + InsertTailList(&NextDescriptor->ListEntry, &Descriptor->ListEntry); + } + +Quickie: + /* Release any global descriptors allocated */ + MmMdFreeGlobalDescriptors(); + --MmDescriptorCallTreeCount; + return STATUS_SUCCESS; +}
NTSTATUS MmTrInitialize ( @@ -142,6 +202,11 @@ PVOID MappedBase; ULONGLONG MapSize; UCHAR CacheAttributes; + ULONGLONG BasePage, EndPage, MappedPage, FoundBasePage; + ULONGLONG PageOffset, FoundPageCount; + PBL_MEMORY_DESCRIPTOR Descriptor, NewDescriptor; + PBL_MEMORY_DESCRIPTOR_LIST List; + ULONG AddPages;
/* Increase call depth */ ++MmDescriptorCallTreeCount; @@ -206,21 +271,174 @@ }
/* Compute the final address where the mapping was made */ - MappedBase = (PVOID)((ULONG_PTR)MappingAddress + - PhysicalAddress.LowPart - - MappedAddress.LowPart); + MappedBase = (PVOID)(ULONG_PTR)((ULONG_PTR)MappingAddress + + PhysicalAddress.QuadPart - + MappedAddress.QuadPart); + MappedAddress.QuadPart = (ULONG_PTR)MappedBase;
/* Check if we're in physical or virtual mode */ - if (MmTranslationType != BlNone) - { - /* We don't support virtual memory yet @TODO */ - EfiPrintf(L"not yet implemented in BlMmMapPhysicalAddressEx\r\n"); - EfiStall(1000000); - Status = STATUS_NOT_IMPLEMENTED; - goto Quickie; - } - - /* Return the mapped virtual address */ + if (MmTranslationType == BlNone) + { + /* We are in physical mode -- just return this address directly */ + Status = STATUS_SUCCESS; + *VirtualAddress = MappedBase; + goto Quickie; + } + + /* Remove the mapping address from the list of free virtual memory */ + Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual, + BL_MM_REMOVE_VIRTUAL_REGION_FLAG, + (ULONG_PTR)MappingAddress >> PAGE_SHIFT, + MapSize >> PAGE_SHIFT, + NULL); + if (NT_SUCCESS(Status)) + { + /* And then add an entry for the fact we mapped it */ + Status = TrpGenerateMappingTracker(MappedBase, + CacheAttributes, + PhysicalAddress, + MapSize); + } + + /* Abandon if we didn't update the memory map successfully */ + if (!NT_SUCCESS(Status)) + { + /* Unmap the virtual address so it can be used later */ + MmUnmapVirtualAddress(MappingAddress, &MapSize); + goto Quickie; + } + + /* Check if no real mapping into RAM was made */ + if (PhysicalAddress.QuadPart == -1) + { + /* Then we're done here */ + Status = STATUS_SUCCESS; + *VirtualAddress = MappedBase; + goto Quickie; + } + + + /* Loop over the entire allocation */ + BasePage = MappedAddress.QuadPart >> PAGE_SHIFT; + EndPage = (MappedAddress.QuadPart + MapSize) >> PAGE_SHIFT; + MappedPage = (ULONG_PTR)MappingAddress >> PAGE_SHIFT; + do + { + /* Start with the unmapped allocated list */ + List = &MmMdlUnmappedAllocated; + Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_ALLOCATED, + BL_MM_REMOVE_PHYSICAL_REGION_FLAG, + BasePage); + if (!Descriptor) + { + /* Try persistent next */ + List = &MmMdlPersistentMemory; + Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_PERSISTENT_MEMORY, + BL_MM_REMOVE_PHYSICAL_REGION_FLAG, + BasePage); + } + if (!Descriptor) + { + /* Try unmapped, unallocated, next */ + List = &MmMdlUnmappedUnallocated; + Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_UNALLOCATED, + BL_MM_REMOVE_PHYSICAL_REGION_FLAG, + BasePage); + } + if (!Descriptor) + { + /* Try reserved next */ + List = &MmMdlReservedAllocated; + Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_RESERVED_ALLOCATED, + BL_MM_REMOVE_PHYSICAL_REGION_FLAG, + BasePage); + } + + /* Check if we have a descriptor */ + if (Descriptor) + { + /* Remove it from its list */ + MmMdRemoveDescriptorFromList(List, Descriptor); + + /* Check if it starts before our allocation */ + FoundBasePage = Descriptor->BasePage; + if (FoundBasePage < BasePage) + { + /* Create a new descriptor to cover the gap before our allocation */ + PageOffset = BasePage - FoundBasePage; + NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags, + Descriptor->Type, + FoundBasePage, + 0, + PageOffset); + + /* Insert it */ + MmMdAddDescriptorToList(List, NewDescriptor, 0); + + /* Adjust ours to ignore that piece */ + Descriptor->PageCount -= PageOffset; + Descriptor->BasePage = BasePage; + } + + /* Check if it goes beyond our allocation */ + FoundPageCount = Descriptor->PageCount; + if (EndPage < (FoundPageCount + Descriptor->BasePage)) + { + /* Create a new descriptor to cover the range after our allocation */ + PageOffset = EndPage - BasePage; + NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags, + Descriptor->Type, + EndPage, + 0, + FoundPageCount - + PageOffset); + + /* Insert it */ + MmMdAddDescriptorToList(List, NewDescriptor, 0); + + /* Adjust ours to ignore that piece */ + Descriptor->PageCount = PageOffset; + } + + /* Update the descriptor to be mapepd at this virtual page */ + Descriptor->VirtualPage = MappedPage; + + /* Check if this was one of the regular lists */ + if ((List != &MmMdlReservedAllocated) && + (List != &MmMdlPersistentMemory)) + { + /* Was it allocated, or unallocated? */ + if (List != &MmMdlUnmappedAllocated) + { + /* In which case use the unallocated mapped list */ + List = &MmMdlMappedUnallocated; + } + else + { + /* Insert it into the mapped list */ + List = &MmMdlMappedAllocated; + } + } + + /* Add the descriptor that was removed, into the right list */ + MmMdAddDescriptorToList(List, Descriptor, 0); + + /* Add the pages this descriptor had */ + AddPages = Descriptor->PageCount; + } + else + { + /* Nope, so just add one page */ + AddPages = 1; + } + + /* Increment the number of pages the descriptor had */ + MappedPage += AddPages; + BasePage += AddPages; + } + while (BasePage < EndPage); + + /* We're done -- returned the address */ Status = STATUS_SUCCESS; *VirtualAddress = MappedBase;
@@ -250,7 +468,7 @@ else { /* We don't support virtual memory yet @TODO */ - EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__); + EfiPrintf(L"unmap not yet implemented in %S\r\n", __FUNCTION__); EfiStall(1000000); Status = STATUS_NOT_IMPLEMENTED; }
Modified: trunk/reactos/boot/environ/lib/mm/pagealloc.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/environ/lib/mm/pageall... ============================================================================== --- trunk/reactos/boot/environ/lib/mm/pagealloc.c [iso-8859-1] (original) +++ trunk/reactos/boot/environ/lib/mm/pagealloc.c [iso-8859-1] Wed May 10 14:38:34 2017 @@ -187,12 +187,34 @@ /* Remove the descriptor from the original list it was on */ MmMdRemoveDescriptorFromList(CurrentList, FoundDescriptor);
+ /* Get the end pages */ + LocalEndPage = LocalDescriptor.PageCount + LocalDescriptor.BasePage; + FoundEndPage = FoundDescriptor->PageCount + FoundDescriptor->BasePage; + /* Are we allocating from the virtual memory list? */ if (CurrentList == &MmMdlMappedUnallocated) { - EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__); - EfiStall(1000000); - return STATUS_NOT_IMPLEMENTED; + /* Check if the region matches perfectly */ + if ((LocalDescriptor.BasePage == FoundDescriptor->BasePage) && + (LocalEndPage == FoundEndPage)) + { + /* Check if the original descriptor had the flag set */ + if ((FoundDescriptor->Flags & 0x40000000) && (Descriptor)) + { + /* Make our local one have it too, even if not needed */ + LocalDescriptor.Flags |= 0x40000000; + } + } + else + { + /* Write the 'incomplete mapping' flag */ + FoundDescriptor->Flags |= 0x40000000; + if (Descriptor) + { + /* Including on the local one if there's one passed in */ + LocalDescriptor.Flags |= 0x40000000; + } + } }
/* Does the memory we received not exactly fall onto the beginning of its descriptor? */ @@ -212,8 +234,6 @@ }
/* Does the memory we received not exactly fall onto the end of its descriptor? */ - LocalEndPage = LocalDescriptor.PageCount + LocalDescriptor.BasePage; - FoundEndPage = FoundDescriptor->PageCount + FoundDescriptor->BasePage; LocalVirtualEndPage = LocalDescriptor.VirtualPage ? LocalDescriptor.VirtualPage + LocalDescriptor.PageCount : 0; if (LocalEndPage != FoundEndPage) @@ -303,7 +323,7 @@ /* Are we failing due to some attributes? */ if (Request->Flags & BlMemoryValidAllocationAttributeMask) { - EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__); + EfiPrintf(L"alloc fail not yet implemented %lx in %S\r\n", Status, __FUNCTION__); EfiStall(1000000); return STATUS_NOT_IMPLEMENTED; } @@ -532,7 +552,6 @@ AllocationFlags | CacheAttributes, NewDescriptor.PageCount << PAGE_SHIFT, PhysicalAddress); - EfiPrintf(L"MAP status: %lx\r\n", Status); if (Status == STATUS_SUCCESS) { /* Add the cache attributes now that the mapping worked */ @@ -627,7 +646,7 @@ if (Range) { /* We don't support virtual memory yet @TODO */ - EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__); + EfiPrintf(L"virt range not yet implemented in %S\r\n", __FUNCTION__); EfiStall(1000000); Status = STATUS_NOT_IMPLEMENTED; goto Exit; @@ -643,26 +662,26 @@ if (Attributes & BlMemoryFixed) { /* We don't support virtual memory yet @TODO */ - EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__); + EfiPrintf(L"fixed not yet implemented in %S\r\n", __FUNCTION__); EfiStall(1000000); Status = STATUS_NOT_IMPLEMENTED; goto Exit; } else { - /* Check if non-fixed was specifically requested */ + /* Check if kernel range was specifically requested */ if (Attributes & BlMemoryKernelRange) { - /* We don't support virtual memory yet @TODO */ - EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__); - EfiStall(1000000); - Status = STATUS_NOT_IMPLEMENTED; - goto Exit; + /* Use the kernel range */ + Request.VirtualRange.Minimum = MmArchKsegAddressRange.Minimum >> PAGE_SHIFT; + Request.VirtualRange.Maximum = MmArchKsegAddressRange.Maximum >> PAGE_SHIFT; } - - /* Set the virtual address range */ - Request.VirtualRange.Minimum = 0; - Request.VirtualRange.Maximum = 0xFFFFFFFF >> PAGE_SHIFT; + else + { + /* Set the virtual address range */ + Request.VirtualRange.Minimum = 0; + Request.VirtualRange.Maximum = 0xFFFFFFFF >> PAGE_SHIFT; + } }
/* Check what type of allocation was requested */ @@ -702,7 +721,7 @@ if (!NT_SUCCESS(Status)) { /* Fail since we're out of memory */ - EfiPrintf(L"OUT OF MEMORY: %lx\r\n", Status); + EfiPrintf(L"EXTEND OUT OF MEMORY: %lx\r\n", Status); Status = STATUS_NO_MEMORY; goto Exit; } @@ -716,7 +735,7 @@ if (!NT_SUCCESS(Status)) { /* Fail since we're out of memory */ - EfiPrintf(L"OUT OF MEMORY: %lx\r\n", Status); + EfiPrintf(L"PALLOC OUT OF MEMORY: %lx\r\n", Status); goto Exit; } } @@ -1082,7 +1101,7 @@ /* Handle virtual memory scenario */ if (MmTranslationType != BlNone) { - EfiPrintf(L"Unimplemented free virtual path\r\n"); + EfiPrintf(L"Unimplemented free virtual path: %p %lx\r\n", Address, WhichList); return STATUS_SUCCESS; }