1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 ULONG MmGlobalKernelPageDirectory[1024];
18 MMPTE MiArmTemplatePte;
19 MMPDE_HARDWARE MiArmTemplatePde;
20
21 /* PRIVATE FUNCTIONS **********************************************************/
22
23 BOOLEAN
24 NTAPI
MiUnmapPageTable(IN PMMPTE PointerPde)25 MiUnmapPageTable(IN PMMPTE PointerPde)
26 {
27 //
28 // Check if this address belongs to the kernel
29 //
30 if (((ULONG_PTR)PointerPde > PDE_BASE) ||
31 ((ULONG_PTR)PointerPde < (PDE_BASE + 1024*1024)))
32 {
33 //
34 // Nothing to do
35 //
36 return TRUE;
37 }
38
39 //
40 // FIXME-USER: Shouldn't get here yet
41 //
42 ERROR_FATAL();
43 return FALSE;
44 }
45
46 VOID
47 NTAPI
MiFlushTlb(IN PMMPTE PointerPte,IN PVOID Address)48 MiFlushTlb(IN PMMPTE PointerPte,
49 IN PVOID Address)
50 {
51 //
52 // Make sure the PTE is valid, and unmap the pagetable if user-mode
53 //
54 if (((PointerPte) && (MiUnmapPageTable(PointerPte))) ||
55 (Address >= MmSystemRangeStart))
56 {
57 //
58 // Invalidate this page
59 //
60 KeArmInvalidateTlbEntry(Address);
61 }
62 }
63
64 PMMPTE
65 NTAPI
MiGetPageTableForProcess(IN PEPROCESS Process,IN PVOID Address,IN BOOLEAN Create)66 MiGetPageTableForProcess(IN PEPROCESS Process,
67 IN PVOID Address,
68 IN BOOLEAN Create)
69 {
70 //ULONG PdeOffset;
71 PMMPTE PointerPte;
72 PMMPDE_HARDWARE PointerPde;
73 MMPDE_HARDWARE TempPde;
74 MMPTE TempPte;
75 NTSTATUS Status;
76 PFN_NUMBER Pfn;
77
78 //
79 // Check if this is a user-mode, non-kernel or non-current address
80 //
81 if ((Address < MmSystemRangeStart) &&
82 (Process) &&
83 (Process != PsGetCurrentProcess()))
84 {
85 //
86 // FIXME-USER: No user-mode memory support
87 //
88 ASSERT(FALSE);
89 }
90
91 //
92 // Get our templates
93 //
94 TempPde = MiArmTemplatePde;
95 TempPte = MiArmTemplatePte;
96
97 //
98 // Get the PDE
99 //
100 PointerPde = MiAddressToPde(Address);
101 if (PointerPde->u.Hard.Coarse.Valid)
102 {
103 //
104 // Invalid PDE, is this a kernel address?
105 //
106 if (Address >= MmSystemRangeStart)
107 {
108 //
109 // Does it exist in the kernel page directory?
110 //
111 //PdeOffset = MiGetPdeOffset(Address);
112 //if (MmGlobalKernelPageDirectory[PdeOffset] == 0)
113 {
114 //
115 // It doesn't. Is this a create operation? If not, fail
116 //
117 if (Create == FALSE) return NULL;
118 kernelHack:
119 DPRINT1("Must create a page for: %p PDE: %p\n", // Offset: %lx!\n",
120 Address, PointerPde);//, PdeOffset);
121
122 //
123 // Allocate a non paged pool page for the PDE
124 //
125 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
126 if (!NT_SUCCESS(Status)) return NULL;
127
128 //
129 // Setup the PFN
130 //
131 TempPde.u.Hard.Coarse.PageFrameNumber = (Pfn << PAGE_SHIFT) >> CPT_SHIFT;
132
133 //
134 // Write the PDE
135 //
136 ASSERT(PointerPde->u.Hard.Coarse.Valid == 0);
137 ASSERT(TempPde.u.Hard.Coarse.Valid == 1);
138 *PointerPde = TempPde;
139
140 //
141 // Save it
142 //
143 //MmGlobalKernelPageDirectory[PdeOffset] = TempPde.u.Hard.AsUlong;
144 //DPRINT1("KPD: %p PDEADDR: %p\n", &MmGlobalKernelPageDirectory[PdeOffset], MiAddressToPde(Address));
145
146 //
147 // FIXFIX: Double check with Felix tomorrow
148 //
149 /////
150 //
151 // Get the PTE for this 1MB region
152 //
153 PointerPte = MiAddressToPte(MiAddressToPte(Address));
154 DPRINT1("PointerPte: %p\n", PointerPte);
155
156 //
157 // Write the PFN of the PDE
158 //
159 TempPte.u.Hard.PageFrameNumber = Pfn;
160
161 //
162 // Write the PTE
163 //
164 ASSERT(PointerPte->u.Hard.Valid == 0);
165 ASSERT(TempPte.u.Hard.Valid == 1);
166 *PointerPte = TempPte;
167 /////
168 }
169
170 //
171 // Now set the actual PDE
172 //
173 //PointerPde = (PMMPTE)&MmGlobalKernelPageDirectory[PdeOffset];
174 }
175 else
176 {
177 //
178 // Is this a create operation? If not, fail
179 //
180 if (Create == FALSE) return NULL;
181
182 //
183 // THIS WHOLE PATH IS TODO
184 //
185 #if 1
186 goto kernelHack;
187 #else
188 ASSERT(FALSE);
189
190 //
191 // Allocate a non paged pool page for the PDE
192 //
193 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
194 if (!NT_SUCCESS(Status)) return NULL;
195
196 //
197 // Make the entry valid
198 //
199 TempPde.u.Hard.AsUlong = 0xDEADBEEF;
200
201 //
202 // Set it
203 //
204 *PointerPde = TempPde;
205 #endif
206 }
207 }
208
209 //
210 // Return the PTE
211 //
212 return MiAddressToPte(Address);
213 }
214
215 MMPTE
216 NTAPI
MiGetPageEntryForProcess(IN PEPROCESS Process,IN PVOID Address)217 MiGetPageEntryForProcess(IN PEPROCESS Process,
218 IN PVOID Address)
219 {
220 PMMPTE PointerPte;
221 MMPTE Pte;
222 Pte.u.Hard.AsUlong = 0;
223
224 //
225 // Get the PTE
226 //
227 PointerPte = MiGetPageTableForProcess(Process, Address, FALSE);
228 if (PointerPte)
229 {
230 //
231 // Capture the PTE value and unmap the page table
232 //
233 Pte = *PointerPte;
234 MiUnmapPageTable(PointerPte);
235 }
236
237 //
238 // Return the PTE value
239 //
240 return Pte;
241 }
242
243 BOOLEAN
244 NTAPI
MmCreateProcessAddressSpace(IN ULONG MinWs,IN PEPROCESS Process,IN PULONG DirectoryTableBase)245 MmCreateProcessAddressSpace(IN ULONG MinWs,
246 IN PEPROCESS Process,
247 IN PULONG DirectoryTableBase)
248 {
249 NTSTATUS Status;
250 ULONG i;
251 PFN_NUMBER Pfn[2];
252 PMMPDE_HARDWARE PageDirectory, PointerPde;
253 MMPDE_HARDWARE TempPde;
254 ASSERT(FALSE);
255
256 //
257 // Loop two tables (Hyperspace and TTB). Each one is 16KB
258 //
259 //
260 for (i = 0; i < sizeof(Pfn) / sizeof(Pfn[0]); i++)
261 {
262 //
263 // Allocate a page
264 //
265 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn[i]);
266 if (!NT_SUCCESS(Status)) ASSERT(FALSE);
267 }
268
269 //
270 // Map the base
271 //
272 PageDirectory = MmCreateHyperspaceMapping(Pfn[0]);
273
274 //
275 // Copy the PDEs for kernel-mode
276 //
277 RtlCopyMemory(PageDirectory + MiGetPdeOffset(MmSystemRangeStart),
278 MmGlobalKernelPageDirectory + MiGetPdeOffset(MmSystemRangeStart),
279 (1024 - MiGetPdeOffset(MmSystemRangeStart)) * sizeof(ULONG));
280
281
282 //
283 // Setup the PDE for the table base
284 //
285 TempPde = MiArmTemplatePde;
286 TempPde.u.Hard.Coarse.PageFrameNumber = (Pfn[0] << PAGE_SHIFT) >> CPT_SHIFT;
287 PointerPde = &PageDirectory[MiGetPdeOffset(PTE_BASE)];
288
289 //
290 // Write the PDE
291 //
292 ASSERT(PointerPde->u.Hard.Coarse.Valid == 0);
293 ASSERT(TempPde.u.Hard.Coarse.Valid == 1);
294 *PointerPde = TempPde;
295
296 //
297 // Setup the PDE for the hyperspace
298 //
299 TempPde.u.Hard.Coarse.PageFrameNumber = (Pfn[1] << PAGE_SHIFT) >> CPT_SHIFT;
300 PointerPde = &PageDirectory[MiGetPdeOffset(HYPER_SPACE)];
301
302 //
303 // Write the PDE
304 //
305 ASSERT(PointerPde->u.Hard.Coarse.Valid == 0);
306 ASSERT(TempPde.u.Hard.Coarse.Valid == 1);
307 *PointerPde = TempPde;
308
309 //
310 // Unmap the page directory
311 //
312 MmDeleteHyperspaceMapping(PageDirectory);
313
314 //
315 // Return the page table base
316 //
317 DirectoryTableBase[0] = Pfn[0] << PAGE_SHIFT;
318 return TRUE;
319 }
320
321 NTSTATUS
322 NTAPI
MmCreateVirtualMappingInternal(IN PEPROCESS Process,IN PVOID Address,IN ULONG Protection,IN PPFN_NUMBER Pages,IN ULONG PageCount,IN BOOLEAN MarkAsMapped)323 MmCreateVirtualMappingInternal(IN PEPROCESS Process,
324 IN PVOID Address,
325 IN ULONG Protection,
326 IN PPFN_NUMBER Pages,
327 IN ULONG PageCount,
328 IN BOOLEAN MarkAsMapped)
329 {
330 PMMPTE PointerPte = NULL;
331 MMPTE TempPte;
332 PVOID Addr;
333 ULONG OldPdeOffset, PdeOffset, i;
334 DPRINT("[KMAP]: %p %d\n", Address, PageCount);
335 //ASSERT(Address >= MmSystemRangeStart);
336
337 //
338 // Get our template PTE
339 //
340 TempPte = MiArmTemplatePte;
341
342 //
343 // Loop every page
344 //
345 Addr = Address;
346 OldPdeOffset = MiGetPdeOffset(Addr) + 1;
347 for (i = 0; i < PageCount; i++)
348 {
349 //
350 // Get the next PDE offset and check if it's a new one
351 //
352 PdeOffset = MiGetPdeOffset(Addr);
353 if (OldPdeOffset != PdeOffset)
354 {
355 //
356 // Get rid of the old L2 Table, if this was the last PTE on it
357 //
358 MiUnmapPageTable(PointerPte);
359
360 //
361 // Get the PTE for this address, and create the PDE for it
362 //
363 PointerPte = MiGetPageTableForProcess(NULL, Addr, TRUE);
364 ASSERT(PointerPte);
365 }
366 else
367 {
368 //
369 // Go to the next PTE on this PDE
370 //
371 ASSERT(PointerPte);
372 PointerPte++;
373 }
374
375 //
376 // Save the current PDE
377 //
378 OldPdeOffset = PdeOffset;
379
380 //
381 // Set the PFN
382 //
383 TempPte.u.Hard.PageFrameNumber = *Pages++;
384
385 //
386 // Write the PTE
387 //
388 ASSERT(PointerPte->u.Hard.Valid == 0);
389 ASSERT(TempPte.u.Hard.Valid == 1);
390 *PointerPte = TempPte;
391
392 //
393 // Move to the next page
394 //
395 Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE);
396 }
397
398 //
399 // All done
400 //
401 return STATUS_SUCCESS;
402 }
403
404 NTSTATUS
405 NTAPI
MmCreateVirtualMappingUnsafe(IN PEPROCESS Process,IN PVOID Address,IN ULONG Protection,IN PPFN_NUMBER Pages,IN ULONG PageCount)406 MmCreateVirtualMappingUnsafe(IN PEPROCESS Process,
407 IN PVOID Address,
408 IN ULONG Protection,
409 IN PPFN_NUMBER Pages,
410 IN ULONG PageCount)
411 {
412 //
413 // Are we only handling the kernel?
414 //
415 if (!(Process) || (Process == PsGetCurrentProcess()))
416 {
417 //
418 // Call the internal version
419 //
420 return MmCreateVirtualMappingInternal(Process,
421 Address,
422 Protection,
423 Pages,
424 PageCount,
425 TRUE);
426 }
427
428 //
429 // FIXME-USER: Support user-mode mappings
430 //
431 ASSERT(FALSE);
432 return 0;
433 }
434
435 NTSTATUS
436 NTAPI
MmCreateVirtualMapping(IN PEPROCESS Process,IN PVOID Address,IN ULONG Protection,IN PPFN_NUMBER Pages,IN ULONG PageCount)437 MmCreateVirtualMapping(IN PEPROCESS Process,
438 IN PVOID Address,
439 IN ULONG Protection,
440 IN PPFN_NUMBER Pages,
441 IN ULONG PageCount)
442 {
443 ULONG i;
444
445 //
446 // Loop each page
447 //
448 for (i = 0; i < PageCount; i++)
449 {
450 //
451 // Make sure the page is marked as in use
452 //
453 ASSERT(MmIsPageInUse(Pages[i]));
454 }
455
456 //
457 // Call the unsafe version
458 //
459 return MmCreateVirtualMappingUnsafe(Process,
460 Address,
461 Protection,
462 Pages,
463 PageCount);
464 }
465
466 VOID
467 NTAPI
MmDeleteVirtualMapping(IN PEPROCESS Process,IN PVOID Address,OUT PBOOLEAN WasDirty,OUT PPFN_NUMBER Page)468 MmDeleteVirtualMapping(IN PEPROCESS Process,
469 IN PVOID Address,
470 OUT PBOOLEAN WasDirty,
471 OUT PPFN_NUMBER Page)
472 {
473 PMMPTE PointerPte;
474 MMPTE Pte;
475 PFN_NUMBER Pfn = 0;
476
477 //
478 // Get the PTE
479 //
480 PointerPte = MiGetPageTableForProcess(NULL, Address, FALSE);
481 if (PointerPte)
482 {
483 //
484 // Save and destroy the PTE
485 //
486 Pte = *PointerPte;
487 PointerPte->u.Hard.AsUlong = 0;
488
489 //
490 // Flush the TLB
491 //
492 MiFlushTlb(PointerPte, Address);
493
494 //
495 // Unmap the PFN
496 //
497 Pfn = Pte.u.Hard.PageFrameNumber;
498
499 //
500 // Release the PFN if it was ours
501 //
502 if ((FreePage) && (Pfn)) MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
503 }
504
505 //
506 // Return if the page was dirty
507 //
508 if (WasDirty) *WasDirty = FALSE; // LIE!!!
509 if (Page) *Page = Pfn;
510 }
511
512 VOID
513 NTAPI
MmDeletePageFileMapping(IN PEPROCESS Process,IN PVOID Address,IN SWAPENTRY * SwapEntry)514 MmDeletePageFileMapping(IN PEPROCESS Process,
515 IN PVOID Address,
516 IN SWAPENTRY *SwapEntry)
517 {
518 //
519 // TODO
520 //
521 UNIMPLEMENTED_DBGBREAK();
522 }
523
524 NTSTATUS
525 NTAPI
MmCreatePageFileMapping(IN PEPROCESS Process,IN PVOID Address,IN SWAPENTRY SwapEntry)526 MmCreatePageFileMapping(IN PEPROCESS Process,
527 IN PVOID Address,
528 IN SWAPENTRY SwapEntry)
529 {
530 //
531 // TODO
532 //
533 UNIMPLEMENTED_DBGBREAK();
534 return STATUS_NOT_IMPLEMENTED;
535 }
536
537 PFN_NUMBER
538 NTAPI
MmGetPfnForProcess(IN PEPROCESS Process,IN PVOID Address)539 MmGetPfnForProcess(IN PEPROCESS Process,
540 IN PVOID Address)
541 {
542 MMPTE Pte;
543
544 //
545 // Get the PTE
546 //
547 Pte = MiGetPageEntryForProcess(Process, Address);
548 if (Pte.u.Hard.Valid == 0) return 0;
549
550 //
551 // Return PFN
552 //
553 return Pte.u.Hard.PageFrameNumber;
554 }
555
556 BOOLEAN
557 NTAPI
MmIsDirtyPage(IN PEPROCESS Process,IN PVOID Address)558 MmIsDirtyPage(IN PEPROCESS Process,
559 IN PVOID Address)
560 {
561 //
562 // TODO
563 //
564 UNIMPLEMENTED_DBGBREAK();
565 return FALSE;
566 }
567
568 VOID
569 NTAPI
MmSetCleanPage(IN PEPROCESS Process,IN PVOID Address)570 MmSetCleanPage(IN PEPROCESS Process,
571 IN PVOID Address)
572 {
573 //
574 // TODO
575 //
576 UNIMPLEMENTED_DBGBREAK();
577 }
578
579 VOID
580 NTAPI
MmSetDirtyPage(IN PEPROCESS Process,IN PVOID Address)581 MmSetDirtyPage(IN PEPROCESS Process,
582 IN PVOID Address)
583 {
584 //
585 // TODO
586 //
587 UNIMPLEMENTED_DBGBREAK();
588 }
589
590 BOOLEAN
591 NTAPI
MmIsPagePresent(IN PEPROCESS Process,IN PVOID Address)592 MmIsPagePresent(IN PEPROCESS Process,
593 IN PVOID Address)
594 {
595 //
596 // Fault PTEs are 0, which is FALSE (non-present)
597 //
598 return MiGetPageEntryForProcess(Process, Address).u.Hard.Valid;
599 }
600
601 BOOLEAN
602 NTAPI
MmIsPageSwapEntry(IN PEPROCESS Process,IN PVOID Address)603 MmIsPageSwapEntry(IN PEPROCESS Process,
604 IN PVOID Address)
605 {
606 MMPTE Pte;
607
608 //
609 // Get the PTE
610 //
611 Pte = MiGetPageEntryForProcess(Process, Address);
612
613 //
614 // Make sure it exists, but is faulting
615 //
616 return (Pte.u.Hard.Valid == 0) && (Pte.u.Hard.AsUlong);
617 }
618
619 ULONG
620 NTAPI
MmGetPageProtect(IN PEPROCESS Process,IN PVOID Address)621 MmGetPageProtect(IN PEPROCESS Process,
622 IN PVOID Address)
623 {
624 //
625 // We don't enforce any protection on the pages -- they are all RWX
626 //
627 return PAGE_READWRITE;
628 }
629
630 VOID
631 NTAPI
MmSetPageProtect(IN PEPROCESS Process,IN PVOID Address,IN ULONG Protection)632 MmSetPageProtect(IN PEPROCESS Process,
633 IN PVOID Address,
634 IN ULONG Protection)
635 {
636 //
637 // We don't enforce any protection on the pages -- they are all RWX
638 //
639 return;
640 }
641
642 VOID
643 NTAPI
MmInitGlobalKernelPageDirectory(VOID)644 MmInitGlobalKernelPageDirectory(VOID)
645 {
646 ULONG i;
647 PULONG CurrentPageDirectory = (PULONG)PDE_BASE;
648
649 //
650 // Good place to setup template PTE/PDEs.
651 // We are lazy and pick a known-good PTE
652 //
653 MiArmTemplatePte = *MiAddressToPte(0x80000000);
654 MiArmTemplatePde = *MiAddressToPde(0x80000000);
655
656 //
657 // Loop the 2GB of address space which belong to the kernel
658 //
659 for (i = MiGetPdeOffset(MmSystemRangeStart); i < 1024; i++)
660 {
661 //
662 // Check if we have an entry for this already
663 //
664 if ((i != MiGetPdeOffset(PTE_BASE)) &&
665 (i != MiGetPdeOffset(HYPER_SPACE)) &&
666 (!MmGlobalKernelPageDirectory[i]) &&
667 (CurrentPageDirectory[i]))
668 {
669 //
670 // We don't, link it in our global page directory
671 //
672 MmGlobalKernelPageDirectory[i] = CurrentPageDirectory[i];
673 }
674 }
675 }
676
677
678 /* PUBLIC FUNCTIONS ***********************************************************/
679
680 /*
681 * @implemented
682 */
683 PHYSICAL_ADDRESS
684 NTAPI
MmGetPhysicalAddress(IN PVOID Address)685 MmGetPhysicalAddress(IN PVOID Address)
686 {
687 PHYSICAL_ADDRESS PhysicalAddress;
688 MMPTE Pte;
689
690 //
691 // Early boot PCR check
692 //
693 if (Address == PCR)
694 {
695 //
696 // ARM Hack while we still use a section PTE
697 //
698 PMMPDE_HARDWARE PointerPde;
699 PointerPde = MiAddressToPde(PCR);
700 ASSERT(PointerPde->u.Hard.Section.Valid == 1);
701 PhysicalAddress.QuadPart = PointerPde->u.Hard.Section.PageFrameNumber;
702 PhysicalAddress.QuadPart <<= CPT_SHIFT;
703 PhysicalAddress.LowPart += BYTE_OFFSET(Address);
704 return PhysicalAddress;
705 }
706
707 //
708 // Get the PTE
709 //
710 Pte = MiGetPageEntryForProcess(NULL, Address);
711 if (Pte.u.Hard.Valid)
712 {
713 //
714 // Return the information
715 //
716 PhysicalAddress.QuadPart = Pte.u.Hard.PageFrameNumber;
717 PhysicalAddress.QuadPart <<= PAGE_SHIFT;
718 PhysicalAddress.LowPart += BYTE_OFFSET(Address);
719 }
720 else
721 {
722 //
723 // Invalid or unmapped
724 //
725 PhysicalAddress.QuadPart = 0;
726 }
727
728 //
729 // Return the physical address
730 //
731 return PhysicalAddress;
732 }
733