[BOOTLIB]: Clarify some attributes now that their meaning is clearer.
[reactos.git] / reactos / boot / environ / lib / mm / i386 / mmx86.c
index 36c5742..4078177 100644 (file)
@@ -9,6 +9,17 @@
 /* INCLUDES ******************************************************************/
 
 #include "bl.h"
+#include "bcd.h"
+
+#define PTE_BASE                0xC0000000
+
+//
+// Specific PDE/PTE macros to be used inside the boot library environment
+//
+#define MiAddressToPte(x)       ((PMMPTE)(((((ULONG)(x)) >> 12) << 2) + (ULONG_PTR)MmPteBase))
+#define MiAddressToPde(x)       ((PMMPDE)(((((ULONG)(x)) >> 22) << 2) + (ULONG_PTR)MmPdeBase))
+#define MiAddressToPteOffset(x) ((((ULONG)(x)) << 10) >> 22)
+#define MiAddressToPdeOffset(x) (((ULONG)(x)) / (1024 * PAGE_SIZE))
 
 /* DATA VARIABLES ************************************************************/
 
@@ -17,7 +28,13 @@ ULONG_PTR MmArchKsegBias;
 ULONG MmArchLargePageSize;
 BL_ADDRESS_RANGE MmArchKsegAddressRange;
 ULONG_PTR MmArchTopOfApplicationAddressSpace;
-ULONG_PTR Mmx86SelfMapBase;
+PHYSICAL_ADDRESS Mmx86SelfMapBase;
+ULONG MmDeferredMappingCount;
+PMMPTE MmPdpt;
+PULONG MmArchReferencePage;
+PVOID MmPteBase;
+PVOID MmPdeBase;
+ULONG MmArchReferencePageSize;
 
 typedef VOID
 (*PBL_MM_FLUSH_TLB) (
@@ -29,13 +46,90 @@ typedef VOID
     VOID
     );
 
+typedef NTSTATUS
+(*PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE) (
+    _In_ PVOID DestinationAddress,
+    _In_ PVOID SourceAddress,
+    _In_ ULONGLONG Size
+    );
+
+typedef NTSTATUS
+(*PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE) (
+    _In_ PVOID DestinationAddress,
+    _In_ ULONGLONG Size
+    );
+
+typedef VOID
+(*PBL_MM_DESTROY_SELF_MAP) (
+    VOID
+    );
+
+typedef VOID
+(*PBL_MM_FLUSH_TLB_ENTRY) (
+    _In_ PVOID VirtualAddress
+    );
+
+typedef VOID
+(*PBL_MM_FLUSH_TLB) (
+    VOID
+    );
+
+typedef NTSTATUS
+(*PBL_MM_UNMAP_VIRTUAL_ADDRESS) (
+    _In_ PVOID VirtualAddress,
+    _In_ ULONG Size
+    );
+
+typedef NTSTATUS
+(*PBL_MM_REMAP_VIRTUAL_ADDRESS) (
+    _In_ PPHYSICAL_ADDRESS PhysicalAddress,
+    _Out_ PVOID VirtualAddress,
+    _In_ ULONG Size,
+    _In_ ULONG CacheAttributes
+    );
+
+typedef NTSTATUS
+(*PBL_MM_MAP_PHYSICAL_ADDRESS) (
+    _In_ PHYSICAL_ADDRESS PhysicalAddress,
+    _Out_ PVOID VirtualAddress,
+    _In_ ULONG Size,
+    _In_ ULONG CacheAttributes
+    );
+
+typedef BOOLEAN
+(*PBL_MM_TRANSLATE_VIRTUAL_ADDRESS) (
+    _In_ PVOID VirtualAddress,
+    _Out_ PPHYSICAL_ADDRESS PhysicalAddress,
+    _Out_opt_ PULONG CacheAttributes
+    );
+
+PBL_MM_TRANSLATE_VIRTUAL_ADDRESS Mmx86TranslateVirtualAddress;
+PBL_MM_MAP_PHYSICAL_ADDRESS Mmx86MapPhysicalAddress;
+PBL_MM_REMAP_VIRTUAL_ADDRESS Mmx86RemapVirtualAddress;
+PBL_MM_UNMAP_VIRTUAL_ADDRESS Mmx86UnmapVirtualAddress;
+PBL_MM_FLUSH_TLB Mmx86FlushTlb;
+PBL_MM_FLUSH_TLB_ENTRY Mmx86FlushTlbEntry;
+PBL_MM_DESTROY_SELF_MAP Mmx86DestroySelfMap;
+
 PBL_MM_RELOCATE_SELF_MAP BlMmRelocateSelfMap;
 PBL_MM_FLUSH_TLB BlMmFlushTlb;
+PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE BlMmMoveVirtualAddressRange;
+PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE BlMmZeroVirtualAddressRange;
 
-ULONG MmDeferredMappingCount;
+PBL_MM_FLUSH_TLB Mmx86FlushTlb;
 
 /* FUNCTIONS *****************************************************************/
 
+BOOLEAN
+BlMmIsTranslationEnabled (
+    VOID
+    )
+{
+    /* Return if paging is on */
+    return ((CurrentExecutionContext) &&
+            (CurrentExecutionContext->Mode & BL_CONTEXT_PAGING_ON));
+}
+
 VOID
 MmArchNullFunction (
     VOID
@@ -45,48 +139,36 @@ MmArchNullFunction (
     return;
 }
 
-NTSTATUS
-Mmx86pMapMemoryRegions (
-    _In_ ULONG Phase,
-    _In_ PBL_MEMORY_DATA MemoryData
+VOID
+MmDefRelocateSelfMap (
+    VOID
     )
 {
-    BOOLEAN DoDeferred;
-
-    /* In phase 1 we don't initialize deferred mappings*/
-    if (Phase == 1)
+    if (MmPteBase != (PVOID)PTE_BASE)
     {
-        DoDeferred = 0;
-    }
-    else
-    {
-        /* Don't do anything if there's nothing to initialize */
-        if (!MmDeferredMappingCount)
-        {
-            return STATUS_SUCCESS;
-        }
-
-        DoDeferred = 1;
-    }
-
-    if (DoDeferred)
-    {
-        EfiPrintf(L"Deferred todo\r\n");
+        EfiPrintf(L"Supposed to relocate CR3\r\n");
     }
+}
 
-    EfiPrintf(L"Phase 1 TODO\r\n");
+NTSTATUS
+MmDefMoveVirtualAddressRange (
+    _In_ PVOID DestinationAddress,
+    _In_ PVOID SourceAddress,
+    _In_ ULONGLONG Size
+    )
+{
+    EfiPrintf(L"Supposed to move shit\r\n");
     return STATUS_NOT_IMPLEMENTED;
 }
 
-BOOLEAN
-Mmx86TranslateVirtualAddress (
-    _In_ PVOID VirtualAddress,
-    _Out_opt_ PPHYSICAL_ADDRESS PhysicalAddress,
-    _Out_opt_ PULONG CachingFlags
+NTSTATUS
+MmDefZeroVirtualAddressRange (
+    _In_ PVOID DestinationAddress,
+    _In_ ULONGLONG Size
     )
 {
-    EfiPrintf(L"paging  TODO\r\n");
-    return FALSE;
+    EfiPrintf(L"Supposed to zero shit\r\n");
+    return STATUS_NOT_IMPLEMENTED;
 }
 
 BOOLEAN
@@ -131,6 +213,824 @@ MmArchTranslateVirtualAddress (
     return Descriptor != NULL;
 }
 
+VOID
+MmDefpDestroySelfMap (
+    VOID
+    )
+{
+    EfiPrintf(L"No destroy\r\n");
+}
+
+VOID
+MmDefpFlushTlbEntry (
+    _In_ PVOID VirtualAddress
+    )
+{
+    /* Flush the TLB */
+    __invlpg(VirtualAddress);
+}
+
+VOID
+MmDefpFlushTlb (
+    VOID
+    )
+{
+    /* Flush the TLB */
+    __writecr3(__readcr3());
+}
+
+NTSTATUS
+MmDefpUnmapVirtualAddress (
+    _In_ PVOID VirtualAddress,
+    _In_ ULONG Size
+    )
+{
+    EfiPrintf(L"No unmap\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+MmDefpRemapVirtualAddress (
+    _In_ PPHYSICAL_ADDRESS PhysicalAddress,
+    _Out_ PVOID VirtualAddress,
+    _In_ ULONG Size,
+    _In_ ULONG CacheAttributes
+    )
+{
+    EfiPrintf(L"No remap\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+MmDefpMapPhysicalAddress (
+    _In_ PHYSICAL_ADDRESS PhysicalAddress,
+    _In_ PVOID VirtualAddress,
+    _In_ ULONG Size,
+    _In_ ULONG CacheAttributes
+    )
+{
+    BOOLEAN Enabled;
+    ULONG i, PageCount, PdeOffset;
+    ULONGLONG CurrentAddress;
+    PMMPDE Pde;
+    PMMPTE Pte;
+    PMMPTE PageTable;
+    PHYSICAL_ADDRESS PageTableAddress;
+    NTSTATUS Status;
+
+    /* Check if paging is on yet */
+    Enabled = BlMmIsTranslationEnabled();
+
+    /* Get the physical address aligned */
+    CurrentAddress = (PhysicalAddress.QuadPart >> PAGE_SHIFT) << PAGE_SHIFT;
+
+    /* Get the number of pages and loop through each one */
+    PageCount = Size >> PAGE_SHIFT;
+    for (i = 0; i < PageCount; i++)
+    {
+        /* Check if translation already exists for this page */
+        if (Mmx86TranslateVirtualAddress(VirtualAddress, NULL, NULL))
+        {
+            /* Ignore it and move to the next one */
+            VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
+            CurrentAddress += PAGE_SIZE;
+            continue;
+        }
+
+        /* Get the PDE offset */
+        PdeOffset = MiAddressToPdeOffset(VirtualAddress);
+
+        /* Check if paging is actually turned on */
+        if (Enabled)
+        {
+            /* Get the PDE entry using the self-map */
+            Pde = MiAddressToPde(VirtualAddress);
+        }
+        else
+        {
+            /* Get it using our physical mappings */
+            Pde = &MmPdpt[PdeOffset];
+            PageTable = (PMMPDE)(Pde->u.Hard.PageFrameNumber << PAGE_SHIFT);
+        }
+
+        /* Check if we don't yet have a PDE */
+        if (!Pde->u.Hard.Valid)
+        {
+            /* Allocate a page table */
+            Status = MmPapAllocatePhysicalPagesInRange(&PageTableAddress,
+                                                       BlLoaderPageDirectory,
+                                                       1,
+                                                       0,
+                                                       0,
+                                                       &MmMdlUnmappedAllocated,
+                                                       0,
+                                                       0);
+            if (!NT_SUCCESS(Status))
+            {
+                return STATUS_NO_MEMORY;
+            }
+
+            /* This is our page table */
+            PageTable = (PVOID)(ULONG_PTR)PageTableAddress.QuadPart;
+
+            /* Build the PDE for it */
+            Pde->u.Hard.PageFrameNumber = PageTableAddress.QuadPart >> PAGE_SHIFT;
+            Pde->u.Hard.Write = 1;
+            Pde->u.Hard.CacheDisable = 1;
+            Pde->u.Hard.WriteThrough = 1;
+            Pde->u.Hard.Valid = 1;
+
+            /* Check if paging is enabled */
+            if (Enabled)
+            {
+                /* Then actually, get the page table's virtual address */
+                PageTable = (PVOID)PAGE_ROUND_DOWN(MiAddressToPte(VirtualAddress));
+
+                /* Flush the TLB */
+                Mmx86FlushTlb();
+            }
+
+            /* Zero out the page table */
+            RtlZeroMemory(PageTable, PAGE_SIZE);
+
+            /* Reset caching attributes now */
+            Pde->u.Hard.CacheDisable = 0;
+            Pde->u.Hard.WriteThrough = 0;
+
+            /* Check for paging again */
+            if (Enabled)
+            {
+                /* Flush the TLB entry for the page table only */
+                Mmx86FlushTlbEntry(PageTable);
+            }
+        }
+
+        /* Add a reference to this page table */
+        MmArchReferencePage[PdeOffset]++;
+
+        /* Check if a physical address was given */
+        if (PhysicalAddress.QuadPart != -1)
+        {
+            /* Check if paging is turned on */
+            if (Enabled)
+            {
+                /* Get the PTE using the self-map */
+                Pte = MiAddressToPte(VirtualAddress);
+            }
+            else
+            {
+                /* Get the PTE using physical addressing */
+                Pte = &PageTable[MiAddressToPteOffset(VirtualAddress)];
+            }
+
+            /* Build a valid PTE for it */
+            Pte->u.Hard.PageFrameNumber = CurrentAddress >> PAGE_SHIFT;
+            Pte->u.Hard.Write = 1;
+            Pte->u.Hard.Valid = 1;
+
+            /* Check if this is uncached */
+            if (CacheAttributes == BlMemoryUncached)
+            {
+                /* Set the flags */
+                Pte->u.Hard.CacheDisable = 1;
+                Pte->u.Hard.WriteThrough = 1;
+            }
+            else if (CacheAttributes == BlMemoryWriteThrough)
+            {
+                /* It's write-through, set the flag */
+                Pte->u.Hard.WriteThrough = 1;
+            }
+        }
+
+        /* Move to the next physical/virtual address */
+        VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
+        CurrentAddress += PAGE_SIZE;
+    }
+
+    /* All done! */
+    return STATUS_SUCCESS;
+}
+
+BOOLEAN
+MmDefpTranslateVirtualAddress (
+    _In_ PVOID VirtualAddress,
+    _Out_ PPHYSICAL_ADDRESS PhysicalAddress,
+    _Out_opt_ PULONG CacheAttributes
+    )
+{
+    PMMPDE Pde;
+    PMMPTE Pte;
+    PMMPTE PageTable;
+    BOOLEAN Enabled;
+
+    /* Is there no page directory yet? */
+    if (!MmPdpt)
+    {
+        return FALSE;
+    }
+
+    /* Is paging enabled? */
+    Enabled = BlMmIsTranslationEnabled();
+
+    /* Check if paging is actually turned on */
+    if (Enabled)
+    {
+        /* Get the PDE entry using the self-map */
+        Pde = MiAddressToPde(VirtualAddress);
+    }
+    else
+    {
+        /* Get it using our physical mappings */
+        Pde = &MmPdpt[MiAddressToPdeOffset(VirtualAddress)];
+    }
+
+    /* Is the PDE valid? */
+    if (!Pde->u.Hard.Valid)
+    {
+        return FALSE;
+    }
+
+    /* Check if paging is turned on */
+    if (Enabled)
+    {
+        /* Get the PTE using the self-map */
+        Pte = MiAddressToPte(VirtualAddress);
+    }
+    else
+    {
+        /* Get the PTE using physical addressing */
+        PageTable = (PMMPTE)(Pde->u.Hard.PageFrameNumber << PAGE_SHIFT);
+        Pte = &PageTable[MiAddressToPteOffset(VirtualAddress)];
+    }
+
+    /* Is the PTE valid? */
+    if (!Pte->u.Hard.Valid)
+    {
+        return FALSE;
+    }
+
+    /* Does caller want the physical address?  */
+    if (PhysicalAddress)
+    {
+        /* Return it */
+        PhysicalAddress->QuadPart = (Pte->u.Hard.PageFrameNumber << PAGE_SHIFT) +
+                                     BYTE_OFFSET(VirtualAddress);
+    }
+
+    /* Does caller want cache attributes? */
+    if (CacheAttributes)
+    {
+        /* Not yet -- lie and say it's cached */
+        EfiPrintf(L"Cache checking not yet enabled\r\n");
+        *CacheAttributes = BlMemoryWriteBack;
+    }
+
+    /* It exists! */
+    return TRUE;
+}
+
+NTSTATUS
+MmMapPhysicalAddress (
+    _Inout_ PPHYSICAL_ADDRESS PhysicalAddressPtr,
+    _Inout_ PVOID* VirtualAddressPtr,
+    _Inout_ PULONGLONG SizePtr,
+    _In_ ULONG CacheAttributes
+    )
+{
+    ULONGLONG Size, TotalSize;
+    ULONGLONG PhysicalAddress;
+    PVOID VirtualAddress;
+    PHYSICAL_ADDRESS TranslatedAddress;
+    ULONG_PTR CurrentAddress, VirtualAddressEnd;
+    NTSTATUS Status;
+
+    /* Fail if any parameters are missing */
+    if (!(PhysicalAddressPtr) || !(VirtualAddressPtr) || !(SizePtr))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Fail if the size is over 32-bits */
+    Size = *SizePtr;
+    if (Size > 0xFFFFFFFF)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Nothing to do if we're in physical mode */
+    if (MmTranslationType == BlNone)
+    {
+        return STATUS_SUCCESS;
+    }
+
+    /* Can't use virtual memory in real mode */
+    if (CurrentExecutionContext->Mode == BlRealMode)
+    {
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    /* Capture the current virtual and physical addresses */
+    VirtualAddress = *VirtualAddressPtr;
+    PhysicalAddress = PhysicalAddressPtr->QuadPart;
+
+    /* Check if a physical address was requested */
+    if (PhysicalAddress != 0xFFFFFFFF)
+    {
+        /* Round down the base addresses */
+        PhysicalAddress = PAGE_ROUND_DOWN(PhysicalAddress);
+        VirtualAddress = (PVOID)PAGE_ROUND_DOWN(VirtualAddress);
+
+        /* Round up the size */
+        TotalSize = ROUND_TO_PAGES(PhysicalAddressPtr->QuadPart -
+                                   PhysicalAddress +
+                                   Size);
+
+        /* Loop every virtual page */
+        CurrentAddress = (ULONG_PTR)VirtualAddress;
+        VirtualAddressEnd = CurrentAddress + TotalSize - 1;
+        while (CurrentAddress < VirtualAddressEnd)
+        {
+            /* Get the physical page of this virtual page */
+            if (MmArchTranslateVirtualAddress((PVOID)CurrentAddress,
+                                              &TranslatedAddress,
+                                              &CacheAttributes))
+            {
+                /* Make sure the physical page of the virtual page, matches our page */
+                if (TranslatedAddress.QuadPart !=
+                    (PhysicalAddress +
+                     (CurrentAddress - (ULONG_PTR)VirtualAddress)))
+                {
+                    /* There is an existing virtual mapping for a different address */
+                    EfiPrintf(L"Existing mapping exists: %lx vs %lx\r\n",
+                              TranslatedAddress.QuadPart,
+                              PhysicalAddress + (CurrentAddress - (ULONG_PTR)VirtualAddress));
+                    return STATUS_INVALID_PARAMETER;
+                }
+            }
+
+            /* Try the next one */
+            CurrentAddress += PAGE_SIZE;
+        }
+    }
+
+    /* Aactually do the mapping */
+    TranslatedAddress.QuadPart = PhysicalAddress;
+    Status = Mmx86MapPhysicalAddress(TranslatedAddress,
+                                     VirtualAddress,
+                                     Size,
+                                     CacheAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        EfiPrintf(L"Failed to map!: %lx\r\n", Status);
+        return Status;
+    }
+
+    /* Return aligned/fixed up output parameters */
+    PhysicalAddressPtr->QuadPart = PhysicalAddress;
+    *VirtualAddressPtr = VirtualAddress;
+    *SizePtr = Size;
+    
+    /* Flush the TLB if paging is enabled */
+    if (BlMmIsTranslationEnabled())
+    {
+        Mmx86FlushTlb();
+    }
+
+    /* All good! */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+Mmx86MapInitStructure (
+    _In_ PVOID VirtualAddress,
+    _In_ ULONGLONG Size,
+    _In_ PHYSICAL_ADDRESS PhysicalAddress
+    )
+{
+    NTSTATUS Status;
+    
+    /* Make a virtual mapping for this physical address */
+    Status = MmMapPhysicalAddress(&PhysicalAddress, &VirtualAddress, &Size, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Nothing else to do if we're not in paging mode */
+    if (MmTranslationType == BlNone)
+    {
+        return STATUS_SUCCESS;
+    }
+
+    /* Otherwise, remove this region from the list of free virtual ranges */
+    Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual,
+                                       BL_MM_REMOVE_VIRTUAL_REGION_FLAG,
+                                       (ULONG_PTR)VirtualAddress >> PAGE_SHIFT,
+                                       Size >> PAGE_SHIFT,
+                                       0);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Unmap the address if that failed */
+        MmUnmapVirtualAddress(&VirtualAddress, &Size);
+    }
+
+    /* Return back to caller */
+    return Status;
+}
+
+NTSTATUS
+Mmx86pMapMemoryRegions (
+    _In_ ULONG Phase,
+    _In_ PBL_MEMORY_DATA MemoryData
+    )
+{
+    BOOLEAN DoDeferred;
+    ULONG DescriptorCount;
+    PBL_MEMORY_DESCRIPTOR Descriptor;
+    ULONG FinalOffset;
+    PHYSICAL_ADDRESS PhysicalAddress;
+    ULONGLONG Size;
+    NTSTATUS Status;
+    PVOID VirtualAddress;
+    BL_MEMORY_DESCRIPTOR_LIST FirmwareMdl;
+    PLIST_ENTRY Head, NextEntry;
+
+    /* Check which phase this is */
+    if (Phase == 1)
+    {
+        /* In phase 1 we don't initialize deferred mappings */
+        DoDeferred = FALSE;
+    }
+    else
+    {
+        /* Don't do anything if there's nothing to initialize */
+        if (!MmDeferredMappingCount)
+        {
+            return STATUS_SUCCESS;
+        }
+
+        /* We'll do deferred descriptors in phase 2 */
+        DoDeferred = TRUE;
+    }
+
+    /*
+    * Because BL supports cross x86-x64 application launches and a LIST_ENTRY
+    * is of variable size, care must be taken here to ensure that we see a
+    * consistent view of descriptors. BL uses some offset magic to figure out
+    * where the data actually starts, since everything is ULONGLONG past the
+    * LIST_ENTRY itself
+    */
+    FinalOffset = MemoryData->MdListOffset + MemoryData->DescriptorOffset;
+    Descriptor = (PBL_MEMORY_DESCRIPTOR)((ULONG_PTR)MemoryData + FinalOffset -
+                                         FIELD_OFFSET(BL_MEMORY_DESCRIPTOR, BasePage));
+
+    /* Scan all of them */
+    DescriptorCount = MemoryData->DescriptorCount;
+    while (DescriptorCount != 0)
+    {
+        /* Ignore application data */
+        if (Descriptor->Type != BlApplicationData)
+        {
+            /* If this is a ramdisk, do it in phase 2 */
+            if ((Descriptor->Type == BlLoaderRamDisk) == DoDeferred)
+            {
+                /* Get the current physical address and size */
+                PhysicalAddress.QuadPart = Descriptor->BasePage << PAGE_SHIFT;
+                Size = Descriptor->PageCount << PAGE_SHIFT;
+
+                /* Check if it was already mapped */
+                if (Descriptor->VirtualPage)
+                {
+                    /* Use the existing address */
+                    VirtualAddress = (PVOID)(ULONG_PTR)(Descriptor->VirtualPage << PAGE_SHIFT);
+                }
+                else
+                {
+                    /* Use the physical address */
+                    VirtualAddress = (PVOID)(ULONG_PTR)PhysicalAddress.QuadPart;
+                }
+
+                /* Crete the mapping */
+                Status = Mmx86MapInitStructure(VirtualAddress,
+                                               Size,
+                                               PhysicalAddress);
+                if (!NT_SUCCESS(Status))
+                {
+                    return Status;
+                }
+            }
+
+            /* Check if we're in phase 1 and deferring RAM disk */
+            if ((Phase == 1) && (Descriptor->Type == BlLoaderRamDisk))
+            {
+                MmDeferredMappingCount++;
+            }
+        }
+
+        /* Move on to the next descriptor */
+        DescriptorCount--;
+        Descriptor = (PBL_MEMORY_DESCRIPTOR)((ULONG_PTR)Descriptor + MemoryData->DescriptorSize);
+    }
+
+    /* In phase 1, also do UEFI mappings */
+    if (Phase != 2)
+    {
+        /* Get the memory map */
+        MmMdInitializeListHead(&FirmwareMdl);
+        Status = MmFwGetMemoryMap(&FirmwareMdl, BL_MM_FLAG_REQUEST_COALESCING);
+        if (!NT_SUCCESS(Status))
+        {
+            return Status;
+        }
+
+        /* Iterate over it */
+        Head = FirmwareMdl.First;
+        NextEntry = Head->Flink;
+        while (NextEntry != Head)
+        {
+            /* Check if this is a UEFI-related descriptor, unless it's the self-map page */
+            Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
+            if (((Descriptor->Type == BlEfiBootMemory) ||
+                 (Descriptor->Type == BlEfiRuntimeMemory) ||
+                 (Descriptor->Type == BlLoaderMemory)) &&
+                ((Descriptor->BasePage << PAGE_SHIFT) != Mmx86SelfMapBase.QuadPart))
+            {
+                /* Identity-map it */
+                PhysicalAddress.QuadPart = Descriptor->BasePage << PAGE_SHIFT;
+                Status = Mmx86MapInitStructure((PVOID)((ULONG_PTR)Descriptor->BasePage << PAGE_SHIFT),
+                                               Descriptor->PageCount << PAGE_SHIFT,
+                                               PhysicalAddress);
+                if (!NT_SUCCESS(Status))
+                {
+                    return Status;
+                }
+            }
+
+            /* Move to the next descriptor */
+            NextEntry = NextEntry->Flink;
+        }
+
+        /* Reset */
+        NextEntry = Head->Flink;
+        while (NextEntry != Head)
+        {
+            /* Get the descriptor */
+            Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
+
+            /* Skip to the next entry before we free */
+            NextEntry = NextEntry->Flink;
+
+            /* Remove and free it */
+            MmMdRemoveDescriptorFromList(&FirmwareMdl, Descriptor);
+            MmMdFreeDescriptor(Descriptor);
+        }
+    }
+
+    /* All library mappings identity mapped now */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+Mmx86InitializeMemoryMap (
+    _In_ ULONG Phase,
+    _In_ PBL_MEMORY_DATA MemoryData
+    )
+{
+    ULONG ImageSize;
+    PVOID ImageBase;
+    KDESCRIPTOR Gdt, Idt;
+    NTSTATUS Status;
+    PHYSICAL_ADDRESS PhysicalAddress;
+
+    /* If this is phase 2, map the memory regions */
+    if (Phase != 1)
+    {
+        return Mmx86pMapMemoryRegions(Phase, MemoryData);
+    }
+
+    /* Get the application image base/size */
+    Status = BlGetApplicationBaseAndSize(&ImageBase, &ImageSize);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Map the image back at the same place */
+    PhysicalAddress.QuadPart = (ULONG_PTR)ImageBase;
+    Status = Mmx86MapInitStructure(ImageBase, ImageSize, PhysicalAddress);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Map the first 4MB of memory */
+    PhysicalAddress.QuadPart = 0;
+    Status = Mmx86MapInitStructure(NULL, 4 * 1024 * 1024, PhysicalAddress);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Map the GDT */
+    _sgdt(&Gdt.Limit);
+    PhysicalAddress.QuadPart = Gdt.Base;
+    Status = Mmx86MapInitStructure((PVOID)Gdt.Base, Gdt.Limit + 1, PhysicalAddress);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Map the IDT */
+    __sidt(&Idt.Limit);
+    PhysicalAddress.QuadPart = Idt.Base;
+    Status = Mmx86MapInitStructure((PVOID)Idt.Base, Idt.Limit + 1, PhysicalAddress);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Map the reference page */
+    PhysicalAddress.QuadPart = (ULONG_PTR)MmArchReferencePage;
+    Status = Mmx86MapInitStructure(MmArchReferencePage,
+                                   MmArchReferencePageSize,
+                                   PhysicalAddress);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* More to do */
+    return Mmx86pMapMemoryRegions(Phase, MemoryData);
+}
+
+NTSTATUS
+MmDefInitializeTranslation (
+    _In_ PBL_MEMORY_DATA MemoryData,
+    _In_ BL_TRANSLATION_TYPE TranslationType
+    )
+{
+    NTSTATUS Status;
+    PHYSICAL_ADDRESS PhysicalAddress;
+    ULONG PdeIndex;
+
+    /* Set the global function pointers for memory translation */
+    Mmx86TranslateVirtualAddress = MmDefpTranslateVirtualAddress;
+    Mmx86MapPhysicalAddress = MmDefpMapPhysicalAddress;
+    Mmx86UnmapVirtualAddress = MmDefpUnmapVirtualAddress;
+    Mmx86RemapVirtualAddress = MmDefpRemapVirtualAddress;
+    Mmx86FlushTlb = MmDefpFlushTlb;
+    Mmx86FlushTlbEntry = MmDefpFlushTlbEntry;
+    Mmx86DestroySelfMap = MmDefpDestroySelfMap;
+
+    /* Check what mode we're currently in */
+    if (TranslationType == BlVirtual)
+    {
+        EfiPrintf(L"Virtual->Virtual not yet supported\r\n");
+        return STATUS_NOT_IMPLEMENTED;
+    }
+    else if (TranslationType != BlNone)
+    {
+        /* Not even Windows supports PAE->Virtual downgrade */
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    /* The None->Virtual case */
+    MmPdpt = NULL;
+    Mmx86SelfMapBase.QuadPart = 0;
+    MmArchReferencePage = NULL;
+
+    /* Truncate all memory above 4GB so that we don't use it @TODO: FIXME */
+    EfiPrintf(L"Warning: not truncating > 4GB memory. Don't boot with more than 4GB of RAM!\r\n");
+    //Status = MmPaTruncateMemory(0x100000);
+    Status = STATUS_SUCCESS;
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Allocate a page directory */
+    Status = MmPapAllocatePhysicalPagesInRange(&PhysicalAddress,
+                                               BlLoaderPageDirectory,
+                                               1,
+                                               0,
+                                               0,
+                                               &MmMdlUnmappedAllocated,
+                                               0,
+                                               0);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Zero out the page directory */
+    MmPdpt = (PVOID)PhysicalAddress.LowPart;
+    RtlZeroMemory(MmPdpt, PAGE_SIZE);
+
+    /* Set the page size */
+    MmArchReferencePageSize = PAGE_SIZE;
+
+    /* Allocate the self-map page */
+    Status = MmPapAllocatePhysicalPagesInRange(&PhysicalAddress,
+                                               BlLoaderReferencePage,
+                                               1,
+                                               0,
+                                               0,
+                                               &MmMdlUnmappedAllocated,
+                                               0,
+                                               0);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Set the reference page */
+    MmArchReferencePage = (PVOID)PhysicalAddress.LowPart;
+
+    /* Zero it out */
+    RtlZeroMemory(MmArchReferencePage, MmArchReferencePageSize);
+
+    /* Allocate 4MB worth of self-map pages */
+    Status = MmPaReserveSelfMapPages(&Mmx86SelfMapBase, 
+                                     (4 * 1024 * 1024) >> PAGE_SHIFT,
+                                     (4 * 1024 * 1024) >> PAGE_SHIFT);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Zero them out */
+    RtlZeroMemory((PVOID)Mmx86SelfMapBase.LowPart, 4 * 1024 * 1024);
+    EfiPrintf(L"PDPT at 0x%p Reference Page at 0x%p Self-map at 0x%p\r\n",
+              MmPdpt, MmArchReferencePage, Mmx86SelfMapBase.LowPart);
+
+    /* Align PTE base to 4MB region */
+    MmPteBase = (PVOID)(Mmx86SelfMapBase.LowPart & ~0x3FFFFF);
+
+    /* The PDE is the PTE of the PTE base */
+    MmPdeBase = MiAddressToPte(MmPteBase);
+    PdeIndex = MiAddressToPdeOffset(MmPdeBase);
+    MmPdpt[PdeIndex].u.Hard.Valid = 1;
+    MmPdpt[PdeIndex].u.Hard.Write = 1;
+    MmPdpt[PdeIndex].u.Hard.PageFrameNumber = (ULONG_PTR)MmPdpt >> PAGE_SHIFT;
+    MmArchReferencePage[PdeIndex]++;
+
+    /* Remove PTE_BASE from free virtual memory */
+    Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual,
+                                       BL_MM_REMOVE_VIRTUAL_REGION_FLAG,
+                                       PTE_BASE >> PAGE_SHIFT,
+                                       (4 * 1024 * 1024) >> PAGE_SHIFT,
+                                       0);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Remove HAL_HEAP from free virtual memory */
+    Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual,
+                                       BL_MM_REMOVE_VIRTUAL_REGION_FLAG,
+                                       MM_HAL_VA_START >> PAGE_SHIFT,
+                                       (4 * 1024 * 1024) >> PAGE_SHIFT,
+                                       0);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Initialize the virtual->physical memory mappings */
+    Status = Mmx86InitializeMemoryMap(1, MemoryData);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    EfiPrintf(L"Ready to turn on motherfucking paging, brah!\r\n");
+    Status = STATUS_NOT_IMPLEMENTED;
+
+Quickie:
+    /* Free reference page if we allocated it */
+    if (MmArchReferencePage)
+    {
+        PhysicalAddress.QuadPart = (ULONG_PTR)MmArchReferencePage;
+        BlMmFreePhysicalPages(PhysicalAddress);
+    }
+
+    /* Free page directory if we allocated it */
+    if (MmPdpt)
+    {
+        PhysicalAddress.QuadPart = (ULONG_PTR)MmPdpt;
+        BlMmFreePhysicalPages(PhysicalAddress);
+    }
+
+    /* Free the self map if we allocated it */
+    if (Mmx86SelfMapBase.QuadPart)
+    {
+        MmPaReleaseSelfMapPages(Mmx86SelfMapBase);
+    }
+
+    /* All done */
+    return Status;
+}
+
 NTSTATUS
 MmArchInitialize (
     _In_ ULONG Phase,
@@ -140,6 +1040,8 @@ MmArchInitialize (
     )
 {
     NTSTATUS Status;
+    ULONGLONG IncreaseUserVa, PerfCounter, CpuRandom;
+    INT CpuInfo[4];
 
     /* For phase 2, just map deferred regions */
     if (Phase != 1)
@@ -160,7 +1062,7 @@ MmArchInitialize (
             MmArchKsegAddressRange.Minimum = 0;
             MmArchKsegAddressRange.Maximum = (ULONGLONG)~0;
             MmArchTopOfApplicationAddressSpace = 0;
-            Mmx86SelfMapBase = 0;
+            Mmx86SelfMapBase.QuadPart = 0;
 
             /* Set stub functions */
             BlMmRelocateSelfMap = MmArchNullFunction;
@@ -172,19 +1074,85 @@ MmArchInitialize (
 
         case BlVirtual:
 
-            Status = STATUS_NOT_IMPLEMENTED;
+            /* Set the large page size to 1024 pages (4MB) */
+            MmArchLargePageSize = (4 * 1024 * 1024) / PAGE_SIZE;
+
+            /* Check if /USERVA option was used */
+            Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
+                                            BcdOSLoaderInteger_IncreaseUserVa,
+                                            &IncreaseUserVa);
+            if (NT_SUCCESS(Status) && (IncreaseUserVa))
+            {
+                /* Yes -- load the kernel at 0xE0000000 instead */
+                MmArchKsegBase = 0xE0000000;
+            }
+            else
+            {
+                /* Nope, load at the standard 2GB split */
+                MmArchKsegBase = 0x80000000;
+            }
+
+            /* Check if CPUID 01h is supported */
+            CpuRandom = 0;
+            if (BlArchIsCpuIdFunctionSupported(1))
+            {
+                /* Call it */
+                BlArchCpuId(1, 0, CpuInfo);
+
+                /* Check if RDRAND is supported */
+                if (CpuInfo[2] & 0x40000000)
+                {
+                    EfiPrintf(L"Your CPU can do RDRAND! Good for you!\r\n");
+                    CpuRandom = 0;
+                }
+            }
+
+            /* Read the TSC */
+            PerfCounter = BlArchGetPerformanceCounter();
+            PerfCounter >>= 4;
+            _rotl16(PerfCounter, 5);
+
+            /* Set the address range */
+            MmArchKsegAddressRange.Minimum = 0;
+            MmArchKsegAddressRange.Maximum = (ULONGLONG)~0;
+
+            /* Set the KASLR bias */
+            MmArchKsegBias = ((PerfCounter ^ CpuRandom) & 0xFFF) << 12;
+            MmArchKsegBias = 0;
+            MmArchKsegBase += MmArchKsegBias;
+
+            /* Set the kernel range */
+            MmArchKsegAddressRange.Minimum = MmArchKsegBase;
+            MmArchKsegAddressRange.Maximum = (ULONGLONG)~0;
+
+            /* Set the boot application top maximum */
+            MmArchTopOfApplicationAddressSpace = 0x70000000;
+
+            /* Initialize virtual address space translation */
+            Status = MmDefInitializeTranslation(MemoryData, TranslationType);
+            if (NT_SUCCESS(Status))
+            {
+                /* Set stub functions */
+                BlMmRelocateSelfMap = MmDefRelocateSelfMap;
+                BlMmFlushTlb = Mmx86FlushTlb;
+                BlMmMoveVirtualAddressRange = MmDefMoveVirtualAddressRange;
+                BlMmZeroVirtualAddressRange = MmDefZeroVirtualAddressRange;
+            }
             break;
 
         case BlPae:
 
+            /* We don't support PAE */
             Status = STATUS_NOT_SUPPORTED;
             break;
 
         default:
+
+            /* Invalid architecture type*/
             Status = STATUS_INVALID_PARAMETER;
             break;
     }
 
+    /* Back to caller */
     return Status;
-
 }