xref: /reactos/ntoskrnl/mm/arm/stubs.c (revision 6924b8ff)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
570 MmSetCleanPage(IN PEPROCESS Process,
571                IN PVOID Address)
572 {
573     //
574     // TODO
575     //
576     UNIMPLEMENTED_DBGBREAK();
577 }
578 
579 VOID
580 NTAPI
581 MmSetDirtyPage(IN PEPROCESS Process,
582                IN PVOID Address)
583 {
584     //
585     // TODO
586     //
587     UNIMPLEMENTED_DBGBREAK();
588 }
589 
590 BOOLEAN
591 NTAPI
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
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
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
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
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
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