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
< sizeof(Pfn
) / sizeof(Pfn
[0]); 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 Mmi386ReleaseMmInfo(IN PEPROCESS Process
)
375 // FIXME-USER: Need to delete address space
377 UNIMPLEMENTED_DBGBREAK();
378 return STATUS_NOT_IMPLEMENTED
;
383 MmGetPageDirectory(VOID
)
388 return (PULONG
)KeArmTranslationTableRegisterGet().AsUlong
;
393 MmDisableVirtualMapping(IN PEPROCESS Process
,
395 OUT PBOOLEAN WasDirty
,
396 OUT PPFN_NUMBER Page
)
401 UNIMPLEMENTED_DBGBREAK();
406 MmEnableVirtualMapping(IN PEPROCESS Process
,
412 UNIMPLEMENTED_DBGBREAK();
417 MmCreateVirtualMappingInternal(IN PEPROCESS Process
,
420 IN PPFN_NUMBER Pages
,
422 IN BOOLEAN MarkAsMapped
)
424 PMMPTE PointerPte
= NULL
;
427 ULONG OldPdeOffset
, PdeOffset
, i
;
428 DPRINT("[KMAP]: %p %d\n", Address
, PageCount
);
429 //ASSERT(Address >= MmSystemRangeStart);
432 // Get our template PTE
434 TempPte
= MiArmTemplatePte
;
440 OldPdeOffset
= MiGetPdeOffset(Addr
) + 1;
441 for (i
= 0; i
< PageCount
; i
++)
444 // Get the next PDE offset and check if it's a new one
446 PdeOffset
= MiGetPdeOffset(Addr
);
447 if (OldPdeOffset
!= PdeOffset
)
450 // Get rid of the old L2 Table, if this was the last PTE on it
452 MiUnmapPageTable(PointerPte
);
455 // Get the PTE for this address, and create the PDE for it
457 PointerPte
= MiGetPageTableForProcess(NULL
, Addr
, TRUE
);
463 // Go to the next PTE on this PDE
470 // Save the current PDE
472 OldPdeOffset
= PdeOffset
;
477 TempPte
.u
.Hard
.PageFrameNumber
= *Pages
++;
482 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
483 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
484 *PointerPte
= TempPte
;
487 // Move to the next page
489 Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
);
495 return STATUS_SUCCESS
;
500 MmCreateVirtualMappingForKernel(IN PVOID Address
,
502 IN PPFN_NUMBER Pages
,
506 // Call the internal version
508 return MmCreateVirtualMappingInternal(NULL
,
518 MmCreateVirtualMappingUnsafe(IN PEPROCESS Process
,
521 IN PPFN_NUMBER Pages
,
525 // Are we only handling the kernel?
527 if (!(Process
) || (Process
== PsGetCurrentProcess()))
530 // Call the internal version
532 return MmCreateVirtualMappingInternal(Process
,
541 // FIXME-USER: Support user-mode mappings
549 MmCreateVirtualMapping(IN PEPROCESS Process
,
552 IN PPFN_NUMBER Pages
,
560 for (i
= 0; i
< PageCount
; i
++)
563 // Make sure the page is marked as in use
565 ASSERT(MmIsPageInUse(Pages
[i
]));
569 // Call the unsafe version
571 return MmCreateVirtualMappingUnsafe(Process
,
580 MmRawDeleteVirtualMapping(IN PVOID Address
)
587 PointerPte
= MiGetPageTableForProcess(NULL
, Address
, FALSE
);
588 if ((PointerPte
) && (PointerPte
->u
.Hard
.Valid
))
593 PointerPte
->u
.Hard
.AsUlong
= 0;
598 MiFlushTlb(PointerPte
, Address
);
604 MmDeleteVirtualMapping(IN PEPROCESS Process
,
607 OUT PBOOLEAN WasDirty
,
608 OUT PPFN_NUMBER Page
)
617 PointerPte
= MiGetPageTableForProcess(NULL
, Address
, FALSE
);
621 // Save and destroy the PTE
624 PointerPte
->u
.Hard
.AsUlong
= 0;
629 MiFlushTlb(PointerPte
, Address
);
634 Pfn
= Pte
.u
.Hard
.PageFrameNumber
;
637 // Release the PFN if it was ours
639 if ((FreePage
) && (Pfn
)) MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
643 // Return if the page was dirty
645 if (WasDirty
) *WasDirty
= FALSE
; // LIE!!!
646 if (Page
) *Page
= Pfn
;
651 MmDeletePageFileMapping(IN PEPROCESS Process
,
653 IN SWAPENTRY
*SwapEntry
)
658 UNIMPLEMENTED_DBGBREAK();
663 MmCreatePageFileMapping(IN PEPROCESS Process
,
665 IN SWAPENTRY SwapEntry
)
670 UNIMPLEMENTED_DBGBREAK();
671 return STATUS_NOT_IMPLEMENTED
;
676 MmGetPfnForProcess(IN PEPROCESS Process
,
684 Pte
= MiGetPageEntryForProcess(Process
, Address
);
685 if (Pte
.u
.Hard
.Valid
== 0) return 0;
690 return Pte
.u
.Hard
.PageFrameNumber
;
695 MmIsDirtyPage(IN PEPROCESS Process
,
701 UNIMPLEMENTED_DBGBREAK();
707 MmSetCleanPage(IN PEPROCESS Process
,
713 UNIMPLEMENTED_DBGBREAK();
718 MmSetDirtyPage(IN PEPROCESS Process
,
724 UNIMPLEMENTED_DBGBREAK();
729 MmIsPagePresent(IN PEPROCESS Process
,
733 // Fault PTEs are 0, which is FALSE (non-present)
735 return MiGetPageEntryForProcess(Process
, Address
).u
.Hard
.Valid
;
740 MmIsPageSwapEntry(IN PEPROCESS Process
,
748 Pte
= MiGetPageEntryForProcess(Process
, Address
);
751 // Make sure it exists, but is faulting
753 return (Pte
.u
.Hard
.Valid
== 0) && (Pte
.u
.Hard
.AsUlong
);
758 MmGetPageProtect(IN PEPROCESS Process
,
762 // We don't enforce any protection on the pages -- they are all RWX
764 return PAGE_READWRITE
;
769 MmSetPageProtect(IN PEPROCESS Process
,
774 // We don't enforce any protection on the pages -- they are all RWX
781 MmInitGlobalKernelPageDirectory(VOID
)
784 PULONG CurrentPageDirectory
= (PULONG
)PDE_BASE
;
787 // Good place to setup template PTE/PDEs.
788 // We are lazy and pick a known-good PTE
790 MiArmTemplatePte
= *MiGetPteAddress(0x80000000);
791 MiArmTemplatePde
= *MiGetPdeAddress(0x80000000);
794 // Loop the 2GB of address space which belong to the kernel
796 for (i
= MiGetPdeOffset(MmSystemRangeStart
); i
< 1024; i
++)
799 // Check if we have an entry for this already
801 if ((i
!= MiGetPdeOffset(PTE_BASE
)) &&
802 (i
!= MiGetPdeOffset(HYPER_SPACE
)) &&
803 (!MmGlobalKernelPageDirectory
[i
]) &&
804 (CurrentPageDirectory
[i
]))
807 // We don't, link it in our global page directory
809 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
816 MiInitPageDirectoryMap(VOID
)
818 MEMORY_AREA
* MemoryArea
= NULL
;
819 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
824 // Create memory area for the PTE area
826 BoundaryAddressMultiple
.QuadPart
= 0;
827 BaseAddress
= (PVOID
)PTE_BASE
;
828 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
829 MEMORY_AREA_OWNED_BY_ARM3
,
836 BoundaryAddressMultiple
);
837 ASSERT(NT_SUCCESS(Status
));
840 // Create memory area for the PDE area
842 BaseAddress
= (PVOID
)PDE_BASE
;
843 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
844 MEMORY_AREA_OWNED_BY_ARM3
,
851 BoundaryAddressMultiple
);
852 ASSERT(NT_SUCCESS(Status
));
855 // And finally, hyperspace
857 BaseAddress
= (PVOID
)HYPER_SPACE
;
858 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
859 MEMORY_AREA_OWNED_BY_ARM3
,
866 BoundaryAddressMultiple
);
867 ASSERT(NT_SUCCESS(Status
));
870 /* PUBLIC FUNCTIONS ***********************************************************/
877 MmGetPhysicalAddress(IN PVOID Address
)
879 PHYSICAL_ADDRESS PhysicalAddress
;
883 // Early boot PCR check
888 // ARM Hack while we still use a section PTE
890 PMMPDE_HARDWARE PointerPde
;
891 PointerPde
= MiGetPdeAddress(PCR
);
892 ASSERT(PointerPde
->u
.Hard
.Section
.Valid
== 1);
893 PhysicalAddress
.QuadPart
= PointerPde
->u
.Hard
.Section
.PageFrameNumber
;
894 PhysicalAddress
.QuadPart
<<= CPT_SHIFT
;
895 PhysicalAddress
.LowPart
+= BYTE_OFFSET(Address
);
896 return PhysicalAddress
;
902 Pte
= MiGetPageEntryForProcess(NULL
, Address
);
903 if (Pte
.u
.Hard
.Valid
)
906 // Return the information
908 PhysicalAddress
.QuadPart
= Pte
.u
.Hard
.PageFrameNumber
;
909 PhysicalAddress
.QuadPart
<<= PAGE_SHIFT
;
910 PhysicalAddress
.LowPart
+= BYTE_OFFSET(Address
);
915 // Invalid or unmapped
917 PhysicalAddress
.QuadPart
= 0;
921 // Return the physical address
923 return PhysicalAddress
;