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