1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Reserved Mapping test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 
10 #ifdef _M_IX86
11 
12 #define PTE_BASE    0xC0000000
13 #define MiAddressToPte(x) \
14     ((PMMPTE)(((((ULONG)(x)) >> 12) << 2) + PTE_BASE))
15 #define MiPteToAddress(_Pte) ((PVOID)((ULONG)(_Pte) << 10))
16 
17 #elif defined(_M_AMD64)
18 
19 #define PTI_SHIFT  12L
20 #define PTE_BASE    0xFFFFF68000000000ULL
21 PMMPTE
22 FORCEINLINE
23 _MiAddressToPte(PVOID Address)
24 {
25     ULONG64 Offset = (ULONG64)Address >> (PTI_SHIFT - 3);
26     Offset &= 0xFFFFFFFFFULL << 3;
27     return (PMMPTE)(PTE_BASE + Offset);
28 }
29 #define MiAddressToPte(x) _MiAddressToPte((PVOID)(x))
30 
31 #endif
32 
33 static
34 _Must_inspect_result_
35 _IRQL_requires_max_ (DISPATCH_LEVEL)
36 PMDL
37 (NTAPI
38 *pMmAllocatePagesForMdlEx)(
39     _In_ PHYSICAL_ADDRESS LowAddress,
40     _In_ PHYSICAL_ADDRESS HighAddress,
41     _In_ PHYSICAL_ADDRESS SkipBytes,
42     _In_ SIZE_T TotalBytes,
43     _In_ MEMORY_CACHING_TYPE CacheType,
44     _In_ ULONG Flags);
45 
46 static
47 BOOLEAN
48 ValidateMapping(
49     _In_ PVOID BaseAddress,
50     _In_ ULONG TotalPtes,
51     _In_ ULONG PoolTag,
52     _In_ ULONG ValidPtes,
53     _In_ PPFN_NUMBER Pfns)
54 {
55     BOOLEAN Valid = TRUE;
56 #if defined(_M_IX86) || defined(_M_AMD64)
57     PMMPTE PointerPte;
58     ULONG i;
59 
60     PointerPte = MiAddressToPte(BaseAddress);
61     for (i = 0; i < ValidPtes; i++)
62     {
63         Valid = Valid &&
64                 ok(PointerPte[i].u.Hard.Valid == 1,
65                    "[%lu] PTE %p is not valid\n", i, &PointerPte[i]);
66 
67         Valid = Valid &&
68                 ok(PointerPte[i].u.Hard.PageFrameNumber == Pfns[i],
69                    "[%lu] PTE %p has PFN %Ix, expected %Ix\n",
70                    i, &PointerPte[i], PointerPte[i].u.Hard.PageFrameNumber, Pfns[i]);
71     }
72     for (; i < TotalPtes; i++)
73     {
74         Valid = Valid &&
75                 ok_eq_hex(PointerPte[i].u.Long, 0UL);
76     }
77     Valid = Valid &&
78             ok_eq_tag(PointerPte[-1].u.Long, PoolTag & ~1);
79     Valid = Valid &&
80             ok_eq_ulong(PointerPte[-2].u.Long, (TotalPtes + 2) * 2);
81 #endif
82 
83     return Valid;
84 }
85 
86 static
87 VOID
88 TestMap(
89     _In_ PVOID Mapping,
90     _In_ ULONG TotalPtes,
91     _In_ ULONG PoolTag)
92 {
93     PMDL Mdl;
94     PHYSICAL_ADDRESS ZeroPhysical;
95     PHYSICAL_ADDRESS MaxPhysical;
96     PVOID BaseAddress;
97     PPFN_NUMBER MdlPages;
98     ULONG i;
99 
100     if (skip(pMmAllocatePagesForMdlEx != NULL, "MmAllocatePagesForMdlEx unavailable\n"))
101     {
102         return;
103     }
104 
105     ZeroPhysical.QuadPart = 0;
106     MaxPhysical.QuadPart = 0xffffffffffffffffLL;
107 
108     /* Create a one-page MDL and map it */
109     Mdl = pMmAllocatePagesForMdlEx(ZeroPhysical,
110                                    MaxPhysical,
111                                    ZeroPhysical,
112                                    PAGE_SIZE,
113                                    MmCached,
114                                    0);
115     if (skip(Mdl != NULL, "No MDL\n"))
116     {
117         return;
118     }
119 
120     MdlPages = (PVOID)(Mdl + 1);
121 
122     BaseAddress = MmMapLockedPagesWithReservedMapping(Mapping,
123                                                       PoolTag,
124                                                       Mdl,
125                                                       MmCached);
126     ok(BaseAddress != NULL, "MmMapLockedPagesWithReservedMapping failed\n");
127     if (!skip(BaseAddress != NULL, "Failed to map MDL\n"))
128     {
129         ok_eq_pointer(BaseAddress, Mapping);
130 
131         ok_bool_true(ValidateMapping(BaseAddress, TotalPtes, PoolTag, 1, MdlPages),
132                      "ValidateMapping returned");
133 
134         KmtStartSeh()
135             *(volatile ULONG *)BaseAddress = 0x01234567;
136         KmtEndSeh(STATUS_SUCCESS);
137 
138         MmUnmapReservedMapping(BaseAddress,
139                                PoolTag,
140                                Mdl);
141 
142         ok_bool_true(ValidateMapping(Mapping, TotalPtes, PoolTag, 0, NULL),
143                      "ValidateMapping returned");
144     }
145 
146     /* Try again but at an unaligned address */
147     BaseAddress = MmMapLockedPagesWithReservedMapping((PUCHAR)Mapping + sizeof(ULONG),
148                                                       PoolTag,
149                                                       Mdl,
150                                                       MmCached);
151     ok(BaseAddress != NULL, "MmMapLockedPagesWithReservedMapping failed\n");
152     if (!skip(BaseAddress != NULL, "Failed to map MDL\n"))
153     {
154         ok_eq_pointer(BaseAddress, (PUCHAR)Mapping + sizeof(ULONG));
155 
156         ok_bool_true(ValidateMapping(BaseAddress, TotalPtes, PoolTag, 1, MdlPages),
157                      "ValidateMapping returned");
158 
159         KmtStartSeh()
160             *(volatile ULONG *)BaseAddress = 0x01234567;
161         KmtEndSeh(STATUS_SUCCESS);
162 
163         MmUnmapReservedMapping(BaseAddress,
164                                PoolTag,
165                                Mdl);
166 
167         ok_bool_true(ValidateMapping(Mapping, TotalPtes, PoolTag, 0, NULL),
168                      "ValidateMapping returned");
169     }
170 
171     MmFreePagesFromMdl(Mdl);
172 
173     /* Map all pages */
174     Mdl = pMmAllocatePagesForMdlEx(ZeroPhysical,
175                                    MaxPhysical,
176                                    ZeroPhysical,
177                                    TotalPtes * PAGE_SIZE,
178                                    MmCached,
179                                    0);
180     if (skip(Mdl != NULL, "No MDL\n"))
181     {
182         return;
183     }
184 
185     MdlPages = (PVOID)(Mdl + 1);
186 
187     BaseAddress = MmMapLockedPagesWithReservedMapping(Mapping,
188                                                       PoolTag,
189                                                       Mdl,
190                                                       MmCached);
191     ok(BaseAddress != NULL, "MmMapLockedPagesWithReservedMapping failed\n");
192     if (!skip(BaseAddress != NULL, "Failed to map MDL\n"))
193     {
194         ok_eq_pointer(BaseAddress, Mapping);
195 
196         ok_bool_true(ValidateMapping(BaseAddress, TotalPtes, PoolTag, TotalPtes, MdlPages),
197                      "ValidateMapping returned");
198 
199         for (i = 0; i < TotalPtes; i++)
200         {
201             KmtStartSeh()
202                 *((volatile ULONG *)BaseAddress + i * PAGE_SIZE / sizeof(ULONG)) = 0x01234567;
203             KmtEndSeh(STATUS_SUCCESS);
204         }
205 
206         MmUnmapReservedMapping(BaseAddress,
207                                PoolTag,
208                                Mdl);
209 
210         ok_bool_true(ValidateMapping(Mapping, TotalPtes, PoolTag, 0, NULL),
211                      "ValidateMapping returned");
212     }
213 
214     MmFreePagesFromMdl(Mdl);
215 
216     /* Try to map more pages than we reserved */
217     Mdl = pMmAllocatePagesForMdlEx(ZeroPhysical,
218                                    MaxPhysical,
219                                    ZeroPhysical,
220                                    (TotalPtes + 1) * PAGE_SIZE,
221                                    MmCached,
222                                    0);
223     if (skip(Mdl != NULL, "No MDL\n"))
224     {
225         return;
226     }
227 
228     BaseAddress = MmMapLockedPagesWithReservedMapping(Mapping,
229                                                       PoolTag,
230                                                       Mdl,
231                                                       MmCached);
232     ok_eq_pointer(BaseAddress, NULL);
233     if (BaseAddress)
234     {
235         MmUnmapReservedMapping(BaseAddress,
236                                PoolTag,
237                                Mdl);
238     }
239 
240     MmFreePagesFromMdl(Mdl);
241 }
242 
243 START_TEST(MmReservedMapping)
244 {
245     PVOID Mapping;
246 
247     pMmAllocatePagesForMdlEx = KmtGetSystemRoutineAddress(L"MmAllocatePagesForMdlEx");
248 
249     /* one byte - single page */
250     Mapping = MmAllocateMappingAddress(1, 'MRmK');
251     ok(Mapping != NULL, "MmAllocateMappingAddress failed\n");
252     if (!skip(Mapping != NULL, "No mapping\n"))
253     {
254         ok_bool_true(ValidateMapping(Mapping, 1, 'MRmK', 0, NULL),
255                      "ValidateMapping returned");
256 
257         MmFreeMappingAddress(Mapping, 'MRmK');
258     }
259 
260     /* 10 pages */
261     Mapping = MmAllocateMappingAddress(10 * PAGE_SIZE, 'MRmK' & ~1);
262     ok(Mapping != NULL, "MmAllocateMappingAddress failed\n");
263     if (!skip(Mapping != NULL, "No mapping\n"))
264     {
265         ok_bool_true(ValidateMapping(Mapping, 10, 'MRmK', 0, NULL),
266                      "ValidateMapping returned");
267 
268         /* PAGE_FAULT_IN_NONPAGED_AREA can't be caught with SEH */
269         if (0)
270         {
271             (void)*(volatile UCHAR *)Mapping;
272         }
273 
274         TestMap(Mapping, 10, 'MRmK');
275 
276         MmFreeMappingAddress(Mapping, 'MRmK');
277     }
278 
279     /* PoolTag = 0 */
280     Mapping = MmAllocateMappingAddress(1, 0);
281     ok(Mapping == NULL, "MmAllocateMappingAddress failed\n");
282     if (Mapping != NULL)
283     {
284         MmFreeMappingAddress(Mapping, 0);
285     }
286 
287     /* PoolTag = 1 */
288     Mapping = MmAllocateMappingAddress(1, 1);
289     ok(Mapping != NULL, "MmAllocateMappingAddress failed\n");
290     if (Mapping != NULL)
291     {
292         ok_bool_true(ValidateMapping(Mapping, 1, 1, 0, NULL),
293                      "ValidateMapping returned");
294 
295         TestMap(Mapping, 1, 1);
296 
297         MmFreeMappingAddress(Mapping, 1);
298     }
299 
300     /* Free an unaligned address */
301     Mapping = MmAllocateMappingAddress(PAGE_SIZE, 'MRmK');
302     ok(Mapping != NULL, "MmAllocateMappingAddress failed\n");
303     if (Mapping != NULL)
304     {
305         ok_bool_true(ValidateMapping(Mapping, 1, 'MRmK', 0, NULL),
306                      "ValidateMapping returned");
307 
308         TestMap(Mapping, 1, 'MRmK');
309 
310         MmFreeMappingAddress((PUCHAR)Mapping + sizeof(ULONG), 'MRmK');
311     }
312 }
313