From 0b44376e2798ba55e9e2f9531ebfb6e774adea16 Mon Sep 17 00:00:00 2001 From: ReactOS Portable Systems Group Date: Mon, 10 Mar 2008 17:27:14 +0000 Subject: [PATCH] ARM Port Memory Management Checkpoint: - 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 | 66 ++ .../boot/freeldr/freeldr/arch/arm/loader.c | 1052 ++++++++++++++++- .../boot/freeldr/freeldr/arch/arm/macharm.c | 20 + .../boot/freeldr/freeldr/reactos/imageldr.c | 27 +- reactos/include/ndk/arm/mmtypes.h | 188 ++- reactos/ntoskrnl/include/internal/arm/ke.h | 1 + reactos/ntoskrnl/include/internal/arm/mm.h | 1 + reactos/ntoskrnl/ke/arm/arm_kprintf.c | 2 +- reactos/ntoskrnl/ke/freeldr.c | 2 +- reactos/ntoskrnl/mm/arm/stubs.c | 432 ++++++- reactos/ntoskrnl/mm/mminit.c | 7 +- 11 files changed, 1704 insertions(+), 94 deletions(-) diff --git a/reactos/boot/freeldr/freeldr/arch/arm/boot.s b/reactos/boot/freeldr/freeldr/arch/arm/boot.s index bafcd28de61..3c046c0c622 100644 --- a/reactos/boot/freeldr/freeldr/arch/arm/boot.s +++ b/reactos/boot/freeldr/freeldr/arch/arm/boot.s @@ -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: diff --git a/reactos/boot/freeldr/freeldr/arch/arm/loader.c b/reactos/boot/freeldr/freeldr/arch/arm/loader.c index 1d1a97be655..9881224d277 100644 --- a/reactos/boot/freeldr/freeldr/arch/arm/loader.c +++ b/reactos/boot/freeldr/freeldr/arch/arm/loader.c @@ -13,8 +13,16 @@ #include #include +#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; - + // - // Allocate PDR pages -- align them to 1MB (we only need 3xKB) + // 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 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 // diff --git a/reactos/boot/freeldr/freeldr/arch/arm/macharm.c b/reactos/boot/freeldr/freeldr/arch/arm/macharm.c index 28d99662b89..08dc68918b3 100644 --- a/reactos/boot/freeldr/freeldr/arch/arm/macharm.c +++ b/reactos/boot/freeldr/freeldr/arch/arm/macharm.c @@ -15,12 +15,16 @@ 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 // diff --git a/reactos/boot/freeldr/freeldr/reactos/imageldr.c b/reactos/boot/freeldr/freeldr/reactos/imageldr.c index c6a1c24605a..396f47874f8 100644 --- a/reactos/boot/freeldr/freeldr/reactos/imageldr.c +++ b/reactos/boot/freeldr/freeldr/reactos/imageldr.c @@ -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); diff --git a/reactos/include/ndk/arm/mmtypes.h b/reactos/include/ndk/arm/mmtypes.h index 558f1c1d67a..255d89921f1 100644 --- a/reactos/include/ndk/arm/mmtypes.h +++ b/reactos/include/ndk/arm/mmtypes.h @@ -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; // diff --git a/reactos/ntoskrnl/include/internal/arm/ke.h b/reactos/ntoskrnl/include/internal/arm/ke.h index a8f150f36d9..3906c45b456 100644 --- a/reactos/ntoskrnl/include/internal/arm/ke.h +++ b/reactos/ntoskrnl/include/internal/arm/ke.h @@ -174,5 +174,6 @@ KeFlushTb( ); #define KeArchInitThreadWithContext KeArmInitThreadWithContext +#define KiSystemStartupReal KiSystemStartup #endif diff --git a/reactos/ntoskrnl/include/internal/arm/mm.h b/reactos/ntoskrnl/include/internal/arm/mm.h index 6e4698174da..20ef06bd4c7 100644 --- a/reactos/ntoskrnl/include/internal/arm/mm.h +++ b/reactos/ntoskrnl/include/internal/arm/mm.h @@ -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 diff --git a/reactos/ntoskrnl/ke/arm/arm_kprintf.c b/reactos/ntoskrnl/ke/arm/arm_kprintf.c index af68c618ff6..69a59736673 100644 --- a/reactos/ntoskrnl/ke/arm/arm_kprintf.c +++ b/reactos/ntoskrnl/ke/arm/arm_kprintf.c @@ -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) diff --git a/reactos/ntoskrnl/ke/freeldr.c b/reactos/ntoskrnl/ke/freeldr.c index 619ac57d224..1d9a0b31ba8 100644 --- a/reactos/ntoskrnl/ke/freeldr.c +++ b/reactos/ntoskrnl/ke/freeldr.c @@ -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 */ diff --git a/reactos/ntoskrnl/mm/arm/stubs.c b/reactos/ntoskrnl/mm/arm/stubs.c index fd8a82b6a49..75b4331e8bd 100644 --- a/reactos/ntoskrnl/mm/arm/stubs.c +++ b/reactos/ntoskrnl/mm/arm/stubs.c @@ -20,6 +20,29 @@ 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); + // - // TODO + // Get our templates // - UNIMPLEMENTED; - return 0; + 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++; + } + + // + // 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++; + } + + // + // 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); + // - // TODO + // Loop hyperspace PTEs (1MB) // - UNIMPLEMENTED; - return 0; + 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++; + } + + // + // Check if we didn't find anything + // + 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 + // Good place to setup template PTE/PDEs. + // We are lazy and pick a known-good PTE // - UNIMPLEMENTED; + 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"); + // - // TODO + // Create memory area for the PTE area // - UNIMPLEMENTED; + 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)); + + // + // 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)); } diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c index bdd67eca134..7a7d04d0531 100644 --- a/reactos/ntoskrnl/mm/mminit.c +++ b/reactos/ntoskrnl/mm/mminit.c @@ -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);