1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite MmMapLockedPagesSpecifyCache test user-mode part
5 * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org>
6 */
7
8 #include <kmt_test.h>
9 #include <ndk/exfuncs.h>
10
11 #include "MmMapLockedPagesSpecifyCache.h"
12
13 #define ALIGN_DOWN_BY(size, align) \
14 ((ULONG_PTR)(size) & ~((ULONG_PTR)(align) - 1))
15
16 #define SET_BUFFER_LENGTH(Var, Length) \
17 { \
18 C_ASSERT(((Length) % sizeof(ULONG)) == 0); \
19 Var = (Length); \
20 }
21
22 #define FILL_QUERY_BUFFER(QueryBuffer, BufferLength, UseCache) \
23 { \
24 QueryBuffer.Length = BufferLength; \
25 QueryBuffer.Buffer = NULL; \
26 QueryBuffer.Cached = UseCache; \
27 QueryBuffer.Status = STATUS_SUCCESS; \
28 }
29
30 #define FILL_READ_BUFFER(QueryBuffer, ReadBuffer) \
31 { \
32 PULONG Buffer; \
33 ReadBuffer.Buffer = QueryBuffer.Buffer; \
34 if (!skip(QueryBuffer.Buffer != NULL, "Buffer is NULL\n")) \
35 { \
36 ReadBuffer.Pattern = WRITE_PATTERN; \
37 ReadBuffer.Length = QueryBuffer.Length; \
38 Buffer = QueryBuffer.Buffer; \
39 for (i = 0; i < ReadBuffer.Length / sizeof(ULONG); ++i) \
40 { \
41 Buffer[i] = ReadBuffer.Pattern; \
42 } \
43 } \
44 }
45
46 #define CHECK_ALLOC(MappedBuffer, BufferLength) \
47 { \
48 NTSTATUS Status; \
49 PVOID BaseAddress; \
50 SIZE_T Size; \
51 BaseAddress = MappedBuffer; \
52 Size = BufferLength; \
53 Status = NtAllocateVirtualMemory(NtCurrentProcess(), \
54 &BaseAddress, \
55 0, \
56 &Size, \
57 MEM_RESERVE, \
58 PAGE_READWRITE); \
59 ok_eq_hex(Status, STATUS_CONFLICTING_ADDRESSES); \
60 BaseAddress = MappedBuffer; \
61 Size = 0; \
62 Status = NtFreeVirtualMemory(NtCurrentProcess(), \
63 &BaseAddress, \
64 &Size, \
65 MEM_DECOMMIT); \
66 ok_eq_hex(Status, STATUS_UNABLE_TO_DELETE_SECTION); \
67 BaseAddress = MappedBuffer; \
68 Size = 0; \
69 Status = NtFreeVirtualMemory(NtCurrentProcess(), \
70 &BaseAddress, \
71 &Size, \
72 MEM_RELEASE); \
73 ok_eq_hex(Status, STATUS_UNABLE_TO_DELETE_SECTION); \
74 Status = NtUnmapViewOfSection(NtCurrentProcess(), \
75 MappedBuffer); \
76 ok_eq_hex(Status, STATUS_NOT_MAPPED_VIEW); \
77 }
78
START_TEST(MmMapLockedPagesSpecifyCache)79 START_TEST(MmMapLockedPagesSpecifyCache)
80 {
81 QUERY_BUFFER QueryBuffer;
82 READ_BUFFER ReadBuffer;
83 DWORD Length;
84 USHORT i;
85 USHORT BufferLength;
86 SYSTEM_BASIC_INFORMATION BasicInfo;
87 NTSTATUS Status;
88 ULONG_PTR HighestAddress;
89 DWORD Error;
90
91 Error = KmtLoadAndOpenDriver(L"MmMapLockedPagesSpecifyCache", FALSE);
92 ok_eq_int(Error, ERROR_SUCCESS);
93 if (Error)
94 return;
95
96 // Less than a page
97 SET_BUFFER_LENGTH(BufferLength, 2048);
98 Length = sizeof(QUERY_BUFFER);
99 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, FALSE);
100 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
101 ok_eq_int(QueryBuffer.Length, BufferLength);
102 ok(QueryBuffer.Buffer != NULL, "Buffer is NULL\n");
103 CHECK_ALLOC(QueryBuffer.Buffer, BufferLength);
104
105 Length = 0;
106 FILL_READ_BUFFER(QueryBuffer, ReadBuffer);
107 ok(KmtSendBufferToDriver(IOCTL_READ_BUFFER, &ReadBuffer, sizeof(READ_BUFFER), &Length) == ERROR_SUCCESS, "\n");
108
109 Length = sizeof(QUERY_BUFFER);
110 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, TRUE);
111 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
112 ok_eq_int(QueryBuffer.Length, BufferLength);
113 ok(QueryBuffer.Buffer != NULL, "Buffer is NULL\n");
114 CHECK_ALLOC(QueryBuffer.Buffer, BufferLength);
115
116 Length = 0;
117 FILL_READ_BUFFER(QueryBuffer, ReadBuffer);
118 ok(KmtSendBufferToDriver(IOCTL_READ_BUFFER, &ReadBuffer, sizeof(READ_BUFFER), &Length) == ERROR_SUCCESS, "\n");
119
120 // 1 page
121 SET_BUFFER_LENGTH(BufferLength, 4096);
122 Length = sizeof(QUERY_BUFFER);
123 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, FALSE);
124 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
125 ok_eq_int(QueryBuffer.Length, BufferLength);
126 ok(QueryBuffer.Buffer != NULL, "Buffer is NULL\n");
127 CHECK_ALLOC(QueryBuffer.Buffer, BufferLength);
128
129 Length = 0;
130 FILL_READ_BUFFER(QueryBuffer, ReadBuffer);
131 ok(KmtSendBufferToDriver(IOCTL_READ_BUFFER, &ReadBuffer, sizeof(READ_BUFFER), &Length) == ERROR_SUCCESS, "\n");
132
133 Length = sizeof(QUERY_BUFFER);
134 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, TRUE);
135 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
136 ok_eq_int(QueryBuffer.Length, BufferLength);
137 ok(QueryBuffer.Buffer != NULL, "Buffer is NULL\n");
138 CHECK_ALLOC(QueryBuffer.Buffer, BufferLength);
139
140 Length = 0;
141 FILL_READ_BUFFER(QueryBuffer, ReadBuffer);
142 ok(KmtSendBufferToDriver(IOCTL_READ_BUFFER, &ReadBuffer, sizeof(READ_BUFFER), &Length) == ERROR_SUCCESS, "\n");
143
144 // more than 1 page
145 SET_BUFFER_LENGTH(BufferLength, 4096 + 2048);
146 Length = sizeof(QUERY_BUFFER);
147 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, FALSE);
148 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
149 ok_eq_int(QueryBuffer.Length, BufferLength);
150 ok(QueryBuffer.Buffer != NULL, "Buffer is NULL\n");
151 CHECK_ALLOC(QueryBuffer.Buffer, BufferLength);
152
153 Length = 0;
154 FILL_READ_BUFFER(QueryBuffer, ReadBuffer);
155 ok(KmtSendBufferToDriver(IOCTL_READ_BUFFER, &ReadBuffer, sizeof(READ_BUFFER), &Length) == ERROR_SUCCESS, "\n");
156
157 Length = sizeof(QUERY_BUFFER);
158 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, TRUE);
159 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
160 ok_eq_int(QueryBuffer.Length, BufferLength);
161 ok(QueryBuffer.Buffer != NULL, "Buffer is NULL\n");
162 CHECK_ALLOC(QueryBuffer.Buffer, BufferLength);
163
164 Length = 0;
165 FILL_READ_BUFFER(QueryBuffer, ReadBuffer);
166 ok(KmtSendBufferToDriver(IOCTL_READ_BUFFER, &ReadBuffer, sizeof(READ_BUFFER), &Length) == ERROR_SUCCESS, "\n");
167
168 // 2 pages
169 SET_BUFFER_LENGTH(BufferLength, 2 * 4096);
170 Length = sizeof(QUERY_BUFFER);
171 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, FALSE);
172 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
173 ok_eq_int(QueryBuffer.Length, BufferLength);
174 ok(QueryBuffer.Buffer != NULL, "Buffer is NULL\n");
175 CHECK_ALLOC(QueryBuffer.Buffer, BufferLength);
176
177 Length = 0;
178 FILL_READ_BUFFER(QueryBuffer, ReadBuffer);
179 ok(KmtSendBufferToDriver(IOCTL_READ_BUFFER, &ReadBuffer, sizeof(READ_BUFFER), &Length) == ERROR_SUCCESS, "\n");
180
181 Length = sizeof(QUERY_BUFFER);
182 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, TRUE);
183 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
184 ok_eq_int(QueryBuffer.Length, BufferLength);
185 ok(QueryBuffer.Buffer != NULL, "Buffer is NULL\n");
186 CHECK_ALLOC(QueryBuffer.Buffer, BufferLength);
187
188 Length = 0;
189 FILL_READ_BUFFER(QueryBuffer, ReadBuffer);
190 ok(KmtSendBufferToDriver(IOCTL_READ_BUFFER, &ReadBuffer, sizeof(READ_BUFFER), &Length) == ERROR_SUCCESS, "\n");
191
192 // more than 2 pages
193 SET_BUFFER_LENGTH(BufferLength, 2 * 4096 + 2048);
194 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, FALSE);
195 Length = sizeof(QUERY_BUFFER);
196 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
197 ok_eq_int(QueryBuffer.Length, BufferLength);
198 ok(QueryBuffer.Buffer != NULL, "Buffer is NULL\n");
199 CHECK_ALLOC(QueryBuffer.Buffer, BufferLength);
200
201 Length = 0;
202 FILL_READ_BUFFER(QueryBuffer, ReadBuffer);
203 ok(KmtSendBufferToDriver(IOCTL_READ_BUFFER, &ReadBuffer, sizeof(READ_BUFFER), &Length) == ERROR_SUCCESS, "\n");
204
205 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, TRUE);
206 Length = sizeof(QUERY_BUFFER);
207 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
208 ok_eq_int(QueryBuffer.Length, BufferLength);
209 ok(QueryBuffer.Buffer != NULL, "Buffer is NULL\n");
210 CHECK_ALLOC(QueryBuffer.Buffer, BufferLength);
211
212 Length = 0;
213 FILL_READ_BUFFER(QueryBuffer, ReadBuffer);
214 ok(KmtSendBufferToDriver(IOCTL_READ_BUFFER, &ReadBuffer, sizeof(READ_BUFFER), &Length) == ERROR_SUCCESS, "\n");
215
216 // ask for a specific address (we know that ReadBuffer.Buffer is free)
217 SET_BUFFER_LENGTH(BufferLength, 4096);
218 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, FALSE);
219 QueryBuffer.Buffer = ReadBuffer.Buffer;
220 Length = sizeof(QUERY_BUFFER);
221 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
222 ok_eq_int(QueryBuffer.Length, BufferLength);
223 ok(QueryBuffer.Buffer == ReadBuffer.Buffer, "Buffer is NULL\n");
224 CHECK_ALLOC(QueryBuffer.Buffer, BufferLength);
225
226 Length = 0;
227 FILL_READ_BUFFER(QueryBuffer, ReadBuffer);
228 ok(KmtSendBufferToDriver(IOCTL_READ_BUFFER, &ReadBuffer, sizeof(READ_BUFFER), &Length) == ERROR_SUCCESS, "\n");
229
230 // ask for an unaligned address
231 SET_BUFFER_LENGTH(BufferLength, 4096);
232 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, FALSE);
233 QueryBuffer.Buffer = (PVOID)((ULONG_PTR)ReadBuffer.Buffer + 2048);
234 QueryBuffer.Status = STATUS_INVALID_ADDRESS;
235 Length = sizeof(QUERY_BUFFER);
236 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
237 ok_eq_int(QueryBuffer.Length, BufferLength);
238 ok(QueryBuffer.Buffer == NULL, "Buffer is %p\n", QueryBuffer.Buffer);
239
240 Length = 0;
241 ok(KmtSendBufferToDriver(IOCTL_CLEAN, NULL, 0, &Length) == ERROR_SUCCESS, "\n");
242
243 // get system info for MmHighestUserAddress
244 Status = NtQuerySystemInformation(SystemBasicInformation,
245 &BasicInfo,
246 sizeof(BasicInfo),
247 NULL);
248 ok_eq_hex(Status, STATUS_SUCCESS);
249 trace("MaximumUserModeAddress: %lx\n", BasicInfo.MaximumUserModeAddress);
250 HighestAddress = ALIGN_DOWN_BY(BasicInfo.MaximumUserModeAddress, PAGE_SIZE);
251
252 // near MmHighestUserAddress
253 SET_BUFFER_LENGTH(BufferLength, 4096);
254 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, FALSE);
255 QueryBuffer.Buffer = (PVOID)(HighestAddress - 15 * PAGE_SIZE); // 7ffe0000
256 QueryBuffer.Status = STATUS_INVALID_ADDRESS;
257 trace("QueryBuffer.Buffer %p\n", QueryBuffer.Buffer);
258 Length = sizeof(QUERY_BUFFER);
259 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
260 ok_eq_int(QueryBuffer.Length, BufferLength);
261 ok(QueryBuffer.Buffer == NULL, "Buffer is %p\n", QueryBuffer.Buffer);
262
263 Length = 0;
264 ok(KmtSendBufferToDriver(IOCTL_CLEAN, NULL, 0, &Length) == ERROR_SUCCESS, "\n");
265
266 // far enough away from MmHighestUserAddress
267 SET_BUFFER_LENGTH(BufferLength, 4096);
268 FILL_QUERY_BUFFER(QueryBuffer, BufferLength, FALSE);
269 QueryBuffer.Buffer = (PVOID)(HighestAddress - 16 * PAGE_SIZE); // 7ffdf000
270 QueryBuffer.Status = -1;
271 trace("QueryBuffer.Buffer %p\n", QueryBuffer.Buffer);
272 Length = sizeof(QUERY_BUFFER);
273 ok(KmtSendBufferToDriver(IOCTL_QUERY_BUFFER, &QueryBuffer, sizeof(QUERY_BUFFER), &Length) == ERROR_SUCCESS, "\n");
274 ok_eq_int(QueryBuffer.Length, BufferLength);
275 ok(QueryBuffer.Status == STATUS_SUCCESS ||
276 QueryBuffer.Status == STATUS_CONFLICTING_ADDRESSES, "Status = %lx\n", QueryBuffer.Status);
277
278 Length = 0;
279 ok(KmtSendBufferToDriver(IOCTL_CLEAN, NULL, 0, &Length) == ERROR_SUCCESS, "\n");
280
281 KmtCloseDriver();
282 KmtUnloadDriver();
283 }
284