Merge the following revisions from kernel-fun branch:
[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 = MiGetPdeAddress(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], MiGetPdeAddress(Address));
145
146 //
147 // FIXFIX: Double check with Felix tomorrow
148 //
149 /////
150 //
151 // Get the PTE for this 1MB region
152 //
153 PointerPte = MiGetPteAddress(MiGetPteAddress(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 MiGetPteAddress(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 PULONG
319 NTAPI
320 MmGetPageDirectory(VOID)
321 {
322 //
323 // Return the TTB
324 //
325 return (PULONG)KeArmTranslationTableRegisterGet().AsUlong;
326 }
327
328 NTSTATUS
329 NTAPI
330 MmCreateVirtualMappingInternal(IN PEPROCESS Process,
331 IN PVOID Address,
332 IN ULONG Protection,
333 IN PPFN_NUMBER Pages,
334 IN ULONG PageCount,
335 IN BOOLEAN MarkAsMapped)
336 {
337 PMMPTE PointerPte = NULL;
338 MMPTE TempPte;
339 PVOID Addr;
340 ULONG OldPdeOffset, PdeOffset, i;
341 DPRINT("[KMAP]: %p %d\n", Address, PageCount);
342 //ASSERT(Address >= MmSystemRangeStart);
343
344 //
345 // Get our template PTE
346 //
347 TempPte = MiArmTemplatePte;
348
349 //
350 // Loop every page
351 //
352 Addr = Address;
353 OldPdeOffset = MiGetPdeOffset(Addr) + 1;
354 for (i = 0; i < PageCount; i++)
355 {
356 //
357 // Get the next PDE offset and check if it's a new one
358 //
359 PdeOffset = MiGetPdeOffset(Addr);
360 if (OldPdeOffset != PdeOffset)
361 {
362 //
363 // Get rid of the old L2 Table, if this was the last PTE on it
364 //
365 MiUnmapPageTable(PointerPte);
366
367 //
368 // Get the PTE for this address, and create the PDE for it
369 //
370 PointerPte = MiGetPageTableForProcess(NULL, Addr, TRUE);
371 ASSERT(PointerPte);
372 }
373 else
374 {
375 //
376 // Go to the next PTE on this PDE
377 //
378 ASSERT(PointerPte);
379 PointerPte++;
380 }
381
382 //
383 // Save the current PDE
384 //
385 OldPdeOffset = PdeOffset;
386
387 //
388 // Set the PFN
389 //
390 TempPte.u.Hard.PageFrameNumber = *Pages++;
391
392 //
393 // Write the PTE
394 //
395 ASSERT(PointerPte->u.Hard.Valid == 0);
396 ASSERT(TempPte.u.Hard.Valid == 1);
397 *PointerPte = TempPte;
398
399 //
400 // Move to the next page
401 //
402 Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE);
403 }
404
405 //
406 // All done
407 //
408 return STATUS_SUCCESS;
409 }
410
411 NTSTATUS
412 NTAPI
413 MmCreateVirtualMappingUnsafe(IN PEPROCESS Process,
414 IN PVOID Address,
415 IN ULONG Protection,
416 IN PPFN_NUMBER Pages,
417 IN ULONG PageCount)
418 {
419 //
420 // Are we only handling the kernel?
421 //
422 if (!(Process) || (Process == PsGetCurrentProcess()))
423 {
424 //
425 // Call the internal version
426 //
427 return MmCreateVirtualMappingInternal(Process,
428 Address,
429 Protection,
430 Pages,
431 PageCount,
432 TRUE);
433 }
434
435 //
436 // FIXME-USER: Support user-mode mappings
437 //
438 ASSERT(FALSE);
439 return 0;
440 }
441
442 NTSTATUS
443 NTAPI
444 MmCreateVirtualMapping(IN PEPROCESS Process,
445 IN PVOID Address,
446 IN ULONG Protection,
447 IN PPFN_NUMBER Pages,
448 IN ULONG PageCount)
449 {
450 ULONG i;
451
452 //
453 // Loop each page
454 //
455 for (i = 0; i < PageCount; i++)
456 {
457 //
458 // Make sure the page is marked as in use
459 //
460 ASSERT(MmIsPageInUse(Pages[i]));
461 }
462
463 //
464 // Call the unsafe version
465 //
466 return MmCreateVirtualMappingUnsafe(Process,
467 Address,
468 Protection,
469 Pages,
470 PageCount);
471 }
472
473 VOID
474 NTAPI
475 MmDeleteVirtualMapping(IN PEPROCESS Process,
476 IN PVOID Address,
477 OUT PBOOLEAN WasDirty,
478 OUT PPFN_NUMBER Page)
479 {
480 PMMPTE PointerPte;
481 MMPTE Pte;
482 PFN_NUMBER Pfn = 0;
483
484 //
485 // Get the PTE
486 //
487 PointerPte = MiGetPageTableForProcess(NULL, Address, FALSE);
488 if (PointerPte)
489 {
490 //
491 // Save and destroy the PTE
492 //
493 Pte = *PointerPte;
494 PointerPte->u.Hard.AsUlong = 0;
495
496 //
497 // Flush the TLB
498 //
499 MiFlushTlb(PointerPte, Address);
500
501 //
502 // Unmap the PFN
503 //
504 Pfn = Pte.u.Hard.PageFrameNumber;
505
506 //
507 // Release the PFN if it was ours
508 //
509 if ((FreePage) && (Pfn)) MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
510 }
511
512 //
513 // Return if the page was dirty
514 //
515 if (WasDirty) *WasDirty = FALSE; // LIE!!!
516 if (Page) *Page = Pfn;
517 }
518
519 VOID
520 NTAPI
521 MmDeletePageFileMapping(IN PEPROCESS Process,
522 IN PVOID Address,
523 IN SWAPENTRY *SwapEntry)
524 {
525 //
526 // TODO
527 //
528 UNIMPLEMENTED_DBGBREAK();
529 }
530
531 NTSTATUS
532 NTAPI
533 MmCreatePageFileMapping(IN PEPROCESS Process,
534 IN PVOID Address,
535 IN SWAPENTRY SwapEntry)
536 {
537 //
538 // TODO
539 //
540 UNIMPLEMENTED_DBGBREAK();
541 return STATUS_NOT_IMPLEMENTED;
542 }
543
544 PFN_NUMBER
545 NTAPI
546 MmGetPfnForProcess(IN PEPROCESS Process,
547 IN PVOID Address)
548 {
549 MMPTE Pte;
550
551 //
552 // Get the PTE
553 //
554 Pte = MiGetPageEntryForProcess(Process, Address);
555 if (Pte.u.Hard.Valid == 0) return 0;
556
557 //
558 // Return PFN
559 //
560 return Pte.u.Hard.PageFrameNumber;
561 }
562
563 BOOLEAN
564 NTAPI
565 MmIsDirtyPage(IN PEPROCESS Process,
566 IN PVOID Address)
567 {
568 //
569 // TODO
570 //
571 UNIMPLEMENTED_DBGBREAK();
572 return FALSE;
573 }
574
575 VOID
576 NTAPI
577 MmSetCleanPage(IN PEPROCESS Process,
578 IN PVOID Address)
579 {
580 //
581 // TODO
582 //
583 UNIMPLEMENTED_DBGBREAK();
584 }
585
586 VOID
587 NTAPI
588 MmSetDirtyPage(IN PEPROCESS Process,
589 IN PVOID Address)
590 {
591 //
592 // TODO
593 //
594 UNIMPLEMENTED_DBGBREAK();
595 }
596
597 BOOLEAN
598 NTAPI
599 MmIsPagePresent(IN PEPROCESS Process,
600 IN PVOID Address)
601 {
602 //
603 // Fault PTEs are 0, which is FALSE (non-present)
604 //
605 return MiGetPageEntryForProcess(Process, Address).u.Hard.Valid;
606 }
607
608 BOOLEAN
609 NTAPI
610 MmIsPageSwapEntry(IN PEPROCESS Process,
611 IN PVOID Address)
612 {
613 MMPTE Pte;
614
615 //
616 // Get the PTE
617 //
618 Pte = MiGetPageEntryForProcess(Process, Address);
619
620 //
621 // Make sure it exists, but is faulting
622 //
623 return (Pte.u.Hard.Valid == 0) && (Pte.u.Hard.AsUlong);
624 }
625
626 ULONG
627 NTAPI
628 MmGetPageProtect(IN PEPROCESS Process,
629 IN PVOID Address)
630 {
631 //
632 // We don't enforce any protection on the pages -- they are all RWX
633 //
634 return PAGE_READWRITE;
635 }
636
637 VOID
638 NTAPI
639 MmSetPageProtect(IN PEPROCESS Process,
640 IN PVOID Address,
641 IN ULONG Protection)
642 {
643 //
644 // We don't enforce any protection on the pages -- they are all RWX
645 //
646 return;
647 }
648
649 VOID
650 NTAPI
651 MmInitGlobalKernelPageDirectory(VOID)
652 {
653 ULONG i;
654 PULONG CurrentPageDirectory = (PULONG)PDE_BASE;
655
656 //
657 // Good place to setup template PTE/PDEs.
658 // We are lazy and pick a known-good PTE
659 //
660 MiArmTemplatePte = *MiGetPteAddress(0x80000000);
661 MiArmTemplatePde = *MiGetPdeAddress(0x80000000);
662
663 //
664 // Loop the 2GB of address space which belong to the kernel
665 //
666 for (i = MiGetPdeOffset(MmSystemRangeStart); i < 1024; i++)
667 {
668 //
669 // Check if we have an entry for this already
670 //
671 if ((i != MiGetPdeOffset(PTE_BASE)) &&
672 (i != MiGetPdeOffset(HYPER_SPACE)) &&
673 (!MmGlobalKernelPageDirectory[i]) &&
674 (CurrentPageDirectory[i]))
675 {
676 //
677 // We don't, link it in our global page directory
678 //
679 MmGlobalKernelPageDirectory[i] = CurrentPageDirectory[i];
680 }
681 }
682 }
683
684
685 /* PUBLIC FUNCTIONS ***********************************************************/
686
687 /*
688 * @implemented
689 */
690 PHYSICAL_ADDRESS
691 NTAPI
692 MmGetPhysicalAddress(IN PVOID Address)
693 {
694 PHYSICAL_ADDRESS PhysicalAddress;
695 MMPTE Pte;
696
697 //
698 // Early boot PCR check
699 //
700 if (Address == PCR)
701 {
702 //
703 // ARM Hack while we still use a section PTE
704 //
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;
712 }
713
714 //
715 // Get the PTE
716 //
717 Pte = MiGetPageEntryForProcess(NULL, Address);
718 if (Pte.u.Hard.Valid)
719 {
720 //
721 // Return the information
722 //
723 PhysicalAddress.QuadPart = Pte.u.Hard.PageFrameNumber;
724 PhysicalAddress.QuadPart <<= PAGE_SHIFT;
725 PhysicalAddress.LowPart += BYTE_OFFSET(Address);
726 }
727 else
728 {
729 //
730 // Invalid or unmapped
731 //
732 PhysicalAddress.QuadPart = 0;
733 }
734
735 //
736 // Return the physical address
737 //
738 return PhysicalAddress;
739 }