2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/arm/stubs.c
5 * PURPOSE: ARM Memory Manager
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 ULONG MmGlobalKernelPageDirectory
[1024];
18 MMPTE MiArmTemplatePte
;
19 MMPDE_HARDWARE MiArmTemplatePde
;
21 /* PRIVATE FUNCTIONS **********************************************************/
25 MiUnmapPageTable(IN PMMPTE PointerPde
)
28 // Check if this address belongs to the kernel
30 if (((ULONG_PTR
)PointerPde
> PDE_BASE
) ||
31 ((ULONG_PTR
)PointerPde
< (PDE_BASE
+ 1024*1024)))
40 // FIXME-USER: Shouldn't get here yet
48 MiFlushTlb(IN PMMPTE PointerPte
,
52 // Make sure the PTE is valid, and unmap the pagetable if user-mode
54 if (((PointerPte
) && (MiUnmapPageTable(PointerPte
))) ||
55 (Address
>= MmSystemRangeStart
))
58 // Invalidate this page
60 KeArmInvalidateTlbEntry(Address
);
66 MiGetPageTableForProcess(IN PEPROCESS Process
,
72 PMMPDE_HARDWARE PointerPde
;
73 MMPDE_HARDWARE TempPde
;
79 // Check if this is a user-mode, non-kernel or non-current address
81 if ((Address
< MmSystemRangeStart
) &&
83 (Process
!= PsGetCurrentProcess()))
86 // FIXME-USER: No user-mode memory support
94 TempPde
= MiArmTemplatePde
;
95 TempPte
= MiArmTemplatePte
;
100 PointerPde
= MiGetPdeAddress(Address
);
101 if (PointerPde
->u
.Hard
.Coarse
.Valid
)
104 // Invalid PDE, is this a kernel address?
106 if (Address
>= MmSystemRangeStart
)
109 // Does it exist in the kernel page directory?
111 //PdeOffset = MiGetPdeOffset(Address);
112 //if (MmGlobalKernelPageDirectory[PdeOffset] == 0)
115 // It doesn't. Is this a create operation? If not, fail
117 if (Create
== FALSE
) return NULL
;
119 DPRINT1("Must create a page for: %p PDE: %p\n", // Offset: %lx!\n",
120 Address
, PointerPde
);//, PdeOffset);
123 // Allocate a non paged pool page for the PDE
125 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
126 if (!NT_SUCCESS(Status
)) return NULL
;
131 TempPde
.u
.Hard
.Coarse
.PageFrameNumber
= (Pfn
<< PAGE_SHIFT
) >> CPT_SHIFT
;
136 ASSERT(PointerPde
->u
.Hard
.Coarse
.Valid
== 0);
137 ASSERT(TempPde
.u
.Hard
.Coarse
.Valid
== 1);
138 *PointerPde
= TempPde
;
143 //MmGlobalKernelPageDirectory[PdeOffset] = TempPde.u.Hard.AsUlong;
144 //DPRINT1("KPD: %p PDEADDR: %p\n", &MmGlobalKernelPageDirectory[PdeOffset], MiGetPdeAddress(Address));
147 // FIXFIX: Double check with Felix tomorrow
151 // Get the PTE for this 1MB region
153 PointerPte
= MiGetPteAddress(MiGetPteAddress(Address
));
154 DPRINT1("PointerPte: %p\n", PointerPte
);
157 // Write the PFN of the PDE
159 TempPte
.u
.Hard
.PageFrameNumber
= Pfn
;
164 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
165 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
166 *PointerPte
= TempPte
;
171 // Now set the actual PDE
173 //PointerPde = (PMMPTE)&MmGlobalKernelPageDirectory[PdeOffset];
178 // Is this a create operation? If not, fail
180 if (Create
== FALSE
) return NULL
;
183 // THIS WHOLE PATH IS TODO
189 // Allocate a non paged pool page for the PDE
191 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
192 if (!NT_SUCCESS(Status
)) return NULL
;
195 // Make the entry valid
197 TempPde
.u
.Hard
.AsUlong
= 0xDEADBEEF;
202 *PointerPde
= TempPde
;
209 return MiGetPteAddress(Address
);
214 MiGetPageEntryForProcess(IN PEPROCESS Process
,
219 Pte
.u
.Hard
.AsUlong
= 0;
224 PointerPte
= MiGetPageTableForProcess(Process
, Address
, FALSE
);
228 // Capture the PTE value and unmap the page table
231 MiUnmapPageTable(PointerPte
);
235 // Return the PTE value
242 MmDeletePageTable(IN PEPROCESS Process
,
245 PMMPDE_HARDWARE PointerPde
;
248 // Not valid for kernel addresses
250 DPRINT("MmDeletePageTable(%p, %p)\n", Process
, Address
);
251 ASSERT(Address
< MmSystemRangeStart
);
254 // Check if this is for a different process
256 if ((Process
) && (Process
!= PsGetCurrentProcess()))
259 // FIXME-USER: Need to attach to the process
267 PointerPde
= MiGetPdeAddress(Address
);
270 // On ARM, we use a section mapping for the original low-memory mapping
272 if ((Address
) || (PointerPde
->u
.Hard
.Section
.Valid
== 0))
275 // Make sure it's valid
277 ASSERT(PointerPde
->u
.Hard
.Coarse
.Valid
== 1);
283 PointerPde
->u
.Hard
.AsUlong
= 0;
284 ASSERT(PointerPde
->u
.Hard
.Coarse
.Valid
== 0);
287 // Invalidate the TLB entry
289 MiFlushTlb((PMMPTE
)PointerPde
, MiGetPteAddress(Address
));
294 MmCreateProcessAddressSpace(IN ULONG MinWs
,
295 IN PEPROCESS Process
,
296 IN PULONG DirectoryTableBase
)
301 PMMPDE_HARDWARE PageDirectory
, PointerPde
;
302 MMPDE_HARDWARE TempPde
;
306 // Loop two tables (Hyperspace and TTB). Each one is 16KB
309 for (i
= 0; i
< 8; i
++)
314 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
[i
]);
315 if (!NT_SUCCESS(Status
)) ASSERT(FALSE
);
321 PageDirectory
= MmCreateHyperspaceMapping(Pfn
[0]);
324 // Copy the PDEs for kernel-mode
326 RtlCopyMemory(PageDirectory
+ MiGetPdeOffset(MmSystemRangeStart
),
327 MmGlobalKernelPageDirectory
+ MiGetPdeOffset(MmSystemRangeStart
),
328 (1024 - MiGetPdeOffset(MmSystemRangeStart
)) * sizeof(ULONG
));
332 // Setup the PDE for the table base
334 TempPde
= MiArmTemplatePde
;
335 TempPde
.u
.Hard
.Coarse
.PageFrameNumber
= (Pfn
[0] << PAGE_SHIFT
) >> CPT_SHIFT
;
336 PointerPde
= &PageDirectory
[MiGetPdeOffset(PTE_BASE
)];
341 ASSERT(PointerPde
->u
.Hard
.Coarse
.Valid
== 0);
342 ASSERT(TempPde
.u
.Hard
.Coarse
.Valid
== 1);
343 *PointerPde
= TempPde
;
346 // Setup the PDE for the hyperspace
348 TempPde
.u
.Hard
.Coarse
.PageFrameNumber
= (Pfn
[1] << PAGE_SHIFT
) >> CPT_SHIFT
;
349 PointerPde
= &PageDirectory
[MiGetPdeOffset(HYPER_SPACE
)];
354 ASSERT(PointerPde
->u
.Hard
.Coarse
.Valid
== 0);
355 ASSERT(TempPde
.u
.Hard
.Coarse
.Valid
== 1);
356 *PointerPde
= TempPde
;
359 // Unmap the page directory
361 MmDeleteHyperspaceMapping(PageDirectory
);
364 // Return the page table base
366 DirectoryTableBase
[0] = Pfn
[0] << PAGE_SHIFT
;
372 MmUpdatePageDir(IN PEPROCESS Process
,
384 Mmi386ReleaseMmInfo(IN PEPROCESS Process
)
387 // FIXME-USER: Need to delete address space
396 MmInitializeHandBuiltProcess(IN PEPROCESS Process
,
397 IN PULONG DirectoryTableBase
)
400 // Share the directory base with the idle process
402 DirectoryTableBase
[0] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0];
403 DirectoryTableBase
[1] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[1];
406 // Initialize the Addresss Space
408 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
409 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= NULL
;
412 // The process now has an address space
414 Process
->HasAddressSpace
= TRUE
;
415 return STATUS_SUCCESS
;
420 MmGetPageDirectory(VOID
)
425 return (PULONG
)KeArmTranslationTableRegisterGet().AsUlong
;
430 MmDisableVirtualMapping(IN PEPROCESS Process
,
432 OUT PBOOLEAN WasDirty
,
433 OUT PPFN_NUMBER Page
)
444 MmEnableVirtualMapping(IN PEPROCESS Process
,
456 MmCreateVirtualMappingInternal(IN PEPROCESS Process
,
459 IN PPFN_NUMBER Pages
,
461 IN BOOLEAN MarkAsMapped
)
463 PMMPTE PointerPte
= NULL
;
466 ULONG OldPdeOffset
, PdeOffset
, i
;
467 DPRINT("[KMAP]: %p %d\n", Address
, PageCount
);
468 //ASSERT(Address >= MmSystemRangeStart);
471 // Get our template PTE
473 TempPte
= MiArmTemplatePte
;
479 OldPdeOffset
= MiGetPdeOffset(Addr
) + 1;
480 for (i
= 0; i
< PageCount
; i
++)
483 // Get the next PDE offset and check if it's a new one
485 PdeOffset
= MiGetPdeOffset(Addr
);
486 if (OldPdeOffset
!= PdeOffset
)
489 // Get rid of the old L2 Table, if this was the last PTE on it
491 MiUnmapPageTable(PointerPte
);
494 // Get the PTE for this address, and create the PDE for it
496 PointerPte
= MiGetPageTableForProcess(NULL
, Addr
, TRUE
);
502 // Go to the next PTE on this PDE
509 // Save the current PDE
511 OldPdeOffset
= PdeOffset
;
516 TempPte
.u
.Hard
.PageFrameNumber
= *Pages
++;
521 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
522 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
523 *PointerPte
= TempPte
;
526 // Move to the next page
528 Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
);
534 return STATUS_SUCCESS
;
539 MmCreateVirtualMappingForKernel(IN PVOID Address
,
541 IN PPFN_NUMBER Pages
,
545 // Call the internal version
547 return MmCreateVirtualMappingInternal(NULL
,
557 MmCreateVirtualMappingUnsafe(IN PEPROCESS Process
,
560 IN PPFN_NUMBER Pages
,
564 // Are we only handling the kernel?
566 if (!(Process
) || (Process
== PsGetCurrentProcess()))
569 // Call the internal version
571 return MmCreateVirtualMappingInternal(Process
,
580 // FIXME-USER: Support user-mode mappings
588 MmCreateVirtualMapping(IN PEPROCESS Process
,
591 IN PPFN_NUMBER Pages
,
599 for (i
= 0; i
< PageCount
; i
++)
602 // Make sure the page is marked as in use
604 ASSERT(MmIsPageInUse(Pages
[i
]));
608 // Call the unsafe version
610 return MmCreateVirtualMappingUnsafe(Process
,
619 MmRawDeleteVirtualMapping(IN PVOID Address
)
626 PointerPte
= MiGetPageTableForProcess(NULL
, Address
, FALSE
);
627 if ((PointerPte
) && (PointerPte
->u
.Hard
.Valid
))
632 PointerPte
->u
.Hard
.AsUlong
= 0;
637 MiFlushTlb(PointerPte
, Address
);
643 MmDeleteVirtualMapping(IN PEPROCESS Process
,
646 OUT PBOOLEAN WasDirty
,
647 OUT PPFN_NUMBER Page
)
656 PointerPte
= MiGetPageTableForProcess(NULL
, Address
, FALSE
);
660 // Save and destroy the PTE
663 PointerPte
->u
.Hard
.AsUlong
= 0;
668 MiFlushTlb(PointerPte
, Address
);
673 Pfn
= Pte
.u
.Hard
.PageFrameNumber
;
676 // Release the PFN if it was ours
678 if ((FreePage
) && (Pfn
)) MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
682 // Return if the page was dirty
684 if (WasDirty
) *WasDirty
= FALSE
; // LIE!!!
685 if (Page
) *Page
= Pfn
;
690 MmDeletePageFileMapping(IN PEPROCESS Process
,
692 IN SWAPENTRY
*SwapEntry
)
703 MmCreatePageFileMapping(IN PEPROCESS Process
,
705 IN SWAPENTRY SwapEntry
)
717 MmGetPfnForProcess(IN PEPROCESS Process
,
725 Pte
= MiGetPageEntryForProcess(Process
, Address
);
726 if (Pte
.u
.Hard
.Valid
== 0) return 0;
731 return Pte
.u
.Hard
.PageFrameNumber
;
736 MmIsDirtyPage(IN PEPROCESS Process
,
749 MmSetCleanPage(IN PEPROCESS Process
,
761 MmSetDirtyPage(IN PEPROCESS Process
,
773 MmIsPagePresent(IN PEPROCESS Process
,
777 // Fault PTEs are 0, which is FALSE (non-present)
779 return MiGetPageEntryForProcess(Process
, Address
).u
.Hard
.Valid
;
784 MmIsPageSwapEntry(IN PEPROCESS Process
,
792 Pte
= MiGetPageEntryForProcess(Process
, Address
);
795 // Make sure it exists, but is faulting
797 return (Pte
.u
.Hard
.Valid
== 0) && (Pte
.u
.Hard
.AsUlong
);
802 MmGetPageProtect(IN PEPROCESS Process
,
806 // We don't enforce any protection on the pages -- they are all RWX
808 return PAGE_READWRITE
;
813 MmSetPageProtect(IN PEPROCESS Process
,
818 // We don't enforce any protection on the pages -- they are all RWX
825 MmInitGlobalKernelPageDirectory(VOID
)
828 PULONG CurrentPageDirectory
= (PULONG
)PDE_BASE
;
831 // Good place to setup template PTE/PDEs.
832 // We are lazy and pick a known-good PTE
834 MiArmTemplatePte
= *MiGetPteAddress(0x80000000);
835 MiArmTemplatePde
= *MiGetPdeAddress(0x80000000);
838 // Loop the 2GB of address space which belong to the kernel
840 for (i
= MiGetPdeOffset(MmSystemRangeStart
); i
< 1024; i
++)
843 // Check if we have an entry for this already
845 if ((i
!= MiGetPdeOffset(PTE_BASE
)) &&
846 (i
!= MiGetPdeOffset(HYPER_SPACE
)) &&
847 (!MmGlobalKernelPageDirectory
[i
]) &&
848 (CurrentPageDirectory
[i
]))
851 // We don't, link it in our global page directory
853 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
860 MiInitPageDirectoryMap(VOID
)
862 MEMORY_AREA
* MemoryArea
= NULL
;
863 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
868 // Create memory area for the PTE area
870 BoundaryAddressMultiple
.QuadPart
= 0;
871 BaseAddress
= (PVOID
)PTE_BASE
;
872 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
880 BoundaryAddressMultiple
);
881 ASSERT(NT_SUCCESS(Status
));
884 // Create memory area for the PDE area
886 BaseAddress
= (PVOID
)PDE_BASE
;
887 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
895 BoundaryAddressMultiple
);
896 ASSERT(NT_SUCCESS(Status
));
899 // And finally, hyperspace
901 BaseAddress
= (PVOID
)HYPER_SPACE
;
902 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
910 BoundaryAddressMultiple
);
911 ASSERT(NT_SUCCESS(Status
));
914 /* PUBLIC FUNCTIONS ***********************************************************/
921 MmGetPhysicalAddress(IN PVOID Address
)
923 PHYSICAL_ADDRESS PhysicalAddress
;
927 // Early boot PCR check
932 // ARM Hack while we still use a section PTE
934 PMMPDE_HARDWARE PointerPde
;
935 PointerPde
= MiGetPdeAddress(PCR
);
936 ASSERT(PointerPde
->u
.Hard
.Section
.Valid
== 1);
937 PhysicalAddress
.QuadPart
= PointerPde
->u
.Hard
.Section
.PageFrameNumber
;
938 PhysicalAddress
.QuadPart
<<= CPT_SHIFT
;
939 PhysicalAddress
.LowPart
+= BYTE_OFFSET(Address
);
940 return PhysicalAddress
;
946 Pte
= MiGetPageEntryForProcess(NULL
, Address
);
947 if (Pte
.u
.Hard
.Valid
)
950 // Return the information
952 PhysicalAddress
.QuadPart
= Pte
.u
.Hard
.PageFrameNumber
;
953 PhysicalAddress
.QuadPart
<<= PAGE_SHIFT
;
954 PhysicalAddress
.LowPart
+= BYTE_OFFSET(Address
);
959 // Invalid or unmapped
961 PhysicalAddress
.QuadPart
= 0;
965 // Return the physical address
967 return PhysicalAddress
;