- Fix epic naming fail (DhcpEnabled -> EnableDHCP
[reactos.git] / rostests / drivers / kmtest / kmtest.c
index 948797a..3164688 100644 (file)
 #include <ddk/ntddk.h>
 #include "kmtest.h"
 
+#define NDEBUG
+#include <debug.h>
+
 LONG successes;
 LONG failures;
+LONG skipped;
 tls_data glob_data;
 
 /* PRIVATE FUNCTIONS ***********************************************************/
@@ -35,12 +39,61 @@ StartTest()
 {
     successes = 0;
     failures = 0;
+    skipped = 0;
 }
 
 VOID
-FinishTest(LPSTR TestName)
+FinishTest(HANDLE KeyHandle, LPWSTR TestName)
 {
-    DbgPrint("%s: %d test executed (0 marked as todo, %d failures), 0 skipped.\n", TestName, successes + failures, failures);
+    WCHAR KeyName[100];
+    LONG total = successes + failures;
+    UNICODE_STRING KeyNameU;
+
+    wcscpy(KeyName, TestName);
+    wcscat(KeyName, L"SuccessCount");
+    RtlInitUnicodeString(&KeyNameU, KeyName);
+
+    ZwSetValueKey(KeyHandle,
+                  &KeyNameU,
+                  0,
+                  REG_DWORD,
+                  &successes,
+                  sizeof(ULONG));
+
+    wcscpy(KeyName, TestName);
+    wcscat(KeyName, L"FailureCount");
+    RtlInitUnicodeString(&KeyNameU, KeyName);
+
+    ZwSetValueKey(KeyHandle,
+                  &KeyNameU,
+                  0,
+                  REG_DWORD,
+                  &failures,
+                  sizeof(ULONG));
+
+    wcscpy(KeyName, TestName);
+    wcscat(KeyName, L"TotalCount");
+    RtlInitUnicodeString(&KeyNameU, KeyName);
+
+    ZwSetValueKey(KeyHandle,
+                  &KeyNameU,
+                  0,
+                  REG_DWORD,
+                  &total,
+                  sizeof(ULONG));
+
+    wcscpy(KeyName, TestName);
+    wcscat(KeyName, L"SkipCount");
+    RtlInitUnicodeString(&KeyNameU, KeyName);
+
+    ZwSetValueKey(KeyHandle,
+                  &KeyNameU,
+                  0,
+                  REG_DWORD,
+                  &skipped,
+                  sizeof(ULONG));
+
+    DbgPrint("%S: %d test executed (0 marked as todo, %d failures), %d skipped.\n", TestName, total, failures, skipped);
 }
 
 void kmtest_set_location(const char* file, int line)
@@ -105,10 +158,14 @@ PWCHAR CreateLowerDeviceRegistryKey(PUNICODE_STRING RegistryPath, PWCHAR NewDriv
 /*
  * Test Declarations
  */
-VOID NtoskrnlIoTests();
-VOID NtoskrnlObTest();
-VOID NtoskrnlExecutiveTests();
-VOID NtoskrnlPoolsTest();
+VOID RegisterDI_Test(HANDLE KeyHandle);
+VOID NtoskrnlIoMdlTest(HANDLE KeyHandle);
+VOID NtoskrnlIoIrpTest(HANDLE KeyHandle);
+VOID NtoskrnlObTest(HANDLE KeyHandle);
+VOID ExTimerTest(HANDLE KeyHandle);
+VOID PoolsTest(HANDLE KeyHandle);
+VOID PoolsCorruption(HANDLE KeyHandle);
+VOID KeStallTest(HANDLE KeyHandle);
 VOID DriverObjectTest(PDRIVER_OBJECT, int);
 VOID DeviceCreateDeleteTest(PDRIVER_OBJECT);
 VOID DeviceObjectTest(PDEVICE_OBJECT);
@@ -118,6 +175,19 @@ BOOLEAN DetachDeviceTest(PDEVICE_OBJECT);
 BOOLEAN AttachDeviceTest(PDEVICE_OBJECT,  PWCHAR);
 VOID LowerDeviceKernelAPITest(PDEVICE_OBJECT, BOOLEAN);
 
+typedef enum {
+    TestStageExTimer = 0,
+    TestStageIoMdl,
+    TestStageIoDi,
+    TestStageIoIrp,
+    TestStageMmPoolTest,
+    TestStageMmPoolCorruption,
+    TestStageOb,
+    TestStageKeStall,
+    TestStageDrv,
+    TestStageMax
+} TEST_STAGE;
+
 /*
  * KmtestDispatch
  */
@@ -191,7 +261,148 @@ KmtestUnload(IN PDRIVER_OBJECT DriverObject)
 
         IoDeleteDevice(MainDeviceObject);
     }
-    FinishTest("Driver Tests");
+}
+
+static
+PKEY_VALUE_PARTIAL_INFORMATION
+NTAPI
+ReadRegistryValue(HANDLE KeyHandle, PWCHAR ValueName)
+{
+    NTSTATUS Status;
+    PKEY_VALUE_PARTIAL_INFORMATION InformationBuffer = NULL;
+    ULONG AllocatedLength = 0, RequiredLength = 0;
+    UNICODE_STRING ValueNameU;
+
+    RtlInitUnicodeString(&ValueNameU, ValueName);
+
+    Status = ZwQueryValueKey(KeyHandle,
+                             &ValueNameU,
+                             KeyValuePartialInformation,
+                             NULL,
+                             0,
+                             &RequiredLength);
+    if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW)
+    {
+        InformationBuffer = ExAllocatePool(PagedPool, RequiredLength);
+        AllocatedLength = RequiredLength;
+        if (!InformationBuffer) return NULL;
+
+        Status = ZwQueryValueKey(KeyHandle,
+                                 &ValueNameU,
+                                 KeyValuePartialInformation,
+                                 InformationBuffer,
+                                 AllocatedLength,
+                                 &RequiredLength);
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to read %S (0x%x)\n", ValueName, Status);
+        if (InformationBuffer != NULL)
+            ExFreePool(InformationBuffer);
+        return NULL;
+    }
+
+    return InformationBuffer;
+}
+
+static
+VOID
+RunKernelModeTest(PDRIVER_OBJECT DriverObject,
+                  PUNICODE_STRING RegistryPath,
+                  HANDLE KeyHandle,
+                  TEST_STAGE Stage)
+{
+    UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"CurrentStage");
+    PWCHAR LowerDriverRegPath;
+
+    DPRINT1("Running stage %d test...\n", Stage);
+
+    ZwSetValueKey(KeyHandle,
+                  &KeyName,
+                  0,
+                  REG_DWORD,
+                  &Stage,
+                  sizeof(ULONG));
+
+    switch (Stage)
+    {
+       case TestStageExTimer:
+         ExTimerTest(KeyHandle);
+         break;
+
+       case TestStageIoMdl:
+         NtoskrnlIoMdlTest(KeyHandle);
+         break;
+
+       case TestStageIoDi:
+         RegisterDI_Test(KeyHandle);
+         break;
+
+       case TestStageIoIrp:
+         NtoskrnlIoIrpTest(KeyHandle);
+         break;
+
+       case TestStageMmPoolTest:
+         PoolsTest(KeyHandle);
+         break;
+
+       case TestStageMmPoolCorruption:
+         PoolsCorruption(KeyHandle);
+         break;
+
+       case TestStageOb:
+         NtoskrnlObTest(KeyHandle);
+         break;
+
+       case TestStageKeStall:
+         KeStallTest(KeyHandle);
+         break;
+
+       case TestStageDrv:
+         /* 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");
+                 }
+             }
+         }
+
+         FinishTest(KeyHandle, L"DriverTest");
+         break;
+
+       default:
+         ASSERT(FALSE);
+         break;
+     }
 }
 
 /*
@@ -203,60 +414,98 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
             PUNICODE_STRING RegistryPath)
 {
     int i;
-    PWCHAR LowerDriverRegPath;
+    NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING ParameterKeyName = RTL_CONSTANT_STRING(L"Parameters");
+    PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
+    PULONG KeyValue;
+    TEST_STAGE CurrentStage;
+    HANDLE DriverKeyHandle, ParameterKeyHandle;
 
     DbgPrint("\n===============================================\n");
     DbgPrint("Kernel Mode Regression Driver Test starting...\n");
     DbgPrint("===============================================\n");
 
-    MainDeviceObject = NULL;
-    AttachDeviceObject = NULL;
-    ThisDriverObject = DriverObject;
-
-    NtoskrnlExecutiveTests();
-    NtoskrnlIoTests();
-    NtoskrnlObTest();
-    NtoskrnlPoolsTest();
+    InitializeObjectAttributes(&ObjectAttributes,
+                               RegistryPath,
+                               OBJ_CASE_INSENSITIVE,
+                               0,
+                               NULL);
 
-    /* Start the tests for the driver routines */
-    StartTest();
+    Status = ZwOpenKey(&DriverKeyHandle,
+                       KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS,
+                       &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to open %wZ\n", RegistryPath);
+        return Status;
+    }
 
-    /* Do DriverObject Test for Driver Entry */
-    DriverObjectTest(DriverObject, 0);
-    /* Create and delete device, on return MainDeviceObject has been created */
-    DeviceCreateDeleteTest(DriverObject);
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &ParameterKeyName,
+                               OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
+                               DriverKeyHandle,
+                               NULL);
+    Status = ZwCreateKey(&ParameterKeyHandle,
+                         KEY_SET_VALUE | KEY_QUERY_VALUE,
+                         &ObjectAttributes,
+                         0,
+                         NULL,
+                         REG_OPTION_NON_VOLATILE,
+                         NULL);
+    ZwClose(DriverKeyHandle);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to create %wZ\\%wZ\n", RegistryPath, &ParameterKeyName);
+        return Status;
+    }
 
-    /* Make sure a device object was created */
-    if (MainDeviceObject)
+    KeyInfo = ReadRegistryValue(ParameterKeyHandle, L"CurrentStage");
+    if (KeyInfo)
     {
-        LowerDriverRegPath = CreateLowerDeviceRegistryKey(RegistryPath, L"kmtestassist");
+        if (KeyInfo->DataLength != sizeof(ULONG))
+        {
+            DPRINT1("Invalid data length for CurrentStage: %d\n", KeyInfo->DataLength);
+            ExFreePool(KeyInfo);
+            return STATUS_UNSUCCESSFUL;
+        }
 
-        if (LowerDriverRegPath)
+        KeyValue = (PULONG)KeyInfo->Data;
+
+        if ((*KeyValue) + 1 < TestStageMax)
+        {
+            DPRINT1("Resuming testing after a crash at stage %d\n", (*KeyValue));
+
+            CurrentStage = (TEST_STAGE)((*KeyValue) + 1);
+        }
+        else
         {
-            /* 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");
-            }
+            DPRINT1("Testing was completed on a previous boot\n");
+            ExFreePool(KeyInfo);
+            return STATUS_UNSUCCESSFUL;
         }
+
+        ExFreePool(KeyInfo);
     }
     else
     {
-        return STATUS_UNSUCCESSFUL;
+        DPRINT1("Starting a fresh test\n");
+        CurrentStage = (TEST_STAGE)0;
     }
 
+    /* Run the tests */
+    while (CurrentStage < TestStageMax)
+    {
+       RunKernelModeTest(DriverObject,
+                         RegistryPath,
+                         ParameterKeyHandle,
+                         CurrentStage);
+       CurrentStage++;
+    }
+
+    DPRINT1("Testing is complete!\n");
+    ZwClose(ParameterKeyHandle);
+
     /* Set all MajorFunctions to NULL to verify that kernel fixes them */
     for (i = 1; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
         DriverObject->MajorFunction[i] = NULL;