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