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 MmCreateVirtualMappingInternal(IN PEPROCESS Process
,
323 IN PPFN_NUMBER Pages
,
325 IN BOOLEAN MarkAsMapped
)
327 PMMPTE PointerPte
= NULL
;
330 ULONG OldPdeOffset
, PdeOffset
, i
;
331 DPRINT("[KMAP]: %p %d\n", Address
, PageCount
);
332 //ASSERT(Address >= MmSystemRangeStart);
335 // Get our template PTE
337 TempPte
= MiArmTemplatePte
;
343 OldPdeOffset
= MiGetPdeOffset(Addr
) + 1;
344 for (i
= 0; i
< PageCount
; i
++)
347 // Get the next PDE offset and check if it's a new one
349 PdeOffset
= MiGetPdeOffset(Addr
);
350 if (OldPdeOffset
!= PdeOffset
)
353 // Get rid of the old L2 Table, if this was the last PTE on it
355 MiUnmapPageTable(PointerPte
);
358 // Get the PTE for this address, and create the PDE for it
360 PointerPte
= MiGetPageTableForProcess(NULL
, Addr
, TRUE
);
366 // Go to the next PTE on this PDE
373 // Save the current PDE
375 OldPdeOffset
= PdeOffset
;
380 TempPte
.u
.Hard
.PageFrameNumber
= *Pages
++;
385 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
386 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
387 *PointerPte
= TempPte
;
390 // Move to the next page
392 Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
);
398 return STATUS_SUCCESS
;
403 MmCreateVirtualMappingUnsafe(IN PEPROCESS Process
,
406 IN PPFN_NUMBER Pages
,
410 // Are we only handling the kernel?
412 if (!(Process
) || (Process
== PsGetCurrentProcess()))
415 // Call the internal version
417 return MmCreateVirtualMappingInternal(Process
,
426 // FIXME-USER: Support user-mode mappings
434 MmCreateVirtualMapping(IN PEPROCESS Process
,
437 IN PPFN_NUMBER Pages
,
445 for (i
= 0; i
< PageCount
; i
++)
448 // Make sure the page is marked as in use
450 ASSERT(MmIsPageInUse(Pages
[i
]));
454 // Call the unsafe version
456 return MmCreateVirtualMappingUnsafe(Process
,
465 MmDeleteVirtualMapping(IN PEPROCESS Process
,
467 OUT PBOOLEAN WasDirty
,
468 OUT PPFN_NUMBER Page
)
477 PointerPte
= MiGetPageTableForProcess(NULL
, Address
, FALSE
);
481 // Save and destroy the PTE
484 PointerPte
->u
.Hard
.AsUlong
= 0;
489 MiFlushTlb(PointerPte
, Address
);
494 Pfn
= Pte
.u
.Hard
.PageFrameNumber
;
497 // Release the PFN if it was ours
499 if ((FreePage
) && (Pfn
)) MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
503 // Return if the page was dirty
505 if (WasDirty
) *WasDirty
= FALSE
; // LIE!!!
506 if (Page
) *Page
= Pfn
;
511 MmDeletePageFileMapping(IN PEPROCESS Process
,
513 IN SWAPENTRY
*SwapEntry
)
518 UNIMPLEMENTED_DBGBREAK();
523 MmCreatePageFileMapping(IN PEPROCESS Process
,
525 IN SWAPENTRY SwapEntry
)
530 UNIMPLEMENTED_DBGBREAK();
531 return STATUS_NOT_IMPLEMENTED
;
536 MmGetPfnForProcess(IN PEPROCESS Process
,
544 Pte
= MiGetPageEntryForProcess(Process
, Address
);
545 if (Pte
.u
.Hard
.Valid
== 0) return 0;
550 return Pte
.u
.Hard
.PageFrameNumber
;
555 MmIsDirtyPage(IN PEPROCESS Process
,
561 UNIMPLEMENTED_DBGBREAK();
567 MmSetCleanPage(IN PEPROCESS Process
,
573 UNIMPLEMENTED_DBGBREAK();
578 MmSetDirtyPage(IN PEPROCESS Process
,
584 UNIMPLEMENTED_DBGBREAK();
589 MmIsPagePresent(IN PEPROCESS Process
,
593 // Fault PTEs are 0, which is FALSE (non-present)
595 return MiGetPageEntryForProcess(Process
, Address
).u
.Hard
.Valid
;
600 MmIsPageSwapEntry(IN PEPROCESS Process
,
608 Pte
= MiGetPageEntryForProcess(Process
, Address
);
611 // Make sure it exists, but is faulting
613 return (Pte
.u
.Hard
.Valid
== 0) && (Pte
.u
.Hard
.AsUlong
);
618 MmGetPageProtect(IN PEPROCESS Process
,
622 // We don't enforce any protection on the pages -- they are all RWX
624 return PAGE_READWRITE
;
629 MmSetPageProtect(IN PEPROCESS Process
,
634 // We don't enforce any protection on the pages -- they are all RWX
641 MmInitGlobalKernelPageDirectory(VOID
)
644 PULONG CurrentPageDirectory
= (PULONG
)PDE_BASE
;
647 // Good place to setup template PTE/PDEs.
648 // We are lazy and pick a known-good PTE
650 MiArmTemplatePte
= *MiGetPteAddress(0x80000000);
651 MiArmTemplatePde
= *MiGetPdeAddress(0x80000000);
654 // Loop the 2GB of address space which belong to the kernel
656 for (i
= MiGetPdeOffset(MmSystemRangeStart
); i
< 1024; i
++)
659 // Check if we have an entry for this already
661 if ((i
!= MiGetPdeOffset(PTE_BASE
)) &&
662 (i
!= MiGetPdeOffset(HYPER_SPACE
)) &&
663 (!MmGlobalKernelPageDirectory
[i
]) &&
664 (CurrentPageDirectory
[i
]))
667 // We don't, link it in our global page directory
669 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
675 /* PUBLIC FUNCTIONS ***********************************************************/
682 MmGetPhysicalAddress(IN PVOID Address
)
684 PHYSICAL_ADDRESS PhysicalAddress
;
688 // Early boot PCR check
693 // ARM Hack while we still use a section PTE
695 PMMPDE_HARDWARE PointerPde
;
696 PointerPde
= MiGetPdeAddress(PCR
);
697 ASSERT(PointerPde
->u
.Hard
.Section
.Valid
== 1);
698 PhysicalAddress
.QuadPart
= PointerPde
->u
.Hard
.Section
.PageFrameNumber
;
699 PhysicalAddress
.QuadPart
<<= CPT_SHIFT
;
700 PhysicalAddress
.LowPart
+= BYTE_OFFSET(Address
);
701 return PhysicalAddress
;
707 Pte
= MiGetPageEntryForProcess(NULL
, Address
);
708 if (Pte
.u
.Hard
.Valid
)
711 // Return the information
713 PhysicalAddress
.QuadPart
= Pte
.u
.Hard
.PageFrameNumber
;
714 PhysicalAddress
.QuadPart
<<= PAGE_SHIFT
;
715 PhysicalAddress
.LowPart
+= BYTE_OFFSET(Address
);
720 // Invalid or unmapped
722 PhysicalAddress
.QuadPart
= 0;
726 // Return the physical address
728 return PhysicalAddress
;