ARM Port Memory Management Checkpoint:
authorReactOS Portable Systems Group <ros-arm-bringup@svn.reactos.org>
Mon, 10 Mar 2008 17:27:14 +0000 (17:27 +0000)
committerReactOS Portable Systems Group <ros-arm-bringup@svn.reactos.org>
Mon, 10 Mar 2008 17:27:14 +0000 (17:27 +0000)
- Implemented and defined the MMU-OS architecture for the ARM port. The details are too long for a commit message, but we have decided to replicate the x86 NT memory manager layout. We've defined a PTE_BASE at 0xC0000000 just like on x86, and we use a PDE_BASE at 0xC1000000. Unlike the x86, we can't use PDE-PTE self-mapping because ARM has different formats (and sizes!) for PDE vs PTEs! We emulate the behavior however (which adds a small performance hit) and the Mm porting is thus at least 10 times easier.
- Moved serial port to 0xE0000000 for now.
- We now parse the board memory map from u-boot.
- Added memory allocation code to FreeLDR -- we now build a full ARC memory map for the kernel.
- FreeLDR allocates page tables and sets up the initial support for our memory layout (see comments for some lengthier explenations)
- Allocations made by FreeLDR for loading ReactOS are now made from a "shared heap" page that's also marked in the memory map.
- Registry and NLS data are now being put into the loader block.
- We now create a loader entry for the kernel (but not anything else -- we'll have to parse the list properly later).
- Defined correct _HARDWARE_PTE_ARM and _MMPTE_HARDWARE for ARM.
- ARM_COARSE_PAGE_TABLE is now 4KB instead of 1KB, going against the architecture! We do this for proper OS support of the PTE_BASE.
- Fixed build due to KiSystemStartulReal change.
- Fixed a bug on the x86 build when creating memory allocation descriptors. Memory corruption could occur in certain scenarios.
- Implemented significant portions of the ARM memory manager code in the kernel:
  - MmGetPageDirectory.
  - MmDeletePageTable (for the kernel address space only).
  - MmIsPagePresent (for the kernel address space only).
  - MmCreateVirtualMappingForKernel.
  - MmCreateVirtualMapping (calls MmCreateVirtualMappingUnsafe).
  - MmCreateVirtualMappingUnsafe (for the kernel address space only).
  - MmSetPageProtect (unused on ARM).
  - MmCreateHyperspaceMapping.
  - MmDeleteHyperspaceMapping.
  - MmInitGlobalKernelPageDirectory.
  - MmInitPageDirectoryMap.
- With the above, this means we now go well inside MmInit1: the PFN database is setup and works, memory areas are functional, and non-paged pool is fully working.
- We currently hit a data abort during paged pool setup -- this is to be expected, since we don't have any exception handlers yet. These are coming up next -- we have to start handling crashes (and page faults).

svn path=/trunk/; revision=32640

reactos/boot/freeldr/freeldr/arch/arm/boot.s
reactos/boot/freeldr/freeldr/arch/arm/loader.c
reactos/boot/freeldr/freeldr/arch/arm/macharm.c
reactos/boot/freeldr/freeldr/reactos/imageldr.c
reactos/include/ndk/arm/mmtypes.h
reactos/ntoskrnl/include/internal/arm/ke.h
reactos/ntoskrnl/include/internal/arm/mm.h
reactos/ntoskrnl/ke/arm/arm_kprintf.c
reactos/ntoskrnl/ke/freeldr.c
reactos/ntoskrnl/mm/arm/stubs.c
reactos/ntoskrnl/mm/mminit.c

index bafcd28..3c046c0 100644 (file)
@@ -61,12 +61,16 @@ L_ArmInit:
     .long ArmInit
 
        .align 4
+.global BootStack
 BootStack:
        .space 0x4000
 BootStackEnd:
     .long 0
 
 .section pagedata
+.global TranslationTableStart
+TranslationTableStart:
+
 .global ArmTranslationTable
 ArmTranslationTable:
     .space 0x4000 // 0x00000000->0xFFFFFFFF
@@ -74,19 +78,81 @@ ArmTranslationTable:
 .global BootTranslationTable
 BootTranslationTable:
     .space 0x0400 // 0x00000000->0x800FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00100000->0x801FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00200000->0x802FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00300000->0x803FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00400000->0x804FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00500000->0x805FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00600000->0x806FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00700000->0x807FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     
 .global KernelTranslationTable
 KernelTranslationTable:
     .space 0x0400 // 0x00800000->0x808FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00900000->0x809FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00A00000->0x80AFFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00B00000->0x80BFFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00C00000->0x80CFFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
     .space 0x0400 // 0x00D00000->0x80DFFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    
+.global FlatMapTranslationTable
+FlatMapTranslationTable:
+    .space 0x0400 // 0xYYYYYYYY->0xC00FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC01FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC02FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC03FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC04FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC05FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC06FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC07FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC08FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC09FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC0AFFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC0BFFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC0CFFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC0DFFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC0EFFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    .space 0x0400 // 0xYYYYYYYY->0xC0FFFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+    
+.global MasterTranslationTable
+MasterTranslationTable:
+    .space 0x0400 // 0xYYYYYYYY->0xC10FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+
+.global HyperSpaceTranslationTable
+HyperSpaceTranslationTable:
+    .space 0x0400 // 0xYYYYYYYY->0xC10FFFFF
+    .space 0x0C00 // PADDING FOR 4KB GRANULARITY
+
+.global TranslationTableEnd
+TranslationTableEnd:
index 1d1a97b..9881224 100644 (file)
 #include <internal/arm/mm.h>
 #include <internal/arm/intrin_i.h>
 
+#define KERNEL_DESCRIPTOR_PAGE(x) (((ULONG_PTR)x &~ KSEG0_BASE) >> PAGE_SHIFT)
+
 /* GLOBALS ********************************************************************/
 
+typedef struct _BIOS_MEMORY_DESCRIPTOR
+{
+    ULONG BlockBase;
+    ULONG BlockSize;
+} BIOS_MEMORY_DESCRIPTOR, *PBIOS_MEMORY_DESCRIPTOR;
+
 ULONG PageDirectoryStart, PageDirectoryEnd;
 PLOADER_PARAMETER_BLOCK ArmLoaderBlock;
 CHAR ArmCommandLine[256];
@@ -24,11 +32,23 @@ CHAR ArmNtHalPath[64];
 CHAR ArmNtBootPath[64];
 PNLS_DATA_BLOCK ArmNlsDataBlock;
 PLOADER_PARAMETER_EXTENSION ArmExtension;
+BIOS_MEMORY_DESCRIPTOR ArmBoardMemoryDescriptors[16] = {{0}};
+PBIOS_MEMORY_DESCRIPTOR ArmBoardMemoryList = ArmBoardMemoryDescriptors;
+ULONG NumberDescriptors = 0;
+MEMORY_DESCRIPTOR MDArray[16] = {{0}};
+ULONG ArmSharedHeapSize;
+PCHAR ArmSharedHeap;
+
+extern ADDRESS_RANGE ArmBoardMemoryMap[16];
+extern ULONG ArmBoardMemoryMapRangeCount;
 extern ARM_TRANSLATION_TABLE ArmTranslationTable;
-extern ARM_COARSE_PAGE_TABLE BootTranslationTable, KernelTranslationTable;
+extern ARM_COARSE_PAGE_TABLE BootTranslationTable, KernelTranslationTable, FlatMapTranslationTable, MasterTranslationTable, HyperSpaceTranslationTable;
 extern ROS_KERNEL_ENTRY_POINT KernelEntryPoint;
 extern ULONG_PTR KernelBase;
-extern ULONG_PTR AnsiData, OemData, UnicodeData, RegistryData;
+extern ULONG_PTR AnsiData, OemData, UnicodeData, RegistryData, KernelData, HalData, DriverData[16];
+extern ULONG RegistrySize, AnsiSize, OemSize, UnicodeSize, KernelSize, HalSize, DriverSize[16];
+extern ULONG Drivers;
+extern ULONG BootStack, TranslationTableStart, TranslationTableEnd;
 
 ULONG SizeBits[] =
 {
@@ -59,10 +79,615 @@ ULONG LenBits[] =
 //
 // Where to map the serial port
 //
-#define UART_VIRTUAL 0xC0000000
+#define UART_VIRTUAL 0xE0000000
+
+#define PTE_BASE     0xC0000000
+#define PDE_BASE     0xC1000000
+#define HYPER_SPACE  0xC1100000
+
+//
+// Take 0x80812345 and extract:
+// PTE_BASE[0x808][0x12]
+//
+#define MiAddressToPte(x)         \
+    (PTE_BASE + (((x) >> 20) << 12) + ((((x) >> 12) & 0xFF) << 2))
+
+#define MiAddressToPde(x)         \
+    (PDE_BASE + (((x) >> 20) << 2))
 
 /* FUNCTIONS ******************************************************************/
 
+PVOID
+ArmAllocateFromSharedHeap(IN ULONG Size)
+{
+    PVOID Buffer;
+
+    //
+    // Allocate from the shared heap
+    //
+    Buffer = &ArmSharedHeap[ArmSharedHeapSize];
+    ArmSharedHeapSize += Size;
+    return Buffer;
+}
+
+PMEMORY_ALLOCATION_DESCRIPTOR
+NTAPI
+ArmAllocateMemoryDescriptor(VOID)
+{
+    //
+    // Allocate a descriptor from the heap
+    //
+    return ArmAllocateFromSharedHeap(sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
+}
+
+VOID
+NTAPI
+ArmAddBoardMemoryDescriptor(IN ULONG Address,
+                            IN ULONG Size)
+{
+    PBIOS_MEMORY_DESCRIPTOR BiosBlock = ArmBoardMemoryList;
+    
+    //
+    // Loop board DRAM configuration
+    //
+    while (BiosBlock->BlockSize > 0)
+    {
+        /* Check if we've found a matching head block */
+        if (Address + Size == BiosBlock->BlockBase)
+        {
+            /* Simply enlarge and rebase it */
+            BiosBlock->BlockBase = Address;
+            BiosBlock->BlockSize += Size;
+            break;
+        }
+        
+        /* Check if we've found a matching tail block */
+        if (Address == (BiosBlock->BlockBase + BiosBlock->BlockSize))
+        {
+            /* Simply enlarge it */
+            BiosBlock->BlockSize += Size;
+            break;
+        }
+        
+        /* Nothing suitable found, try the next block */
+        BiosBlock++;
+    }
+    
+    /* No usable blocks found, found a free block instead */
+    if (!BiosBlock->BlockSize)
+    {
+        /* Write our data */
+        BiosBlock->BlockBase = Address;
+        BiosBlock->BlockSize = Size;
+        
+        /* Create a new block and mark it as the end of the array */
+        BiosBlock++;
+        BiosBlock->BlockBase = BiosBlock->BlockSize = 0L;
+    }
+}
+
+VOID
+NTAPI
+ArmBuildBoardMemoryMap(VOID)
+{
+    ULONG BlockBegin, BlockEnd;
+    ULONG j;
+    
+    /* Loop the BIOS Memory Map */
+    for (j = 0; j < ArmBoardMemoryMapRangeCount; j++)
+    {
+        /* Get the start and end addresses */
+        BlockBegin = ArmBoardMemoryMap[j].BaseAddrLow;
+        BlockEnd = ArmBoardMemoryMap[j].BaseAddrLow + ArmBoardMemoryMap[j].LengthLow - 1;
+        
+        /* Make sure this isn't a > 4GB descriptor */
+        if (!ArmBoardMemoryMap[j].BaseAddrHigh)
+        {
+            /* Make sure we don't overflow */
+            if (BlockEnd < BlockBegin) BlockEnd = 0xFFFFFFFF;
+            
+            /* Check if this is free memory */
+            if (ArmBoardMemoryMap[j].Type == 1)
+            {
+                /* Add it to our BIOS descriptors */
+                ArmAddBoardMemoryDescriptor(BlockBegin, BlockEnd - BlockBegin + 1);
+            }
+        }
+    }
+}
+
+NTSTATUS
+NTAPI
+ArmConfigureArcDescriptor(IN ULONG PageBegin,
+                          IN ULONG PageEnd,
+                          IN TYPE_OF_MEMORY MemoryType)
+{
+    ULONG i;
+    ULONG BlockBegin, BlockEnd;
+    MEMORY_TYPE BlockType;
+    BOOLEAN Combined = FALSE;
+    
+    /* If this descriptor seems bogus, just return */
+    if (PageEnd <= PageBegin) return STATUS_SUCCESS;
+    
+    /* Loop every ARC descriptor, trying to find one we can modify */
+    for (i = 0; i < NumberDescriptors; i++)
+    {
+        /* Get its settings */
+        BlockBegin = MDArray[i].BasePage;
+        BlockEnd = MDArray[i].BasePage + MDArray[i].PageCount;
+        BlockType = MDArray[i].MemoryType;
+        
+        /* Check if we can fit inside this block */
+        if (BlockBegin < PageBegin)
+        {
+            /* Check if we are larger then it */
+            if ((BlockEnd > PageBegin) && (BlockEnd <= PageEnd))
+            {
+                /* Make it end where we start */
+                BlockEnd = PageBegin;
+            }
+            
+            /* Check if it ends after we do */
+            if (BlockEnd > PageEnd)
+            {
+                /* Make sure we can allocate a descriptor */
+                if (NumberDescriptors == 60) return ENOMEM;
+                
+                /* Create a descriptor for whatever memory we're not part of */
+                MDArray[NumberDescriptors].MemoryType = BlockType;
+                MDArray[NumberDescriptors].BasePage = PageEnd;
+                MDArray[NumberDescriptors].PageCount  = BlockEnd - PageEnd;
+                NumberDescriptors++;
+                
+                /* The next block ending is now where we begin */
+                BlockEnd = PageBegin;
+            }
+        }
+        else
+        {
+            /* Check if the blog begins inside our range */
+            if (BlockBegin < PageEnd)
+            {
+                /* Check if it ends before we do */
+                if (BlockEnd < PageEnd)
+                {
+                    /* Then make it disappear */
+                    BlockEnd = BlockBegin;
+                }
+                else
+                {
+                    /* Otherwise make it start where we end */
+                    BlockBegin = PageEnd;
+                }
+            }
+        }
+        
+        /* Check if the block matches us, and we haven't tried combining yet */
+        if ((BlockType == MemoryType) && !(Combined))
+        {
+            /* Check if it starts where we end */
+            if (BlockBegin == PageEnd)
+            {
+                /* Make it start with us, and combine us */
+                BlockBegin = PageBegin;
+                Combined = TRUE;
+            }
+            else if (BlockEnd == PageBegin)
+            {
+                /* Otherwise, it ends where we begin, combine its ending */
+                BlockEnd = PageEnd;
+                Combined = TRUE;
+            }
+        }
+        
+        /* Check the original block data matches with what we came up with */
+        if ((MDArray[i].BasePage == BlockBegin) &&
+            (MDArray[i].PageCount == BlockEnd - BlockBegin))
+        {
+            /* Then skip it */
+            continue;
+        }
+        
+        /* Otherwise, set our new settings for this block */
+        MDArray[i].BasePage  = BlockBegin;
+        MDArray[i].PageCount = BlockEnd - BlockBegin;
+        
+        /* Check if we are killing the block */
+        if (BlockBegin == BlockEnd)
+        {
+            /* Delete this block and restart the loop properly */
+            NumberDescriptors--;
+            if (i < NumberDescriptors) MDArray[i] = MDArray[NumberDescriptors];
+            i--;
+        }
+    }
+    
+    /* If we got here without combining, we need to allocate a new block */
+    if (!(Combined) && (MemoryType < LoaderMaximum))
+    {
+        /* Make sure there's enough descriptors */
+        if (NumberDescriptors == 60) return ENOMEM;
+        
+        /* Allocate a new block with our data */
+        MDArray[NumberDescriptors].MemoryType = MemoryType;
+        MDArray[NumberDescriptors].BasePage = PageBegin;
+        MDArray[NumberDescriptors].PageCount  = PageEnd - PageBegin;
+        NumberDescriptors++;
+    }
+    
+    /* Changes complete, return success */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+ArmBuildOsMemoryMap(VOID)
+{
+    PBIOS_MEMORY_DESCRIPTOR MdBlock;
+    ULONG BlockStart, BlockEnd, BiasedStart, BiasedEnd, PageStart, PageEnd;
+    NTSTATUS Status = STATUS_SUCCESS;
+    
+    /* Loop the BIOS Memory Descriptor List */
+    MdBlock = ArmBoardMemoryList;
+    while (MdBlock->BlockSize)
+    {
+        /* Get the statrt and end addresses */
+        BlockStart = MdBlock->BlockBase;
+        BlockEnd = BlockStart + MdBlock->BlockSize - 1;
+        
+        /* Align them to page boundaries */
+        BiasedStart = BlockStart & (PAGE_SIZE - 1);
+        if (BiasedStart) BlockStart = BlockStart + PAGE_SIZE - BiasedStart;
+        BiasedEnd = (BlockEnd + 1) & (ULONG)(PAGE_SIZE - 1);
+        if (BiasedEnd) BlockEnd -= BiasedEnd;
+        
+        /* Get the actual page numbers */
+        PageStart = BlockStart >> PAGE_SHIFT;
+        PageEnd = (BlockEnd + 1) >> PAGE_SHIFT;
+
+        /* Check if we did any alignment */
+        if (BiasedStart)
+        {
+            /* Mark that region as reserved */
+            Status = ArmConfigureArcDescriptor(PageStart - 1,
+                                               PageStart,
+                                               MemorySpecialMemory);
+            if (Status != STATUS_SUCCESS) break;
+        }
+        
+        /* Check if we did any alignment */
+        if (BiasedEnd)
+        {
+            /* Mark that region as reserved */
+            Status = ArmConfigureArcDescriptor(PageEnd - 1,
+                                               PageEnd,
+                                               MemorySpecialMemory);
+            if (Status != STATUS_SUCCESS) break;
+        }
+        
+        /* It is, mark the memory a free */
+        Status = ArmConfigureArcDescriptor(PageStart,
+                                           PageEnd,
+                                           LoaderFree);
+        
+        /* If we failed, break out, otherwise, go to the next BIOS block */
+        if (Status != STATUS_SUCCESS) break;
+        MdBlock++;
+    }
+    
+    /* Return error code */
+    return Status;
+}
+
+VOID
+NTAPI
+ArmInsertMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
+{
+    PLIST_ENTRY ListHead, PreviousEntry, NextEntry;
+    PMEMORY_ALLOCATION_DESCRIPTOR Descriptor = NULL, NextDescriptor = NULL;
+    
+    /* Loop the memory descriptor list */
+    ListHead = &ArmLoaderBlock->MemoryDescriptorListHead;
+    PreviousEntry = ListHead;
+    NextEntry = ListHead->Flink;
+    while (NextEntry != ListHead)
+    {
+        /* Get the current descriptor and check if it's below ours */
+        NextDescriptor = CONTAINING_RECORD(NextEntry,
+                                           MEMORY_ALLOCATION_DESCRIPTOR,
+                                           ListEntry);
+        if (NewDescriptor->BasePage < NextDescriptor->BasePage) break;
+        
+        /* It isn't, save the previous entry and descriptor, and try again */
+        PreviousEntry = NextEntry;
+        Descriptor = NextDescriptor;
+        NextEntry = NextEntry->Flink;
+    }
+    
+    /* So we found the right spot to insert. Is this free memory? */
+    if (NewDescriptor->MemoryType != LoaderFree)
+    {
+        /* It isn't, so insert us before the last descriptor */
+        InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
+    }
+    else
+    {
+        /* We're free memory. Check if the entry we found is also free memory */
+        if ((PreviousEntry != ListHead) &&
+            ((Descriptor->MemoryType == LoaderFree) ||
+             (Descriptor->MemoryType == LoaderReserve)) &&
+            ((Descriptor->BasePage + Descriptor->PageCount) ==
+             NewDescriptor->BasePage))
+        {
+            /* It's free memory, and we're right after it. Enlarge that block */
+            Descriptor->PageCount += NewDescriptor->PageCount;
+            NewDescriptor = Descriptor;
+        }
+        else
+        {
+            /* Our range scan't be combined, so just insert us separately */
+            InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
+        }
+        
+        /* Check if we merged with an existing free memory block */
+        if ((NextEntry != ListHead) &&
+            ((NextDescriptor->MemoryType == LoaderFree) ||
+             (NextDescriptor->MemoryType == LoaderReserve)) &&
+            ((NewDescriptor->BasePage + NewDescriptor->PageCount) ==
+             NextDescriptor->BasePage))
+        {
+            /* Update our own block */
+            NewDescriptor->PageCount += NextDescriptor->PageCount;
+            
+            /* Remove the next block */
+            RemoveEntryList(&NextDescriptor->ListEntry);
+        }
+    }
+}
+
+NTSTATUS
+NTAPI
+ArmBuildMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
+                         IN MEMORY_TYPE MemoryType,
+                         IN ULONG BasePage,
+                         IN ULONG PageCount)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR Descriptor, NextDescriptor = NULL;
+    LONG Delta;
+    TYPE_OF_MEMORY CurrentType;
+    BOOLEAN UseNext;
+    
+    /* Check how many pages we'll be consuming */
+    Delta = BasePage - MemoryDescriptor->BasePage;
+    if (!(Delta) && (PageCount == MemoryDescriptor->PageCount))
+    {
+        /* We can simply convert the current descriptor into our new type */
+        MemoryDescriptor->MemoryType = MemoryType;
+    }
+    else
+    {
+        /* Get the current memory type of the descriptor, and reserve it */
+        CurrentType = MemoryDescriptor->MemoryType;
+        MemoryDescriptor->MemoryType = LoaderSpecialMemory;
+        
+        /* Check if we'll need another descriptor for what's left of memory */
+        UseNext = ((BasePage != MemoryDescriptor->BasePage) &&
+                   (Delta + PageCount != MemoryDescriptor->PageCount));
+        
+        /* Get a descriptor */
+        Descriptor = ArmAllocateMemoryDescriptor();
+        if (!Descriptor) return STATUS_INSUFFICIENT_RESOURCES;
+        
+        /* Check if we are using another descriptor */
+        if (UseNext)
+        {
+            /* Allocate that one too */
+            NextDescriptor = ArmAllocateMemoryDescriptor();
+            if (!NextDescriptor) return STATUS_INSUFFICIENT_RESOURCES;
+        }
+        
+        /* Build the descriptor we got */
+        Descriptor->MemoryType = MemoryType;
+        Descriptor->BasePage = BasePage;
+        Descriptor->PageCount = PageCount;
+        
+        /* Check if we're starting at the same place as the old one */
+        if (BasePage == MemoryDescriptor->BasePage)
+        {
+            /* Simply decrease the old descriptor and rebase it */
+            MemoryDescriptor->BasePage += PageCount;
+            MemoryDescriptor->PageCount -= PageCount;
+            MemoryDescriptor->MemoryType = CurrentType;
+        }
+        else if (Delta + PageCount == MemoryDescriptor->PageCount)
+        {
+            /* We finish where the old one did, shorten it */
+            MemoryDescriptor->PageCount -= PageCount;
+            MemoryDescriptor->MemoryType = CurrentType;
+        }
+        else
+        {
+            /* We're inside the current block, mark our free region */
+            NextDescriptor->MemoryType = LoaderFree;
+            NextDescriptor->BasePage = BasePage + PageCount;
+            NextDescriptor->PageCount = MemoryDescriptor->PageCount -
+            (PageCount + Delta);
+            
+            /* And cut down the current descriptor */
+            MemoryDescriptor->PageCount = Delta;
+            MemoryDescriptor->MemoryType = CurrentType;
+            
+            /* Finally, insert our new free descriptor into the list */
+            ArmInsertMemoryDescriptor(NextDescriptor);
+        }
+        
+        /* Insert the descriptor we allocated */
+        ArmInsertMemoryDescriptor(Descriptor);
+    }
+    
+    /* Return success */
+    return STATUS_SUCCESS;
+}
+
+PMEMORY_ALLOCATION_DESCRIPTOR
+NTAPI
+ArmFindMemoryDescriptor(IN ULONG BasePage)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR MdBlock = NULL;
+    PLIST_ENTRY NextEntry, ListHead;
+    
+    /* Scan the memory descriptor list */
+    ListHead = &ArmLoaderBlock->MemoryDescriptorListHead;
+    NextEntry = ListHead->Flink;
+    while (NextEntry != ListHead)
+    {
+        /* Get the current descriptor */
+        MdBlock = CONTAINING_RECORD(NextEntry,
+                                    MEMORY_ALLOCATION_DESCRIPTOR,
+                                    ListEntry);
+
+        /* Check if it can contain our memory range */
+        if ((MdBlock->BasePage <= BasePage) &&
+            (MdBlock->BasePage + MdBlock->PageCount > BasePage))
+        {
+            /* It can, break out */
+            break;
+        }
+        
+        /* Go to the next descriptor */
+        NextEntry = NextEntry->Flink;
+    }
+    
+    /* Return the descriptor we found, if any */
+    return MdBlock;
+}
+
+NTSTATUS
+NTAPI
+ArmCreateMemoryDescriptor(IN TYPE_OF_MEMORY MemoryType,
+                      IN ULONG BasePage,
+                      IN ULONG PageCount,
+                      IN ULONG Alignment,
+                      OUT PULONG ReturnedBase)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
+    ULONG AlignedBase, AlignedLimit;
+    PMEMORY_ALLOCATION_DESCRIPTOR ActiveMdBlock;
+    ULONG ActiveAlignedBase = 0;
+    PLIST_ENTRY NextEntry, ListHead;
+    
+    /* If no information was given, make some assumptions */
+    if (!Alignment) Alignment = 1;
+    if (!PageCount) PageCount = 1;
+    
+    /* Start looking for a matching descvriptor */
+    do
+    {
+        /* Calculate the limit of the range */
+        AlignedLimit = PageCount + BasePage;
+        
+        /* Find a descriptor that already contains our base address */
+        MdBlock = ArmFindMemoryDescriptor(BasePage);
+        if (MdBlock)
+        {
+            /* If it contains our limit as well, break out early */
+            if ((MdBlock->PageCount + MdBlock->BasePage) >= AlignedLimit) break;
+        }
+        
+        /* Loop the memory list */
+        AlignedBase = 0;
+        ActiveMdBlock = NULL;
+        ListHead = &ArmLoaderBlock->MemoryDescriptorListHead;
+        NextEntry = ListHead->Flink;
+        while (NextEntry != ListHead)
+        {
+            /* Get the current descriptors */
+            MdBlock = CONTAINING_RECORD(NextEntry,
+                                        MEMORY_ALLOCATION_DESCRIPTOR,
+                                        ListEntry);
+            
+            /* Align the base address and our limit */
+            AlignedBase = (MdBlock->BasePage + (Alignment - 1)) &~ Alignment;
+            AlignedLimit = MdBlock->PageCount -
+                           AlignedBase +
+                           MdBlock->BasePage;
+            
+            /* Check if this is a free block that can satisfy us */
+            if ((MdBlock->MemoryType == LoaderFree) &&
+                (AlignedLimit <= MdBlock->PageCount) &&
+                (PageCount <= AlignedLimit))
+            {
+                /* It is, stop searching */
+                ActiveMdBlock = MdBlock;
+                ActiveAlignedBase = AlignedBase;
+                break;
+            }
+            
+            /* Try the next block */
+            NextEntry = NextEntry->Flink;
+        }
+        
+        /* See if we came up with an adequate block */
+        if (ActiveMdBlock)
+        {
+            /* Generate a descriptor in it */
+            *ReturnedBase = AlignedBase;
+            return ArmBuildMemoryDescriptor(ActiveMdBlock,
+                                          MemoryType,
+                                          ActiveAlignedBase,
+                                          PageCount);
+        }
+    } while (TRUE);
+    
+    /* We found a matching block, generate a descriptor with it */
+    *ReturnedBase = BasePage;
+    return ArmBuildMemoryDescriptor(MdBlock, MemoryType, BasePage, PageCount);
+}
+
+NTSTATUS
+NTAPI
+ArmBuildLoaderMemoryList(VOID)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+    MEMORY_DESCRIPTOR *Memory;
+    ULONG i;
+    
+    /* Loop all BIOS Memory Descriptors */
+    for (i = 0; i < NumberDescriptors; i++)
+    {
+        /* Get the current descriptor */
+        Memory = &MDArray[i];
+        
+        /* Allocate an NT Memory Descriptor */
+        Descriptor = ArmAllocateMemoryDescriptor();
+        if (!Descriptor) return ENOMEM;
+        
+        /* Copy the memory type */
+        Descriptor->MemoryType = Memory->MemoryType;
+        if (Memory->MemoryType == MemoryFreeContiguous)
+        {
+            /* Convert this to free */
+            Descriptor->MemoryType = LoaderFree;
+        }
+        else if (Memory->MemoryType == MemorySpecialMemory)
+        {
+            /* Convert this to special memory */
+            Descriptor->MemoryType = LoaderSpecialMemory;
+        }
+        
+        /* Copy the range data */
+        Descriptor->BasePage = Memory->BasePage;
+        Descriptor->PageCount = Memory->PageCount;
+        
+        /* Insert the descriptor */
+        if (Descriptor->PageCount) ArmInsertMemoryDescriptor(Descriptor);
+    }
+    
+    /* All went well */
+    return STATUS_SUCCESS;
+}
+
 VOID
 ArmSetupPageDirectory(VOID)
 {   
@@ -70,20 +695,23 @@ ArmSetupPageDirectory(VOID)
     ARM_DOMAIN_REGISTER DomainRegister;
     ARM_PTE Pte;
     ULONG i, j;
-    PARM_TRANSLATION_TABLE MasterTable;
-    PARM_COARSE_PAGE_TABLE BootTable, KernelTable;
+    PARM_TRANSLATION_TABLE ArmTable;
+    PARM_COARSE_PAGE_TABLE BootTable, KernelTable, FlatMapTable, MasterTable, HyperSpaceTable;
     
     //
     // Get the PDEs that we will use
     //
-    MasterTable = &ArmTranslationTable;
+    ArmTable = &ArmTranslationTable;
     BootTable = &BootTranslationTable;
     KernelTable = &KernelTranslationTable;
+    FlatMapTable = &FlatMapTranslationTable;
+    MasterTable = &MasterTranslationTable;
+    HyperSpaceTable = &HyperSpaceTranslationTable;
     
     //
     // Set the master L1 PDE as the TTB
     //
-    TtbRegister.AsUlong = (ULONG)MasterTable;
+    TtbRegister.AsUlong = (ULONG)ArmTable;
     ASSERT(TtbRegister.Reserved == 0);
     KeArmTranslationTableRegisterSet(TtbRegister);
     
@@ -97,7 +725,7 @@ ArmSetupPageDirectory(VOID)
     //
     // Set Fault PTEs everywhere
     //
-    RtlZeroMemory(MasterTable, sizeof(ARM_TRANSLATION_TABLE));
+    RtlZeroMemory(ArmTable, sizeof(ARM_TRANSLATION_TABLE));
     
     //
     // Identity map the first MB of memory
@@ -110,22 +738,102 @@ ArmSetupPageDirectory(VOID)
     Pte.L1.Section.Access = SupervisorAccess;
     Pte.L1.Section.BaseAddress = 0;
     Pte.L1.Section.Ignored = Pte.L1.Section.Ignored1 = 0;
-    MasterTable->Pte[0] = Pte;
-
+    ArmTable->Pte[0] = Pte;
+    
     //
     // Map the page in MMIO space that contains the serial port into virtual memory
     //
     Pte.L1.Section.BaseAddress = ArmBoardBlock->UartRegisterBase >> PDE_SHIFT;
-    MasterTable->Pte[UART_VIRTUAL >> PDE_SHIFT] = Pte;
+    ArmTable->Pte[UART_VIRTUAL >> PDE_SHIFT] = Pte;
 
     //
-    // Create template PTE for the coarse page tables which map the first 8MB
+    // Create template PTE for the coarse page table which maps the PTE_BASE
     //
     Pte.L1.Coarse.Type = CoarsePte;
     Pte.L1.Coarse.Domain = Domain0;
     Pte.L1.Coarse.Reserved = 1; // ARM926EJ-S manual recommends setting to 1
-    Pte.L1.Coarse.BaseAddress = (ULONG)BootTable >> CPT_SHIFT;
     Pte.L1.Coarse.Ignored = Pte.L1.Coarse.Ignored1 = 0;
+    Pte.L1.Coarse.BaseAddress = (ULONG)FlatMapTable >> CPT_SHIFT;
+
+    //
+    // On x86, there is 4MB of space, starting at 0xC0000000 to 0xC0400000
+    // which contains the mappings for each PTE on the system. 4MB is needed
+    // since for 4GB, there will be 1 million PTEs, each of 4KB.
+    //
+    // To describe a 4MB region, on x86, only requires a page table, which can
+    // be linked from the page table directory.
+    //
+    // On the other hand, on ARM, we can only describe 1MB regions, so we need
+    // four times less PTE entries to represent a single mapping (an L2 coarse
+    // page table). This is problematic, because this would only take up 1KB of
+    // space, and we can't have a page that small.
+    //
+    // This means we must:
+    //
+    // - Allocate page tables (in physical memory) with 4KB granularity, instead
+    //   of 1KB (the other 3KB is unused and invalid).
+    //
+    // - "Skip" the other 3KB in the region, because we can't point to another
+    //   coarse page table after just 1KB.
+    //
+    // So 0xC0000000 will be mapped to the page table that maps the range of
+    // 0x00000000 to 0x01000000, while 0xC0001000 till be mapped to the page
+    // table that maps the area from 0x01000000 to 0x02000000, and so on. In
+    // total, this will require 4 million entries, and additionally, because of
+    // the padding, since each 256 entries will be 4KB (instead of 1KB), this
+    // means we'll need 16MB (0xC0000000 to 0xC1000000).
+    //
+    // We call this region the flat-map area
+    //
+    for (i = (PTE_BASE >> PDE_SHIFT); i < ((PTE_BASE + 0x1000000) >> PDE_SHIFT); i++)
+    {
+        //
+        // Write PTE and update the base address (next MB) for the next one
+        //
+        ArmTable->Pte[i] = Pte;
+        Pte.L1.Coarse.BaseAddress += 4;
+    }
+    
+    //
+    // On x86, there is also the region of 0xC0300000 to 0xC03080000 which maps
+    // to the various PDEs on the system. Yes, this overlaps with the above, and
+    // works because of an insidious dark magic (self-mapping the PDE as a PTE).
+    // Unfortunately, this doesn't work on ARM, firstly because the size of a L1
+    // page table is different than from an L2 page table, and secondly, which
+    // is even worse, the format for an L1 page table is different than the one
+    // for an L2 page table -- basically meaning we cannot self-map.
+    //
+    // However, we somewhat emulate this behavior on ARM. This will be expensive
+    // since we manually need to keep track of every page directory added and
+    // add an entry in our flat-map region. We also need to keep track of every
+    // change in the TTB, so that we can update the mappings in our PDE region.
+    //
+    // Note that for us, this region starts at 0xC1000000, after the flat-map
+    // area.
+    //
+    // Finally, to deal with different sizes (1KB page tables, 4KB page size!),
+    // we pad the ARM L2 page tables to make them 4KB, so that each page will
+    // therefore point to an L2 page table.
+    //
+    // This region is a lot easier than the first -- an L1 page table is only
+    // 16KB, so to access any index inside it, we just need 4 pages, since each
+    // page is 4KB... Clearly, there's also no need to pad in this case.
+    //
+    // We'll call this region the master translation area.
+    //
+    Pte.L1.Coarse.BaseAddress = (ULONG)MasterTable >> CPT_SHIFT;
+    ArmTable->Pte[PDE_BASE >> PDE_SHIFT] = Pte;
+    
+    //
+    // Now create the template for the hyperspace table which maps 1MB
+    //
+    Pte.L1.Coarse.BaseAddress = (ULONG)HyperSpaceTable >> CPT_SHIFT;
+    ArmTable->Pte[HYPER_SPACE >> PDE_SHIFT] = Pte;
+
+    //
+    // Now create the template for the coarse page tables which map the first 8MB
+    //
+    Pte.L1.Coarse.BaseAddress = (ULONG)BootTable >> CPT_SHIFT;
 
     //
     // Map 0x00000000 - 0x007FFFFF to 0x80000000 - 0x807FFFFF.
@@ -136,8 +844,8 @@ ArmSetupPageDirectory(VOID)
         //
         // Write PTE and update the base address (next MB) for the next one
         //
-        MasterTable->Pte[i] = Pte;
-        Pte.L1.Coarse.BaseAddress++;
+        ArmTable->Pte[i] = Pte;
+        Pte.L1.Coarse.BaseAddress += 4;
     }
     
     //
@@ -156,8 +864,8 @@ ArmSetupPageDirectory(VOID)
         //
         // Write PTE and update the base address (next MB) for the next one
         //
-        MasterTable->Pte[i] = Pte;
-        Pte.L1.Coarse.BaseAddress++;
+        ArmTable->Pte[i] = Pte;
+        Pte.L1.Coarse.BaseAddress += 4;
     }
     
     //
@@ -225,6 +933,88 @@ ArmSetupPageDirectory(VOID)
         //
         KernelTable++;
     }
+
+    //
+    // Now we need to create the PTEs for the addresses which have been mapped
+    // already.
+    //
+    // We have allocated 4 page table directories:
+    //
+    // - One for the kernel, 6MB
+    // - One for low-memory FreeLDR, 8MB
+    // - One for identity-mapping below 1MB, 1MB
+    // - And finally, one for the flat-map itself, 16MB
+    // 
+    // - Each MB mapped is a 1KB table, which we'll use a page to reference, so
+    //   we will require 31 pages.
+    //
+   
+    //
+    // For the 0x80000000 region (8MB)
+    //
+    Pte.L2.Small.BaseAddress = (ULONG)&BootTranslationTable >> PTE_SHIFT;
+    FlatMapTable = &(&FlatMapTranslationTable)[0x80000000 >> 28];
+    for (i = 0; i < 8; i++)
+    {
+        //
+        // Point to the page table mapping the next MB
+        //
+        FlatMapTable->Pte[i] = Pte;
+        Pte.L2.Small.BaseAddress++;        
+    }
+    
+    //
+    // For the 0x80800000 region (6MB)
+    //
+    Pte.L2.Small.BaseAddress = (ULONG)&KernelTranslationTable >> PTE_SHIFT;
+    for (i = 8; i < 14; i++)
+    {
+        //
+        // Point to the page table mapping the next MB
+        //
+        FlatMapTable->Pte[i] = Pte;
+        Pte.L2.Small.BaseAddress++;        
+    }
+    
+    //
+    // For the 0xC0000000 region (16MB)
+    //
+    Pte.L2.Small.BaseAddress = (ULONG)&FlatMapTranslationTable >> PTE_SHIFT;
+    FlatMapTable = &(&FlatMapTranslationTable)[0xC0000000 >> 28];
+    for (i = 0; i < 16; i++)
+    {
+        //
+        // Point to the page table mapping the next MB
+        //
+        FlatMapTable->Pte[i] = Pte;
+        Pte.L2.Small.BaseAddress++;        
+    }
+    
+    //
+    // For the 0xC1000000 region (1MB)
+    //
+    Pte.L2.Small.BaseAddress = (ULONG)&MasterTranslationTable >> PTE_SHIFT;
+    FlatMapTable->Pte[16] = Pte;
+    
+    //
+    // And finally for the 0xC1100000 region (1MB)
+    //
+    Pte.L2.Small.BaseAddress = (ULONG)&HyperSpaceTranslationTable >> PTE_SHIFT;
+    FlatMapTable->Pte[17] = Pte;
+
+    //
+    // Now we handle the master translation area for our PDEs. We'll just make
+    // the 4 page tables point to the ARM TTB.
+    //
+    Pte.L2.Small.BaseAddress = (ULONG)&ArmTranslationTable >> PTE_SHIFT;
+    for (i = 0; i < 4; i++)
+    {
+        //
+        // Point to the page table mapping the next MB
+        //
+        MasterTable->Pte[i] = Pte;
+        Pte.L2.Small.BaseAddress++;        
+    }
 }
 
 VOID
@@ -259,17 +1049,25 @@ VOID
 ArmPrepareForReactOS(IN BOOLEAN Setup)
 {   
     ARM_CACHE_REGISTER CacheReg;
-    PVOID Base;
+    PVOID Base, MemBase;
     PCHAR BootPath, HalPath;
+    NTSTATUS Status;
+    ULONG Dummy, i;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    
+    //
+    // Allocate the ARM Shared Heap
+    //
+    ArmSharedHeap = MmAllocateMemory(PAGE_SIZE);
+    ArmSharedHeapSize = 0;
+    if (!ArmSharedHeap) return;
     
     //
     // Allocate the loader block and extension
     //
-    ArmLoaderBlock = MmAllocateMemoryWithType(sizeof(LOADER_PARAMETER_BLOCK),
-                                              LoaderOsloaderHeap);
+    ArmLoaderBlock = ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_BLOCK));
     if (!ArmLoaderBlock) return;
-    ArmExtension = MmAllocateMemoryWithType(sizeof(LOADER_PARAMETER_EXTENSION),
-                                            LoaderOsloaderHeap);
+    ArmExtension = ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_EXTENSION));
     if (!ArmExtension) return;
     
     //
@@ -286,14 +1084,95 @@ ArmPrepareForReactOS(IN BOOLEAN Setup)
     ArmLoaderBlock->SetupLdrBlock = NULL;
     
     //
-    // TODO: Setup memory descriptors
+    // Add the Board Memory Map from U-Boot into the STARTUP.COM-style 
+    // BIOS descriptor format -- this needs to be removed later.
+    //
+    ArmBuildBoardMemoryMap();
+    
+    //
+    // Now basically convert these entries to the ARC format, so that we can
+    // get a good map of free (usable) memory
+    //
+    ArmBuildOsMemoryMap();
+
+    //
+    // NT uses an extended ARC format, with slightly different memory types.
+    // We also want to link the ARC descriptors together into a linked list,
+    // instead of the array, and allocate the semi-permanent storage in which
+    // these entries will be stored so that the kernel can read them.
+    //
+    ArmBuildLoaderMemoryList();
+    
+    //
+    // Setup descriptor for the shared heap
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderOsloaderHeap,
+                                       (ULONG_PTR)ArmSharedHeap >> PAGE_SHIFT,
+                                       ADDRESS_AND_SIZE_TO_SPAN_PAGES(ArmSharedHeap,
+                                                                      ArmSharedHeapSize),
+                                       0,
+                                       &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+
+    //
+    // Setup descriptor for the boot stack
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderOsloaderStack,
+                                       (ULONG_PTR)&BootStack >> PAGE_SHIFT,
+                                       4,
+                                       0,
+                                       &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+
+    //
+    // Setup descriptor for the boot page tables
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderMemoryData,
+                                       (ULONG_PTR)&TranslationTableStart >> PAGE_SHIFT,
+                                       ((ULONG_PTR)&TranslationTableEnd -
+                                        (ULONG_PTR)&TranslationTableStart) / PAGE_SIZE,
+                                       0,
+                                       &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+
+    //
+    // Setup descriptor for the kernel
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderSystemCode,
+                                       KernelData >> PAGE_SHIFT,
+                                       ADDRESS_AND_SIZE_TO_SPAN_PAGES(KernelData,
+                                                                      KernelSize),
+                                       0,
+                                       &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+    
+    //
+    // Setup descriptor for the HAL
     //
+    Status = ArmCreateMemoryDescriptor(LoaderHalCode,
+                                       HalData >> PAGE_SHIFT,
+                                       ADDRESS_AND_SIZE_TO_SPAN_PAGES(HalData,
+                                                                      HalSize),
+                                       0,
+                                       &Dummy);
+    if (Status != STATUS_SUCCESS) return;
     
     //
     // Setup registry data
     //
     ArmLoaderBlock->RegistryBase = (PVOID)((ULONG_PTR)RegistryData | KSEG0_BASE);
     
+    //
+    // Create an MD for it
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderRegistryData,
+                                       RegistryData >> PAGE_SHIFT,
+                                       ADDRESS_AND_SIZE_TO_SPAN_PAGES(RegistryData,
+                                                                      RegistrySize),
+                                       0,
+                                       &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+    
     //
     // TODO: Setup ARC Hardware tree data
     //
@@ -301,18 +1180,79 @@ ArmPrepareForReactOS(IN BOOLEAN Setup)
     //
     // Setup NLS data
     //
-    ArmNlsDataBlock = MmAllocateMemoryWithType(sizeof(NLS_DATA_BLOCK),
-                                               LoaderOsloaderHeap);
+    ArmNlsDataBlock = ArmAllocateFromSharedHeap(sizeof(NLS_DATA_BLOCK));
     ArmLoaderBlock->NlsData = ArmNlsDataBlock;
     ArmLoaderBlock->NlsData->AnsiCodePageData = (PVOID)(AnsiData | KSEG0_BASE);
     ArmLoaderBlock->NlsData->OemCodePageData = (PVOID)(OemData | KSEG0_BASE);
     ArmLoaderBlock->NlsData->UnicodeCodePageData = (PVOID)(UnicodeData | KSEG0_BASE);
     ArmLoaderBlock->NlsData = (PVOID)((ULONG_PTR)ArmLoaderBlock->NlsData | KSEG0_BASE);
     
+    //
+    // Setup ANSI NLS Memory Descriptor
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderNlsData,
+                                       AnsiData >> PAGE_SHIFT,
+                                       ADDRESS_AND_SIZE_TO_SPAN_PAGES(AnsiData,
+                                                                      AnsiSize),
+                                       0,
+                                       &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+    
+    //
+    // Setup OEM NLS Memory Descriptor
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderNlsData,
+                                       OemData >> PAGE_SHIFT,
+                                       ADDRESS_AND_SIZE_TO_SPAN_PAGES(OemData,
+                                                                      OemSize),
+                                       0,
+                                       &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+    
+    //
+    // Setup Unicode NLS Memory Descriptor
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderNlsData,
+                                       UnicodeData >> PAGE_SHIFT,
+                                       ADDRESS_AND_SIZE_TO_SPAN_PAGES(UnicodeData,
+                                                                      UnicodeSize),
+                                       0,
+                                       &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+    
+    //
+    // Setup loader entry for the kernel
+    //
+    LdrEntry = ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY));
+    RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
+    LdrEntry->DllBase = (PVOID)KernelBase;
+    LdrEntry->SizeOfImage = KernelSize;
+    LdrEntry->EntryPoint = KernelEntryPoint;
+    LdrEntry->LoadCount = 1;
+    LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
+    InsertTailList(&ArmLoaderBlock->LoadOrderListHead, &LdrEntry->InLoadOrderLinks);
+    
     //
     // TODO: Setup boot-driver data
     //
     
+    //
+    // Build descriptors for the drivers loaded
+    //
+    for (i = 0; i < Drivers; i++)
+    {
+        //
+        // Build a descriptor for the driver
+        //
+        Status = ArmCreateMemoryDescriptor(LoaderBootDriver,
+                                           DriverData[i] >> PAGE_SHIFT,
+                                           ADDRESS_AND_SIZE_TO_SPAN_PAGES(DriverData[i],
+                                                                          DriverSize[i]),
+                                           0,
+                                           &Dummy);
+        if (Status != STATUS_SUCCESS) return;
+    }
+    
     //
     // Setup extension parameters
     //
@@ -377,7 +1317,7 @@ ArmPrepareForReactOS(IN BOOLEAN Setup)
     ArmLoaderBlock->u.Arm.SecondLevelDcacheFillSize =
     ArmLoaderBlock->u.Arm.SecondLevelIcacheSize =
     ArmLoaderBlock->u.Arm.SecondLevelIcacheFillSize = 0;
-
+    
     //
     // Allocate the Interrupt stack
     //
@@ -385,6 +1325,16 @@ ArmPrepareForReactOS(IN BOOLEAN Setup)
     ArmLoaderBlock->u.Arm.InterruptStack = KSEG0_BASE | (ULONG)Base;
     ArmLoaderBlock->u.Arm.InterruptStack += KERNEL_STACK_SIZE;
     
+    //
+    // Build an entry for it
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderStartupDpcStack,
+                                         (ULONG_PTR)Base >> PAGE_SHIFT,
+                                         KERNEL_STACK_SIZE / PAGE_SIZE,
+                                         0,
+                                         &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+        
     //
     // Allocate the Kernel Boot stack
     //
@@ -392,27 +1342,69 @@ ArmPrepareForReactOS(IN BOOLEAN Setup)
     ArmLoaderBlock->KernelStack = KSEG0_BASE | (ULONG)Base;
     ArmLoaderBlock->KernelStack += KERNEL_STACK_SIZE;
     
+    //
+    // Build an entry for it
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderStartupKernelStack,
+                                         (ULONG_PTR)Base >> PAGE_SHIFT,
+                                         KERNEL_STACK_SIZE / PAGE_SIZE,
+                                         0,
+                                         &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+
     //
     // Allocate the Abort stack
     //
     Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupPanicStack);
     ArmLoaderBlock->u.Arm.PanicStack = KSEG0_BASE | (ULONG)Base;
     ArmLoaderBlock->u.Arm.PanicStack += KERNEL_STACK_SIZE;
+    
+    //
+    // Build an entry for it
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderStartupPanicStack,
+                                         (ULONG_PTR)Base >> PAGE_SHIFT,
+                                         KERNEL_STACK_SIZE / PAGE_SIZE,
+                                         0,
+                                         &Dummy);
+    if (Status != STATUS_SUCCESS) return;
 
     //
-    // Allocate the PCR page -- align it to 1MB (we only need 4KB)
+    // Allocate the PCR/KUSER_SHARED page -- align it to 1MB (we only need 2x4KB)
     //
     Base = MmAllocateMemoryWithType(2 * 1024 * 1024, LoaderStartupPcrPage);
+    MemBase = Base;
     Base = (PVOID)ROUND_UP(Base, 1 * 1024 * 1024);
     ArmLoaderBlock->u.Arm.PcrPage = (ULONG)Base >> PDE_SHIFT;
-
+    
+    //
+    // Build an entry for the KPCR and KUSER_SHARED_DATA
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderStartupPcrPage,
+                                         (ULONG_PTR)MemBase >> PAGE_SHIFT,
+                                         (2 * 1024 * 1024) / PAGE_SIZE,
+                                         0,
+                                         &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+    
     //
-    // Allocate PDR pages -- align them to 1MB (we only need 3xKB)
+    // Allocate PDR pages -- align them to 1MB (we only need 3x4KB)
     //
     Base = MmAllocateMemoryWithType(4 * 1024 * 1024, LoaderStartupPdrPage);
+    MemBase = Base;
     Base = (PVOID)ROUND_UP(Base, 1 * 1024 * 1024);
     ArmLoaderBlock->u.Arm.PdrPage = (ULONG)Base >> PDE_SHIFT;
-    
+
+    //
+    // Build an entry for the PDR, PRCB and initial KPROCESS/KTHREAD
+    //
+    Status = ArmCreateMemoryDescriptor(LoaderStartupPdrPage,
+                                         (ULONG_PTR)MemBase >> PAGE_SHIFT,
+                                         (4 * 1024 * 1024) / PAGE_SIZE,
+                                         0,
+                                         &Dummy);
+    if (Status != STATUS_SUCCESS) return;
+
     //
     // Set initial PRCB, Thread and Process on the last PDR page
     //
index 28d9966..08dc689 100644 (file)
 PARM_BOARD_CONFIGURATION_BLOCK ArmBoardBlock;
 ULONG BootDrive, BootPartition;
 VOID ArmPrepareForReactOS(IN BOOLEAN Setup);
+ADDRESS_RANGE ArmBoardMemoryMap[16];
+ULONG ArmBoardMemoryMapRangeCount;
 
 /* FUNCTIONS ******************************************************************/
 
 VOID
 ArmInit(IN PARM_BOARD_CONFIGURATION_BLOCK BootContext)
 {
+    ULONG i;
+
     //
     // Remember the pointer
     //
@@ -38,6 +42,22 @@ ArmInit(IN PARM_BOARD_CONFIGURATION_BLOCK BootContext)
     ASSERT((ArmBoardBlock->BoardType == MACH_TYPE_FEROCEON) ||
            (ArmBoardBlock->BoardType == MACH_TYPE_VERSATILE_PB));
 
+    //
+    // Save data required for memory initialization
+    //
+    ArmBoardMemoryMapRangeCount = ArmBoardBlock->MemoryMapEntryCount;
+    ASSERT(ArmBoardMemoryMapRangeCount != 0);
+    ASSERT(ArmBoardMemoryMapRangeCount < 16);
+    for (i = 0; i < ArmBoardMemoryMapRangeCount; i++)
+    {
+        //
+        // Copy each entry
+        //
+        RtlCopyMemory(&ArmBoardMemoryMap[i],
+                      &ArmBoardBlock->MemoryMap[i],
+                      sizeof(ADDRESS_RANGE));
+    }
+
     //
     // Call FreeLDR's portable entrypoint with our command-line
     //
index c6a1c24..396f478 100644 (file)
@@ -16,7 +16,10 @@ LdrPEGetExportByName(
 );
 
 extern BOOLEAN FrLdrLoadDriver(PCHAR szFileName, INT nPos);
-PVOID AnsiData, OemData, UnicodeData, RegistryData;
+ULONG Drivers;
+PVOID AnsiData, OemData, UnicodeData, RegistryData, KernelData, HalData, DriverData[16];
+ULONG RegistrySize, AnsiSize, OemSize, UnicodeSize, KernelSize, HalSize, DriverSize[16];
+
 /* MODULE MANAGEMENT **********************************************************/
 
 PLOADER_MODULE
@@ -101,19 +104,23 @@ FrLdrLoadModule(FILE *ModuleImage,
     if (!_stricmp(NameBuffer, "ansi.nls"))
     {
         AnsiData = (PVOID)NextModuleBase;
+        AnsiSize = LocalModuleSize;
     }
     else if (!_stricmp(NameBuffer, "oem.nls"))
     {
         OemData = (PVOID)NextModuleBase;
+        OemSize = LocalModuleSize;
     }
     else if (!_stricmp(NameBuffer, "casemap.nls"))
     {
         UnicodeData = (PVOID)NextModuleBase;
+        UnicodeSize = LocalModuleSize;
     }
     else if (!(_stricmp(NameBuffer, "system")) ||
              !(_stricmp(NameBuffer, "system.hiv")))
     {
         RegistryData = (PVOID)NextModuleBase;
+        RegistrySize = LocalModuleSize;
     }
 
     /* Load the file image */
@@ -548,6 +555,24 @@ FrLdrMapImage(IN FILE *Image,
     reactos_modules[ImageId].String = (ULONG_PTR)reactos_module_strings[ImageId];
     LoaderBlock.ModsCount++;
     
+    /* Detect kernel or HAL */
+    if (!_stricmp(Name, "ntoskrnl.exe"))
+    {
+        KernelData = (PVOID)NextModuleBase;
+        KernelSize = ImageSize;
+    }
+    else if (!_stricmp(Name, "hal.dll"))
+    {
+        HalData = (PVOID)NextModuleBase;
+        HalSize = ImageSize;
+    }
+    else
+    {
+        DriverData[Drivers] = (PVOID)NextModuleBase;
+        DriverSize[Drivers] = ImageSize;
+        Drivers++;
+    }
+    
     /* Increase the next Load Base */
     NextModuleBase = ROUND_UP(NextModuleBase + ImageSize, PAGE_SIZE);
     
index 558f1c1..255d899 100644 (file)
@@ -47,19 +47,87 @@ C_ASSERT(MM_ALLOCATION_GRANULARITY >= PAGE_SIZE);
 //
 typedef struct _HARDWARE_PTE_ARM
 {
-    ULONG Valid:1;
-    ULONG Write:1;
-    ULONG Owner:1;
-    ULONG WriteThrough:1;
-    ULONG CacheDisable:1;
-    ULONG Accessed:1;
-    ULONG Dirty:1;
-    ULONG LargePage:1;
-    ULONG Global:1;
-    ULONG CopyOnWrite:1;
-    ULONG Prototype: 1;
-    ULONG reserved: 1;
-    ULONG PageFrameNumber:20;
+    union
+    {
+        union
+        {
+            struct
+            {
+                ULONG Type:2;
+                ULONG Unused:30;
+            } Fault;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Ignored:2;
+                ULONG Reserved:1;
+                ULONG Domain:4;
+                ULONG Ignored1:1;
+                ULONG BaseAddress:22;
+            } Coarse;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Buffered:1;
+                ULONG Cached:1;
+                ULONG Reserved:1;
+                ULONG Domain:4;
+                ULONG Ignored:1;
+                ULONG Access:2;
+                ULONG Ignored1:8;
+                ULONG BaseAddress:12;
+            } Section;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Reserved:3;
+                ULONG Domain:4;
+                ULONG Ignored:3;
+                ULONG BaseAddress:20;
+            } Fine;
+        } L1;
+        union
+        {
+            struct
+            {
+                ULONG Type:2;
+                ULONG Unused:30;
+            } Fault;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Buffered:1;
+                ULONG Cached:1;
+                ULONG Access0:2;
+                ULONG Access1:2;
+                ULONG Access2:2;
+                ULONG Access3:2;
+                ULONG Ignored:4;
+                ULONG BaseAddress:16;
+            } Large;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Buffered:1;
+                ULONG Cached:1;
+                ULONG Access0:2;
+                ULONG Access1:2;
+                ULONG Access2:2;
+                ULONG Access3:2;
+                ULONG BaseAddress:20;
+            } Small;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Buffered:1;
+                ULONG Cached:1;
+                ULONG Access0:2;
+                ULONG Ignored:4;
+                ULONG BaseAddress:22;
+            } Tiny; 
+        } L2;
+        ULONG AsUlong;
+    };
 } HARDWARE_PTE_ARM, *PHARDWARE_PTE_ARM;
 
 typedef struct _MMPTE_SOFTWARE
@@ -117,19 +185,87 @@ typedef struct _MMPTE_LIST
 
 typedef struct _MMPTE_HARDWARE
 {
-    ULONG Valid:1;
-    ULONG Write:1;
-    ULONG Owner:1;
-    ULONG WriteThrough:1;
-    ULONG CacheDisable:1;
-    ULONG Accessed:1;
-    ULONG Dirty:1;
-    ULONG LargePage:1;
-    ULONG Global:1;
-    ULONG CopyOnWrite:1;
-    ULONG Prototype:1;
-    ULONG reserved:1;
-    ULONG PageFrameNumber:20;
+    union
+    {
+        union
+        {
+            struct
+            {
+                ULONG Type:2;
+                ULONG Unused:30;
+            } Fault;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Ignored:2;
+                ULONG Reserved:1;
+                ULONG Domain:4;
+                ULONG Ignored1:1;
+                ULONG BaseAddress:22;
+            } Coarse;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Buffered:1;
+                ULONG Cached:1;
+                ULONG Reserved:1;
+                ULONG Domain:4;
+                ULONG Ignored:1;
+                ULONG Access:2;
+                ULONG Ignored1:8;
+                ULONG BaseAddress:12;
+            } Section;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Reserved:3;
+                ULONG Domain:4;
+                ULONG Ignored:3;
+                ULONG BaseAddress:20;
+            } Fine;
+        } L1;
+        union
+        {
+            struct
+            {
+                ULONG Type:2;
+                ULONG Unused:30;
+            } Fault;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Buffered:1;
+                ULONG Cached:1;
+                ULONG Access0:2;
+                ULONG Access1:2;
+                ULONG Access2:2;
+                ULONG Access3:2;
+                ULONG Ignored:4;
+                ULONG BaseAddress:16;
+            } Large;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Buffered:1;
+                ULONG Cached:1;
+                ULONG Access0:2;
+                ULONG Access1:2;
+                ULONG Access2:2;
+                ULONG Access3:2;
+                ULONG BaseAddress:20;
+            } Small;
+            struct
+            {
+                ULONG Type:2;
+                ULONG Buffered:1;
+                ULONG Cached:1;
+                ULONG Access0:2;
+                ULONG Ignored:4;
+                ULONG BaseAddress:22;
+            } Tiny; 
+        } L2;
+        ULONG AsUlong;
+    };
 } MMPTE_HARDWARE, *PMMPTE_HARDWARE;
 
 //
index a8f150f..3906c45 100644 (file)
@@ -174,5 +174,6 @@ KeFlushTb(
 );
 
 #define KeArchInitThreadWithContext KeArmInitThreadWithContext
+#define KiSystemStartupReal KiSystemStartup
 
 #endif
index 6e46981..20ef06b 100644 (file)
@@ -113,6 +113,7 @@ typedef struct _ARM_TRANSLATION_TABLE
 typedef struct _ARM_COARSE_PAGE_TABLE
 {
     ARM_PTE Pte[256];
+    ULONG Padding[768];
 } ARM_COARSE_PAGE_TABLE, *PARM_COARSE_PAGE_TABLE;
 
 typedef enum _ARM_L1_PTE_TYPE
index af68c61..69a5973 100644 (file)
@@ -17,7 +17,7 @@
 //
 // UART Registers
 //
-#define UART_BASE (void*)0xc00f1000 /* HACK: freeldr mapped it here */
+#define UART_BASE (void*)0xe00f1000 /* HACK: freeldr mapped it here */
 
 #define UART_PL01x_DR            (UART_BASE + 0x00)
 #define UART_PL01x_RSR           (UART_BASE + 0x04)
index 619ac57..1d9a0b3 100644 (file)
@@ -771,7 +771,7 @@ KiRosAllocateNtDescriptor(IN TYPE_OF_MEMORY MemoryType,
         if (MdBlock)
         {
             /* If it contains our limit as well, break out early */
-            if ((MdBlock->PageCount + MdBlock->BasePage) > AlignedLimit) break;
+            if ((MdBlock->PageCount + MdBlock->BasePage) >= AlignedLimit) break;
         }
 
         /* Loop the memory list */
index fd8a82b..75b4331 100644 (file)
     while (TRUE); \
 }
 
+//
+// Take 0x80812345 and extract:
+// PTE_BASE[0x808][0x12]
+//
+#define MiGetPteAddress(x)         \
+    (PMMPTE)(PTE_BASE + (((ULONG)(x) >> 20) << 12) + ((((ULONG)(x) >> 12) & 0xFF) << 2))
+
+#define MiGetPdeAddress(x)         \
+    (PMMPTE)(PDE_BASE + (((ULONG)(x) >> 20) << 2))
+
+#define MiGetPdeOffset(x) (((ULONG)(x)) >> 22)
+
+#define PTE_BASE    0xC0000000
+#define PDE_BASE    0xC1000000
+#define HYPER_SPACE ((PVOID)0xC1100000)
+
+ULONG MmGlobalKernelPageDirectory[1024];
+MMPTE MiArmTemplatePte, MiArmTemplatePde;
+
+VOID
+KiFlushSingleTb(IN BOOLEAN Invalid,
+                IN PVOID Virtual);
+
 /* FUNCTIONS ******************************************************************/
 
 VOID
@@ -71,10 +94,9 @@ PULONG
 MmGetPageDirectory(VOID)
 {
     //
-    // TODO
+    // Return the TTB
     //
-    UNIMPLEMENTED;
-    return 0;
+    return (PULONG)KeArmTranslationTableRegisterGet().AsUlong;
 }
 
 
@@ -96,10 +118,65 @@ NTAPI
 MmDeletePageTable(IN PEPROCESS Process,
                   IN PVOID Address)
 {
+    PMMPTE PointerPde;
+    
     //
-    // TODO
+    // Not valid for kernel addresses
     //
-    UNIMPLEMENTED;
+    DPRINT1("MmDeletePageTable(%p, %p)\n", Process, Address);
+    ASSERT(Address < MmSystemRangeStart);
+    
+    //
+    // Check if this is for a different process
+    //
+    if ((Process) && (Process != PsGetCurrentProcess()))
+    {
+        //
+        // TODO
+        //
+        UNIMPLEMENTED;
+        return;
+    }
+       
+    //
+    // Get the PDE
+    //
+    PointerPde = MiGetPdeAddress(Address);
+
+    //
+    // On ARM, we use a section mapping for the original low-memory mapping
+    //
+    if ((Address) || (PointerPde->u.Hard.L1.Section.Type != SectionPte))
+    {
+        //
+        // Make sure it's valid
+        //
+        ASSERT(PointerPde->u.Hard.L1.Coarse.Type == CoarsePte);
+    }
+    
+    //
+    // Clear the PDE
+    //
+    PointerPde->u.Hard.AsUlong = 0;
+    ASSERT(PointerPde->u.Hard.L1.Fault.Type == FaultPte);
+    
+    //
+    // Check if this is a kernel PDE
+    //
+    if ((PointerPde >= (PMMPTE)PTE_BASE) && (PointerPde < (PMMPTE)PTE_BASE + (1024 * 1024)))
+    {
+        //
+        // Invalidate the TLB entry
+        //
+        KiFlushSingleTb(TRUE, Address);
+    }
+    else
+    {
+        //
+        // Process PDE, unmap it from hyperspace (will also invalidate TLB entry)
+        //
+        MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(PointerPde));
+    }
 }
 
 PFN_TYPE
@@ -215,11 +292,38 @@ NTAPI
 MmIsPagePresent(IN PEPROCESS Process,
                 IN PVOID Address)
 {
+    PMMPTE Pte;
+    
     //
-    // TODO
+    // Check if this is for a different process
     //
-    UNIMPLEMENTED;
-    return 0;
+    if ((Process) && (Process != PsGetCurrentProcess()))
+    {
+        //
+        // TODO
+        //
+        UNIMPLEMENTED;
+        return 0;
+    }
+
+    //
+    // Get the PDE
+    //
+    Pte = MiGetPdeAddress(Address);
+    if (Pte->u.Hard.L1.Fault.Type != FaultPte)
+    {
+        //
+        // Get the PTE
+        //
+        Pte = MiGetPteAddress(Address);
+    }
+    
+    //
+    // Return whether or not it's valid
+    //
+    return (Pte->u.Hard.L1.Fault.Type != FaultPte);
+    
+    
 }
 
 BOOLEAN
@@ -237,15 +341,107 @@ MmIsPageSwapEntry(IN PEPROCESS Process,
 NTSTATUS
 NTAPI
 MmCreateVirtualMappingForKernel(IN PVOID Address,
-                                IN ULONG flProtect,
-                                IN PPFN_TYPE Pages,
+                                IN ULONG Protection,
+                                IN PPFN_NUMBER Pages,
                                 IN ULONG PageCount)
 {
+    PMMPTE PointerPte, LastPte, PointerPde, LastPde;
+    MMPTE TempPte, TempPde;
+    NTSTATUS Status;
+    PFN_NUMBER Pfn;
+    DPRINT1("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n",
+            Address, Protection, *Pages, PageCount);
+    ASSERT(Address >= MmSystemRangeStart);
+
+    //
+    // Get our templates
+    //
+    TempPte = MiArmTemplatePte;
+    TempPde = MiArmTemplatePde;
+
+    //
+    // Check if we have PDEs for this region
+    //
+    PointerPde = MiGetPdeAddress(Address);
+    LastPde = PointerPde + (PageCount / 256);
+    while (PointerPde <= LastPde)
+    {
+        //
+        // Check if we need to allocate the PDE
+        //
+        if (PointerPde->u.Hard.L1.Fault.Type == FaultPte)
+        {
+            //
+            // Request a page
+            //
+            Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
+            if (!NT_SUCCESS(Status)) return Status;
+            
+            //
+            // Setup the PFN
+            //
+            TempPde.u.Hard.L1.Coarse.BaseAddress = (Pfn << PAGE_SHIFT) >> CPT_SHIFT;
+            
+            //
+            // Write the PDE
+            //
+            ASSERT(PointerPde->u.Hard.L1.Fault.Type == FaultPte);
+            ASSERT(TempPde.u.Hard.L1.Coarse.Type == CoarsePte);
+            *PointerPde = TempPde;
+            
+            //
+            // Get the PTE for this 1MB region
+            //
+            PointerPte = MiGetPteAddress(MiGetPteAddress(Address));
+            
+            //
+            // Write the PFN of the PDE
+            //
+            TempPte.u.Hard.L2.Small.BaseAddress = Pfn;
+
+            //
+            // Write the PTE
+            //
+            ASSERT(PointerPte->u.Hard.L2.Fault.Type == FaultPte);
+            ASSERT(TempPte.u.Hard.L2.Small.Type == SmallPte);
+            *PointerPte = TempPte;
+        }
+        
+        //
+        // Next
+        //
+        PointerPde++;
+    }
+    
     //
-    // TODO
+    // Get start and end address and loop each PTE
+    //
+    PointerPte = MiGetPteAddress(Address);
+    LastPte = PointerPte + PageCount - 1;
+    while (PointerPte <= LastPte)
+    {
+        //
+        // Set the PFN
+        //
+        TempPte.u.Hard.L2.Small.BaseAddress = *Pages++;
+        
+        //
+        // Write the PTE
+        //
+        ASSERT(PointerPte->u.Hard.L2.Fault.Type == FaultPte);
+        ASSERT(TempPte.u.Hard.L2.Small.Type == SmallPte);
+        *PointerPte = TempPte;
+        
+        //
+        // Next
+        //
+        PointerPte++;
+    }
+    
     //
-    UNIMPLEMENTED;
-    return 0;
+    // All done
+    //
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
@@ -265,10 +461,27 @@ NTSTATUS
 NTAPI
 MmCreateVirtualMappingUnsafe(IN PEPROCESS Process,
                              IN PVOID Address,
-                             IN ULONG flProtect,
+                             IN ULONG Protection,
                              IN PPFN_TYPE Pages,
                              IN ULONG PageCount)
 {
+    DPRINT1("MmCreateVirtualMappingUnsafe(%p %x, %x, %x, %d)\n",
+            Process, Address, Protection, *Pages, PageCount);
+    
+    //
+    // Are we only handling the kernel?
+    //
+    if (!Process)
+    {
+        //
+        // Call the kernel version
+        //
+        return MmCreateVirtualMappingForKernel(Address,
+                                               Protection,
+                                               Pages,
+                                               PageCount);
+    }
+    
     //
     // TODO
     //
@@ -280,15 +493,33 @@ NTSTATUS
 NTAPI
 MmCreateVirtualMapping(IN PEPROCESS Process,
                        IN PVOID Address,
-                       IN ULONG flProtect,
+                       IN ULONG Protection,
                        IN PPFN_TYPE Pages,
                        IN ULONG PageCount)
 {
+    ULONG i;
+    DPRINT1("MmCreateVirtualMapping(%p %x, %x, %x, %d)\n",
+            Process, Address, Protection, *Pages, PageCount);
+    
     //
-    // TODO
+    // Loop each page
     //
-    UNIMPLEMENTED;
-    return 0;
+    for (i = 0; i < PageCount; i++)
+    {
+        //
+        // Make sure the page is marked as in use
+        //
+        ASSERT(MmIsPageInUse(Pages[i]));
+    }
+    
+    //
+    // Call the unsafe version
+    //
+    return MmCreateVirtualMappingUnsafe(Process,
+                                        Address,
+                                        Protection,
+                                        Pages,
+                                        PageCount);
 }
 
 ULONG
@@ -307,12 +538,12 @@ VOID
 NTAPI
 MmSetPageProtect(IN PEPROCESS Process,
                  IN PVOID Address,
-                 IN ULONG flProtect)
+                 IN ULONG Protection)
 {
     //
-    // TODO
+    // We don't enforce any protection on the pages -- they are all RWX
     //
-    UNIMPLEMENTED;
+    return;
 }
 
 /*
@@ -335,34 +566,124 @@ PVOID
 NTAPI
 MmCreateHyperspaceMapping(IN PFN_TYPE Page)
 {
+    PMMPTE PointerPte, FirstPte, LastPte;
+    MMPTE TempPte;
+    PVOID Address;
+    DPRINT1("MmCreateHyperspaceMapping(%lx)\n", Page);
+
+    //
+    // Loop hyperspace PTEs (1MB)
+    //
+    FirstPte = PointerPte = MiGetPteAddress(HYPER_SPACE);
+    LastPte = PointerPte + 256;
+    while (PointerPte <= LastPte)
+    {
+        //
+        // Find a free slot
+        //
+        if (PointerPte->u.Hard.L2.Fault.Type == FaultPte)
+        {
+            //
+            // Use this entry
+            //
+            break;
+        }
+        
+        //
+        // Try the next one
+        //
+        PointerPte++;
+    }
+    
     //
-    // TODO
+    // Check if we didn't find anything
     //
-    UNIMPLEMENTED;
-    return 0;
+    if (PointerPte > LastPte) return NULL;
+    
+    //
+    // Create the mapping
+    //
+    TempPte = MiArmTemplatePte;
+    TempPte.u.Hard.L2.Small.BaseAddress = Page;
+    ASSERT(PointerPte->u.Hard.L2.Fault.Type == FaultPte);
+    ASSERT(TempPte.u.Hard.L2.Small.Type == SmallPte);
+    *PointerPte = TempPte;
+
+    //
+    // Return the address
+    //
+    Address = HYPER_SPACE + ((PointerPte - FirstPte) * PAGE_SIZE);
+    KiFlushSingleTb(FALSE, Address);
+    DPRINT1("MmCreateHyperspaceMapping(%lx)\n", Address);
+    return Address;
 }
 
 PFN_TYPE
 NTAPI
 MmDeleteHyperspaceMapping(IN PVOID Address)
 {
-    PFN_TYPE Pfn = {0};
-      
+    PFN_TYPE Pfn;
+    PMMPTE PointerPte;
+    DPRINT1("MmDeleteHyperspaceMapping(%lx)\n", Address);
+    
     //
-    // TODO
+    // Get the PTE
     //
-    UNIMPLEMENTED;
+    PointerPte = MiGetPteAddress(Address);
+    ASSERT(PointerPte->u.Hard.L2.Small.Type == SmallPte);
+    
+    //
+    // Save the PFN
+    //
+    Pfn = PointerPte->u.Hard.L2.Small.BaseAddress;
+    
+    //
+    // Destroy the PTE
+    //
+    PointerPte->u.Hard.AsUlong = 0;
+    ASSERT(PointerPte->u.Hard.L2.Fault.Type == FaultPte);
+    
+    //
+    // Flush the TLB entry and return the PFN
+    //
+    KiFlushSingleTb(TRUE, Address);
     return Pfn;
+    
 }
 
 VOID
 NTAPI
 MmInitGlobalKernelPageDirectory(VOID)
 {
+    ULONG i;
+    PULONG CurrentPageDirectory = (PULONG)PDE_BASE;
+    
     //
-    // TODO
-    //
-    UNIMPLEMENTED;
+    // Good place to setup template PTE/PDEs.
+    // We are lazy and pick a known-good PTE
+    //
+    MiArmTemplatePte = *MiGetPteAddress(0x80000000);
+    MiArmTemplatePde = *MiGetPdeAddress(0x80000000);
+
+    //
+    // Loop the 2GB of address space which belong to the kernel
+    //
+    for (i = MiGetPdeOffset(MmSystemRangeStart); i < 1024; i++)
+    {
+        //
+        // Check if we have an entry for this already
+        //
+        if ((i != MiGetPdeOffset(PTE_BASE)) &&
+            (i != MiGetPdeOffset(HYPER_SPACE)) &&
+            (!MmGlobalKernelPageDirectory[i]) &&
+            (CurrentPageDirectory[i]))
+        {
+            //
+            // We don't, link it in our global page directory
+            //
+            MmGlobalKernelPageDirectory[i] = CurrentPageDirectory[i];
+        }
+    }
 }
 
 ULONG
@@ -380,8 +701,55 @@ VOID
 NTAPI
 MiInitPageDirectoryMap(VOID)
 {
+    MEMORY_AREA* MemoryArea = NULL;
+    PHYSICAL_ADDRESS BoundaryAddressMultiple;
+    PVOID BaseAddress;
+    NTSTATUS Status;
+    DPRINT1("MiInitPageDirectoryMap()\n");
+
+    //
+    // Create memory area for the PTE area
+    //
+    BoundaryAddressMultiple.QuadPart = 0;
+    BaseAddress = (PVOID)PTE_BASE;
+    Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
+                                MEMORY_AREA_SYSTEM,
+                                &BaseAddress,
+                                0x1000000,
+                                PAGE_READWRITE,
+                                &MemoryArea,
+                                TRUE,
+                                0,
+                                BoundaryAddressMultiple);
+    ASSERT(NT_SUCCESS(Status));
+
+    //
+    // Create memory area for the PDE area
+    //
+    BaseAddress = (PVOID)PDE_BASE;
+    Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
+                                MEMORY_AREA_SYSTEM,
+                                &BaseAddress,
+                                0x100000,
+                                PAGE_READWRITE,
+                                &MemoryArea,
+                                TRUE,
+                                0,
+                                BoundaryAddressMultiple);
+    ASSERT(NT_SUCCESS(Status));
+    
     //
-    // TODO
-    //
-    UNIMPLEMENTED;
+    // And finally, hyperspace
+    //
+    BaseAddress = (PVOID)HYPER_SPACE;
+    Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
+                                MEMORY_AREA_SYSTEM,
+                                &BaseAddress,
+                                PAGE_SIZE,
+                                PAGE_READWRITE,
+                                &MemoryArea,
+                                TRUE,
+                                0,
+                                BoundaryAddressMultiple);
+    ASSERT(NT_SUCCESS(Status));
 }
index bdd67ec..7a7d04d 100644 (file)
@@ -347,9 +347,7 @@ MiGetLastKernelAddress(VOID)
          NextEntry = NextEntry->Flink)
     {
         Md = CONTAINING_RECORD(NextEntry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
-        if (Md->MemoryType == LoaderBootDriver ||
-            Md->MemoryType == LoaderSystemCode ||
-            Md->MemoryType == LoaderHalCode)
+        if (Md->MemoryType != LoaderFree)
         {
             if (Md->BasePage+Md->PageCount > LastKrnlPhysAddr)
                 LastKrnlPhysAddr = Md->BasePage+Md->PageCount;   
@@ -432,10 +430,13 @@ MmInit1(VOID)
     MmPagedPoolBase = (PVOID)PAGE_ROUND_UP((ULONG_PTR)MiNonPagedPoolStart +
                                            MiNonPagedPoolLength);
     MmPagedPoolSize = MM_PAGED_POOL_SIZE;
+    
     /* Dump kernel memory layout */
     MiDbgKernelLayout();
+    
     /* Initialize the page list */
     MmInitializePageList();
+    
     /* Unmap low memory */
     MmDeletePageTable(NULL, 0);