Merge trunk HEAD (r46369)
[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 PFN_NUMBER *Pages,
118 IN PFN_NUMBER NumberOfPages)
119 {
120 MMPTE TempPte;
121 PMMPTE PointerPte;
122 PFN_NUMBER Offset, PageFrameIndex;
123
124 //
125 // Sanity checks
126 //
127 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
128 ASSERT(NumberOfPages != 0);
129 ASSERT(NumberOfPages <= (MI_ZERO_PTES - 1));
130
131 //
132 // Pick the first zeroing PTE
133 //
134 PointerPte = MiFirstReservedZeroingPte;
135
136 //
137 // Now get the first free PTE
138 //
139 Offset = PFN_FROM_PTE(PointerPte);
140 if (NumberOfPages > Offset)
141 {
142 //
143 // Reset the PTEs
144 //
145 Offset = MI_ZERO_PTES - 1;
146 PointerPte->u.Hard.PageFrameNumber = Offset;
147 KeFlushProcessTb();
148 }
149
150 //
151 // Prepare the next PTE
152 //
153 PointerPte->u.Hard.PageFrameNumber = Offset - NumberOfPages;
154
155 //
156 // Write the current PTE
157 //
158 PointerPte += (Offset + 1);
159 TempPte = ValidKernelPte;
160 MI_MAKE_LOCAL_PAGE(&TempPte); // Hyperspace is local!
161 do
162 {
163 //
164 // Get the first page entry and its PFN
165 //
166 PageFrameIndex = *Pages++;
167
168 //
169 // Write the PFN
170 //
171 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
172
173 //
174 // Set the correct PTE to write to, and set its new value
175 //
176 PointerPte--;
177 ASSERT(PointerPte->u.Hard.Valid == 0);
178 ASSERT(TempPte.u.Hard.Valid == 1);
179 *PointerPte = TempPte;
180 } while (--NumberOfPages);
181
182 //
183 // Return the address
184 //
185 return MiPteToAddress(PointerPte);
186 }
187
188 VOID
189 NTAPI
190 MiUnmapPagesInZeroSpace(IN PVOID VirtualAddress,
191 IN PFN_NUMBER NumberOfPages)
192 {
193 PMMPTE PointerPte;
194
195 //
196 // Sanity checks
197 //
198 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
199 ASSERT (NumberOfPages != 0);
200 ASSERT (NumberOfPages <= (MI_ZERO_PTES - 1));
201
202 //
203 // Get the first PTE for the mapped zero VA
204 //
205 PointerPte = MiAddressToPte(VirtualAddress);
206
207 //
208 // Blow away the mapped zero PTEs
209 //
210 RtlZeroMemory(PointerPte, NumberOfPages * sizeof(MMPTE));
211 }
212