- FinishTest: Modify DbgPrint to match format of winetests.
authorMichael Martin <michael.martin@reactos.org>
Thu, 11 Jun 2009 14:13:11 +0000 (14:13 +0000)
committerMichael Martin <michael.martin@reactos.org>
Thu, 11 Jun 2009 14:13:11 +0000 (14:13 +0000)
- Added basic tests for DriverObject, DeviceObject and Loading/Unloading of drivers.
- Added kmtestassist to be used for testing Attached DeviceObject.
- Added CreateLowerDeviceRegistryKey to manually create volatile registry entry for kmtestassist driver.
- More tests still need to be implemented and still need a user mode application to control kmtest.

svn path=/trunk/; revision=41381

rostests/drivers/directory.rbuild
rostests/drivers/kmtest/devobj_test.c [new file with mode: 0644]
rostests/drivers/kmtest/drvobj_test.c [new file with mode: 0644]
rostests/drivers/kmtest/kmtest.c
rostests/drivers/kmtest/kmtest.h
rostests/drivers/kmtest/kmtest.rbuild
rostests/drivers/kmtest/kmtestassist.c [new file with mode: 0644]
rostests/drivers/kmtest/kmtestassist.rbuild [new file with mode: 0644]
rostests/drivers/kmtest/reghelper.c [new file with mode: 0644]

index f989e45..322935e 100644 (file)
@@ -7,6 +7,9 @@
        <directory name="kmtest">
                <xi:include href="kmtest/kmtest.rbuild" />
        </directory>
+       <directory name="kmtest">
+               <xi:include href="kmtest/kmtestassist.rbuild" />
+       </directory>
        <directory name="memtest">
                <xi:include href="memtest/memtest.rbuild" />
        </directory>
diff --git a/rostests/drivers/kmtest/devobj_test.c b/rostests/drivers/kmtest/devobj_test.c
new file mode 100644 (file)
index 0000000..00e96ce
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Driver Regression Tests
+ *
+ * Copyright 2009 Michael Martin <martinmnet@hotmail.com>
+ *
+ * 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 <ddk/ntddk.h>
+#include <ddk/ntifs.h>
+#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 (file)
index 0000000..ad3675a
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Driver Regression Tests
+ *
+ * Copyright 2009 Michael Martin <martinmnet@hotmail.com>
+ *
+ * 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 <ddk/ntddk.h>
+#include <ddk/ntifs.h>
+
+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;
+}
index d30f348..948797a 100644 (file)
@@ -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;
 }
index 658bf8b..a0f20d3 100644 (file)
@@ -4,6 +4,8 @@
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
+#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 */
index 4b9a036..c1e34ff 100644 (file)
@@ -6,6 +6,9 @@
        <file>kmtest.c</file>
        <file>deviface.c</file>
        <file>deviface_test.c</file>
+       <file>drvobj_test.c</file>
+       <file>devobj_test.c</file>
+       <file>reghelper.c</file>
        <file>ntos_ex.c</file>
        <file>ntos_io.c</file>
        <file>ntos_ob.c</file>
diff --git a/rostests/drivers/kmtest/kmtestassist.c b/rostests/drivers/kmtest/kmtestassist.c
new file mode 100644 (file)
index 0000000..1bed164
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Driver Regression Tests
+ *
+ * Copyright 2009 Michael Martin <martinmnet@hotmail.com>
+ *
+ * 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 (file)
index 0000000..96e49b1
--- /dev/null
@@ -0,0 +1,8 @@
+<module name="kmtestassist" type="kernelmodedriver" installbase="system32/drivers" installname="kmtestassist.sys">
+       <bootstrap base="$(CDOUTPUT)" />
+       <define name="__USE_W32API" />
+       <include base="ReactOS">include/reactos/drivers</include>
+       <library>ntoskrnl</library>
+       <library>hal</library>
+       <file>kmtestassist.c</file>
+</module>
diff --git a/rostests/drivers/kmtest/reghelper.c b/rostests/drivers/kmtest/reghelper.c
new file mode 100644 (file)
index 0000000..c3a54d6
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Driver Regression Tests
+ *
+ * Copyright 2009 Michael Martin <martinmnet@hotmail.com>
+ *
+ * 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;
+
+}