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 MDL test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 
10 static
11 VOID
12 TestMmAllocatePagesForMdl(VOID)
13 {
14     PMDL Mdl;
15     PHYSICAL_ADDRESS LowAddress;
16     PHYSICAL_ADDRESS HighAddress;
17     PHYSICAL_ADDRESS SkipBytes;
18     PVOID SystemVa;
19     PMDL Mdls[32];
20     PVOID SystemVas[32];
21     ULONG i;
22     PPFN_NUMBER MdlPages;
23     ULONG MdlPageCount;
24 
25     LowAddress.QuadPart = 0;
26     HighAddress.QuadPart = -1;
27     SkipBytes.QuadPart = 0;
28     /* simple allocate/free */
29     Mdl = MmAllocatePagesForMdl(LowAddress,
30                                 HighAddress,
31                                 SkipBytes,
32                                 2 * 1024 * 1024);
33     ok(Mdl != NULL, "MmAllocatePagesForMdl failed\n");
34     if (skip(Mdl != NULL, "No Mdl\n"))
35         return;
36     ok(MmGetMdlByteCount(Mdl) == 2 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdl));
37     ok(MmGetMdlVirtualAddress(Mdl) == NULL, "Virtual address: %p\n", MmGetMdlVirtualAddress(Mdl));
38     ok(!(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdl->MdlFlags);
39     MdlPages = MmGetMdlPfnArray(Mdl);
40     MdlPageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Mdl), MmGetMdlByteCount(Mdl));
41     ok(MdlPageCount == 2 * 1024 * 1024 / PAGE_SIZE, "MdlPageCount = %lu\n", MdlPageCount);
42     for (i = 0; i < MdlPageCount; i++)
43     {
44         ok(MdlPages[i] != 0 && MdlPages[i] != (PFN_NUMBER)-1,
45            "MdlPages[%lu] = 0x%I64x\n", i, (ULONGLONG)MdlPages[i]);
46     }
47     MmFreePagesFromMdl(Mdl);
48     ExFreePoolWithTag(Mdl, 0);
49 
50     /* Now map/unmap it */
51     Mdl = MmAllocatePagesForMdl(LowAddress,
52                                 HighAddress,
53                                 SkipBytes,
54                                 2 * 1024 * 1024);
55     ok(Mdl != NULL, "MmAllocatePagesForMdl failed\n");
56     if (skip(Mdl != NULL, "No Mdl\n"))
57         return;
58     ok(MmGetMdlByteCount(Mdl) == 2 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdl));
59     ok(MmGetMdlVirtualAddress(Mdl) == NULL, "Virtual address: %p\n", MmGetMdlVirtualAddress(Mdl));
60     ok(!(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdl->MdlFlags);
61     SystemVa = MmMapLockedPagesSpecifyCache(Mdl,
62                                             KernelMode,
63                                             MmCached,
64                                             NULL,
65                                             FALSE,
66                                             NormalPagePriority);
67     ok(SystemVa != NULL, "MmMapLockedPagesSpecifyCache failed\n");
68     if (!skip(SystemVa != NULL, "No system VA\n"))
69     {
70         ok(MmGetMdlByteCount(Mdl) == 2 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdl));
71         ok(MmGetMdlVirtualAddress(Mdl) == NULL, "Virtual address: %p, System VA: %p\n", MmGetMdlVirtualAddress(Mdl), SystemVa);
72         ok(Mdl->MappedSystemVa == SystemVa, "MappedSystemVa: %p, System VA: %p\n", Mdl->MappedSystemVa, SystemVa);
73         ok((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdl->MdlFlags);
74         MmUnmapLockedPages(SystemVa, Mdl);
75     }
76     ok(MmGetMdlByteCount(Mdl) == 2 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdl));
77     ok(MmGetMdlVirtualAddress(Mdl) == NULL, "Virtual address: %p\n", MmGetMdlVirtualAddress(Mdl));
78     ok(!(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdl->MdlFlags);
79     MmFreePagesFromMdl(Mdl);
80     ExFreePoolWithTag(Mdl, 0);
81 
82     /* Now map it, and free without unmapping */
83     Mdl = MmAllocatePagesForMdl(LowAddress,
84                                 HighAddress,
85                                 SkipBytes,
86                                 2 * 1024 * 1024);
87     ok(Mdl != NULL, "MmAllocatePagesForMdl failed\n");
88     if (skip(Mdl != NULL, "No Mdl\n"))
89         return;
90     ok(MmGetMdlByteCount(Mdl) == 2 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdl));
91     ok(MmGetMdlVirtualAddress(Mdl) == NULL, "Virtual address: %p\n", MmGetMdlVirtualAddress(Mdl));
92     ok(!(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdl->MdlFlags);
93     SystemVa = MmMapLockedPagesSpecifyCache(Mdl,
94                                             KernelMode,
95                                             MmCached,
96                                             NULL,
97                                             FALSE,
98                                             NormalPagePriority);
99     ok(SystemVa != NULL, "MmMapLockedPagesSpecifyCache failed\n");
100     ok(MmGetMdlByteCount(Mdl) == 2 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdl));
101     ok(MmGetMdlVirtualAddress(Mdl) == NULL, "Virtual address: %p, System VA: %p\n", MmGetMdlVirtualAddress(Mdl), SystemVa);
102     ok(Mdl->MappedSystemVa == SystemVa, "MappedSystemVa: %p, System VA: %p\n", Mdl->MappedSystemVa, SystemVa);
103     ok((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdl->MdlFlags);
104     MmFreePagesFromMdl(Mdl);
105     ExFreePoolWithTag(Mdl, 0);
106 
107     /* try to allocate 2 GB -- should succeed but not map */
108     Mdl = MmAllocatePagesForMdl(LowAddress,
109                                 HighAddress,
110                                 SkipBytes,
111                                 2UL * 1024 * 1024 * 1024);
112     ok(Mdl != NULL, "MmAllocatePagesForMdl failed for 2 GB\n");
113     if (Mdl != NULL)
114     {
115         ok(MmGetMdlByteCount(Mdl) != 2UL * 1024 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdl));
116         ok(MmGetMdlVirtualAddress(Mdl) == NULL, "Virtual address: %p\n", MmGetMdlVirtualAddress(Mdl));
117         ok(!(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdl->MdlFlags);
118         MdlPages = MmGetMdlPfnArray(Mdl);
119         MdlPageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Mdl), MmGetMdlByteCount(Mdl));
120         ok(MdlPageCount < 2UL * 1024 * 1024 * 1024 / PAGE_SIZE, "MdlPageCount = %lu\n", MdlPageCount);
121         for (i = 0; i < MdlPageCount; i++)
122         {
123             if (MdlPages[i] == 0 ||
124                 MdlPages[i] == (PFN_NUMBER)-1)
125             {
126                 ok(0, "MdlPages[%lu] = 0x%I64x\n", i, (ULONGLONG)MdlPages[i]);
127             }
128         }
129         SystemVa = MmMapLockedPagesSpecifyCache(Mdl,
130                                                 KernelMode,
131                                                 MmCached,
132                                                 NULL,
133                                                 FALSE,
134                                                 NormalPagePriority);
135         ok(SystemVa == NULL, "MmMapLockedPagesSpecifyCache succeeded for 2 GB\n");
136         if (SystemVa != NULL)
137             MmUnmapLockedPages(SystemVa, Mdl);
138         ok(MmGetMdlByteCount(Mdl) != 2UL * 1024 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdl));
139         ok(MmGetMdlVirtualAddress(Mdl) == NULL, "Virtual address: %p\n", MmGetMdlVirtualAddress(Mdl));
140         ok(!(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdl->MdlFlags);
141         MmFreePagesFromMdl(Mdl);
142         ExFreePoolWithTag(Mdl, 0);
143     }
144 
145     /* now allocate and map 32 MB Mdls until we fail */
146     for (i = 0; i < sizeof(Mdls) / sizeof(Mdls[0]); i++)
147     {
148         Mdls[i] = MmAllocatePagesForMdl(LowAddress,
149                                         HighAddress,
150                                         SkipBytes,
151                                         32 * 1024 * 1024);
152         if (Mdls[i] == NULL)
153         {
154             trace("MmAllocatePagesForMdl failed with i = %lu\n", i);
155             break;
156         }
157         ok(MmGetMdlVirtualAddress(Mdls[i]) == NULL, "Virtual address: %p\n", MmGetMdlVirtualAddress(Mdls[i]));
158         ok(!(Mdls[i]->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdls[i]->MdlFlags);
159         SystemVas[i] = MmMapLockedPagesSpecifyCache(Mdls[i],
160                                                     KernelMode,
161                                                     MmCached,
162                                                     NULL,
163                                                     FALSE,
164                                                     NormalPagePriority);
165         if (SystemVas[i] == NULL)
166         {
167             ok(MmGetMdlByteCount(Mdls[i]) <= 32 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdls[i]));
168             ok(MmGetMdlVirtualAddress(Mdls[i]) == NULL, "Virtual address: %p\n", MmGetMdlVirtualAddress(Mdls[i]));
169             ok(!(Mdls[i]->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdls[i]->MdlFlags);
170             trace("MmMapLockedPagesSpecifyCache failed with i = %lu\n", i);
171             break;
172         }
173         ok(MmGetMdlByteCount(Mdls[i]) == 32 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdls[i]));
174         ok(MmGetMdlVirtualAddress(Mdls[i]) == NULL, "Virtual address: %p, System VA: %p\n", MmGetMdlVirtualAddress(Mdls[i]), SystemVas[i]);
175         ok(Mdls[i]->MappedSystemVa == SystemVas[i], "MappedSystemVa: %p\n", Mdls[i]->MappedSystemVa, SystemVas[i]);
176         ok((Mdls[i]->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdls[i]->MdlFlags);
177     }
178     for (i = 0; i < sizeof(Mdls) / sizeof(Mdls[0]); i++)
179     {
180         if (Mdls[i] == NULL)
181             break;
182         if (SystemVas[i] != NULL)
183             MmUnmapLockedPages(SystemVas[i], Mdls[i]);
184         MmFreePagesFromMdl(Mdls[i]);
185         ExFreePoolWithTag(Mdls[i], 0);
186         if (SystemVas[i] == NULL)
187             break;
188     }
189 }
190 
191 static
192 VOID
193 TestMmBuildMdlForNonPagedPool(VOID)
194 {
195     PVOID Page;
196     PMDL Mdl;
197 
198     Page = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, 'Test');
199     ok(Page != NULL, "ExAllocatePoolWithTag failed\n");
200     if (skip(Page != NULL, "No buffer\n"))
201         return;
202 
203     Mdl = IoAllocateMdl(Page, PAGE_SIZE, FALSE, FALSE, NULL);
204     ok(Mdl != NULL, "IoAllocateMdl failed\n");
205     if (skip(Mdl != NULL, "No MDL\n"))
206         return;
207 
208     ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) == 0, "MDL locked\n");
209     ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n");
210 
211     MmBuildMdlForNonPagedPool(Mdl);
212     ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) == 0, "MDL locked\n");
213     ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) != 0, "MDL from paged\n");
214 
215     IoFreeMdl(Mdl);
216     ExFreePoolWithTag(Page, 'Test');
217 
218     Page = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'Test');
219     ok(Page != NULL, "ExAllocatePoolWithTag failed\n");
220     if (skip(Page != NULL, "No buffer\n"))
221         return;
222 
223     Mdl = IoAllocateMdl(Page, PAGE_SIZE, FALSE, FALSE, NULL);
224     ok(Mdl != NULL, "IoAllocateMdl failed\n");
225     if (skip(Mdl != NULL, "No MDL\n"))
226         return;
227 
228     ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) == 0, "MDL locked\n");
229     ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n");
230 
231     MmBuildMdlForNonPagedPool(Mdl);
232     ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) == 0, "MDL locked\n");
233     ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) != 0, "MDL from paged\n");
234 
235     IoFreeMdl(Mdl);
236     ExFreePoolWithTag(Page, 'Test');
237 }
238 
239 START_TEST(MmMdl)
240 {
241     TestMmAllocatePagesForMdl();
242     TestMmBuildMdlForNonPagedPool();
243 }
244