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