From 676adf3c062dda1dacf10729c989fc9efb36c92c Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Wed, 10 May 2017 14:38:34 +0000 Subject: [PATCH] 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. svn path=/trunk/; revision=74519 --- reactos/boot/environ/app/rosload/rosload.c | 5 +- reactos/boot/environ/include/bl.h | 5 + reactos/boot/environ/lib/arch/i386/arch.c | 39 +++- reactos/boot/environ/lib/mm/descriptor.c | 70 +++++- reactos/boot/environ/lib/mm/i386/mmx86.c | 6 +- reactos/boot/environ/lib/mm/mm.c | 238 ++++++++++++++++++++- reactos/boot/environ/lib/mm/pagealloc.c | 63 ++++-- 7 files changed, 382 insertions(+), 44 deletions(-) diff --git a/reactos/boot/environ/app/rosload/rosload.c b/reactos/boot/environ/app/rosload/rosload.c index 012b811ce0f..3ddc4b22fbd 100644 --- a/reactos/boot/environ/app/rosload/rosload.c +++ b/reactos/boot/environ/app/rosload/rosload.c @@ -39,10 +39,11 @@ OslMain ( /* 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); diff --git a/reactos/boot/environ/include/bl.h b/reactos/boot/environ/include/bl.h index ad3479aa036..8d1d015005d 100644 --- a/reactos/boot/environ/include/bl.h +++ b/reactos/boot/environ/include/bl.h @@ -2007,6 +2007,11 @@ BlpArchSwitchContext ( _In_ BL_ARCH_MODE NewMode ); +VOID +BlpArchEnableTranslation ( + VOID + ); + VOID Archx86TransferTo32BitApplicationAsm ( VOID diff --git a/reactos/boot/environ/lib/arch/i386/arch.c b/reactos/boot/environ/lib/arch/i386/arch.c index 1a5778a6983..de5c0e2ccae 100644 --- a/reactos/boot/environ/lib/arch/i386/arch.c +++ b/reactos/boot/environ/lib/arch/i386/arch.c @@ -171,7 +171,10 @@ BlpArchSwitchContext ( /* 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) @@ -182,6 +185,40 @@ BlpArchSwitchContext ( } } +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; + } +} + /*++ * @name BlpArchInitialize * diff --git a/reactos/boot/environ/lib/mm/descriptor.c b/reactos/boot/environ/lib/mm/descriptor.c index ae2ed162c2f..bb2f66a1afd 100644 --- a/reactos/boot/environ/lib/mm/descriptor.c +++ b/reactos/boot/environ/lib/mm/descriptor.c @@ -1022,8 +1022,10 @@ MmMdFindSatisfyingRegion ( _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 @@ MmMdFindSatisfyingRegion ( /* 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 @@ MmMdFindSatisfyingRegion ( 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 @@ MmMdFindSatisfyingRegion ( /* 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 { diff --git a/reactos/boot/environ/lib/mm/i386/mmx86.c b/reactos/boot/environ/lib/mm/i386/mmx86.c index 9c108625769..09e615e74ef 100644 --- a/reactos/boot/environ/lib/mm/i386/mmx86.c +++ b/reactos/boot/environ/lib/mm/i386/mmx86.c @@ -1042,8 +1042,10 @@ MmDefInitializeTranslation ( 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 */ diff --git a/reactos/boot/environ/lib/mm/mm.c b/reactos/boot/environ/lib/mm/mm.c index cb83067fbcb..41d7a62a6d3 100644 --- a/reactos/boot/environ/lib/mm/mm.c +++ b/reactos/boot/environ/lib/mm/mm.c @@ -20,6 +20,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 ( VOID @@ -142,6 +202,11 @@ BlMmMapPhysicalAddressEx ( 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 @@ BlMmMapPhysicalAddressEx ( } /* 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) + 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; + /* 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; } - /* Return the mapped virtual address */ + /* 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 @@ MmUnmapVirtualAddress ( 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; } diff --git a/reactos/boot/environ/lib/mm/pagealloc.c b/reactos/boot/environ/lib/mm/pagealloc.c index c502b468107..c4810d7f0ea 100644 --- a/reactos/boot/environ/lib/mm/pagealloc.c +++ b/reactos/boot/environ/lib/mm/pagealloc.c @@ -187,12 +187,34 @@ MmPapAllocateRegionFromMdl ( /* 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 @@ MmPapAllocateRegionFromMdl ( } /* 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 @@ MmPaAllocatePages ( /* 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 @@ MmPapPageAllocatorExtend ( 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 @@ MmPapAllocatePagesInRange ( 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 @@ MmPapAllocatePagesInRange ( 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; + } + else + { + /* Set the virtual address range */ + Request.VirtualRange.Minimum = 0; + Request.VirtualRange.Maximum = 0xFFFFFFFF >> PAGE_SHIFT; } - - /* 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 @@ MmPapAllocatePagesInRange ( 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 @@ MmPapAllocatePagesInRange ( 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 @@ MmPapFreePages ( /* 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; } -- 2.17.1