1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Test driver for CcMapData function
5 * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org>
6 */
7
8 #include <kmt_test.h>
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #define IOCTL_START_TEST 1
14 #define IOCTL_FINISH_TEST 2
15
16 typedef struct _TEST_FCB
17 {
18 FSRTL_ADVANCED_FCB_HEADER Header;
19 SECTION_OBJECT_POINTERS SectionObjectPointers;
20 FAST_MUTEX HeaderMutex;
21 } TEST_FCB, *PTEST_FCB;
22
23 typedef struct _TEST_CONTEXT
24 {
25 PVOID Bcb;
26 PVOID Buffer;
27 ULONG Length;
28 } TEST_CONTEXT, *PTEST_CONTEXT;
29
30 static ULONG TestTestId = -1;
31 static PFILE_OBJECT TestFileObject;
32 static PDEVICE_OBJECT TestDeviceObject;
33 static KMT_IRP_HANDLER TestIrpHandler;
34 static KMT_MESSAGE_HANDLER TestMessageHandler;
35 static ULONGLONG Memory = 0;
36 static BOOLEAN TS = FALSE;
37
38 NTSTATUS
TestEntry(_In_ PDRIVER_OBJECT DriverObject,_In_ PCUNICODE_STRING RegistryPath,_Out_ PCWSTR * DeviceName,_Inout_ INT * Flags)39 TestEntry(
40 _In_ PDRIVER_OBJECT DriverObject,
41 _In_ PCUNICODE_STRING RegistryPath,
42 _Out_ PCWSTR *DeviceName,
43 _Inout_ INT *Flags)
44 {
45 ULONG Length;
46 SYSTEM_BASIC_INFORMATION SBI;
47 NTSTATUS Status = STATUS_SUCCESS;
48 RTL_OSVERSIONINFOEXW VersionInfo;
49
50 PAGED_CODE();
51
52 UNREFERENCED_PARAMETER(RegistryPath);
53
54 *DeviceName = L"CcMapData";
55 *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE |
56 TESTENTRY_BUFFERED_IO_DEVICE |
57 TESTENTRY_NO_READONLY_DEVICE;
58
59 KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler);
60 KmtRegisterMessageHandler(0, NULL, TestMessageHandler);
61
62 Status = ZwQuerySystemInformation(SystemBasicInformation,
63 &SBI,
64 sizeof(SBI),
65 &Length);
66 if (NT_SUCCESS(Status))
67 {
68 Memory = (SBI.NumberOfPhysicalPages * SBI.PageSize) / 1024 / 1024;
69 }
70 else
71 {
72 Status = STATUS_SUCCESS;
73 }
74
75 VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
76 Status = RtlGetVersion((PRTL_OSVERSIONINFOW)&VersionInfo);
77 if (NT_SUCCESS(Status))
78 {
79 TS = BooleanFlagOn(VersionInfo.wSuiteMask, VER_SUITE_TERMINAL) &&
80 !BooleanFlagOn(VersionInfo.wSuiteMask, VER_SUITE_SINGLEUSERTS);
81 }
82 else
83 {
84 Status = STATUS_SUCCESS;
85 }
86
87 trace("System with %I64dMb RAM and terminal services %S\n", Memory, (TS ? L"enabled" : L"disabled"));
88
89 return Status;
90 }
91
92 VOID
TestUnload(_In_ PDRIVER_OBJECT DriverObject)93 TestUnload(
94 _In_ PDRIVER_OBJECT DriverObject)
95 {
96 PAGED_CODE();
97 }
98
99 BOOLEAN
100 NTAPI
AcquireForLazyWrite(_In_ PVOID Context,_In_ BOOLEAN Wait)101 AcquireForLazyWrite(
102 _In_ PVOID Context,
103 _In_ BOOLEAN Wait)
104 {
105 return TRUE;
106 }
107
108 VOID
109 NTAPI
ReleaseFromLazyWrite(_In_ PVOID Context)110 ReleaseFromLazyWrite(
111 _In_ PVOID Context)
112 {
113 return;
114 }
115
116 BOOLEAN
117 NTAPI
AcquireForReadAhead(_In_ PVOID Context,_In_ BOOLEAN Wait)118 AcquireForReadAhead(
119 _In_ PVOID Context,
120 _In_ BOOLEAN Wait)
121 {
122 return TRUE;
123 }
124
125 VOID
126 NTAPI
ReleaseFromReadAhead(_In_ PVOID Context)127 ReleaseFromReadAhead(
128 _In_ PVOID Context)
129 {
130 return;
131 }
132
133 static CACHE_MANAGER_CALLBACKS Callbacks = {
134 AcquireForLazyWrite,
135 ReleaseFromLazyWrite,
136 AcquireForReadAhead,
137 ReleaseFromReadAhead,
138 };
139
140 static CC_FILE_SIZES FileSizes = {
141 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000), // .AllocationSize
142 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000), // .FileSize
143 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000) // .ValidDataLength
144 };
145
146 static
147 PVOID
MapAndLockUserBuffer(_In_ _Out_ PIRP Irp,_In_ ULONG BufferLength)148 MapAndLockUserBuffer(
149 _In_ _Out_ PIRP Irp,
150 _In_ ULONG BufferLength)
151 {
152 PMDL Mdl;
153
154 if (Irp->MdlAddress == NULL)
155 {
156 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
157 if (Mdl == NULL)
158 {
159 return NULL;
160 }
161
162 _SEH2_TRY
163 {
164 MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoWriteAccess);
165 }
166 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
167 {
168 IoFreeMdl(Mdl);
169 Irp->MdlAddress = NULL;
170 _SEH2_YIELD(return NULL);
171 }
172 _SEH2_END;
173 }
174
175 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
176 }
177
178 static
179 VOID
180 NTAPI
MapInAnotherThread(IN PVOID Context)181 MapInAnotherThread(IN PVOID Context)
182 {
183 BOOLEAN Ret;
184 PULONG Buffer;
185 PVOID Bcb;
186 LARGE_INTEGER Offset;
187 PTEST_CONTEXT TestContext;
188
189 ok(TestFileObject != NULL, "Called in invalid context!\n");
190 ok_eq_ulong(TestTestId, 3);
191
192 TestContext = Context;
193 ok(TestContext != NULL, "Called in invalid context!\n");
194 ok(TestContext->Bcb != NULL, "Called in invalid context!\n");
195 ok(TestContext->Buffer != NULL, "Called in invalid context!\n");
196 ok(TestContext->Length != 0, "Called in invalid context!\n");
197
198 Ret = FALSE;
199 Offset.QuadPart = 0x1000;
200 KmtStartSeh();
201 Ret = CcMapData(TestFileObject, &Offset, TestContext->Length, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
202 KmtEndSeh(STATUS_SUCCESS);
203
204 if (!skip(Ret == TRUE, "CcMapData failed\n"))
205 {
206 ok_eq_pointer(Bcb, TestContext->Bcb);
207 ok_eq_pointer(Buffer, TestContext->Buffer);
208
209 CcUnpinData(Bcb);
210 }
211
212 KmtStartSeh();
213 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, 0, &Bcb, (PVOID *)&Buffer);
214 KmtEndSeh(STATUS_SUCCESS);
215
216 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
217 {
218 ok(Bcb != TestContext->Bcb, "Returned same BCB!\n");
219 ok_eq_pointer(Buffer, TestContext->Buffer);
220
221 CcUnpinData(Bcb);
222 }
223
224 KmtStartSeh();
225 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_IF_BCB, &Bcb, (PVOID *)&Buffer);
226 KmtEndSeh(STATUS_SUCCESS);
227 ok(Ret == FALSE, "CcPinRead succeed\n");
228
229 if (Ret)
230 {
231 CcUnpinData(Bcb);
232 }
233
234 KmtStartSeh();
235 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_EXCLUSIVE, &Bcb, (PVOID *)&Buffer);
236 KmtEndSeh(STATUS_SUCCESS);
237
238 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
239 {
240 ok(Bcb != TestContext->Bcb, "Returned same BCB!\n");
241 ok_eq_pointer(Buffer, TestContext->Buffer);
242
243 CcUnpinData(Bcb);
244 }
245
246 Offset.QuadPart = 0x1500;
247 TestContext->Length -= 0x500;
248
249 KmtStartSeh();
250 Ret = CcMapData(TestFileObject, &Offset, TestContext->Length, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
251 KmtEndSeh(STATUS_SUCCESS);
252
253 if (!skip(Ret == TRUE, "CcMapData failed\n"))
254 {
255 ok_eq_pointer(Bcb, TestContext->Bcb);
256 ok_eq_pointer(Buffer, (PVOID)((ULONG_PTR)TestContext->Buffer + 0x500));
257
258 CcUnpinData(Bcb);
259 }
260
261 return;
262 }
263
264 static
265 VOID
PerformTest(ULONG TestId,PDEVICE_OBJECT DeviceObject)266 PerformTest(
267 ULONG TestId,
268 PDEVICE_OBJECT DeviceObject)
269 {
270 PVOID Bcb;
271 BOOLEAN Ret;
272 PULONG Buffer;
273 PTEST_FCB Fcb;
274 LARGE_INTEGER Offset;
275
276 ok_eq_pointer(TestFileObject, NULL);
277 ok_eq_pointer(TestDeviceObject, NULL);
278 ok_eq_ulong(TestTestId, -1);
279
280 TestDeviceObject = DeviceObject;
281 TestTestId = TestId;
282 TestFileObject = IoCreateStreamFileObject(NULL, DeviceObject);
283 if (!skip(TestFileObject != NULL, "Failed to allocate FO\n"))
284 {
285 Fcb = ExAllocatePool(NonPagedPool, sizeof(TEST_FCB));
286 if (!skip(Fcb != NULL, "ExAllocatePool failed\n"))
287 {
288 RtlZeroMemory(Fcb, sizeof(TEST_FCB));
289 ExInitializeFastMutex(&Fcb->HeaderMutex);
290 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
291
292 TestFileObject->FsContext = Fcb;
293 TestFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
294
295 KmtStartSeh();
296 CcInitializeCacheMap(TestFileObject, &FileSizes, FALSE, &Callbacks, NULL);
297 KmtEndSeh(STATUS_SUCCESS);
298
299 if (!skip(CcIsFileCached(TestFileObject) == TRUE, "CcInitializeCacheMap failed\n"))
300 {
301 if (TestId < 3)
302 {
303 Ret = FALSE;
304 Offset.QuadPart = TestId * 0x1000;
305 KmtStartSeh();
306 Ret = CcMapData(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
307 KmtEndSeh(STATUS_SUCCESS);
308
309 if (!skip(Ret == TRUE, "CcMapData failed\n"))
310 {
311 ok_eq_ulong(Buffer[(0x3000 - TestId * 0x1000) / sizeof(ULONG)], 0xDEADBABE);
312
313 CcUnpinData(Bcb);
314 }
315 }
316 else if (TestId == 3)
317 {
318 PTEST_CONTEXT TestContext;
319
320 TestContext = ExAllocatePool(NonPagedPool, sizeof(TEST_CONTEXT));
321 if (!skip(TestContext != NULL, "ExAllocatePool failed\n"))
322 {
323 Ret = FALSE;
324 Offset.QuadPart = 0x1000;
325 KmtStartSeh();
326 Ret = CcMapData(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, MAP_WAIT, &TestContext->Bcb, &TestContext->Buffer);
327 KmtEndSeh(STATUS_SUCCESS);
328
329 if (!skip(Ret == TRUE, "CcMapData failed\n"))
330 {
331 PKTHREAD ThreadHandle;
332
333 /* That's a bit rough but should do the job */
334 #ifdef _X86_
335 if (Memory >= 2 * 1024)
336 {
337 ok((TestContext->Buffer >= (PVOID)0xC1000000 && TestContext->Buffer < (PVOID)0xE0FFFFFF) ||
338 (TestContext->Buffer >= (PVOID)0xA4000000 && TestContext->Buffer < (PVOID)0xBFFFFFFF),
339 "Buffer %p not mapped in system space\n", TestContext->Buffer);
340 }
341 else if (TS)
342 {
343 ok(TestContext->Buffer >= (PVOID)0xC1000000 && TestContext->Buffer < (PVOID)0xDCFFFFFF,
344 "Buffer %p not mapped in system space\n", TestContext->Buffer);
345 }
346 else
347 {
348 ok(TestContext->Buffer >= (PVOID)0xC1000000 && TestContext->Buffer < (PVOID)0xDBFFFFFF,
349 "Buffer %p not mapped in system space\n", TestContext->Buffer);
350 }
351 #elif defined(_M_AMD64)
352 ok(TestContext->Buffer >= (PVOID)0xFFFFF98000000000 && TestContext->Buffer < (PVOID)0xFFFFFA8000000000,
353 "Buffer %p not mapped in system space\n", TestContext->Buffer);
354 #else
355 skip(FALSE, "System space mapping not defined\n");
356 #endif
357
358 TestContext->Length = FileSizes.FileSize.QuadPart - Offset.QuadPart;
359 ThreadHandle = KmtStartThread(MapInAnotherThread, TestContext);
360 KmtFinishThread(ThreadHandle, NULL);
361
362 TestContext->Length = FileSizes.FileSize.QuadPart - 2 * Offset.QuadPart;
363 ThreadHandle = KmtStartThread(MapInAnotherThread, TestContext);
364 KmtFinishThread(ThreadHandle, NULL);
365
366 CcUnpinData(TestContext->Bcb);
367 }
368
369 ExFreePool(TestContext);
370 }
371 }
372 else if (TestId == 4)
373 {
374 FileSizes.AllocationSize.QuadPart += VACB_MAPPING_GRANULARITY;
375 CcSetFileSizes(TestFileObject, &FileSizes);
376
377 /* Map after EOF */
378 Ret = FALSE;
379 Offset.QuadPart = FileSizes.FileSize.QuadPart + 0x1000;
380
381 KmtStartSeh();
382 Ret = CcMapData(TestFileObject, &Offset, 0x1000, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
383 KmtEndSeh(STATUS_SUCCESS);
384 ok(Ret == TRUE, "CcMapData failed\n");
385
386 if (Ret)
387 {
388 CcUnpinData(Bcb);
389 }
390
391 /* Map a VACB after EOF. */
392 Ret = FALSE;
393 Offset.QuadPart = FileSizes.FileSize.QuadPart + 0x1000 + VACB_MAPPING_GRANULARITY;
394
395 KmtStartSeh();
396 Ret = CcMapData(TestFileObject, &Offset, 0x1000, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
397 KmtEndSeh(STATUS_SUCCESS);
398 ok(Ret == TRUE, "CcMapData failed\n");
399
400 if (Ret)
401 {
402 CcUnpinData(Bcb);
403 }
404
405 /* Map after Allocation */
406 Ret = FALSE;
407 Offset.QuadPart = FileSizes.AllocationSize.QuadPart + 0x1000;
408
409 KmtStartSeh();
410 Ret = CcMapData(TestFileObject, &Offset, 0x1000, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
411 KmtEndSeh(STATUS_SUCCESS);
412 ok(Ret == TRUE, "CcMapData failed\n");
413
414 if (Ret)
415 {
416 CcUnpinData(Bcb);
417 }
418
419 Ret = FALSE;
420 Offset.QuadPart = FileSizes.AllocationSize.QuadPart + 0x1000 + VACB_MAPPING_GRANULARITY;
421
422 KmtStartSeh();
423 Ret = CcMapData(TestFileObject, &Offset, 0x1000, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
424 KmtEndSeh(STATUS_SUCCESS);
425 ok(Ret == TRUE, "CcMapData failed\n");
426
427 if (Ret)
428 {
429 CcUnpinData(Bcb);
430 }
431
432 /* Map more than a VACB */
433 Ret = FALSE;
434 Offset.QuadPart = 0x0;
435
436 KmtStartSeh();
437 Ret = CcMapData(TestFileObject, &Offset, 0x1000 + VACB_MAPPING_GRANULARITY, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
438 KmtEndSeh(STATUS_SUCCESS);
439 ok(Ret == TRUE, "CcMapData failed\n");
440
441 if (Ret)
442 {
443 CcUnpinData(Bcb);
444 }
445 }
446 }
447 }
448 }
449 }
450
451
452 static
453 VOID
CleanupTest(ULONG TestId,PDEVICE_OBJECT DeviceObject)454 CleanupTest(
455 ULONG TestId,
456 PDEVICE_OBJECT DeviceObject)
457 {
458 LARGE_INTEGER Zero = RTL_CONSTANT_LARGE_INTEGER(0LL);
459 CACHE_UNINITIALIZE_EVENT CacheUninitEvent;
460
461 ok_eq_pointer(TestDeviceObject, DeviceObject);
462 ok_eq_ulong(TestTestId, TestId);
463
464 if (!skip(TestFileObject != NULL, "No test FO\n"))
465 {
466 if (CcIsFileCached(TestFileObject))
467 {
468 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE);
469 CcUninitializeCacheMap(TestFileObject, &Zero, &CacheUninitEvent);
470 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL);
471 }
472
473 if (TestFileObject->FsContext != NULL)
474 {
475 ExFreePool(TestFileObject->FsContext);
476 TestFileObject->FsContext = NULL;
477 TestFileObject->SectionObjectPointer = NULL;
478 }
479
480 ObDereferenceObject(TestFileObject);
481 }
482
483 TestFileObject = NULL;
484 TestDeviceObject = NULL;
485 TestTestId = -1;
486 }
487
488
489 static
490 NTSTATUS
TestMessageHandler(_In_ PDEVICE_OBJECT DeviceObject,_In_ ULONG ControlCode,_In_opt_ PVOID Buffer,_In_ SIZE_T InLength,_Inout_ PSIZE_T OutLength)491 TestMessageHandler(
492 _In_ PDEVICE_OBJECT DeviceObject,
493 _In_ ULONG ControlCode,
494 _In_opt_ PVOID Buffer,
495 _In_ SIZE_T InLength,
496 _Inout_ PSIZE_T OutLength)
497 {
498 NTSTATUS Status = STATUS_SUCCESS;
499
500 FsRtlEnterFileSystem();
501
502 switch (ControlCode)
503 {
504 case IOCTL_START_TEST:
505 ok_eq_ulong((ULONG)InLength, sizeof(ULONG));
506 PerformTest(*(PULONG)Buffer, DeviceObject);
507 break;
508
509 case IOCTL_FINISH_TEST:
510 ok_eq_ulong((ULONG)InLength, sizeof(ULONG));
511 CleanupTest(*(PULONG)Buffer, DeviceObject);
512 break;
513
514 default:
515 Status = STATUS_NOT_IMPLEMENTED;
516 break;
517 }
518
519 FsRtlExitFileSystem();
520
521 return Status;
522 }
523
524 static
525 NTSTATUS
TestIrpHandler(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp,_In_ PIO_STACK_LOCATION IoStack)526 TestIrpHandler(
527 _In_ PDEVICE_OBJECT DeviceObject,
528 _In_ PIRP Irp,
529 _In_ PIO_STACK_LOCATION IoStack)
530 {
531 NTSTATUS Status;
532
533 PAGED_CODE();
534
535 DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction);
536 ASSERT(IoStack->MajorFunction == IRP_MJ_READ);
537
538 FsRtlEnterFileSystem();
539
540 Status = STATUS_NOT_SUPPORTED;
541 Irp->IoStatus.Information = 0;
542
543 if (IoStack->MajorFunction == IRP_MJ_READ)
544 {
545 PMDL Mdl;
546 ULONG Length;
547 PVOID Buffer;
548 LARGE_INTEGER Offset;
549
550 Offset = IoStack->Parameters.Read.ByteOffset;
551 Length = IoStack->Parameters.Read.Length;
552
553 ok_eq_pointer(DeviceObject, TestDeviceObject);
554 ok_eq_pointer(IoStack->FileObject, TestFileObject);
555
556 ok(FlagOn(Irp->Flags, IRP_NOCACHE), "Not coming from Cc\n");
557
558 ok_irql(APC_LEVEL);
559 ok((Offset.QuadPart % PAGE_SIZE == 0 || Offset.QuadPart == 0), "Offset is not aligned: %I64i\n", Offset.QuadPart);
560 ok(Length % PAGE_SIZE == 0, "Length is not aligned: %I64i\n", Length);
561
562 ok(Irp->AssociatedIrp.SystemBuffer == NULL, "A SystemBuffer was allocated!\n");
563 Buffer = MapAndLockUserBuffer(Irp, Length);
564 ok(Buffer != NULL, "Null pointer!\n");
565 RtlFillMemory(Buffer, Length, 0xBA);
566
567 Status = STATUS_SUCCESS;
568 if (Offset.QuadPart <= 0x3000 && Offset.QuadPart + Length > 0x3000)
569 {
570 *(PULONG)((ULONG_PTR)Buffer + (ULONG_PTR)(0x3000 - Offset.QuadPart)) = 0xDEADBABE;
571 }
572
573 Mdl = Irp->MdlAddress;
574 ok(Mdl != NULL, "Null pointer for MDL!\n");
575 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n");
576 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n");
577 ok((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0, "Non paging IO\n");
578 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n");
579
580 Irp->IoStatus.Information = Length;
581 }
582
583 if (Status == STATUS_PENDING)
584 {
585 IoMarkIrpPending(Irp);
586 IoCompleteRequest(Irp, IO_NO_INCREMENT);
587 Status = STATUS_PENDING;
588 }
589 else
590 {
591 Irp->IoStatus.Status = Status;
592 IoCompleteRequest(Irp, IO_NO_INCREMENT);
593 }
594
595 FsRtlExitFileSystem();
596
597 return Status;
598 }
599