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 MmCreateProcessAddressSpace(IN ULONG MinWs
,
243 IN PEPROCESS Process
,
244 IN PULONG DirectoryTableBase
)
249 PMMPDE_HARDWARE PageDirectory
, PointerPde
;
250 MMPDE_HARDWARE TempPde
;
254 // Loop two tables (Hyperspace and TTB). Each one is 16KB
257 for (i
= 0; i
< sizeof(Pfn
) / sizeof(Pfn
[0]); i
++)
262 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
[i
]);
263 if (!NT_SUCCESS(Status
)) ASSERT(FALSE
);
269 PageDirectory
= MmCreateHyperspaceMapping(Pfn
[0]);
272 // Copy the PDEs for kernel-mode
274 RtlCopyMemory(PageDirectory
+ MiGetPdeOffset(MmSystemRangeStart
),
275 MmGlobalKernelPageDirectory
+ MiGetPdeOffset(MmSystemRangeStart
),
276 (1024 - MiGetPdeOffset(MmSystemRangeStart
)) * sizeof(ULONG
));
280 // Setup the PDE for the table base
282 TempPde
= MiArmTemplatePde
;
283 TempPde
.u
.Hard
.Coarse
.PageFrameNumber
= (Pfn
[0] << PAGE_SHIFT
) >> CPT_SHIFT
;
284 PointerPde
= &PageDirectory
[MiGetPdeOffset(PTE_BASE
)];
289 ASSERT(PointerPde
->u
.Hard
.Coarse
.Valid
== 0);
290 ASSERT(TempPde
.u
.Hard
.Coarse
.Valid
== 1);
291 *PointerPde
= TempPde
;
294 // Setup the PDE for the hyperspace
296 TempPde
.u
.Hard
.Coarse
.PageFrameNumber
= (Pfn
[1] << PAGE_SHIFT
) >> CPT_SHIFT
;
297 PointerPde
= &PageDirectory
[MiGetPdeOffset(HYPER_SPACE
)];
302 ASSERT(PointerPde
->u
.Hard
.Coarse
.Valid
== 0);
303 ASSERT(TempPde
.u
.Hard
.Coarse
.Valid
== 1);
304 *PointerPde
= TempPde
;
307 // Unmap the page directory
309 MmDeleteHyperspaceMapping(PageDirectory
);
312 // Return the page table base
314 DirectoryTableBase
[0] = Pfn
[0] << PAGE_SHIFT
;
320 MmGetPageDirectory(VOID
)
325 return (PULONG
)KeArmTranslationTableRegisterGet().AsUlong
;
330 MmCreateVirtualMappingInternal(IN PEPROCESS Process
,
333 IN PPFN_NUMBER Pages
,
335 IN BOOLEAN MarkAsMapped
)
337 PMMPTE PointerPte
= NULL
;
340 ULONG OldPdeOffset
, PdeOffset
, i
;
341 DPRINT("[KMAP]: %p %d\n", Address
, PageCount
);
342 //ASSERT(Address >= MmSystemRangeStart);
345 // Get our template PTE
347 TempPte
= MiArmTemplatePte
;
353 OldPdeOffset
= MiGetPdeOffset(Addr
) + 1;
354 for (i
= 0; i
< PageCount
; i
++)
357 // Get the next PDE offset and check if it's a new one
359 PdeOffset
= MiGetPdeOffset(Addr
);
360 if (OldPdeOffset
!= PdeOffset
)
363 // Get rid of the old L2 Table, if this was the last PTE on it
365 MiUnmapPageTable(PointerPte
);
368 // Get the PTE for this address, and create the PDE for it
370 PointerPte
= MiGetPageTableForProcess(NULL
, Addr
, TRUE
);
376 // Go to the next PTE on this PDE
383 // Save the current PDE
385 OldPdeOffset
= PdeOffset
;
390 TempPte
.u
.Hard
.PageFrameNumber
= *Pages
++;
395 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
396 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
397 *PointerPte
= TempPte
;
400 // Move to the next page
402 Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
);
408 return STATUS_SUCCESS
;
413 MmCreateVirtualMappingUnsafe(IN PEPROCESS Process
,
416 IN PPFN_NUMBER Pages
,
420 // Are we only handling the kernel?
422 if (!(Process
) || (Process
== PsGetCurrentProcess()))
425 // Call the internal version
427 return MmCreateVirtualMappingInternal(Process
,
436 // FIXME-USER: Support user-mode mappings
444 MmCreateVirtualMapping(IN PEPROCESS Process
,
447 IN PPFN_NUMBER Pages
,
455 for (i
= 0; i
< PageCount
; i
++)
458 // Make sure the page is marked as in use
460 ASSERT(MmIsPageInUse(Pages
[i
]));
464 // Call the unsafe version
466 return MmCreateVirtualMappingUnsafe(Process
,
475 MmDeleteVirtualMapping(IN PEPROCESS Process
,
477 OUT PBOOLEAN WasDirty
,
478 OUT PPFN_NUMBER Page
)
487 PointerPte
= MiGetPageTableForProcess(NULL
, Address
, FALSE
);
491 // Save and destroy the PTE
494 PointerPte
->u
.Hard
.AsUlong
= 0;
499 MiFlushTlb(PointerPte
, Address
);
504 Pfn
= Pte
.u
.Hard
.PageFrameNumber
;
507 // Release the PFN if it was ours
509 if ((FreePage
) && (Pfn
)) MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
513 // Return if the page was dirty
515 if (WasDirty
) *WasDirty
= FALSE
; // LIE!!!
516 if (Page
) *Page
= Pfn
;
521 MmDeletePageFileMapping(IN PEPROCESS Process
,
523 IN SWAPENTRY
*SwapEntry
)
528 UNIMPLEMENTED_DBGBREAK();
533 MmCreatePageFileMapping(IN PEPROCESS Process
,
535 IN SWAPENTRY SwapEntry
)
540 UNIMPLEMENTED_DBGBREAK();
541 return STATUS_NOT_IMPLEMENTED
;
546 MmGetPfnForProcess(IN PEPROCESS Process
,
554 Pte
= MiGetPageEntryForProcess(Process
, Address
);
555 if (Pte
.u
.Hard
.Valid
== 0) return 0;
560 return Pte
.u
.Hard
.PageFrameNumber
;
565 MmIsDirtyPage(IN PEPROCESS Process
,
571 UNIMPLEMENTED_DBGBREAK();
577 MmSetCleanPage(IN PEPROCESS Process
,
583 UNIMPLEMENTED_DBGBREAK();
588 MmSetDirtyPage(IN PEPROCESS Process
,
594 UNIMPLEMENTED_DBGBREAK();
599 MmIsPagePresent(IN PEPROCESS Process
,
603 // Fault PTEs are 0, which is FALSE (non-present)
605 return MiGetPageEntryForProcess(Process
, Address
).u
.Hard
.Valid
;
610 MmIsPageSwapEntry(IN PEPROCESS Process
,
618 Pte
= MiGetPageEntryForProcess(Process
, Address
);
621 // Make sure it exists, but is faulting
623 return (Pte
.u
.Hard
.Valid
== 0) && (Pte
.u
.Hard
.AsUlong
);
628 MmGetPageProtect(IN PEPROCESS Process
,
632 // We don't enforce any protection on the pages -- they are all RWX
634 return PAGE_READWRITE
;
639 MmSetPageProtect(IN PEPROCESS Process
,
644 // We don't enforce any protection on the pages -- they are all RWX
651 MmInitGlobalKernelPageDirectory(VOID
)
654 PULONG CurrentPageDirectory
= (PULONG
)PDE_BASE
;
657 // Good place to setup template PTE/PDEs.
658 // We are lazy and pick a known-good PTE
660 MiArmTemplatePte
= *MiGetPteAddress(0x80000000);
661 MiArmTemplatePde
= *MiGetPdeAddress(0x80000000);
664 // Loop the 2GB of address space which belong to the kernel
666 for (i
= MiGetPdeOffset(MmSystemRangeStart
); i
< 1024; i
++)
669 // Check if we have an entry for this already
671 if ((i
!= MiGetPdeOffset(PTE_BASE
)) &&
672 (i
!= MiGetPdeOffset(HYPER_SPACE
)) &&
673 (!MmGlobalKernelPageDirectory
[i
]) &&
674 (CurrentPageDirectory
[i
]))
677 // We don't, link it in our global page directory
679 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
685 /* PUBLIC FUNCTIONS ***********************************************************/
692 MmGetPhysicalAddress(IN PVOID Address
)
694 PHYSICAL_ADDRESS PhysicalAddress
;
698 // Early boot PCR check
703 // ARM Hack while we still use a section PTE
705 PMMPDE_HARDWARE PointerPde
;
706 PointerPde
= MiGetPdeAddress(PCR
);
707 ASSERT(PointerPde
->u
.Hard
.Section
.Valid
== 1);
708 PhysicalAddress
.QuadPart
= PointerPde
->u
.Hard
.Section
.PageFrameNumber
;
709 PhysicalAddress
.QuadPart
<<= CPT_SHIFT
;
710 PhysicalAddress
.LowPart
+= BYTE_OFFSET(Address
);
711 return PhysicalAddress
;
717 Pte
= MiGetPageEntryForProcess(NULL
, Address
);
718 if (Pte
.u
.Hard
.Valid
)
721 // Return the information
723 PhysicalAddress
.QuadPart
= Pte
.u
.Hard
.PageFrameNumber
;
724 PhysicalAddress
.QuadPart
<<= PAGE_SHIFT
;
725 PhysicalAddress
.LowPart
+= BYTE_OFFSET(Address
);
730 // Invalid or unmapped
732 PhysicalAddress
.QuadPart
= 0;
736 // Return the physical address
738 return PhysicalAddress
;