xref: /reactos/ntoskrnl/mm/ARM3/hypermap.c (revision 789d7a77)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            ntoskrnl/mm/ARM3/hypermap.c
5  * PURPOSE:         ARM Memory Manager Hyperspace Mapping Functionality
6  * PROGRAMMERS:     ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define MODULE_INVOLVED_IN_ARM3
16 #include <mm/ARM3/miarm.h>
17 
18 /* GLOBALS ********************************************************************/
19 
20 PMMPTE MmFirstReservedMappingPte, MmLastReservedMappingPte;
21 PMMPTE MiFirstReservedZeroingPte;
22 MMPTE HyperTemplatePte;
23 
24 /* PRIVATE FUNCTIONS **********************************************************/
25 
26 PVOID
27 NTAPI
MiMapPageInHyperSpace(IN PEPROCESS Process,IN PFN_NUMBER Page,IN PKIRQL OldIrql)28 MiMapPageInHyperSpace(IN PEPROCESS Process,
29                       IN PFN_NUMBER Page,
30                       IN PKIRQL OldIrql)
31 {
32     MMPTE TempPte;
33     PMMPTE PointerPte;
34     PFN_NUMBER Offset;
35 
36     //
37     // Never accept page 0 or non-physical pages
38     //
39     ASSERT(Page != 0);
40     ASSERT(MiGetPfnEntry(Page) != NULL);
41 
42     //
43     // Build the PTE
44     //
45     TempPte = ValidKernelPteLocal;
46     TempPte.u.Hard.PageFrameNumber = Page;
47 
48     //
49     // Pick the first hyperspace PTE
50     //
51     PointerPte = MmFirstReservedMappingPte;
52 
53     //
54     // Acquire the hyperlock
55     //
56     ASSERT(Process == PsGetCurrentProcess());
57     KeAcquireSpinLock(&Process->HyperSpaceLock, OldIrql);
58 
59     //
60     // Now get the first free PTE
61     //
62     Offset = PFN_FROM_PTE(PointerPte);
63     if (!Offset)
64     {
65         //
66         // Reset the PTEs
67         //
68         Offset = MI_HYPERSPACE_PTES;
69         KeFlushProcessTb();
70     }
71 
72     //
73     // Prepare the next PTE
74     //
75     PointerPte->u.Hard.PageFrameNumber = Offset - 1;
76 
77     //
78     // Write the current PTE
79     //
80     PointerPte += Offset;
81     MI_WRITE_VALID_PTE(PointerPte, TempPte);
82 
83     //
84     // Return the address
85     //
86     return MiPteToAddress(PointerPte);
87 }
88 
89 VOID
90 NTAPI
MiUnmapPageInHyperSpace(IN PEPROCESS Process,IN PVOID Address,IN KIRQL OldIrql)91 MiUnmapPageInHyperSpace(IN PEPROCESS Process,
92                         IN PVOID Address,
93                         IN KIRQL OldIrql)
94 {
95     ASSERT(Process == PsGetCurrentProcess());
96 
97     //
98     // Blow away the mapping
99     //
100     MiAddressToPte(Address)->u.Long = 0;
101 
102     //
103     // Release the hyperlock
104     //
105     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
106     KeReleaseSpinLock(&Process->HyperSpaceLock, OldIrql);
107 }
108 
109 PVOID
110 NTAPI
MiMapPagesInZeroSpace(IN PMMPFN Pfn1,IN PFN_NUMBER NumberOfPages)111 MiMapPagesInZeroSpace(IN PMMPFN Pfn1,
112                       IN PFN_NUMBER NumberOfPages)
113 {
114     MMPTE TempPte;
115     PMMPTE PointerPte;
116     PFN_NUMBER Offset, PageFrameIndex;
117 
118     //
119     // Sanity checks
120     //
121     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
122     ASSERT(NumberOfPages != 0);
123     ASSERT(NumberOfPages <= MI_ZERO_PTES);
124 
125     //
126     // Pick the first zeroing PTE
127     //
128     PointerPte = MiFirstReservedZeroingPte;
129 
130     //
131     // Now get the first free PTE
132     //
133     Offset = PFN_FROM_PTE(PointerPte);
134     if (NumberOfPages > Offset)
135     {
136         //
137         // Reset the PTEs
138         //
139         Offset = MI_ZERO_PTES;
140         PointerPte->u.Hard.PageFrameNumber = Offset;
141         KeFlushProcessTb();
142     }
143 
144     //
145     // Prepare the next PTE
146     //
147     PointerPte->u.Hard.PageFrameNumber = Offset - NumberOfPages;
148 
149     /* Choose the correct PTE to use, and which template */
150     PointerPte += (Offset + 1);
151     TempPte = ValidKernelPte;
152 
153     /* Disable cache. Write through */
154     MI_PAGE_DISABLE_CACHE(&TempPte);
155     MI_PAGE_WRITE_THROUGH(&TempPte);
156 
157     /* Make sure the list isn't empty and loop it */
158     ASSERT(Pfn1 != (PVOID)LIST_HEAD);
159     while (Pfn1 != (PVOID)LIST_HEAD)
160     {
161         /* Get the page index for this PFN */
162         PageFrameIndex = MiGetPfnEntryIndex(Pfn1);
163 
164         //
165         // Write the PFN
166         //
167         TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
168 
169         //
170         // Set the correct PTE to write to, and set its new value
171         //
172         PointerPte--;
173         MI_WRITE_VALID_PTE(PointerPte, TempPte);
174 
175         /* Move to the next PFN */
176         Pfn1 = (PMMPFN)Pfn1->u1.Flink;
177     }
178 
179     //
180     // Return the address
181     //
182     return MiPteToAddress(PointerPte);
183 }
184 
185 VOID
186 NTAPI
MiUnmapPagesInZeroSpace(IN PVOID VirtualAddress,IN PFN_NUMBER NumberOfPages)187 MiUnmapPagesInZeroSpace(IN PVOID VirtualAddress,
188                         IN PFN_NUMBER NumberOfPages)
189 {
190     PMMPTE PointerPte;
191 
192     //
193     // Sanity checks
194     //
195     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
196     ASSERT (NumberOfPages != 0);
197     ASSERT(NumberOfPages <= MI_ZERO_PTES);
198 
199     //
200     // Get the first PTE for the mapped zero VA
201     //
202     PointerPte = MiAddressToPte(VirtualAddress);
203 
204     //
205     // Blow away the mapped zero PTEs
206     //
207     RtlZeroMemory(PointerPte, NumberOfPages * sizeof(MMPTE));
208 }
209 
210