1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Kernel-Mode Test Suite Reserved Mapping test
5 * COPYRIGHT: Copyright 2015,2023 Thomas Faber (thomas.faber@reactos.org)
6 * COPYRIGHT: Copyright 2015 Pierre Schweitzer (pierre@reactos.org)
7 */
8
9 #include <kmt_test.h>
10
11 static BOOLEAN g_IsPae;
12 static ULONG g_OsVersion;
13 static BOOLEAN g_IsReactOS;
14
15 #ifdef _M_IX86
16
17 #define IS_PAE() (g_IsPae)
18
19 #define PTE_BASE 0xC0000000
20
21 #define MiAddressToPteX86(x) \
22 ((PULONG)(((((ULONG)(x)) >> 12) << 2) + PTE_BASE))
23 #define MiAddressToPtePAE(x) \
24 ((PULONGLONG)(((((ULONG)(x)) >> 12) << 3) + PTE_BASE))
25
26 #define GET_PTE_VALUE_X86(Addr) (*MiAddressToPteX86(Addr))
27 #define GET_PTE_VALUE_PAE(Addr) (*MiAddressToPtePAE(Addr))
28 #define GET_PTE_VALUE(Addr) (IS_PAE() ? GET_PTE_VALUE_PAE(Addr) : GET_PTE_VALUE_X86(Addr))
29
30 #define PTE_IS_VALID(PteValue) ((PteValue) & 1)
31
32 #define PTE_GET_PFN_X86(PteValue) (((PteValue) >> PAGE_SHIFT) & 0x0fffffULL)
33 #define PTE_GET_PFN_PAE(PteValue) (((PteValue) >> PAGE_SHIFT) & 0xffffffULL)
34 #define PTE_GET_PFN(PteValue) (IS_PAE() ? PTE_GET_PFN_PAE(PteValue) : PTE_GET_PFN_X86(PteValue))
35
36 #elif defined(_M_AMD64)
37
38 #define PTI_SHIFT 12L
39 #define PTE_BASE 0xFFFFF68000000000ULL
40 PULONGLONG
41 FORCEINLINE
_MiAddressToPte(PVOID Address)42 _MiAddressToPte(PVOID Address)
43 {
44 ULONG64 Offset = (ULONG64)Address >> (PTI_SHIFT - 3);
45 Offset &= 0xFFFFFFFFFULL << 3;
46 return (PULONGLONG)(PTE_BASE + Offset);
47 }
48 #define MiAddressToPte(x) _MiAddressToPte((PVOID)(x))
49
50 #define GET_PTE_VALUE(Addr) (*_MiAddressToPte((PVOID)(Addr)))
51 #define PTE_IS_VALID(PteValue) ((PteValue) & 1)
52 #define PTE_GET_PFN(PteValue) (((PteValue) >> PAGE_SHIFT) & 0xFffffffffULL)
53
54 #endif
55
56 static
57 _Must_inspect_result_
58 _IRQL_requires_max_ (DISPATCH_LEVEL)
59 PMDL
60 (NTAPI
61 *pMmAllocatePagesForMdlEx)(
62 _In_ PHYSICAL_ADDRESS LowAddress,
63 _In_ PHYSICAL_ADDRESS HighAddress,
64 _In_ PHYSICAL_ADDRESS SkipBytes,
65 _In_ SIZE_T TotalBytes,
66 _In_ MEMORY_CACHING_TYPE CacheType,
67 _In_ ULONG Flags);
68
69 static
70 BOOLEAN
ValidateMapping(_In_ PVOID BaseAddress,_In_ ULONG TotalPtes,_In_ ULONG PoolTag,_In_ ULONG ValidPtes,_In_ PPFN_NUMBER Pfns)71 ValidateMapping(
72 _In_ PVOID BaseAddress,
73 _In_ ULONG TotalPtes,
74 _In_ ULONG PoolTag,
75 _In_ ULONG ValidPtes,
76 _In_ PPFN_NUMBER Pfns)
77 {
78 BOOLEAN Valid = TRUE;
79 #if defined(_M_IX86) || defined(_M_AMD64)
80 PUCHAR CurrentAddress;
81 ULONGLONG PteValue, ExpectedValue;
82 ULONG i;
83
84 for (i = 0; i < ValidPtes; i++)
85 {
86 CurrentAddress = (PUCHAR)BaseAddress + i * PAGE_SIZE;
87 PteValue = GET_PTE_VALUE(CurrentAddress);
88 Valid = Valid &&
89 ok(PTE_IS_VALID(PteValue),
90 "[%lu] PTE for %p is not valid (0x%I64x)\n",
91 i, CurrentAddress, PteValue);
92
93 Valid = Valid &&
94 ok(PTE_GET_PFN(PteValue) == Pfns[i],
95 "[%lu] PTE for %p has PFN %Ix, expected %Ix\n",
96 i, CurrentAddress, PTE_GET_PFN(PteValue), Pfns[i]);
97 }
98 for (; i < TotalPtes; i++)
99 {
100 CurrentAddress = (PUCHAR)BaseAddress + i * PAGE_SIZE;
101 PteValue = GET_PTE_VALUE(CurrentAddress);
102 Valid = Valid &&
103 ok(PteValue == 0,
104 "[%lu] PTE for %p is nonzero (0x%I64x)\n",
105 i, CurrentAddress, PteValue);
106 }
107 CurrentAddress = (PUCHAR)BaseAddress - 1 * PAGE_SIZE;
108 PteValue = GET_PTE_VALUE(CurrentAddress);
109 Valid = Valid &&
110 ok(PteValue == (PoolTag & ~1ULL),
111 "PTE for %p contains 0x%I64x, expected %x\n",
112 CurrentAddress, PteValue, PoolTag & ~1);
113 CurrentAddress = (PUCHAR)BaseAddress - 2 * PAGE_SIZE;
114 PteValue = GET_PTE_VALUE(CurrentAddress);
115
116 if (g_IsReactOS || g_OsVersion >= 0x0600)
117 {
118 /* On ReactOS and on Vista+ the size is stored in
119 * the NextEntry field of a MMPTE_LIST structure */
120 #ifdef _M_IX86
121 ExpectedValue = (TotalPtes + 2) << 12;
122 #elif defined(_M_AMD64)
123 ExpectedValue = ((ULONG64)TotalPtes + 2) << 32;
124 #endif
125 }
126 else
127 {
128 /* On Windows 2003 the size is shifted by 1 bit only */
129 ExpectedValue = (TotalPtes + 2) * 2;
130 }
131 Valid = Valid &&
132 ok(PteValue == ExpectedValue,
133 "PTE for %p contains 0x%I64x, expected %x\n",
134 CurrentAddress, PteValue, ExpectedValue);
135 #endif
136
137 return Valid;
138 }
139
140 static
141 VOID
TestMap(_In_ PVOID Mapping,_In_ ULONG TotalPtes,_In_ ULONG PoolTag)142 TestMap(
143 _In_ PVOID Mapping,
144 _In_ ULONG TotalPtes,
145 _In_ ULONG PoolTag)
146 {
147 PMDL Mdl;
148 PHYSICAL_ADDRESS ZeroPhysical;
149 PHYSICAL_ADDRESS MaxPhysical;
150 PVOID BaseAddress;
151 PPFN_NUMBER MdlPages;
152 ULONG i;
153
154 if (skip(pMmAllocatePagesForMdlEx != NULL, "MmAllocatePagesForMdlEx unavailable\n"))
155 {
156 return;
157 }
158
159 ZeroPhysical.QuadPart = 0;
160 MaxPhysical.QuadPart = 0xffffffffffffffffLL;
161
162 /* Create a one-page MDL and map it */
163 Mdl = pMmAllocatePagesForMdlEx(ZeroPhysical,
164 MaxPhysical,
165 ZeroPhysical,
166 PAGE_SIZE,
167 MmCached,
168 0);
169 if (skip(Mdl != NULL, "No MDL\n"))
170 {
171 return;
172 }
173
174 MdlPages = (PVOID)(Mdl + 1);
175
176 BaseAddress = MmMapLockedPagesWithReservedMapping(Mapping,
177 PoolTag,
178 Mdl,
179 MmCached);
180 ok(BaseAddress != NULL, "MmMapLockedPagesWithReservedMapping failed\n");
181 if (!skip(BaseAddress != NULL, "Failed to map MDL\n"))
182 {
183 ok_eq_pointer(BaseAddress, Mapping);
184
185 ok_bool_true(ValidateMapping(BaseAddress, TotalPtes, PoolTag, 1, MdlPages),
186 "ValidateMapping returned");
187
188 KmtStartSeh()
189 *(volatile ULONG *)BaseAddress = 0x01234567;
190 KmtEndSeh(STATUS_SUCCESS);
191
192 MmUnmapReservedMapping(BaseAddress,
193 PoolTag,
194 Mdl);
195
196 ok_bool_true(ValidateMapping(Mapping, TotalPtes, PoolTag, 0, NULL),
197 "ValidateMapping returned");
198 }
199
200 /* Try again but at an unaligned address */
201 BaseAddress = MmMapLockedPagesWithReservedMapping((PUCHAR)Mapping + sizeof(ULONG),
202 PoolTag,
203 Mdl,
204 MmCached);
205 ok(BaseAddress != NULL, "MmMapLockedPagesWithReservedMapping failed\n");
206 if (!skip(BaseAddress != NULL, "Failed to map MDL\n"))
207 {
208 ok_eq_pointer(BaseAddress, (PUCHAR)Mapping + sizeof(ULONG));
209
210 ok_bool_true(ValidateMapping(BaseAddress, TotalPtes, PoolTag, 1, MdlPages),
211 "ValidateMapping returned");
212
213 KmtStartSeh()
214 *(volatile ULONG *)BaseAddress = 0x01234567;
215 KmtEndSeh(STATUS_SUCCESS);
216
217 MmUnmapReservedMapping(BaseAddress,
218 PoolTag,
219 Mdl);
220
221 ok_bool_true(ValidateMapping(Mapping, TotalPtes, PoolTag, 0, NULL),
222 "ValidateMapping returned");
223 }
224
225 MmFreePagesFromMdl(Mdl);
226
227 /* Map all pages */
228 Mdl = pMmAllocatePagesForMdlEx(ZeroPhysical,
229 MaxPhysical,
230 ZeroPhysical,
231 TotalPtes * PAGE_SIZE,
232 MmCached,
233 0);
234 if (skip(Mdl != NULL, "No MDL\n"))
235 {
236 return;
237 }
238
239 MdlPages = (PVOID)(Mdl + 1);
240
241 BaseAddress = MmMapLockedPagesWithReservedMapping(Mapping,
242 PoolTag,
243 Mdl,
244 MmCached);
245 ok(BaseAddress != NULL, "MmMapLockedPagesWithReservedMapping failed\n");
246 if (!skip(BaseAddress != NULL, "Failed to map MDL\n"))
247 {
248 ok_eq_pointer(BaseAddress, Mapping);
249
250 ok_bool_true(ValidateMapping(BaseAddress, TotalPtes, PoolTag, TotalPtes, MdlPages),
251 "ValidateMapping returned");
252
253 for (i = 0; i < TotalPtes; i++)
254 {
255 KmtStartSeh()
256 *((volatile ULONG *)BaseAddress + i * PAGE_SIZE / sizeof(ULONG)) = 0x01234567;
257 KmtEndSeh(STATUS_SUCCESS);
258 }
259
260 MmUnmapReservedMapping(BaseAddress,
261 PoolTag,
262 Mdl);
263
264 ok_bool_true(ValidateMapping(Mapping, TotalPtes, PoolTag, 0, NULL),
265 "ValidateMapping returned");
266 }
267
268 MmFreePagesFromMdl(Mdl);
269
270 /* Try to map more pages than we reserved */
271 Mdl = pMmAllocatePagesForMdlEx(ZeroPhysical,
272 MaxPhysical,
273 ZeroPhysical,
274 (TotalPtes + 1) * PAGE_SIZE,
275 MmCached,
276 0);
277 if (skip(Mdl != NULL, "No MDL\n"))
278 {
279 return;
280 }
281
282 BaseAddress = MmMapLockedPagesWithReservedMapping(Mapping,
283 PoolTag,
284 Mdl,
285 MmCached);
286 ok_eq_pointer(BaseAddress, NULL);
287 if (BaseAddress)
288 {
289 MmUnmapReservedMapping(BaseAddress,
290 PoolTag,
291 Mdl);
292 }
293
294 MmFreePagesFromMdl(Mdl);
295 }
296
START_TEST(MmReservedMapping)297 START_TEST(MmReservedMapping)
298 {
299 PVOID Mapping;
300
301 g_IsPae = ExIsProcessorFeaturePresent(PF_PAE_ENABLED);
302 g_OsVersion = SharedUserData->NtMajorVersion << 8 | SharedUserData->NtMinorVersion;
303 g_IsReactOS = *(PULONG)(KI_USER_SHARED_DATA + PAGE_SIZE - sizeof(ULONG)) == 0x8eac705;
304 ok(g_IsReactOS == 1, "Not reactos\n");
305
306 pMmAllocatePagesForMdlEx = KmtGetSystemRoutineAddress(L"MmAllocatePagesForMdlEx");
307
308 /* one byte - single page */
309 Mapping = MmAllocateMappingAddress(1, 'MRmK');
310 ok(Mapping != NULL, "MmAllocateMappingAddress failed\n");
311 if (!skip(Mapping != NULL, "No mapping\n"))
312 {
313 ok_bool_true(ValidateMapping(Mapping, 1, 'MRmK', 0, NULL),
314 "ValidateMapping returned");
315
316 MmFreeMappingAddress(Mapping, 'MRmK');
317 }
318
319 /* 10 pages */
320 Mapping = MmAllocateMappingAddress(10 * PAGE_SIZE, 'MRmK' & ~1);
321 ok(Mapping != NULL, "MmAllocateMappingAddress failed\n");
322 if (!skip(Mapping != NULL, "No mapping\n"))
323 {
324 ok_bool_true(ValidateMapping(Mapping, 10, 'MRmK', 0, NULL),
325 "ValidateMapping returned");
326
327 /* PAGE_FAULT_IN_NONPAGED_AREA can't be caught with SEH */
328 if (0)
329 {
330 (void)*(volatile UCHAR *)Mapping;
331 }
332
333 TestMap(Mapping, 10, 'MRmK');
334
335 MmFreeMappingAddress(Mapping, 'MRmK');
336 }
337
338 /* PoolTag = 0 */
339 Mapping = MmAllocateMappingAddress(1, 0);
340 ok(Mapping == NULL, "MmAllocateMappingAddress failed\n");
341 if (Mapping != NULL)
342 {
343 MmFreeMappingAddress(Mapping, 0);
344 }
345
346 /* PoolTag = 1 */
347 Mapping = MmAllocateMappingAddress(1, 1);
348 ok(Mapping != NULL, "MmAllocateMappingAddress failed\n");
349 if (Mapping != NULL)
350 {
351 ok_bool_true(ValidateMapping(Mapping, 1, 1, 0, NULL),
352 "ValidateMapping returned");
353
354 TestMap(Mapping, 1, 1);
355
356 MmFreeMappingAddress(Mapping, 1);
357 }
358
359 /* Free an unaligned address */
360 Mapping = MmAllocateMappingAddress(PAGE_SIZE, 'MRmK');
361 ok(Mapping != NULL, "MmAllocateMappingAddress failed\n");
362 if (Mapping != NULL)
363 {
364 ok_bool_true(ValidateMapping(Mapping, 1, 'MRmK', 0, NULL),
365 "ValidateMapping returned");
366
367 TestMap(Mapping, 1, 'MRmK');
368
369 MmFreeMappingAddress((PUCHAR)Mapping + sizeof(ULONG), 'MRmK');
370 }
371 }
372