[NTOSKRNL/FREELDR/NDK]
[reactos.git] / reactos / ntoskrnl / mm / arm / stubs.c
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 goto kernelHack;
186 ASSERT(FALSE);
187
188 //
189 // Allocate a non paged pool page for the PDE
190 //
191 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
192 if (!NT_SUCCESS(Status)) return NULL;
193
194 //
195 // Make the entry valid
196 //
197 TempPde.u.Hard.AsUlong = 0xDEADBEEF;
198
199 //
200 // Set it
201 //
202 *PointerPde = TempPde;
203 }
204 }
205
206 //
207 // Return the PTE
208 //
209 return MiAddressToPte(Address);
210 }
211
212 MMPTE
213 NTAPI
214 MiGetPageEntryForProcess(IN PEPROCESS Process,
215 IN PVOID Address)
216 {
217 PMMPTE PointerPte;
218 MMPTE Pte;
219 Pte.u.Hard.AsUlong = 0;
220
221 //
222 // Get the PTE
223 //
224 PointerPte = MiGetPageTableForProcess(Process, Address, FALSE);
225 if (PointerPte)
226 {
227 //
228 // Capture the PTE value and unmap the page table
229 //
230 Pte = *PointerPte;
231 MiUnmapPageTable(PointerPte);
232 }
233
234 //
235 // Return the PTE value
236 //
237 return Pte;
238 }
239
240 BOOLEAN
241 NTAPI
242 MmCreateProcessAddressSpace(IN ULONG MinWs,
243 IN PEPROCESS Process,
244 IN PULONG DirectoryTableBase)
245 {
246 NTSTATUS Status;
247 ULONG i;
248 PFN_NUMBER Pfn[2];
249 PMMPDE_HARDWARE PageDirectory, PointerPde;
250 MMPDE_HARDWARE TempPde;
251 ASSERT(FALSE);
252
253 //
254 // Loop two tables (Hyperspace and TTB). Each one is 16KB
255 //
256 //
257 for (i = 0; i < sizeof(Pfn) / sizeof(Pfn[0]); i++)
258 {
259 //
260 // Allocate a page
261 //
262 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn[i]);
263 if (!NT_SUCCESS(Status)) ASSERT(FALSE);
264 }
265
266 //
267 // Map the base
268 //
269 PageDirectory = MmCreateHyperspaceMapping(Pfn[0]);
270
271 //
272 // Copy the PDEs for kernel-mode
273 //
274 RtlCopyMemory(PageDirectory + MiGetPdeOffset(MmSystemRangeStart),
275 MmGlobalKernelPageDirectory + MiGetPdeOffset(MmSystemRangeStart),
276 (1024 - MiGetPdeOffset(MmSystemRangeStart)) * sizeof(ULONG));
277
278
279 //
280 // Setup the PDE for the table base
281 //
282 TempPde = MiArmTemplatePde;
283 TempPde.u.Hard.Coarse.PageFrameNumber = (Pfn[0] << PAGE_SHIFT) >> CPT_SHIFT;
284 PointerPde = &PageDirectory[MiGetPdeOffset(PTE_BASE)];
285
286 //
287 // Write the PDE
288 //
289 ASSERT(PointerPde->u.Hard.Coarse.Valid == 0);
290 ASSERT(TempPde.u.Hard.Coarse.Valid == 1);
291 *PointerPde = TempPde;
292
293 //
294 // Setup the PDE for the hyperspace
295 //
296 TempPde.u.Hard.Coarse.PageFrameNumber = (Pfn[1] << PAGE_SHIFT) >> CPT_SHIFT;
297 PointerPde = &PageDirectory[MiGetPdeOffset(HYPER_SPACE)];
298
299 //
300 // Write the PDE
301 //
302 ASSERT(PointerPde->u.Hard.Coarse.Valid == 0);
303 ASSERT(TempPde.u.Hard.Coarse.Valid == 1);
304 *PointerPde = TempPde;
305
306 //
307 // Unmap the page directory
308 //
309 MmDeleteHyperspaceMapping(PageDirectory);
310
311 //
312 // Return the page table base
313 //
314 DirectoryTableBase[0] = Pfn[0] << PAGE_SHIFT;
315 return TRUE;
316 }
317
318 NTSTATUS
319 NTAPI
320 MmCreateVirtualMappingInternal(IN PEPROCESS Process,
321 IN PVOID Address,
322 IN ULONG Protection,
323 IN PPFN_NUMBER Pages,
324 IN ULONG PageCount,
325 IN BOOLEAN MarkAsMapped)
326 {
327 PMMPTE PointerPte = NULL;
328 MMPTE TempPte;
329 PVOID Addr;
330 ULONG OldPdeOffset, PdeOffset, i;
331 DPRINT("[KMAP]: %p %d\n", Address, PageCount);
332 //ASSERT(Address >= MmSystemRangeStart);
333
334 //
335 // Get our template PTE
336 //
337 TempPte = MiArmTemplatePte;
338
339 //
340 // Loop every page
341 //
342 Addr = Address;
343 OldPdeOffset = MiGetPdeOffset(Addr) + 1;
344 for (i = 0; i < PageCount; i++)
345 {
346 //
347 // Get the next PDE offset and check if it's a new one
348 //
349 PdeOffset = MiGetPdeOffset(Addr);
350 if (OldPdeOffset != PdeOffset)
351 {
352 //
353 // Get rid of the old L2 Table, if this was the last PTE on it
354 //
355 MiUnmapPageTable(PointerPte);
356
357 //
358 // Get the PTE for this address, and create the PDE for it
359 //
360 PointerPte = MiGetPageTableForProcess(NULL, Addr, TRUE);
361 ASSERT(PointerPte);
362 }
363 else
364 {
365 //
366 // Go to the next PTE on this PDE
367 //
368 ASSERT(PointerPte);
369 PointerPte++;
370 }
371
372 //
373 // Save the current PDE
374 //
375 OldPdeOffset = PdeOffset;
376
377 //
378 // Set the PFN
379 //
380 TempPte.u.Hard.PageFrameNumber = *Pages++;
381
382 //
383 // Write the PTE
384 //
385 ASSERT(PointerPte->u.Hard.Valid == 0);
386 ASSERT(TempPte.u.Hard.Valid == 1);
387 *PointerPte = TempPte;
388
389 //
390 // Move to the next page
391 //
392 Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE);
393 }
394
395 //
396 // All done
397 //
398 return STATUS_SUCCESS;
399 }
400
401 NTSTATUS
402 NTAPI
403 MmCreateVirtualMappingUnsafe(IN PEPROCESS Process,
404 IN PVOID Address,
405 IN ULONG Protection,
406 IN PPFN_NUMBER Pages,
407 IN ULONG PageCount)
408 {
409 //
410 // Are we only handling the kernel?
411 //
412 if (!(Process) || (Process == PsGetCurrentProcess()))
413 {
414 //
415 // Call the internal version
416 //
417 return MmCreateVirtualMappingInternal(Process,
418 Address,
419 Protection,
420 Pages,
421 PageCount,
422 TRUE);
423 }
424
425 //
426 // FIXME-USER: Support user-mode mappings
427 //
428 ASSERT(FALSE);
429 return 0;
430 }
431
432 NTSTATUS
433 NTAPI
434 MmCreateVirtualMapping(IN PEPROCESS Process,
435 IN PVOID Address,
436 IN ULONG Protection,
437 IN PPFN_NUMBER Pages,
438 IN ULONG PageCount)
439 {
440 ULONG i;
441
442 //
443 // Loop each page
444 //
445 for (i = 0; i < PageCount; i++)
446 {
447 //
448 // Make sure the page is marked as in use
449 //
450 ASSERT(MmIsPageInUse(Pages[i]));
451 }
452
453 //
454 // Call the unsafe version
455 //
456 return MmCreateVirtualMappingUnsafe(Process,
457 Address,
458 Protection,
459 Pages,
460 PageCount);
461 }
462
463 VOID
464 NTAPI
465 MmDeleteVirtualMapping(IN PEPROCESS Process,
466 IN PVOID Address,
467 OUT PBOOLEAN WasDirty,
468 OUT PPFN_NUMBER Page)
469 {
470 PMMPTE PointerPte;
471 MMPTE Pte;
472 PFN_NUMBER Pfn = 0;
473
474 //
475 // Get the PTE
476 //
477 PointerPte = MiGetPageTableForProcess(NULL, Address, FALSE);
478 if (PointerPte)
479 {
480 //
481 // Save and destroy the PTE
482 //
483 Pte = *PointerPte;
484 PointerPte->u.Hard.AsUlong = 0;
485
486 //
487 // Flush the TLB
488 //
489 MiFlushTlb(PointerPte, Address);
490
491 //
492 // Unmap the PFN
493 //
494 Pfn = Pte.u.Hard.PageFrameNumber;
495
496 //
497 // Release the PFN if it was ours
498 //
499 if ((FreePage) && (Pfn)) MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
500 }
501
502 //
503 // Return if the page was dirty
504 //
505 if (WasDirty) *WasDirty = FALSE; // LIE!!!
506 if (Page) *Page = Pfn;
507 }
508
509 VOID
510 NTAPI
511 MmDeletePageFileMapping(IN PEPROCESS Process,
512 IN PVOID Address,
513 IN SWAPENTRY *SwapEntry)
514 {
515 //
516 // TODO
517 //
518 UNIMPLEMENTED_DBGBREAK();
519 }
520
521 NTSTATUS
522 NTAPI
523 MmCreatePageFileMapping(IN PEPROCESS Process,
524 IN PVOID Address,
525 IN SWAPENTRY SwapEntry)
526 {
527 //
528 // TODO
529 //
530 UNIMPLEMENTED_DBGBREAK();
531 return STATUS_NOT_IMPLEMENTED;
532 }
533
534 PFN_NUMBER
535 NTAPI
536 MmGetPfnForProcess(IN PEPROCESS Process,
537 IN PVOID Address)
538 {
539 MMPTE Pte;
540
541 //
542 // Get the PTE
543 //
544 Pte = MiGetPageEntryForProcess(Process, Address);
545 if (Pte.u.Hard.Valid == 0) return 0;
546
547 //
548 // Return PFN
549 //
550 return Pte.u.Hard.PageFrameNumber;
551 }
552
553 BOOLEAN
554 NTAPI
555 MmIsDirtyPage(IN PEPROCESS Process,
556 IN PVOID Address)
557 {
558 //
559 // TODO
560 //
561 UNIMPLEMENTED_DBGBREAK();
562 return FALSE;
563 }
564
565 VOID
566 NTAPI
567 MmSetCleanPage(IN PEPROCESS Process,
568 IN PVOID Address)
569 {
570 //
571 // TODO
572 //
573 UNIMPLEMENTED_DBGBREAK();
574 }
575
576 VOID
577 NTAPI
578 MmSetDirtyPage(IN PEPROCESS Process,
579 IN PVOID Address)
580 {
581 //
582 // TODO
583 //
584 UNIMPLEMENTED_DBGBREAK();
585 }
586
587 BOOLEAN
588 NTAPI
589 MmIsPagePresent(IN PEPROCESS Process,
590 IN PVOID Address)
591 {
592 //
593 // Fault PTEs are 0, which is FALSE (non-present)
594 //
595 return MiGetPageEntryForProcess(Process, Address).u.Hard.Valid;
596 }
597
598 BOOLEAN
599 NTAPI
600 MmIsPageSwapEntry(IN PEPROCESS Process,
601 IN PVOID Address)
602 {
603 MMPTE Pte;
604
605 //
606 // Get the PTE
607 //
608 Pte = MiGetPageEntryForProcess(Process, Address);
609
610 //
611 // Make sure it exists, but is faulting
612 //
613 return (Pte.u.Hard.Valid == 0) && (Pte.u.Hard.AsUlong);
614 }
615
616 ULONG
617 NTAPI
618 MmGetPageProtect(IN PEPROCESS Process,
619 IN PVOID Address)
620 {
621 //
622 // We don't enforce any protection on the pages -- they are all RWX
623 //
624 return PAGE_READWRITE;
625 }
626
627 VOID
628 NTAPI
629 MmSetPageProtect(IN PEPROCESS Process,
630 IN PVOID Address,
631 IN ULONG Protection)
632 {
633 //
634 // We don't enforce any protection on the pages -- they are all RWX
635 //
636 return;
637 }
638
639 VOID
640 NTAPI
641 MmInitGlobalKernelPageDirectory(VOID)
642 {
643 ULONG i;
644 PULONG CurrentPageDirectory = (PULONG)PDE_BASE;
645
646 //
647 // Good place to setup template PTE/PDEs.
648 // We are lazy and pick a known-good PTE
649 //
650 MiArmTemplatePte = *MiAddressToPte(0x80000000);
651 MiArmTemplatePde = *MiAddressToPde(0x80000000);
652
653 //
654 // Loop the 2GB of address space which belong to the kernel
655 //
656 for (i = MiGetPdeOffset(MmSystemRangeStart); i < 1024; i++)
657 {
658 //
659 // Check if we have an entry for this already
660 //
661 if ((i != MiGetPdeOffset(PTE_BASE)) &&
662 (i != MiGetPdeOffset(HYPER_SPACE)) &&
663 (!MmGlobalKernelPageDirectory[i]) &&
664 (CurrentPageDirectory[i]))
665 {
666 //
667 // We don't, link it in our global page directory
668 //
669 MmGlobalKernelPageDirectory[i] = CurrentPageDirectory[i];
670 }
671 }
672 }
673
674
675 /* PUBLIC FUNCTIONS ***********************************************************/
676
677 /*
678 * @implemented
679 */
680 PHYSICAL_ADDRESS
681 NTAPI
682 MmGetPhysicalAddress(IN PVOID Address)
683 {
684 PHYSICAL_ADDRESS PhysicalAddress;
685 MMPTE Pte;
686
687 //
688 // Early boot PCR check
689 //
690 if (Address == PCR)
691 {
692 //
693 // ARM Hack while we still use a section PTE
694 //
695 PMMPDE_HARDWARE PointerPde;
696 PointerPde = MiAddressToPde(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;
702 }
703
704 //
705 // Get the PTE
706 //
707 Pte = MiGetPageEntryForProcess(NULL, Address);
708 if (Pte.u.Hard.Valid)
709 {
710 //
711 // Return the information
712 //
713 PhysicalAddress.QuadPart = Pte.u.Hard.PageFrameNumber;
714 PhysicalAddress.QuadPart <<= PAGE_SHIFT;
715 PhysicalAddress.LowPart += BYTE_OFFSET(Address);
716 }
717 else
718 {
719 //
720 // Invalid or unmapped
721 //
722 PhysicalAddress.QuadPart = 0;
723 }
724
725 //
726 // Return the physical address
727 //
728 return PhysicalAddress;
729 }