diff --git a/rostests/drivers/directory.rbuild b/rostests/drivers/directory.rbuild index f989e45510e..322935ee2f4 100644 --- a/rostests/drivers/directory.rbuild +++ b/rostests/drivers/directory.rbuild @@ -7,6 +7,9 @@ + + + diff --git a/rostests/drivers/kmtest/devobj_test.c b/rostests/drivers/kmtest/devobj_test.c new file mode 100644 index 00000000000..00e96cea36d --- /dev/null +++ b/rostests/drivers/kmtest/devobj_test.c @@ -0,0 +1,266 @@ +/* + * Driver Regression Tests + * + * Copyright 2009 Michael Martin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; see the file COPYING.LIB. + * If not, write to the Free Software Foundation, + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* INCLUDES *******************************************************************/ + +#include "kmtest.h" +#include +#include +#include "ntddser.h" +#include "ntndk.h" + +VOID LowerDeviceKernelAPITest(PDEVICE_OBJECT DeviceObject, BOOLEAN UnLoading) +{ + PDEVICE_OBJECT RetObject; + + RetObject = IoGetLowerDeviceObject(DeviceObject); + + if (UnLoading) + { + ok(RetObject == 0, + "Expected no Lower DeviceObject, got %p", RetObject); + } + else + { + ok(RetObject == AttachDeviceObject, + "Expected an Attached DeviceObject %p, got %p", AttachDeviceObject, RetObject); + } + + if (RetObject) + { + ObDereferenceObject(RetObject); + } + + RetObject = IoGetDeviceAttachmentBaseRef(DeviceObject); + ok(RetObject == DeviceObject, + "Expected an Attached DeviceObject %p, got %p", DeviceObject, RetObject); + + if (RetObject) + { + ObDereferenceObject(RetObject); + } + +} +VOID DeviceCreatedTest(PDEVICE_OBJECT DeviceObject, BOOLEAN ExclusiveAccess) +{ + PEXTENDED_DEVOBJ_EXTENSION extdev; + + /*Check the device object members */ + ok(DeviceObject->Type==3, "Expected Type = 3, got %x", DeviceObject->Type); + ok(DeviceObject->Size = 0xb8, "Expected Size = 0xba, got %x", DeviceObject->Size); + ok(DeviceObject->ReferenceCount == 0, "Expected ReferenceCount = 0, got %lu", + DeviceObject->ReferenceCount); + ok(DeviceObject->DriverObject == ThisDriverObject, + "Expected DriverObject member to match this DriverObject %p, got %p", + ThisDriverObject, DeviceObject->DriverObject); + ok(DeviceObject->NextDevice == NULL, "Expected NextDevice to be NULL, got %p", DeviceObject->NextDevice); + ok(DeviceObject->AttachedDevice == NULL, "Expected AttachDevice to be NULL, got %p", DeviceObject->AttachedDevice); + ok(DeviceObject->Characteristics == 0, "Expected Characteristics to be 0"); + if (ExclusiveAccess) + { + ok((DeviceObject->Flags == (DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING | DO_EXCLUSIVE)), + "Expected Flags DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING | DO_EXCLUSIVE, got %lu", DeviceObject->Flags); + } + else + { + ok((DeviceObject->Flags == (DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING)), + "Expected Flags DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING, got %lu", DeviceObject->Flags); + } + ok(DeviceObject->DeviceType == FILE_DEVICE_UNKNOWN, + "Expected DeviceType to match creation parameter FILE_DEVICE_UNKNWOWN, got %lu", + DeviceObject->DeviceType); + ok(DeviceObject->ActiveThreadCount == 0, "Expected ActiveThreadCount = 0, got %lu\n", DeviceObject->ActiveThreadCount); + + /*Check the extended extension */ + extdev = (PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension; + ok(extdev->ExtensionFlags == 0, "Expected Extended ExtensionFlags to be 0, got %lu", extdev->ExtensionFlags); + ok (extdev->Type == 13, "Expected Type of 13, got %d", extdev->Type); + ok (extdev->Size == 0, "Expected Size of 0, got %d", extdev->Size); + ok (extdev->DeviceObject == DeviceObject, "Expected DeviceOject to match newly created device %p, got %p", + DeviceObject, extdev->DeviceObject); + ok(extdev->AttachedTo == NULL, "Expected AttachTo to be NULL, got %p", extdev->AttachedTo); + ok(extdev->StartIoCount == 0, "Expected StartIoCount = 0, got %lu", extdev->StartIoCount); + ok(extdev->StartIoKey == 0, "Expected StartIoKey = 0, got %lu", extdev->StartIoKey); + ok(extdev->StartIoFlags == 0, "Expected StartIoFlags = 0, got %lu", extdev->StartIoFlags); +} + +VOID DeviceDeletionTest(PDEVICE_OBJECT DeviceObject, BOOLEAN Lower) +{ + PEXTENDED_DEVOBJ_EXTENSION extdev; + + /*Check the device object members */ + ok(DeviceObject->Type==3, "Expected Type = 3, got %d", DeviceObject->Type); + ok(DeviceObject->Size = 0xb8, "Expected Size = 0xba, got %d", DeviceObject->Size); + ok(DeviceObject->ReferenceCount == 0, "Expected ReferenceCount = 0, got %lu", + DeviceObject->ReferenceCount); + if (!Lower) + { + ok(DeviceObject->DriverObject == ThisDriverObject, + "Expected DriverObject member to match this DriverObject %p, got %p", + ThisDriverObject, DeviceObject->DriverObject); + } + ok(DeviceObject->NextDevice == NULL, "Expected NextDevice to be NULL, got %p", DeviceObject->NextDevice); + + if (Lower) + { + ok(DeviceObject->AttachedDevice == MainDeviceObject, + "Expected AttachDevice to be %p, got %p", MainDeviceObject, DeviceObject->AttachedDevice); + } + else + { + ok(DeviceObject->AttachedDevice == NULL, "Expected AttachDevice to be NULL, got %p", DeviceObject->AttachedDevice); + } + + ok(DeviceObject->Flags ==FILE_VIRTUAL_VOLUME, + "Expected Flags FILE_VIRTUAL_VOLUME, got %lu", DeviceObject->Flags); + ok(DeviceObject->DeviceType == FILE_DEVICE_UNKNOWN, + "Expected DeviceType to match creation parameter FILE_DEVICE_UNKNWOWN, got %lu", + DeviceObject->DeviceType); + ok(DeviceObject->ActiveThreadCount == 0, "Expected ActiveThreadCount = 0, got %lu\n", DeviceObject->ActiveThreadCount); + + /*Check the extended extension */ + extdev = (PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension; + ok(extdev->ExtensionFlags == DOE_UNLOAD_PENDING, + "Expected Extended ExtensionFlags to be DOE_UNLOAD_PENDING, got %lu", extdev->ExtensionFlags); + ok (extdev->Type == 13, "Expected Type of 13, got %d", extdev->Type); + ok (extdev->Size == 0, "Expected Size of 0, got %d", extdev->Size); + ok (extdev->DeviceObject == DeviceObject, "Expected DeviceOject to match newly created device %p, got %p", + DeviceObject, extdev->DeviceObject); + if (Lower) + { + /* Skip this for now */ + //ok(extdev->AttachedTo == MainDeviceObject, "Expected AttachTo to %p, got %p", MainDeviceObject, extdev->AttachedTo); + } + else + { + ok(extdev->AttachedTo == NULL, "Expected AttachTo to be NULL, got %p", extdev->AttachedTo); + } + ok(extdev->StartIoCount == 0, "Expected StartIoCount = 0, got %lu", extdev->StartIoCount); + ok(extdev->StartIoKey == 0, "Expected StartIoKey = 0, got %lu", extdev->StartIoKey); + ok(extdev->StartIoFlags == 0, "Expected StartIoFlags = 0, got %lu", extdev->StartIoFlags); +} + +VOID DeviceCreateDeleteTest(PDRIVER_OBJECT DriverObject) +{ + NTSTATUS Status; + UNICODE_STRING DeviceString; + UNICODE_STRING DosDeviceString; + PDEVICE_OBJECT DeviceObject; + + /* Create using wrong directory */ + RtlInitUnicodeString(&DeviceString, L"\\Device1\\Kmtest"); + Status = IoCreateDevice(DriverObject, + 0, + &DeviceString, + FILE_DEVICE_UNKNOWN, + 0, + FALSE, + &DeviceObject); + ok(Status == STATUS_OBJECT_PATH_NOT_FOUND, "Expected STATUS_OBJECT_PATH_NOT_FOUND, got 0x%lX", Status); + + /* Create using correct params with exlusice access */ + RtlInitUnicodeString(&DeviceString, L"\\Device\\Kmtest"); + Status = IoCreateDevice(DriverObject, + 0, + &DeviceString, + FILE_DEVICE_UNKNOWN, + 0, + TRUE, + &DeviceObject); + ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status); + + DeviceCreatedTest(DeviceObject, TRUE); + + /* Delete the device */ + if (NT_SUCCESS(Status)) + { + IoDeleteDevice(DeviceObject); + ok(DriverObject->DeviceObject == 0, "Expected DriverObject->DeviceObject to be NULL, got %p", + DriverObject->DeviceObject); + } + + /* Create using correct params with exlusice access */ + Status = IoCreateDevice(DriverObject, + 0, + &DeviceString, + FILE_DEVICE_UNKNOWN, + 0, + FALSE, + &DeviceObject); + ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status); + + DeviceCreatedTest(DeviceObject, FALSE); + + /* Delete the device */ + if (NT_SUCCESS(Status)) + { + IoDeleteDevice(DeviceObject); + ok(DriverObject->DeviceObject == 0, "Expected DriverObject->DeviceObject to be NULL, got %p", + DriverObject->DeviceObject); + } + + /* Recreate device */ + Status = IoCreateDevice(DriverObject, + 0, + &DeviceString, + FILE_DEVICE_UNKNOWN, + 0, + FALSE, + &DeviceObject); + ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status); + + RtlInitUnicodeString(&DosDeviceString, L"\\DosDevices\\kmtest"); + Status = IoCreateSymbolicLink(&DosDeviceString, &DeviceString); + + if (!NT_SUCCESS(Status)) + { + /* Delete device object if not successful */ + IoDeleteDevice(DeviceObject); + return; + } + + MainDeviceObject = DeviceObject; + + return; +} + +BOOLEAN AttachDeviceTest(PDEVICE_OBJECT DeviceObject, PWCHAR NewDriverRegPath) +{ + NTSTATUS Status; + UNICODE_STRING LowerDeviceName; + + RtlInitUnicodeString(&LowerDeviceName, NewDriverRegPath); + Status = IoAttachDevice(DeviceObject, &LowerDeviceName, &AttachDeviceObject); + + /* TODO: Add more tests */ + + return TRUE; +} + +BOOLEAN DetachDeviceTest(PDEVICE_OBJECT AttachedDevice) +{ + + IoDetachDevice(AttachedDevice); + + /* TODO: Add more tests */ + + return TRUE; +} diff --git a/rostests/drivers/kmtest/drvobj_test.c b/rostests/drivers/kmtest/drvobj_test.c new file mode 100644 index 00000000000..ad3675a6c2a --- /dev/null +++ b/rostests/drivers/kmtest/drvobj_test.c @@ -0,0 +1,141 @@ +/* + * Driver Regression Tests + * + * Copyright 2009 Michael Martin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; see the file COPYING.LIB. + * If not, write to the Free Software Foundation, + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* INCLUDES *******************************************************************/ + +#include "kmtest.h" +#include +#include + +VOID DriverObjectTest(PDRIVER_OBJECT DriverObject, int DriverStatus) +{ + BOOLEAN CheckThisDispatchRoutine; + PVOID FirstMajorFunc; + int i; + + ok(DriverObject->Size == sizeof(DRIVER_OBJECT), "Size does not match, got %x",DriverObject->Size); + ok(DriverObject->Type == 4, "Type does not match 4. got %d",DriverObject->Type); + + if (DriverStatus == 0) + { + ok(DriverObject->DeviceObject == NULL, "Expected DeviceObject pointer to be 0, got %p", + DriverObject->DeviceObject); + ok (DriverObject->Flags == DRVO_LEGACY_DRIVER, + "Expected Flags to be DRVO_LEGACY_DRIVER, got %lu", + DriverObject->Flags); + } + else if (DriverStatus == 1) + { + ok(DriverObject->DeviceObject != NULL, "Expected DeviceObject pointer to non null"); + ok (DriverObject->Flags == (DRVO_LEGACY_DRIVER | DRVO_INITIALIZED), + "Expected Flags to be DRVO_LEGACY_DRIVER | DRVO_INITIALIZED, got %lu", + DriverObject->Flags); + } + else + { + ok(DriverObject->DeviceObject != NULL, "Expected DeviceObject pointer to non null"); + ok (DriverObject->Flags == (DRVO_LEGACY_DRIVER | DRVO_INITIALIZED | DRVO_UNLOAD_INVOKED), + "Expected Flags to be DRVO_LEGACY_DRIVER | DRVO_INITIALIZED | DRVO_UNLOAD_INVOKED, got %lu", + DriverObject->Flags); + } + + /* Select a routine that was not changed */ + FirstMajorFunc = DriverObject->MajorFunction[1]; + ok(FirstMajorFunc != 0, "Expected MajorFunction[1] to be non NULL"); + + if (FirstMajorFunc) + { + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) + { + if (DriverStatus > 0) CheckThisDispatchRoutine = (i > 3) && (i != 14); + else CheckThisDispatchRoutine = TRUE; + + if (CheckThisDispatchRoutine) + { + ok(DriverObject->MajorFunction[i] == FirstMajorFunc, "Expected MajorFunction[%d] to match %p", + i, FirstMajorFunc); + } + } + } + else + { + ok(TRUE, "Skipped testing for all MajorFunction"); + } +} + +BOOLEAN ZwLoadTest(PDRIVER_OBJECT DriverObject, PUNICODE_STRING DriverRegistryPath, PWCHAR NewDriverRegPath) +{ + UNICODE_STRING RegPath; + NTSTATUS Status; + + /* Try to load ourself */ + Status = ZwLoadDriver(DriverRegistryPath); + ok (Status == STATUS_IMAGE_ALREADY_LOADED, "Expected NTSTATUS STATUS_IMAGE_ALREADY_LOADED, got 0x%lX", Status); + + if (Status != STATUS_IMAGE_ALREADY_LOADED) + { + DbgPrint("WARNING: Loading this a second time will cause BUGCHECK!\n"); + } + + /* Try to load with a Registry Path that doesnt exist */ + RtlInitUnicodeString(&RegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\deadbeef"); + Status = ZwLoadDriver(&RegPath); + ok (Status == STATUS_OBJECT_NAME_NOT_FOUND, "Expected NTSTATUS STATUS_OBJECT_NAME_NOT_FOUND, got 0x%lX", Status); + + /* Load the driver */ + RtlInitUnicodeString(&RegPath, NewDriverRegPath); + Status = ZwLoadDriver(&RegPath); + ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status); + + if (!NT_SUCCESS(Status)) + { + return FALSE; + } + + return TRUE; +} + +BOOLEAN ZwUnloadTest(PDRIVER_OBJECT DriverObject, PUNICODE_STRING DriverRegistryPath, PWCHAR NewDriverRegPath) +{ + UNICODE_STRING RegPath; + NTSTATUS Status; + + /* Try to unload ourself, which should fail as our Unload routine hasnt been set yet. */ + Status = ZwUnloadDriver(DriverRegistryPath); + ok (Status == STATUS_INVALID_DEVICE_REQUEST, "Expected NTSTATUS STATUS_INVALID_DEVICE_REQUEST, got 0x%lX", Status); + + /* Try to unload with a Registry Path that doesnt exist */ + RtlInitUnicodeString(&RegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\deadbeef"); + Status = ZwUnloadDriver(&RegPath); + ok (Status == STATUS_OBJECT_NAME_NOT_FOUND, "Expected NTSTATUS STATUS_OBJECT_NAME_NOT_FOUND, got 0x%lX", Status); + + /* Unload the driver */ + RtlInitUnicodeString(&RegPath, NewDriverRegPath); + Status = ZwUnloadDriver(&RegPath); + ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status); + + if (!NT_SUCCESS(Status)) + { + return FALSE; + } + + return TRUE; +} diff --git a/rostests/drivers/kmtest/kmtest.c b/rostests/drivers/kmtest/kmtest.c index d30f3486752..948797a3273 100644 --- a/rostests/drivers/kmtest/kmtest.c +++ b/rostests/drivers/kmtest/kmtest.c @@ -40,7 +40,7 @@ StartTest() VOID FinishTest(LPSTR TestName) { - DbgPrint("Test %s finished with %d succeses and %d failures\n", TestName, successes, failures); + DbgPrint("%s: %d test executed (0 marked as todo, %d failures), 0 skipped.\n", TestName, successes + failures, failures); } void kmtest_set_location(const char* file, int line) @@ -100,6 +100,8 @@ int kmtest_ok(int condition, const char *msg, ... ) /* PUBLIC FUNCTIONS ***********************************************************/ +PWCHAR CreateLowerDeviceRegistryKey(PUNICODE_STRING RegistryPath, PWCHAR NewDriver); + /* * Test Declarations */ @@ -107,6 +109,63 @@ VOID NtoskrnlIoTests(); VOID NtoskrnlObTest(); VOID NtoskrnlExecutiveTests(); VOID NtoskrnlPoolsTest(); +VOID DriverObjectTest(PDRIVER_OBJECT, int); +VOID DeviceCreateDeleteTest(PDRIVER_OBJECT); +VOID DeviceObjectTest(PDEVICE_OBJECT); +BOOLEAN ZwLoadTest(PDRIVER_OBJECT, PUNICODE_STRING, PWCHAR); +BOOLEAN ZwUnloadTest(PDRIVER_OBJECT, PUNICODE_STRING, PWCHAR); +BOOLEAN DetachDeviceTest(PDEVICE_OBJECT); +BOOLEAN AttachDeviceTest(PDEVICE_OBJECT, PWCHAR); +VOID LowerDeviceKernelAPITest(PDEVICE_OBJECT, BOOLEAN); + +/* + * KmtestDispatch + */ +NTSTATUS +NTAPI +KmtestDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) + +{ + NTSTATUS Status = STATUS_SUCCESS; + + if (AttachDeviceObject) + { + IoSkipCurrentIrpStackLocation(Irp); + Status = IoCallDriver(AttachDeviceObject, Irp); + return Status; + } + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + +/* + * KmtestCreateClose + */ +NTSTATUS +NTAPI +KmtestCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) +{ + NTSTATUS Status = STATUS_SUCCESS; + + if (AttachDeviceObject) + { + IoSkipCurrentIrpStackLocation(Irp); + Status = IoCallDriver(AttachDeviceObject, Irp); + return Status; + } + + /* Do DriverObject Test with Driver Initialized */ + DriverObjectTest(DeviceObject->DriverObject, 1); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information=0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} /* * KmtestUnload @@ -115,7 +174,24 @@ VOID NTAPI KmtestUnload(IN PDRIVER_OBJECT DriverObject) { - /* Nothing to do here */ + UNICODE_STRING DosDeviceString; + + if(AttachDeviceObject) + { + IoDetachDevice(AttachDeviceObject); + } + + /* Do DriverObject Test for Unload */ + DriverObjectTest(DriverObject, 2); + + if (MainDeviceObject) + { + RtlInitUnicodeString(&DosDeviceString, L"\\DosDevices\\Kmtest"); + IoDeleteSymbolicLink(&DosDeviceString); + + IoDeleteDevice(MainDeviceObject); + } + FinishTest("Driver Tests"); } /* @@ -126,15 +202,70 @@ NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { - DbgPrint("\n===============================================\nKernel Mode Regression Test driver starting...\n"); + int i; + PWCHAR LowerDriverRegPath; - /* Set necessary routines */ - DriverObject->DriverUnload = KmtestUnload; + DbgPrint("\n===============================================\n"); + DbgPrint("Kernel Mode Regression Driver Test starting...\n"); + DbgPrint("===============================================\n"); + + MainDeviceObject = NULL; + AttachDeviceObject = NULL; + ThisDriverObject = DriverObject; NtoskrnlExecutiveTests(); NtoskrnlIoTests(); NtoskrnlObTest(); NtoskrnlPoolsTest(); + /* Start the tests for the driver routines */ + StartTest(); + + /* Do DriverObject Test for Driver Entry */ + DriverObjectTest(DriverObject, 0); + /* Create and delete device, on return MainDeviceObject has been created */ + DeviceCreateDeleteTest(DriverObject); + + /* Make sure a device object was created */ + if (MainDeviceObject) + { + LowerDriverRegPath = CreateLowerDeviceRegistryKey(RegistryPath, L"kmtestassist"); + + if (LowerDriverRegPath) + { + /* Load driver test and load the lower driver */ + if (ZwLoadTest(DriverObject, RegistryPath, LowerDriverRegPath)) + { + AttachDeviceTest(MainDeviceObject, L"kmtestassists"); + if (AttachDeviceObject) + { + LowerDeviceKernelAPITest(MainDeviceObject, FALSE); + } + + /* Unload lower driver without detaching from its device */ + ZwUnloadTest(DriverObject, RegistryPath, LowerDriverRegPath); + LowerDeviceKernelAPITest(MainDeviceObject, TRUE); + } + else + { + DbgPrint("Failed to load kmtestassist driver\n"); + } + } + } + else + { + return STATUS_UNSUCCESSFUL; + } + + /* Set all MajorFunctions to NULL to verify that kernel fixes them */ + for (i = 1; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) + DriverObject->MajorFunction[i] = NULL; + + /* Set necessary routines */ + DriverObject->DriverUnload = KmtestUnload; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KmtestDispatch; + DriverObject->MajorFunction[IRP_MJ_CREATE] = KmtestCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = KmtestCreateClose; + return STATUS_SUCCESS; } diff --git a/rostests/drivers/kmtest/kmtest.h b/rostests/drivers/kmtest/kmtest.h index 658bf8b513b..a0f20d3405d 100644 --- a/rostests/drivers/kmtest/kmtest.h +++ b/rostests/drivers/kmtest/kmtest.h @@ -4,6 +4,8 @@ #include #include #include +#include "ntddk.h" + /* Some macros, structs, and vars are based or inspired from the great @@ -45,4 +47,8 @@ extern int kmtest_ok( int condition, const char *msg, ... ); #define ok_(file, line) (kmtest_set_location(file, line), 0) ? 0 : kmtest_ok #define ok ok_(__FILE__, __LINE__) +PDEVICE_OBJECT AttachDeviceObject; +PDEVICE_OBJECT MainDeviceObject; +PDRIVER_OBJECT ThisDriverObject; + #endif /* PNPTEST_H */ diff --git a/rostests/drivers/kmtest/kmtest.rbuild b/rostests/drivers/kmtest/kmtest.rbuild index 4b9a03692a3..c1e34ff433c 100644 --- a/rostests/drivers/kmtest/kmtest.rbuild +++ b/rostests/drivers/kmtest/kmtest.rbuild @@ -6,6 +6,9 @@ kmtest.c deviface.c deviface_test.c + drvobj_test.c + devobj_test.c + reghelper.c ntos_ex.c ntos_io.c ntos_ob.c diff --git a/rostests/drivers/kmtest/kmtestassist.c b/rostests/drivers/kmtest/kmtestassist.c new file mode 100644 index 00000000000..1bed164b3c1 --- /dev/null +++ b/rostests/drivers/kmtest/kmtestassist.c @@ -0,0 +1,95 @@ +/* + * Driver Regression Tests + * + * Copyright 2009 Michael Martin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; see the file COPYING.LIB. + * If not, write to the Free Software Foundation, + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* INCLUDES *******************************************************************/ + +#include "ntddk.h" +#include "ntddser.h" + +NTSTATUS +NTAPI +DriverDispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) +{ + DbgPrint(" ControlCode %x\n",IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode); + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information=0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +DriverCreateClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) +{ + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_SUCCESS; +} + +VOID +NTAPI +DriverUnload(IN PDRIVER_OBJECT DriverObject) +{ + UNICODE_STRING DeviceString; + + RtlInitUnicodeString(&DeviceString, L"\\DosDevices\\kmtestassist"); + IoDeleteSymbolicLink(&DeviceString); + + IoDeleteDevice(DriverObject->DeviceObject); +} + +NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING path) +{ + PDEVICE_OBJECT pDeviceObject; + UNICODE_STRING DriverString; + UNICODE_STRING DeviceString; + + NTSTATUS Status= STATUS_DEVICE_CONFIGURATION_ERROR; + + RtlInitUnicodeString(&DriverString, L"\\Device\\kmtestassist"); + + Status = IoCreateDevice(DriverObject,0,&DriverString,FILE_DEVICE_UNKNOWN,0,FALSE,&pDeviceObject); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + RtlInitUnicodeString(&DeviceString, L"\\DosDevices\\kmtestassist"); + + Status = IoCreateSymbolicLink(&DeviceString, &DriverString); + if (!NT_SUCCESS(Status)) + { + // Delete device object if not successful + IoDeleteDevice(pDeviceObject); + return Status; + } + + DriverObject->DriverUnload = DriverUnload; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDispatch; + DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverCreateClose; + + return Status; +} diff --git a/rostests/drivers/kmtest/kmtestassist.rbuild b/rostests/drivers/kmtest/kmtestassist.rbuild new file mode 100644 index 00000000000..96e49b10cdd --- /dev/null +++ b/rostests/drivers/kmtest/kmtestassist.rbuild @@ -0,0 +1,8 @@ + + + + include/reactos/drivers + ntoskrnl + hal + kmtestassist.c + diff --git a/rostests/drivers/kmtest/reghelper.c b/rostests/drivers/kmtest/reghelper.c new file mode 100644 index 00000000000..c3a54d67ef3 --- /dev/null +++ b/rostests/drivers/kmtest/reghelper.c @@ -0,0 +1,219 @@ +/* + * Driver Regression Tests + * + * Copyright 2009 Michael Martin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; see the file COPYING.LIB. + * If not, write to the Free Software Foundation, + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* INCLUDES *******************************************************************/ + +#include "kmtest.h" + +/* + Adds a service registry entry for a driver + The driver must reside in the same path as this loaded driver + The caller is resposible for releasing memory +*/ +PWCHAR CreateLowerDeviceRegistryKey(PUNICODE_STRING RegistryPath, PWCHAR NewDriver) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING Name; + UNICODE_STRING Value; + UNICODE_STRING NewDriverRegPath; + PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInfo = NULL; + HANDLE ServiceKey; + NTSTATUS Status; + ULONG Disposition; + ULONG ServiceDWordValue; + ULONG ResultLength = 0; + ULONG Length = 0; + PWCHAR ReturnPath = NULL; + /* Now lets find out where we were loaded from by using registry */ + InitializeObjectAttributes(&ObjectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = ZwOpenKey(&ServiceKey, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwOpenKey () failed (Status %x)\n", Status); + return NULL; + } + + RtlInitUnicodeString(&Name, L"ImagePath"); + + /* First query how much memory we need */ + Status = ZwQueryValueKey(ServiceKey, &Name, KeyValuePartialInformation, 0, 0, &ResultLength); + + ResultLength += sizeof(KEY_VALUE_PARTIAL_INFORMATION); + ValuePartialInfo = ExAllocatePool(PagedPool, ResultLength); + if (!ValuePartialInfo) + { + DbgPrint("Out of memory!\n"); + goto cleanup; + } + + Length = ResultLength; + Status = ZwQueryValueKey(ServiceKey, &Name, KeyValuePartialInformation, (PVOID)ValuePartialInfo, Length, &ResultLength); + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwQueryValueKey() failed (Status %lx)\n", Status); + goto cleanup; + } + + /* Remove the current driver name from the string */ + /* FIXME: Dont use hard coded driver name, determine it from the string returned from the above Query */ + Length = (wcslen((PWCHAR)ValuePartialInfo->Data) * 2) - (wcslen(L"kmtest.sys") * 2); + RtlZeroMemory((PVOID)((ULONG)ValuePartialInfo->Data + Length), + wcslen(L"drvtests.sys") * 2); + ZwClose(ServiceKey); + + /* Now add a registry entry for the driver */ + + NewDriverRegPath.Length = 0; + NewDriverRegPath.MaximumLength = (wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") + + wcslen(NewDriver) + 1) * sizeof(WCHAR); + NewDriverRegPath.Buffer = ExAllocatePool(PagedPool, NewDriverRegPath.MaximumLength); + if (!NewDriverRegPath.Buffer) + { + DbgPrint("Out of memory!\n"); + ExFreePool(NewDriverRegPath.Buffer); + goto cleanup; + } + + RtlAppendUnicodeToString(&NewDriverRegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); + RtlAppendUnicodeToString(&NewDriverRegPath, NewDriver); + + InitializeObjectAttributes(&ObjectAttributes, + &NewDriverRegPath, + OBJ_CASE_INSENSITIVE | OBJ_OPENIF, + 0, + NULL); + + Status = ZwCreateKey(&ServiceKey, + KEY_ALL_ACCESS, + &ObjectAttributes, + 0, + NULL, + REG_OPTION_VOLATILE, + &Disposition); + + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + ExFreePool(NewDriverRegPath.Buffer); + goto cleanup; + } + + ReturnPath = NewDriverRegPath.Buffer; + RtlInitUnicodeString(&Name, L"ImagePath"); + + Value.Length = 0; + Value.MaximumLength = (wcslen((PWCHAR)ValuePartialInfo->Data) + + wcslen(NewDriver) + 5) * sizeof(WCHAR); + Value.Buffer = ExAllocatePool(PagedPool, Value.MaximumLength); + + if (!Value.Buffer) + { + DbgPrint("Out of memory!\n"); + ExFreePool(Value.Buffer); + goto cleanup; + } + + RtlAppendUnicodeToString(&Value, (PWCHAR)ValuePartialInfo->Data); + RtlAppendUnicodeToString(&Value, NewDriver); + RtlAppendUnicodeToString(&Value, L".sys"); + + Status = ZwSetValueKey(ServiceKey, + &Name, + 0, + REG_SZ, + Value.Buffer, + (wcslen(Value.Buffer)+1) * sizeof(WCHAR)); + ExFreePool(Value.Buffer); + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + goto cleanup; + } + + RtlInitUnicodeString(&Name, L"DisplayName"); + RtlInitUnicodeString(&Value, NewDriver); + + Status = ZwSetValueKey(ServiceKey, + &Name, + 0, + REG_SZ, + Value.Buffer, + (wcslen(Value.Buffer)+1) * sizeof(WCHAR)); + + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + goto cleanup; + } + + RtlInitUnicodeString(&Name, L"ErrorControl"); + ServiceDWordValue = 0; + + Status = ZwSetValueKey(ServiceKey, + &Name, + 0, + REG_DWORD, + &ServiceDWordValue, + sizeof(ULONG)); + + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + goto cleanup; + } + + RtlInitUnicodeString(&Name, L"Start"); + ServiceDWordValue = 3; + Status = ZwSetValueKey(ServiceKey, + &Name, + 0, + REG_DWORD, + &ServiceDWordValue, + sizeof(ULONG)); + + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + goto cleanup; + } + + RtlInitUnicodeString(&Name, L"Type"); + ServiceDWordValue = 0; + Status = ZwSetValueKey(ServiceKey, + &Name, + 0, + REG_DWORD, + &ServiceDWordValue, + sizeof(ULONG)); + + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + goto cleanup; + } + +cleanup: + ZwClose(ServiceKey); + if (ValuePartialInfo) ExFreePool(ValuePartialInfo); + + return ReturnPath; + +}