[NTOS:MM] Allow MiMapPageInHyperSpace to be called from DISPATCH_LEVEL
[reactos.git] / ntoskrnl / mm / ARM3 / hypermap.c
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 _Acquires_lock_(Process->HyperSpaceLock)
27 _When_(OldIrql == 0, _IRQL_requires_(DISPATCH_LEVEL))
28 _When_(OldIrql != 0, _IRQL_requires_(PASSIVE_LEVEL))
29 _When_(OldIrql != 0, _At_(*OldIrql, _IRQL_saves_))
30 _When_(OldIrql != 0, _IRQL_raises_(DISPATCH_LEVEL))
31 PVOID
32 NTAPI
33 MiMapPageInHyperSpace(_In_ PEPROCESS Process,
34 _In_ PFN_NUMBER Page,
35 _Out_opt_ PKIRQL OldIrql)
36 {
37 MMPTE TempPte;
38 PMMPTE PointerPte;
39 PFN_NUMBER Offset;
40
41 ASSERT(((OldIrql != NULL) && (KeGetCurrentIrql() == PASSIVE_LEVEL))
42 || ((OldIrql == NULL) && (KeGetCurrentIrql() == DISPATCH_LEVEL)));
43
44 //
45 // Never accept page 0 or non-physical pages
46 //
47 ASSERT(Page != 0);
48 ASSERT(MiGetPfnEntry(Page) != NULL);
49
50 //
51 // Build the PTE
52 //
53 TempPte = ValidKernelPteLocal;
54 TempPte.u.Hard.PageFrameNumber = Page;
55
56 //
57 // Pick the first hyperspace PTE
58 //
59 PointerPte = MmFirstReservedMappingPte;
60
61 //
62 // Acquire the hyperlock
63 //
64 ASSERT(Process == PsGetCurrentProcess());
65 if (OldIrql != NULL)
66 KeAcquireSpinLock(&Process->HyperSpaceLock, OldIrql);
67 else
68 KeAcquireSpinLockAtDpcLevel(&Process->HyperSpaceLock);
69
70 //
71 // Now get the first free PTE
72 //
73 Offset = PFN_FROM_PTE(PointerPte);
74 if (!Offset)
75 {
76 //
77 // Reset the PTEs
78 //
79 Offset = MI_HYPERSPACE_PTES;
80 KeFlushProcessTb();
81 }
82
83 //
84 // Prepare the next PTE
85 //
86 PointerPte->u.Hard.PageFrameNumber = Offset - 1;
87
88 //
89 // Write the current PTE
90 //
91 PointerPte += Offset;
92 MI_WRITE_VALID_PTE(PointerPte, TempPte);
93
94 //
95 // Return the address
96 //
97 return MiPteToAddress(PointerPte);
98 }
99
100 _Requires_lock_held_(Process->HyperSpaceLock)
101 _Releases_lock_(Process->HyperSpaceLock)
102 _IRQL_requires_(DISPATCH_LEVEL)
103 _When_(OldIrql != MM_NOIRQL, _At_(OldIrql, _IRQL_restores_))
104 VOID
105 NTAPI
106 MiUnmapPageInHyperSpace(_In_ PEPROCESS Process,
107 _In_ PVOID Address,
108 _In_ KIRQL OldIrql)
109 {
110 ASSERT(Process == PsGetCurrentProcess());
111
112 //
113 // Blow away the mapping
114 //
115 MiAddressToPte(Address)->u.Long = 0;
116
117 //
118 // Release the hyperlock
119 //
120 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
121 if (OldIrql == MM_NOIRQL)
122 KeReleaseSpinLockFromDpcLevel(&Process->HyperSpaceLock);
123 else
124 KeReleaseSpinLock(&Process->HyperSpaceLock, OldIrql);
125 }
126
127 PVOID
128 NTAPI
129 MiMapPagesInZeroSpace(IN PMMPFN Pfn1,
130 IN PFN_NUMBER NumberOfPages)
131 {
132 MMPTE TempPte;
133 PMMPTE PointerPte;
134 PFN_NUMBER Offset, PageFrameIndex;
135
136 //
137 // Sanity checks
138 //
139 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
140 ASSERT(NumberOfPages != 0);
141 ASSERT(NumberOfPages <= MI_ZERO_PTES);
142
143 //
144 // Pick the first zeroing PTE
145 //
146 PointerPte = MiFirstReservedZeroingPte;
147
148 //
149 // Now get the first free PTE
150 //
151 Offset = PFN_FROM_PTE(PointerPte);
152 if (NumberOfPages > Offset)
153 {
154 //
155 // Reset the PTEs
156 //
157 Offset = MI_ZERO_PTES;
158 PointerPte->u.Hard.PageFrameNumber = Offset;
159 KeFlushProcessTb();
160 }
161
162 //
163 // Prepare the next PTE
164 //
165 PointerPte->u.Hard.PageFrameNumber = Offset - NumberOfPages;
166
167 /* Choose the correct PTE to use, and which template */
168 PointerPte += (Offset + 1);
169 TempPte = ValidKernelPte;
170
171 /* Make sure the list isn't empty and loop it */
172 ASSERT(Pfn1 != (PVOID)LIST_HEAD);
173 while (Pfn1 != (PVOID)LIST_HEAD)
174 {
175 /* Get the page index for this PFN */
176 PageFrameIndex = MiGetPfnEntryIndex(Pfn1);
177
178 //
179 // Write the PFN
180 //
181 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
182
183 //
184 // Set the correct PTE to write to, and set its new value
185 //
186 PointerPte--;
187 MI_WRITE_VALID_PTE(PointerPte, TempPte);
188
189 /* Move to the next PFN */
190 Pfn1 = (PMMPFN)Pfn1->u1.Flink;
191 }
192
193 //
194 // Return the address
195 //
196 return MiPteToAddress(PointerPte);
197 }
198
199 VOID
200 NTAPI
201 MiUnmapPagesInZeroSpace(IN PVOID VirtualAddress,
202 IN PFN_NUMBER NumberOfPages)
203 {
204 PMMPTE PointerPte;
205
206 //
207 // Sanity checks
208 //
209 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
210 ASSERT (NumberOfPages != 0);
211 ASSERT(NumberOfPages <= MI_ZERO_PTES);
212
213 //
214 // Get the first PTE for the mapped zero VA
215 //
216 PointerPte = MiAddressToPte(VirtualAddress);
217
218 //
219 // Blow away the mapped zero PTEs
220 //
221 RtlZeroMemory(PointerPte, NumberOfPages * sizeof(MMPTE));
222 }
223