[NTOS]: When expanding paged pool, use MiRemoveAnyPage, not MmAllocPage.
[reactos.git] / reactos / 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 #line 15 "ARMĀ³::HYPERMAP"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
18
19 /* GLOBALS ********************************************************************/
20
21 PMMPTE MmFirstReservedMappingPte, MmLastReservedMappingPte;
22 PMMPTE MiFirstReservedZeroingPte;
23 MMPTE HyperTemplatePte;
24 PEPROCESS HyperProcess;
25 KIRQL HyperIrql;
26
27 /* PRIVATE FUNCTIONS **********************************************************/
28
29 PVOID
30 NTAPI
31 MiMapPageInHyperSpace(IN PEPROCESS Process,
32 IN PFN_NUMBER Page,
33 IN PKIRQL OldIrql)
34 {
35 MMPTE TempPte;
36 PMMPTE PointerPte;
37 PFN_NUMBER Offset;
38
39 //
40 // Never accept page 0 or non-physical pages
41 //
42 ASSERT(Page != 0);
43 ASSERT(MiGetPfnEntry(Page) != NULL);
44
45 //
46 // Build the PTE
47 //
48 TempPte = ValidKernelPte;
49 TempPte.u.Hard.PageFrameNumber = Page;
50 MI_MAKE_LOCAL_PAGE(&TempPte); // Hyperspace is local!
51
52 //
53 // Pick the first hyperspace PTE
54 //
55 PointerPte = MmFirstReservedMappingPte;
56
57 //
58 // Acquire the hyperlock
59 //
60 ASSERT(Process == PsGetCurrentProcess());
61 KeAcquireSpinLock(&Process->HyperSpaceLock, OldIrql);
62
63 //
64 // Now get the first free PTE
65 //
66 Offset = PFN_FROM_PTE(PointerPte);
67 if (!Offset)
68 {
69 //
70 // Reset the PTEs
71 //
72 Offset = MI_HYPERSPACE_PTES;
73 KeFlushProcessTb();
74 }
75
76 //
77 // Prepare the next PTE
78 //
79 PointerPte->u.Hard.PageFrameNumber = Offset - 1;
80
81 //
82 // Write the current PTE
83 //
84 PointerPte += Offset;
85 ASSERT(PointerPte->u.Hard.Valid == 0);
86 ASSERT(TempPte.u.Hard.Valid == 1);
87 *PointerPte = TempPte;
88
89 //
90 // Return the address
91 //
92 return MiPteToAddress(PointerPte);
93 }
94
95 VOID
96 NTAPI
97 MiUnmapPageInHyperSpace(IN PEPROCESS Process,
98 IN PVOID Address,
99 IN KIRQL OldIrql)
100 {
101 ASSERT(Process == PsGetCurrentProcess());
102
103 //
104 // Blow away the mapping
105 //
106 MiAddressToPte(Address)->u.Long = 0;
107
108 //
109 // Release the hyperlock
110 //
111 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
112 KeReleaseSpinLock(&Process->HyperSpaceLock, OldIrql);
113 }
114
115 PVOID
116 NTAPI
117 MiMapPagesToZeroInHyperSpace(IN PMMPFN *Pages,
118 IN PFN_NUMBER NumberOfPages)
119 {
120 MMPTE TempPte;
121 PMMPTE PointerPte;
122 PFN_NUMBER Offset, PageFrameIndex;
123 PMMPFN Page;
124
125 //
126 // Sanity checks
127 //
128 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
129 ASSERT(NumberOfPages != 0);
130 ASSERT(NumberOfPages <= (MI_ZERO_PTES - 1));
131
132 //
133 // Pick the first zeroing PTE
134 //
135 PointerPte = MiFirstReservedZeroingPte;
136
137 //
138 // Now get the first free PTE
139 //
140 Offset = PFN_FROM_PTE(PointerPte);
141 if (NumberOfPages > Offset)
142 {
143 //
144 // Reset the PTEs
145 //
146 Offset = MI_ZERO_PTES - 1;
147 PointerPte->u.Hard.PageFrameNumber = Offset;
148 KeFlushProcessTb();
149 }
150
151 //
152 // Prepare the next PTE
153 //
154 PointerPte->u.Hard.PageFrameNumber = Offset - NumberOfPages;
155
156 //
157 // Write the current PTE
158 //
159 PointerPte += (Offset + 1);
160 TempPte = ValidKernelPte;
161 MI_MAKE_LOCAL_PAGE(&TempPte); // Hyperspace is local!
162 do
163 {
164 //
165 // Get the first page entry and its PFN
166 //
167 Page = *Pages++;
168 PageFrameIndex = MiGetPfnEntryIndex(Page);
169
170 //
171 // Write the PFN
172 //
173 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
174
175 //
176 // Set the correct PTE to write to, and set its new value
177 //
178 PointerPte--;
179 ASSERT(PointerPte->u.Hard.Valid == 0);
180 ASSERT(TempPte.u.Hard.Valid == 1);
181 *PointerPte = TempPte;
182 } while (--NumberOfPages);
183
184 //
185 // Return the address
186 //
187 return MiPteToAddress(PointerPte);
188 }
189
190 VOID
191 NTAPI
192 MiUnmapPagesInZeroSpace(IN PVOID VirtualAddress,
193 IN PFN_NUMBER NumberOfPages)
194 {
195 PMMPTE PointerPte;
196
197 //
198 // Sanity checks
199 //
200 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
201 ASSERT (NumberOfPages != 0);
202 ASSERT (NumberOfPages <= (MI_ZERO_PTES - 1));
203
204 //
205 // Get the first PTE for the mapped zero VA
206 //
207 PointerPte = MiAddressToPte(VirtualAddress);
208
209 //
210 // Blow away the mapped zero PTEs
211 //
212 RtlZeroMemory(PointerPte, NumberOfPages * sizeof(MMPTE));
213 }
214