[ROSTESTS]
authorThomas Faber <thomas.faber@reactos.org>
Sat, 10 Sep 2011 11:41:33 +0000 (11:41 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Sat, 10 Sep 2011 11:41:33 +0000 (11:41 +0000)
- Merge the Kernel Mode Test Suite Google Summer of Code project
- Happy testing, everyone ;)

svn path=/trunk/; revision=53671

64 files changed:
1  2 
rostests/CMakeLists.txt
rostests/directory.rbuild
rostests/drivers/directory.rbuild
rostests/kmtests/CMakeLists.txt
rostests/kmtests/directory.rbuild
rostests/kmtests/example/CMakeLists.txt
rostests/kmtests/example/Example.c
rostests/kmtests/example/Example.h
rostests/kmtests/example/Example_drv.c
rostests/kmtests/example/Example_user.c
rostests/kmtests/example/KernelType.c
rostests/kmtests/example/example_drv.rbuild
rostests/kmtests/include/kmt_platform.h
rostests/kmtests/include/kmt_public.h
rostests/kmtests/include/kmt_test.h
rostests/kmtests/kmtest.rbuild
rostests/kmtests/kmtest/kmtest.c
rostests/kmtests/kmtest/kmtest.exe.manifest
rostests/kmtests/kmtest/kmtest.h
rostests/kmtests/kmtest/kmtest.rc
rostests/kmtests/kmtest/service.c
rostests/kmtests/kmtest/support.c
rostests/kmtests/kmtest/testlist.c
rostests/kmtests/kmtest_drv.rbuild
rostests/kmtests/kmtest_drv/kmtest_drv.c
rostests/kmtests/kmtest_drv/kmtest_drv.rc
rostests/kmtests/kmtest_drv/kmtest_standalone.c
rostests/kmtests/kmtest_drv/printf_stubs.c
rostests/kmtests/kmtest_drv/testlist.c
rostests/kmtests/ntos_ex/ExDoubleList.c
rostests/kmtests/ntos_ex/ExFastMutex.c
rostests/kmtests/ntos_ex/ExHardError.c
rostests/kmtests/ntos_ex/ExInterlocked.c
rostests/kmtests/ntos_ex/ExPools.c
rostests/kmtests/ntos_ex/ExResource.c
rostests/kmtests/ntos_ex/ExSequencedList.c
rostests/kmtests/ntos_ex/ExSingleList.c
rostests/kmtests/ntos_ex/ExTimer.c
rostests/kmtests/ntos_ex/ExXList.h
rostests/kmtests/ntos_fsrtl/FsRtlExpression.c
rostests/kmtests/ntos_io/CMakeLists.txt
rostests/kmtests/ntos_io/IoDeviceInterface.c
rostests/kmtests/ntos_io/IoDeviceObject_drv.c
rostests/kmtests/ntos_io/IoDeviceObject_user.c
rostests/kmtests/ntos_io/IoHelper_drv.c
rostests/kmtests/ntos_io/IoInterrupt.c
rostests/kmtests/ntos_io/IoIrp.c
rostests/kmtests/ntos_io/IoMdl.c
rostests/kmtests/ntos_io/iodeviceobject_drv.rbuild
rostests/kmtests/ntos_io/iohelper_drv.rbuild
rostests/kmtests/ntos_ke/KeApc.c
rostests/kmtests/ntos_ke/KeDpc.c
rostests/kmtests/ntos_ke/KeEvent.c
rostests/kmtests/ntos_ke/KeGuardedMutex.c
rostests/kmtests/ntos_ke/KeIrql.c
rostests/kmtests/ntos_ke/KeProcessor.c
rostests/kmtests/ntos_ke/KeSpinLock.c
rostests/kmtests/ntos_ob/ObReference.c
rostests/kmtests/ntos_ob/ObType.c
rostests/kmtests/readme.txt
rostests/kmtests/rtl/RtlAvlTree.c
rostests/kmtests/rtl/RtlMemory.c
rostests/kmtests/rtl/RtlSplayTree.c
rostests/win32/testsets.rbuild

diff --combined rostests/CMakeLists.txt
@@@ -1,7 -1,9 +1,9 @@@
  
  add_subdirectory(apitests)
  #add_subdirectory(dibtests)
+ #add_subdirectory(drivers)
  #add_subdirectory(dxtest)
+ add_subdirectory(kmtests)
  #add_subdirectory(regtests)
  if(NOT MSVC) # FIXME: msvc build
      add_subdirectory(rosautotest)
@@@ -1,6 -1,9 +1,9 @@@
  <?xml version="1.0"?>
  <!DOCTYPE group SYSTEM "../../../tools/rbuild/project.dtd">
  <group xmlns:xi="http://www.w3.org/2001/XInclude">
+       <directory name="apitests">
+               <xi:include href="apitests/directory.rbuild" />
+       </directory>
        <directory name="drivers">
                <xi:include href="drivers/directory.rbuild" />
        </directory>
@@@ -10,6 -13,9 +13,9 @@@
        <directory name="dxtest">
                <xi:include href="dxtest/directory.rbuild" />
        </directory>
+       <directory name="kmtests">
+               <xi:include href="kmtests/directory.rbuild" />
+       </directory>
        <directory name="regtests">
                <xi:include href="regtests/directory.rbuild" />
        </directory>
@@@ -25,7 -31,4 +31,4 @@@
        <directory name="winetests">
                <xi:include href="winetests/directory.rbuild" />
        </directory>
-       <directory name="apitests">
-               <xi:include href="apitests/directory.rbuild" />
-       </directory>
  </group>
@@@ -4,12 -4,6 +4,6 @@@
        <directory name="csqtest">
                <xi:include href="csqtest/csqtest.rbuild" />
        </directory>
-       <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>
index 0000000,b505697..b505697
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,105 +1,105 @@@
+ include_directories(
+     include)
+ #
+ # subdirectories containing special-purpose drivers
+ #
+ add_subdirectory(example)
+ add_subdirectory(ntos_io)
+ list(APPEND COMMON_SOURCE
+     rtl/RtlAvlTree.c
+     rtl/RtlMemory.c
+     rtl/RtlSplayTree.c)
+ #
+ # kmtest_drv.sys driver
+ #
+ list(APPEND KMTEST_DRV_SOURCE
+     kmtest_drv/kmtest_drv.c
+     kmtest_drv/testlist.c
+     example/Example.c
+     example/KernelType.c
+     ntos_ex/ExDoubleList.c
+     ntos_ex/ExFastMutex.c
+     ntos_ex/ExHardError.c
+     ntos_ex/ExInterlocked.c
+     ntos_ex/ExPools.c
+     ntos_ex/ExResource.c
+     ntos_ex/ExSequencedList.c
+     ntos_ex/ExSingleList.c
+     ntos_ex/ExTimer.c
+     ntos_fsrtl/FsRtlExpression.c
+     ntos_io/IoDeviceInterface.c
+     ntos_io/IoInterrupt.c
+     ntos_io/IoIrp.c
+     ntos_io/IoMdl.c
+     ntos_ke/KeApc.c
+     ntos_ke/KeDpc.c
+     ntos_ke/KeEvent.c
+     ntos_ke/KeGuardedMutex.c
+     ntos_ke/KeIrql.c
+     ntos_ke/KeProcessor.c
+     ntos_ke/KeSpinLock.c
+     ntos_ob/ObReference.c
+     ntos_ob/ObType.c
+     ${COMMON_SOURCE}
+     kmtest_drv/kmtest_drv.rc)
+ add_library(kmtest_drv SHARED ${KMTEST_DRV_SOURCE})
+ set_module_type(kmtest_drv kernelmodedriver)
+ target_link_libraries(kmtest_drv kmtest_printf ${PSEH_LIB})
+ add_importlibs(kmtest_drv ntoskrnl hal)
+ add_target_compile_definitions(kmtest_drv KMT_KERNEL_MODE NTDDI_VERSION=NTDDI_WS03SP1)
+ #add_pch(kmtest_drv include/kmt_test.h)
+ add_cd_file(TARGET kmtest_drv DESTINATION reactos/bin FOR all)
+ add_library(kmtest_printf
+     kmtest_drv/printf_stubs.c
+     ${REACTOS_SOURCE_DIR}/lib/sdk/crt/printf/streamout.c)
+ add_target_compile_definitions(kmtest_printf _LIBCNT_ _USER32_WSPRINTF wctomb=KmtWcToMb)
+ add_target_include_directories(kmtest_printf ${REACTOS_SOURCE_DIR}/lib/sdk/crt/include)
+ #
+ # kmtest.exe loader application
+ #
+ set_rc_compiler()
+ list(APPEND KMTEST_SOURCE
+     kmtest/kmtest.c
+     kmtest/service.c
+     kmtest/support.c
+     kmtest/testlist.c
+     example/Example_user.c
+     ntos_io/IoDeviceObject_user.c
+     ${COMMON_SOURCE}
+     kmtest/kmtest.rc)
+ add_executable(kmtest ${KMTEST_SOURCE})
+ set_module_type(kmtest win32cui)
+ target_link_libraries(kmtest ${PSEH_LIB})
+ add_importlibs(kmtest advapi32 msvcrt kernel32 ntdll)
+ add_target_compile_definitions(kmtest KMT_USER_MODE)
+ #add_pch(kmtest include/kmt_test.h)
+ set_target_properties(kmtest PROPERTIES OUTPUT_NAME "kmtest_")
+ add_cd_file(TARGET kmtest DESTINATION reactos/bin FOR all)
+ #
+ # Group targets
+ #
+ add_custom_target(kmtest_drivers)
+ add_dependencies(kmtest_drivers
+     kmtest_drv
+     example_drv
+     iodeviceobject_drv
+     iohelper_drv)
+ add_custom_target(kmtest_all)
+ add_dependencies(kmtest_all kmtest_drivers kmtest)
index 0000000,7807604..7807604
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,13 +1,13 @@@
+ <?xml version="1.0"?>
+ <!DOCTYPE group SYSTEM "../../../tools/rbuild/project.dtd">
+ <group xmlns:xi="http://www.w3.org/2001/XInclude">
+       <directory name="example">
+               <xi:include href="example/example_drv.rbuild" />
+       </directory>
+       <directory name="ntos_io">
+               <xi:include href="ntos_io/iodeviceobject_drv.rbuild" />
+               <xi:include href="ntos_io/iohelper_drv.rbuild" />
+       </directory>
+       <xi:include href="kmtest.rbuild" />
+       <xi:include href="kmtest_drv.rbuild" />
+ </group>
index 0000000,1ea2785..1ea2785
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,16 +1,16 @@@
+ include_directories(
+     ../include)
+ list(APPEND EXAMPLE_DRV_SOURCE
+     ../kmtest_drv/kmtest_standalone.c
+     Example_drv.c)
+ add_library(example_drv SHARED ${EXAMPLE_DRV_SOURCE})
+ set_module_type(example_drv kernelmodedriver)
+ target_link_libraries(example_drv kmtest_printf ${PSEH_LIB})
+ add_importlibs(example_drv ntoskrnl hal)
+ add_target_compile_definitions(example_drv KMT_STANDALONE_DRIVER)
+ #add_pch(example_drv ../include/kmt_test.h)
+ add_cd_file(TARGET example_drv DESTINATION reactos/bin FOR all)
index 0000000,1d2c39d..1d2c39d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,43 +1,43 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Example kernel-mode test part
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ START_TEST(Example)
+ {
+     KIRQL Irql;
+     ok(1, "This test should succeed.\n");
+     ok(0, "This test should fail.\n");
+     trace("Message from kernel, low-irql. %s. %ls.\n", "Format strings work", L"Even with Unicode");
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     trace("Message from kernel, high-irql. %s. %ls.\n", "Format strings work", L"Even with Unicode");
+     ok_irql(DISPATCH_LEVEL);
+     ok_eq_int(5, 6);
+     ok_eq_uint(6U, 7U);
+     ok_eq_long(1L, 2L);
+     ok_eq_ulong(3LU, 4LU);
+     ok_eq_pointer((PVOID)8, (PVOID)9);
+     ok_eq_hex(0x1234LU, 0x5678LU);
+     ok_eq_bool(TRUE, TRUE);
+     ok_eq_bool(TRUE, FALSE);
+     ok_eq_bool(FALSE, TRUE);
+     ok_bool_true(FALSE, "foo");
+     ok_bool_false(TRUE, "bar");
+     ok_eq_print(1, 2, "%i");
+     ok_eq_str("Hello", "world");
+     ok_eq_wstr(L"ABC", L"DEF");
+     if (!skip(KeGetCurrentIrql() == HIGH_LEVEL, "This should only work on HIGH_LEVEL\n"))
+     {
+         /* do tests depending on HIGH_LEVEL here */
+         ok(1, "This is fine\n");
+     }
+     KeLowerIrql(Irql);
+ }
index 0000000,7c7bfec..7c7bfec
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,21 +1,21 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Example Test declarations
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+  
+ #ifndef _KMTEST_EXAMPLE_H_
+ #define _KMTEST_EXAMPLE_H_
+ typedef struct
+ {
+     int a;
+     char b[8];
+ } MY_STRUCT, *PMY_STRUCT;
+ #define IOCTL_NOTIFY        1
+ #define IOCTL_SEND_STRING   2
+ #define IOCTL_SEND_MYSTRUCT 3
+ #endif /* !defined _KMTEST_EXAMPLE_H_ */
index 0000000,641c71a..641c71a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,245 +1,245 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Example Test Driver
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ //#define NDEBUG
+ #include <debug.h>
+ #include "Example.h"
+ /* prototypes */
+ static KMT_MESSAGE_HANDLER TestMessageHandler;
+ static KMT_IRP_HANDLER TestIrpHandler;
+ /* globals */
+ static PDRIVER_OBJECT TestDriverObject;
+ /**
+  * @name TestEntry
+  *
+  * Test entry point.
+  * This is called by DriverEntry as early as possible, but with ResultBuffer
+  * initialized, so that test macros work correctly
+  *
+  * @param DriverObject
+  *        Driver Object.
+  *        This is guaranteed not to have been touched by DriverEntry before
+  *        the call to TestEntry
+  * @param RegistryPath
+  *        Driver Registry Path
+  *        This is guaranteed not to have been touched by DriverEntry before
+  *        the call to TestEntry
+  * @param DeviceName
+  *        Pointer to receive a test-specific name for the device to create
+  * @param Flags
+  *        Pointer to a flags variable instructing DriverEntry how to proceed.
+  *        See the KMT_TESTENTRY_FLAGS enumeration for possible values
+  *        Initialized to zero on entry
+  *
+  * @return Status.
+  *         DriverEntry will fail if this is a failure status
+  */
+ NTSTATUS
+ TestEntry(
+     IN PDRIVER_OBJECT DriverObject,
+     IN PCUNICODE_STRING RegistryPath,
+     OUT PCWSTR *DeviceName,
+     IN OUT INT *Flags)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     PAGED_CODE();
+     UNREFERENCED_PARAMETER(RegistryPath);
+     UNREFERENCED_PARAMETER(Flags);
+     DPRINT("Entry!\n");
+     ok_irql(PASSIVE_LEVEL);
+     TestDriverObject = DriverObject;
+     *DeviceName = L"Example";
+     trace("Hi, this is the example driver\n");
+     KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler);
+     KmtRegisterIrpHandler(IRP_MJ_CLOSE, NULL, TestIrpHandler);
+     KmtRegisterMessageHandler(0, NULL, TestMessageHandler);
+     return Status;
+ }
+ /**
+  * @name TestUnload
+  *
+  * Test unload routine.
+  * This is called by the driver's Unload routine as early as possible, with
+  * ResultBuffer and the test device object still valid, so that test macros
+  * work correctly
+  *
+  * @param DriverObject
+  *        Driver Object.
+  *        This is guaranteed not to have been touched by Unload before the call
+  *        to TestEntry
+  *
+  * @return Status
+  */
+ VOID
+ TestUnload(
+     IN PDRIVER_OBJECT DriverObject)
+ {
+     PAGED_CODE();
+     DPRINT("Unload!\n");
+     ok_irql(PASSIVE_LEVEL);
+     ok_eq_pointer(DriverObject, TestDriverObject);
+     trace("Unloading example driver\n");
+ }
+ /**
+  * @name TestMessageHandler
+  *
+  * Test message handler routine
+  *
+  * @param DeviceObject
+  *        Device Object.
+  *        This is guaranteed not to have been touched by the dispatch function
+  *        before the call to the IRP handler
+  * @param Irp
+  *        Device Object.
+  *        This is guaranteed not to have been touched by the dispatch function
+  *        before the call to the IRP handler, except for passing it to
+  *        IoGetCurrentStackLocation
+  * @param IoStackLocation
+  *        Device Object.
+  *        This is guaranteed not to have been touched by the dispatch function
+  *        before the call to the IRP handler
+  *
+  * @return Status
+  */
+ static
+ NTSTATUS
+ TestMessageHandler(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN ULONG ControlCode,
+     IN PVOID Buffer OPTIONAL,
+     IN SIZE_T InLength,
+     IN OUT PSIZE_T OutLength)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     switch (ControlCode)
+     {
+         case IOCTL_NOTIFY:
+         {
+             static int TimesReceived = 0;
+             ++TimesReceived;
+             ok(TimesReceived == 1, "Received control code 1 %d times\n", TimesReceived);
+             ok_eq_pointer(Buffer, NULL);
+             ok_eq_ulong((ULONG)InLength, 0LU);
+             ok_eq_ulong((ULONG)*OutLength, 0LU);
+             break;
+         }
+         case IOCTL_SEND_STRING:
+         {
+             static int TimesReceived = 0;
+             ANSI_STRING ExpectedString = RTL_CONSTANT_STRING("yay");
+             ANSI_STRING ReceivedString;
+             ++TimesReceived;
+             ok(TimesReceived == 1, "Received control code 2 %d times\n", TimesReceived);
+             ok(Buffer != NULL, "Buffer is NULL\n");
+             ok_eq_ulong((ULONG)InLength, (ULONG)ExpectedString.Length);
+             ok_eq_ulong((ULONG)*OutLength, 0LU);
+             ReceivedString.MaximumLength = ReceivedString.Length = (USHORT)InLength;
+             ReceivedString.Buffer = Buffer;
+             ok(RtlCompareString(&ExpectedString, &ReceivedString, FALSE) == 0, "Received string: %Z\n", &ReceivedString);
+             break;
+         }
+         case IOCTL_SEND_MYSTRUCT:
+         {
+             static int TimesReceived = 0;
+             MY_STRUCT ExpectedStruct = { 123, ":D" };
+             MY_STRUCT ResultStruct = { 456, "!!!" };
+             ++TimesReceived;
+             ok(TimesReceived == 1, "Received control code 3 %d times\n", TimesReceived);
+             ok(Buffer != NULL, "Buffer is NULL\n");
+             ok_eq_ulong((ULONG)InLength, (ULONG)sizeof ExpectedStruct);
+             ok_eq_ulong((ULONG)*OutLength, 2LU * sizeof ExpectedStruct);
+             if (!skip(Buffer && InLength >= sizeof ExpectedStruct, "Cannot read from buffer!\n"))
+                 ok(RtlCompareMemory(&ExpectedStruct, Buffer, sizeof ExpectedStruct) == sizeof ExpectedStruct, "Buffer does not contain expected values\n");
+             if (!skip(Buffer && *OutLength >= 2 * sizeof ExpectedStruct, "Cannot write to buffer!\n"))
+             {
+                 RtlCopyMemory((PCHAR)Buffer + sizeof ExpectedStruct, &ResultStruct, sizeof ResultStruct);
+                 *OutLength = 2 * sizeof ExpectedStruct;
+             }
+             break;
+         }
+         default:
+             ok(0, "Got an unknown message! DeviceObject=%p, ControlCode=%lu, Buffer=%p, In=%lu, Out=%lu bytes\n",
+                     DeviceObject, ControlCode, Buffer, InLength, *OutLength);
+             break;
+     }
+     return Status;
+ }
+ /**
+  * @name TestIrpHandler
+  *
+  * Test IRP handler routine
+  *
+  * @param DeviceObject
+  *        Device Object.
+  *        This is guaranteed not to have been touched by the dispatch function
+  *        before the call to the IRP handler
+  * @param Irp
+  *        Device Object.
+  *        This is guaranteed not to have been touched by the dispatch function
+  *        before the call to the IRP handler, except for passing it to
+  *        IoGetCurrentStackLocation
+  * @param IoStackLocation
+  *        Device Object.
+  *        This is guaranteed not to have been touched by the dispatch function
+  *        before the call to the IRP handler
+  *
+  * @return Status
+  */
+ static
+ NTSTATUS
+ TestIrpHandler(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+     IN PIO_STACK_LOCATION IoStackLocation)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     DPRINT("IRP!\n");
+     ok_irql(PASSIVE_LEVEL);
+     ok_eq_pointer(DeviceObject->DriverObject, TestDriverObject);
+     if (IoStackLocation->MajorFunction == IRP_MJ_CREATE)
+         trace("Got IRP_MJ_CREATE!\n");
+     else if (IoStackLocation->MajorFunction == IRP_MJ_CLOSE)
+         trace("Got IRP_MJ_CLOSE!\n");
+     else
+         trace("Got an IRP!\n");
+     Irp->IoStatus.Status = Status;
+     Irp->IoStatus.Information = 0;
+     IoCompleteRequest(Irp, IO_NO_INCREMENT);
+     return Status;
+ }
index 0000000,f462fc6..f462fc6
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,44 +1,44 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Example user-mode test part
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ #include "Example.h"
+ START_TEST(Example)
+ {
+     /* do some user-mode stuff */
+     SYSTEM_INFO SystemInfo;
+     MY_STRUCT MyStruct[2] = { { 123, ":D" }, { 0 } };
+     DWORD Length = sizeof MyStruct;
+     trace("Message from user-mode\n");
+     GetSystemInfo(&SystemInfo);
+     ok(SystemInfo.dwActiveProcessorMask != 0, "No active processors?!\n");
+     /* now run the kernel-mode part (see Example.c).
+      * If no user-mode part exists, this is what's done automatically */
+     KmtRunKernelTest("Example");
+     /* now start the special-purpose driver */
+     KmtLoadDriver(L"Example", FALSE);
+     trace("After Entry\n");
+     KmtOpenDriver();
+     trace("After Create\n");
+     ok(KmtSendToDriver(IOCTL_NOTIFY) == ERROR_SUCCESS, "\n");
+     ok(KmtSendStringToDriver(IOCTL_SEND_STRING, "yay") == ERROR_SUCCESS, "\n");
+     ok(KmtSendBufferToDriver(IOCTL_SEND_MYSTRUCT, MyStruct, sizeof MyStruct[0], &Length) == ERROR_SUCCESS, "\n");
+     ok_eq_int(MyStruct[1].a, 456);
+     ok_eq_str(MyStruct[1].b, "!!!");
+     KmtCloseDriver();
+     trace("After Close\n");
+     KmtUnloadDriver();
+     trace("After Unload\n");
+ }
index 0000000,1df835f..1df835f
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,20 +1,20 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Kernel Type example test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ START_TEST(KernelType)
+ {
+     if (KmtIsMultiProcessorBuild)
+         trace("This is a MultiProcessor kernel\n");
+     else
+         trace("This is a Uniprocessor kernel\n");
+     if (KmtIsCheckedBuild)
+         trace("This is a Checked kernel\n");
+     else
+         trace("This is a Free kernel\n");
+ }
index 0000000,e5460e7..e5460e7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,14 +1,14 @@@
+ <module name="example_drv" type="kernelmodedriver" installbase="bin" installname="example_drv.sys">
+       <include base="kmtest_drv">include</include>
+       <library>ntoskrnl</library>
+       <library>hal</library>
+       <library>pseh</library>
+       <library>kmtest_printf</library>
+       <define name="KMT_STANDALONE_DRIVER" />
+       <file>Example_drv.c</file>
+       <directory name="..">
+               <directory name="kmtest_drv">
+                       <file>kmtest_standalone.c</file>
+               </directory>
+       </directory>
+ </module>
index 0000000,580a098..580a098
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,54 +1,54 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite platform declarations
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #ifndef _KMTEST_PLATFORM_H_
+ #define _KMTEST_PLATFORM_H_
+ #if !defined _KMTEST_TEST_H_
+ #error include kmt_test.h instead of including kmt_platform.h!
+ #endif /* !defined _KMTEST_TEST_H_ */
+ #if defined KMT_KERNEL_MODE || defined KMT_STANDALONE_DRIVER
+ #include <ntddk.h>
+ #include <ntifs.h>
+ #include <ndk/ntndk.h>
+ #include <ntstrsafe.h>
+ #elif defined KMT_USER_MODE
+ #define WIN32_LEAN_AND_MEAN
+ #define WIN32_NO_STATUS
+ #define UNICODE
+ #include <windows.h>
+ #include <ndk/ntndk.h>
+ #include <strsafe.h>
+ #include <winioctl.h>
+ #ifdef KMT_EMULATE_KERNEL
+ #define ok_irql(i)
+ #define KIRQL int
+ typedef const UCHAR CUCHAR, *PCUCHAR;
+ typedef ULONG LOGICAL, *PLOGICAL;
+ #undef KeRaiseIrql
+ #define KeRaiseIrql(new, old) *(old) = 123
+ #undef KeLowerIrql
+ #define KeLowerIrql(i) (void)(i)
+ #define ExAllocatePool(type, size)              HeapAlloc(GetProcessHeap(), 0, size)
+ #define ExAllocatePoolWithTag(type, size, tag)  HeapAlloc(GetProcessHeap(), 0, size)
+ #define ExFreePool(p)                           HeapFree(GetProcessHeap(), 0, p)
+ #define ExFreePoolWithTag(p, tag)               HeapFree(GetProcessHeap(), 0, p)
+ #define RtlCopyMemoryNonTemporal                RtlCopyMemory
+ #define RtlPrefetchMemoryNonTemporal(s, l)
+ #endif /* defined KMT_EMULATE_KERNEL */
+ #endif /* defined KMT_USER_MODE */
+ #include <pseh/pseh2.h>
+ #include <limits.h>
+ #include <stdarg.h>
+ #endif /* !defined _KMTEST_PLATFORM_H_ */
index 0000000,abb260d..abb260d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,24 +1,24 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite public declarations
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #ifndef _KMTEST_PUBLIC_H_
+ #define _KMTEST_PUBLIC_H_
+ #define IOCTL_KMTEST_GET_TESTS \
+     CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_READ_DATA)
+ #define IOCTL_KMTEST_RUN_TEST  \
+     CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
+ #define IOCTL_KMTEST_SET_RESULTBUFFER  \
+     CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
+ #define KMTEST_DEVICE_NAME L"Kmtest"
+ #define KMTEST_DEVICE_DRIVER_PATH L"\\Device\\" KMTEST_DEVICE_NAME
+ #define KMTEST_DEVICE_PATH L"\\\\.\\Global\\GLOBALROOT" KMTEST_DEVICE_DRIVER_PATH
+ #endif /* !defined _KMTEST_PUBLIC_H_ */
index 0000000,73ea959..73ea959
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,416 +1,416 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite test framework declarations
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ /* Inspired by Wine C unit tests, Copyright (C) 2002 Alexandre Julliard
+  * Inspired by ReactOS kernel-mode regression tests,
+  *                                Copyright (C) Aleksey Bragin, Filip Navara
+  */
+ #ifndef _KMTEST_TEST_H_
+ #define _KMTEST_TEST_H_
+ #include <kmt_platform.h>
+ typedef VOID KMT_TESTFUNC(VOID);
+ typedef KMT_TESTFUNC *PKMT_TESTFUNC;
+ typedef struct
+ {
+     const char *TestName;
+     KMT_TESTFUNC *TestFunction;
+ } KMT_TEST, *PKMT_TEST;
+ typedef const KMT_TEST CKMT_TEST, *PCKMT_TEST;
+ extern const KMT_TEST TestList[];
+ typedef struct
+ {
+     volatile LONG Successes;
+     volatile LONG Failures;
+     volatile LONG Skipped;
+     volatile LONG LogBufferLength;
+     LONG LogBufferMaxLength;
+     CHAR LogBuffer[ANYSIZE_ARRAY];
+ } KMT_RESULTBUFFER, *PKMT_RESULTBUFFER;
+ #ifdef KMT_STANDALONE_DRIVER
+ #define KMT_KERNEL_MODE
+ typedef NTSTATUS (KMT_IRP_HANDLER)(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+     IN PIO_STACK_LOCATION IoStackLocation);
+ typedef KMT_IRP_HANDLER *PKMT_IRP_HANDLER;
+ NTSTATUS KmtRegisterIrpHandler(IN UCHAR MajorFunction, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_IRP_HANDLER IrpHandler);
+ NTSTATUS KmtUnregisterIrpHandler(IN UCHAR MajorFunction, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_IRP_HANDLER IrpHandler);
+ typedef NTSTATUS (KMT_MESSAGE_HANDLER)(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN ULONG ControlCode,
+     IN PVOID Buffer OPTIONAL,
+     IN SIZE_T InLength,
+     IN OUT PSIZE_T OutLength);
+ typedef KMT_MESSAGE_HANDLER *PKMT_MESSAGE_HANDLER;
+ NTSTATUS KmtRegisterMessageHandler(IN ULONG ControlCode OPTIONAL, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_MESSAGE_HANDLER MessageHandler);
+ NTSTATUS KmtUnregisterMessageHandler(IN ULONG ControlCode OPTIONAL, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_MESSAGE_HANDLER MessageHandler);
+ typedef enum
+ {
+     TESTENTRY_NO_CREATE_DEVICE = 1,
+     TESTENTRY_NO_REGISTER_DISPATCH = 2,
+     TESTENTRY_NO_REGISTER_UNLOAD = 4,
+ } KMT_TESTENTRY_FLAGS;
+ NTSTATUS TestEntry(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING RegistryPath, OUT PCWSTR *DeviceName, IN OUT INT *Flags);
+ VOID TestUnload(IN PDRIVER_OBJECT DriverObject);
+ #endif /* defined KMT_STANDALONE_DRIVER */
+ #ifdef KMT_KERNEL_MODE
+ /* Device Extension layout */
+ typedef struct
+ {
+     PKMT_RESULTBUFFER ResultBuffer;
+     PMDL Mdl;
+ } KMT_DEVICE_EXTENSION, *PKMT_DEVICE_EXTENSION;
+ extern BOOLEAN KmtIsCheckedBuild;
+ extern BOOLEAN KmtIsMultiProcessorBuild;
+ extern PCSTR KmtMajorFunctionNames[];
+ VOID KmtSetIrql(IN KIRQL NewIrql);
+ BOOLEAN KmtAreInterruptsEnabled(VOID);
+ #elif defined KMT_USER_MODE
+ DWORD KmtRunKernelTest(IN PCSTR TestName);
+ VOID KmtLoadDriver(IN PCWSTR ServiceName, IN BOOLEAN RestartIfRunning);
+ VOID KmtUnloadDriver(VOID);
+ VOID KmtOpenDriver(VOID);
+ VOID KmtCloseDriver(VOID);
+ DWORD KmtSendToDriver(IN DWORD ControlCode);
+ DWORD KmtSendStringToDriver(IN DWORD ControlCode, IN PCSTR String);
+ DWORD KmtSendBufferToDriver(IN DWORD ControlCode, IN OUT PVOID Buffer OPTIONAL, IN DWORD InLength, IN OUT PDWORD OutLength);
+ #else /* if !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
+ #error either KMT_KERNEL_MODE or KMT_USER_MODE must be defined
+ #endif /* !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
+ extern PKMT_RESULTBUFFER ResultBuffer;
+ #ifdef __GNUC__
+ /* TODO: GCC doesn't understand %wZ :( */
+ #define KMT_FORMAT(type, fmt, first) /*__attribute__((__format__(type, fmt, first)))*/
+ #elif !defined __GNUC__
+ #define KMT_FORMAT(type, fmt, first)
+ #endif /* !defined __GNUC__ */
+ #define START_TEST(name) VOID Test_##name(VOID)
+ #ifndef KMT_STRINGIZE
+ #define KMT_STRINGIZE(x) #x
+ #endif /* !defined KMT_STRINGIZE */
+ #define ok(test, ...)                ok_(test,   __FILE__, __LINE__, __VA_ARGS__)
+ #define trace(...)                   trace_(     __FILE__, __LINE__, __VA_ARGS__)
+ #define skip(test, ...)              skip_(test, __FILE__, __LINE__, __VA_ARGS__)
+ #define ok_(test, file, line, ...)   KmtOk(test,   file ":" KMT_STRINGIZE(line), __VA_ARGS__)
+ #define trace_(file, line, ...)      KmtTrace(     file ":" KMT_STRINGIZE(line), __VA_ARGS__)
+ #define skip_(test, file, line, ...) KmtSkip(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
+ VOID KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)      KMT_FORMAT(ms_printf, 3, 0);
+ VOID KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)                     KMT_FORMAT(ms_printf, 3, 4);
+ VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)                  KMT_FORMAT(ms_printf, 2, 0);
+ VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)                                 KMT_FORMAT(ms_printf, 2, 3);
+ BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
+ BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)                KMT_FORMAT(ms_printf, 3, 4);
+ #ifdef KMT_KERNEL_MODE
+ #define ok_irql(irql)                       ok(KeGetCurrentIrql() == irql, "IRQL is %d, expected %d\n", KeGetCurrentIrql(), irql)
+ #endif /* defined KMT_KERNEL_MODE */
+ #define ok_eq_print(value, expected, spec)  ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
+ #define ok_eq_pointer(value, expected)      ok_eq_print(value, expected, "%p")
+ #define ok_eq_int(value, expected)          ok_eq_print(value, expected, "%d")
+ #define ok_eq_uint(value, expected)         ok_eq_print(value, expected, "%u")
+ #define ok_eq_long(value, expected)         ok_eq_print(value, expected, "%ld")
+ #define ok_eq_ulong(value, expected)        ok_eq_print(value, expected, "%lu")
+ #define ok_eq_longlong(value, expected)     ok_eq_print(value, expected, "%I64d")
+ #define ok_eq_ulonglong(value, expected)    ok_eq_print(value, expected, "%I64u")
+ #ifndef _WIN64
+ #define ok_eq_size(value, expected)         ok_eq_print(value, (SIZE_T)(expected), "%lu")
+ #define ok_eq_longptr(value, expected)      ok_eq_print(value, (LONG_PTR)(expected), "%ld")
+ #define ok_eq_ulongptr(value, expected)     ok_eq_print(value, (ULONG_PTR)(expected), "%lu")
+ #elif defined _WIN64
+ #define ok_eq_size(value, expected)         ok_eq_print(value, (SIZE_T)(expected), "%I64u")
+ #define ok_eq_longptr(value, expected)      ok_eq_print(value, (LONG_PTR)(expected), "%I64d")
+ #define ok_eq_ulongptr(value, expected)     ok_eq_print(value, (ULONG_PTR)(expected), "%I64u")
+ #endif /* defined _WIN64 */
+ #define ok_eq_hex(value, expected)          ok_eq_print(value, expected, "0x%08lx")
+ #define ok_bool_true(value, desc)           ok((value) == TRUE, desc " FALSE, expected TRUE\n")
+ #define ok_bool_false(value, desc)          ok((value) == FALSE, desc " TRUE, expected FALSE\n")
+ #define ok_eq_bool(value, expected)         ok((value) == (expected), #value " = %s, expected %s\n",    \
+                                                 (value) ? "TRUE" : "FALSE",                             \
+                                                 (expected) ? "TRUE" : "FALSE")
+ #define ok_eq_str(value, expected)          ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
+ #define ok_eq_wstr(value, expected)         ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
+ #define KMT_MAKE_CODE(ControlCode)  CTL_CODE(FILE_DEVICE_UNKNOWN,           \
+                                              0xC00 + (ControlCode),         \
+                                              METHOD_BUFFERED,               \
+                                              FILE_ANY_ACCESS)
+ #define MICROSECOND     10
+ #define MILLISECOND     (1000 * MICROSECOND)
+ #define SECOND          (1000 * MILLISECOND)
+ #if defined KMT_DEFINE_TEST_FUNCTIONS
+ #if defined KMT_KERNEL_MODE
+ BOOLEAN KmtIsCheckedBuild;
+ BOOLEAN KmtIsMultiProcessorBuild;
+ PCSTR KmtMajorFunctionNames[] =
+ {
+     "Create",
+     "CreateNamedPipe",
+     "Close",
+     "Read",
+     "Write",
+     "QueryInformation",
+     "SetInformation",
+     "QueryEa",
+     "SetEa",
+     "FlushBuffers",
+     "QueryVolumeInformation",
+     "SetVolumeInformation",
+     "DirectoryControl",
+     "FileSystemControl",
+     "DeviceControl",
+     "InternalDeviceControl/Scsi",
+     "Shutdown",
+     "LockControl",
+     "Cleanup",
+     "CreateMailslot",
+     "QuerySecurity",
+     "SetSecurity",
+     "Power",
+     "SystemControl",
+     "DeviceChange",
+     "QueryQuota",
+     "SetQuota",
+     "Pnp/PnpPower"
+ };
+ VOID KmtSetIrql(IN KIRQL NewIrql)
+ {
+     KIRQL Irql = KeGetCurrentIrql();
+     if (Irql > NewIrql)
+         KeLowerIrql(NewIrql);
+     else if (Irql < NewIrql)
+         KeRaiseIrql(NewIrql, &Irql);
+ }
+ BOOLEAN KmtAreInterruptsEnabled(VOID)
+ {
+     return (__readeflags() & (1 << 9)) != 0;
+ }
+ INT __cdecl KmtVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
+ #elif defined KMT_USER_MODE
+ static PKMT_RESULTBUFFER KmtAllocateResultBuffer(SIZE_T ResultBufferSize)
+ {
+     PKMT_RESULTBUFFER Buffer = HeapAlloc(GetProcessHeap(), 0, ResultBufferSize);
+     if (!Buffer)
+         return NULL;
+     Buffer->Successes = 0;
+     Buffer->Failures = 0;
+     Buffer->Skipped = 0;
+     Buffer->LogBufferLength = 0;
+     Buffer->LogBufferMaxLength = ResultBufferSize - FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer);
+     return Buffer;
+ }
+ static VOID KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer)
+ {
+     HeapFree(GetProcessHeap(), 0, Buffer);
+ }
+ #define KmtVSNPrintF vsnprintf
+ #endif /* defined KMT_USER_MODE */
+ PKMT_RESULTBUFFER ResultBuffer = NULL;
+ static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
+ {
+     LONG OldLength;
+     LONG NewLength;
+     if (!Buffer)
+         return;
+     do
+     {
+         OldLength = Buffer->LogBufferLength;
+         NewLength = OldLength + Length;
+         if (NewLength > Buffer->LogBufferMaxLength)
+             return;
+     } while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
+     memcpy(&Buffer->LogBuffer[OldLength], String, Length);
+ }
+ KMT_FORMAT(ms_printf, 5, 0)
+ static SIZE_T KmtXVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, va_list Arguments)
+ {
+     SIZE_T BufferLength = 0;
+     SIZE_T Length;
+     if (FileAndLine)
+     {
+         PCSTR Slash;
+         Slash = strrchr(FileAndLine, '\\');
+         if (Slash)
+             FileAndLine = Slash + 1;
+         Slash = strrchr(FileAndLine, '/');
+         if (Slash)
+             FileAndLine = Slash + 1;
+         Length = min(BufferMaxLength, strlen(FileAndLine));
+         memcpy(Buffer, FileAndLine, Length);
+         Buffer += Length;
+         BufferLength += Length;
+         BufferMaxLength -= Length;
+     }
+     if (Prepend)
+     {
+         Length = min(BufferMaxLength, strlen(Prepend));
+         memcpy(Buffer, Prepend, Length);
+         Buffer += Length;
+         BufferLength += Length;
+         BufferMaxLength -= Length;
+     }
+     if (Format)
+     {
+         Length = KmtVSNPrintF(Buffer, BufferMaxLength, Format, Arguments);
+         /* vsnprintf can return more than maxLength, we don't want to do that */
+         BufferLength += min(Length, BufferMaxLength);
+     }
+     return BufferLength;
+ }
+ KMT_FORMAT(ms_printf, 5, 6)
+ static SIZE_T KmtXSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, ...)
+ {
+     SIZE_T BufferLength;
+     va_list Arguments;
+     va_start(Arguments, Format);
+     BufferLength = KmtXVSNPrintF(Buffer, BufferMaxLength, FileAndLine, Prepend, Format, Arguments);
+     va_end(Arguments);
+     return BufferLength;
+ }
+ VOID KmtFinishTest(PCSTR TestName)
+ {
+     CHAR MessageBuffer[512];
+     SIZE_T MessageLength;
+     if (!ResultBuffer)
+         return;
+     MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, NULL, NULL,
+                                     "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
+                                     TestName,
+                                     ResultBuffer->Successes + ResultBuffer->Failures,
+                                     ResultBuffer->Failures,
+                                     ResultBuffer->Skipped);
+     KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
+ }
+ VOID KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
+ {
+     CHAR MessageBuffer[512];
+     SIZE_T MessageLength;
+     if (!ResultBuffer)
+         return;
+     if (Condition)
+     {
+         InterlockedIncrement(&ResultBuffer->Successes);
+         if (0/*KmtReportSuccess*/)
+         {
+             MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test succeeded\n", NULL);
+             KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
+         }
+     }
+     else
+     {
+         InterlockedIncrement(&ResultBuffer->Failures);
+         MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test failed: ", Format, Arguments);
+         KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
+     }
+ }
+ VOID KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
+ {
+     va_list Arguments;
+     va_start(Arguments, Format);
+     KmtVOk(Condition, FileAndLine, Format, Arguments);
+     va_end(Arguments);
+ }
+ VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)
+ {
+     CHAR MessageBuffer[512];
+     SIZE_T MessageLength;
+     MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": ", Format, Arguments);
+     KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
+ }
+ VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)
+ {
+     va_list Arguments;
+     va_start(Arguments, Format);
+     KmtVTrace(FileAndLine, Format, Arguments);
+     va_end(Arguments);
+ }
+ BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
+ {
+     CHAR MessageBuffer[512];
+     SIZE_T MessageLength;
+     if (!ResultBuffer)
+         return !Condition;
+     if (!Condition)
+     {
+         InterlockedIncrement(&ResultBuffer->Skipped);
+         MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Tests skipped: ", Format, Arguments);
+         KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
+     }
+     return !Condition;
+ }
+ BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
+ {
+     BOOLEAN Ret;
+     va_list Arguments;
+     va_start(Arguments, Format);
+     Ret = KmtVSkip(Condition, FileAndLine, Format, Arguments);
+     va_end(Arguments);
+     return Ret;
+ }
+ #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
+ #endif /* !defined _KMTEST_TEST_H_ */
index 0000000,67c3f0b..67c3f0b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,24 +1,24 @@@
+ <module name="kmtest" type="win32cui" installbase="bin" installname="kmtest_.exe">
+       <include base="kmtest">include</include>
+       <library>advapi32</library>
+       <library>ntdll</library>
+       <library>pseh</library>
+       <define name="KMT_USER_MODE" />
+       <directory name="kmtest">
+               <file>kmtest.c</file>
+               <file>service.c</file>
+               <file>support.c</file>
+               <file>testlist.c</file>
+       </directory>
+       <directory name="example">
+               <file>Example_user.c</file>
+       </directory>
+       <directory name="ntos_io">
+               <file>IoDeviceObject_user.c</file>
+       </directory>
+       <directory name="rtl">
+               <file>RtlAvlTree.c</file>
+               <file>RtlMemory.c</file>
+               <file>RtlSplayTree.c</file>
+       </directory>
+ </module>
index 0000000,f9f3cde..f9f3cde
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,395 +1,395 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Loader Application
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #define KMT_DEFINE_TEST_FUNCTIONS
+ #include <kmt_test.h>
+ #include "kmtest.h"
+ #include <kmt_public.h>
+ #include <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #define SERVICE_NAME        L"Kmtest"
+ #define SERVICE_PATH        L"kmtest_drv.sys"
+ #define SERVICE_DESCRIPTION L"ReactOS Kernel-Mode Test Suite Driver"
+ #define RESULTBUFFER_SIZE   (1024 * 1024)
+ typedef enum
+ {
+     KMT_DO_NOTHING,
+     KMT_LIST_TESTS,
+     KMT_LIST_ALL_TESTS,
+     KMT_RUN_TEST,
+ } KMT_OPERATION;
+ HANDLE KmtestHandle;
+ SC_HANDLE KmtestServiceHandle;
+ PCSTR ErrorFileAndLine = "No error";
+ static void OutputError(IN DWORD Error);
+ static DWORD ListTests(IN BOOLEAN IncludeHidden);
+ static PKMT_TESTFUNC FindTest(IN PCSTR TestName);
+ static DWORD OutputResult(IN PCSTR TestName);
+ static DWORD RunTest(IN PCSTR TestName);
+ int __cdecl main(int ArgCount, char **Arguments);
+ /**
+  * @name OutputError
+  *
+  * Output an error message to the console.
+  *
+  * @param Error
+  *        Win32 error code
+  */
+ static
+ void
+ OutputError(
+     IN DWORD Error)
+ {
+     PSTR Message;
+     if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+                    NULL, Error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&Message, 0, NULL))
+     {
+         fprintf(stderr, "%s: Could not retrieve error message (error 0x%08lx). Original error: 0x%08lx\n",
+             ErrorFileAndLine, GetLastError(), Error);
+         return;
+     }
+     fprintf(stderr, "%s: error 0x%08lx: %s\n", ErrorFileAndLine, Error, Message);
+     LocalFree(Message);
+ }
+ /**
+  * @name CompareTestNames
+  *
+  * strcmp that skips a leading '-' on either string if present
+  *
+  * @param Str1
+  * @param Str2
+  * @return see strcmp
+  */
+ static
+ INT
+ CompareTestNames(
+     IN PCSTR Str1,
+     IN PCSTR Str2)
+ {
+     if (*Str1 == '-')
+         ++Str1;
+     if (*Str2 == '-')
+         ++Str2;
+     while (*Str1 && *Str1 == *Str2)
+     {
+         ++Str1;
+         ++Str2;
+     }
+     return *Str1 - *Str2;
+ }
+ /**
+  * @name ListTests
+  *
+  * Output the list of tests to the console.
+  * The list will comprise tests as listed by the driver
+  * in addition to user-mode tests in TestList.
+  *
+  * @param IncludeHidden
+  *        TRUE to include "hidden" tests prefixed with a '-'
+  *
+  * @return Win32 error code
+  */
+ static
+ DWORD
+ ListTests(
+     IN BOOLEAN IncludeHidden)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     CHAR Buffer[1024];
+     DWORD BytesRead;
+     PCSTR TestName = Buffer;
+     PCKMT_TEST TestEntry = TestList;
+     PCSTR NextTestName;
+     puts("Valid test names:");
+     // get test list from driver
+     if (!DeviceIoControl(KmtestHandle, IOCTL_KMTEST_GET_TESTS, NULL, 0, Buffer, sizeof Buffer, &BytesRead, NULL))
+         error_goto(Error, cleanup);
+     // output test list plus user-mode tests
+     while (TestEntry->TestName || *TestName)
+     {
+         if (!TestEntry->TestName)
+         {
+             NextTestName = TestName;
+             TestName += strlen(TestName) + 1;
+         }
+         else if (!*TestName)
+         {
+             NextTestName = TestEntry->TestName;
+             ++TestEntry;
+         }
+         else
+         {
+             INT Result = CompareTestNames(TestEntry->TestName, TestName);
+             if (Result == 0)
+             {
+                 NextTestName = TestEntry->TestName;
+                 TestName += strlen(TestName) + 1;
+                 ++TestEntry;
+             }
+             else if (Result < 0)
+             {
+                 NextTestName = TestEntry->TestName;
+                 ++TestEntry;
+             }
+             else
+             {
+                 NextTestName = TestName;
+                 TestName += strlen(TestName) + 1;
+             }
+         }
+         if (IncludeHidden && NextTestName[0] == '-')
+             ++NextTestName;
+         if (NextTestName[0] != '-')
+             printf("    %s\n", NextTestName);
+     }
+ cleanup:
+     return Error;
+ }
+ /**
+  * @name FindTest
+  *
+  * Find a test in TestList by name.
+  *
+  * @param TestName
+  *        Name of the test to look for. Case sensitive
+  *
+  * @return pointer to test function, or NULL if not found
+  */
+ static
+ PKMT_TESTFUNC
+ FindTest(
+     IN PCSTR TestName)
+ {
+     PCKMT_TEST TestEntry = TestList;
+     for (TestEntry = TestList; TestEntry->TestName; ++TestEntry)
+     {
+         PCSTR TestEntryName = TestEntry->TestName;
+         // skip leading '-' if present
+         if (*TestEntryName == '-')
+             ++TestEntryName;
+         if (!lstrcmpA(TestEntryName, TestName))
+             break;
+     }
+     return TestEntry->TestFunction;
+ }
+ /**
+  * @name OutputResult
+  *
+  * Output the test results in ResultBuffer to the console.
+  *
+  * @param TestName
+  *        Name of the test whose result is to be printed
+  *
+  * @return Win32 error code
+  */
+ static
+ DWORD
+ OutputResult(
+     IN PCSTR TestName)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     DWORD BytesWritten;
+     DWORD LogBufferLength;
+     DWORD Offset = 0;
+     /* A console window can't handle a single
+      * huge block of data, so split it up */
+     const DWORD BlockSize = 8 * 1024;
+     KmtFinishTest(TestName);
+     LogBufferLength = ResultBuffer->LogBufferLength;
+     for (Offset = 0; Offset < LogBufferLength; Offset += BlockSize)
+     {
+         DWORD Length = min(LogBufferLength - Offset, BlockSize);
+         if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), ResultBuffer->LogBuffer + Offset, Length, &BytesWritten, NULL))
+             error(Error);
+     }
+     return Error;
+ }
+ /**
+  * @name RunTest
+  *
+  * Run the named test and output its results.
+  *
+  * @param TestName
+  *        Name of the test to run. Case sensitive
+  *
+  * @return Win32 error code
+  */
+ static
+ DWORD
+ RunTest(
+     IN PCSTR TestName)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     PKMT_TESTFUNC TestFunction;
+     DWORD BytesRead;
+     assert(TestName != NULL);
+     if (!ResultBuffer)
+     {
+         ResultBuffer = KmtAllocateResultBuffer(RESULTBUFFER_SIZE);
+         if (!ResultBuffer)
+             error_goto(Error, cleanup);
+         if (!DeviceIoControl(KmtestHandle, IOCTL_KMTEST_SET_RESULTBUFFER, ResultBuffer, RESULTBUFFER_SIZE, NULL, 0, &BytesRead, NULL))
+             error_goto(Error, cleanup);
+     }
+     // check test list
+     TestFunction = FindTest(TestName);
+     if (TestFunction)
+     {
+         TestFunction();
+         goto cleanup;
+     }
+     // not found in user-mode test list, call driver
+     Error = KmtRunKernelTest(TestName);
+ cleanup:
+     if (!Error)
+         Error = OutputResult(TestName);
+     return Error;
+ }
+ /**
+  * @name main
+  *
+  * Program entry point
+  *
+  * @param ArgCount
+  * @param Arguments
+  *
+  * @return EXIT_SUCCESS on success, EXIT_FAILURE on failure
+  */
+ int
+ main(
+     int ArgCount,
+     char **Arguments)
+ {
+     INT Status = EXIT_SUCCESS;
+     DWORD Error = ERROR_SUCCESS;
+     PCSTR AppName = "kmtest.exe";
+     PCSTR TestName = NULL;
+     KMT_OPERATION Operation = KMT_DO_NOTHING;
+     BOOLEAN ShowHidden = FALSE;
+     Error = KmtServiceInit();
+     if (Error)
+         goto cleanup;
+     if (ArgCount >= 1)
+         AppName = Arguments[0];
+     if (ArgCount <= 1)
+     {
+         printf("Usage: %s <test_name>                 - run the specified test (creates/starts the driver(s) as appropriate)\n", AppName);
+         printf("       %s --list                      - list available tests\n", AppName);
+         printf("       %s --list-all                  - list available tests, including hidden\n", AppName);
+         printf("       %s <create|delete|start|stop>  - manage the kmtest driver\n\n", AppName);
+         Operation = KMT_LIST_TESTS;
+     }
+     else
+     {
+         TestName = Arguments[1];
+         if (!lstrcmpA(TestName, "create"))
+             Error = KmtCreateService(SERVICE_NAME, SERVICE_PATH, SERVICE_DESCRIPTION, &KmtestServiceHandle);
+         else if (!lstrcmpA(TestName, "delete"))
+             Error = KmtDeleteService(SERVICE_NAME, &KmtestServiceHandle);
+         else if (!lstrcmpA(TestName, "start"))
+             Error = KmtStartService(SERVICE_NAME, &KmtestServiceHandle);
+         else if (!lstrcmpA(TestName, "stop"))
+             Error = KmtStopService(SERVICE_NAME, &KmtestServiceHandle);
+         else if (!lstrcmpA(TestName, "--list"))
+             Operation = KMT_LIST_TESTS;
+         else if (!lstrcmpA(TestName, "--list-all"))
+             Operation = KMT_LIST_ALL_TESTS;
+         else
+             Operation = KMT_RUN_TEST;
+     }
+     if (Operation)
+     {
+         Error = KmtCreateAndStartService(SERVICE_NAME, SERVICE_PATH, SERVICE_DESCRIPTION, &KmtestServiceHandle, FALSE);
+         if (Error)
+             goto cleanup;
+         KmtestHandle = CreateFile(KMTEST_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+         if (KmtestHandle == INVALID_HANDLE_VALUE)
+             error_goto(Error, cleanup);
+         switch (Operation)
+         {
+             case KMT_LIST_ALL_TESTS:
+                 ShowHidden = TRUE;
+                 /* fall through */
+             case KMT_LIST_TESTS:
+                 Error = ListTests(ShowHidden);
+                 break;
+             case KMT_RUN_TEST:
+                 Error = RunTest(TestName);
+                 break;
+             default:
+                 assert(FALSE);
+         }
+     }
+ cleanup:
+     if (KmtestHandle)
+         CloseHandle(KmtestHandle);
+     if (ResultBuffer)
+         KmtFreeResultBuffer(ResultBuffer);
+     KmtCloseService(&KmtestServiceHandle);
+     if (Error)
+         KmtServiceCleanup(TRUE);
+     else
+         Error = KmtServiceCleanup(FALSE);
+     if (Error)
+     {
+         OutputError(Error);
+         Status = EXIT_FAILURE;
+     }
+     return Status;
+ }
index 0000000,07b5944..07b5944
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,12 +1,12 @@@
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+ <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+   <assemblyIdentity version="1.0.0.0" processorArchitecture="x86" name="kmtest"/>
+   <description>ReactOS Kernel-Mode Test Suite Loader Application</description>
+   <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+     <security>
+       <requestedPrivileges>
+         <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
+       </requestedPrivileges>
+     </security>
+   </trustInfo>
+ </assembly>
index 0000000,d7e50ae..d7e50ae
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,64 +1,64 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Loader Application
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #ifndef _KMTESTS_H_
+ #define _KMTESTS_H_
+ extern PCSTR ErrorFileAndLine;
+ #ifndef KMT_STRINGIZE
+ #define KMT_STRINGIZE(x) #x
+ #endif /* !defined KMT_STRINGIZE */
+ #define location(file, line)                    do { ErrorFileAndLine = file ":" KMT_STRINGIZE(line); } while (0)
+ #define error_value(Error, value)               do { location(__FILE__, __LINE__); Error = value; } while (0)
+ #define error(Error)                            error_value(Error, GetLastError())
+ #define error_goto(Error, label)                do { error(Error); goto label; } while (0)
+ #define error_value_goto(Error, value, label)   do { error_value(Error, value); goto label; } while (0)
+ /* service management functions */
+ DWORD
+ KmtServiceInit(VOID);
+ DWORD
+ KmtServiceCleanup(
+     BOOLEAN IgnoreErrors);
+ DWORD
+ KmtCreateService(
+     IN PCWSTR ServiceName,
+     IN PCWSTR ServicePath,
+     IN PCWSTR DisplayName OPTIONAL,
+     OUT SC_HANDLE *ServiceHandle);
+ DWORD
+ KmtStartService(
+     IN PCWSTR ServiceName OPTIONAL,
+     IN OUT SC_HANDLE *ServiceHandle);
+ DWORD
+ KmtCreateAndStartService(
+     IN PCWSTR ServiceName,
+     IN PCWSTR ServicePath,
+     IN PCWSTR DisplayName OPTIONAL,
+     OUT SC_HANDLE *ServiceHandle,
+     IN BOOLEAN RestartIfRunning);
+ DWORD
+ KmtStopService(
+     IN PCWSTR ServiceName OPTIONAL,
+     IN OUT SC_HANDLE *ServiceHandle);
+ DWORD
+ KmtDeleteService(
+     IN PCWSTR ServiceName OPTIONAL,
+     IN OUT SC_HANDLE *ServiceHandle);
+ DWORD KmtCloseService(
+     IN OUT SC_HANDLE *ServiceHandle);
+ #endif /* !defined _KMTESTS_H_ */
index 0000000,890e56e..890e56e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,15 +1,15 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Loader Resource File
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <windows.h>
+ #define REACTOS_STR_FILE_DESCRIPTION    "ReactOS Kernel-Mode Test Suite Loader Application\0"
+ #define REACTOS_STR_INTERNAL_NAME       "kmtest.exe\0"
+ #define REACTOS_STR_ORIGINAL_FILENAME   "kmtest.exe\0"
+ #include <reactos/version.rc>
+ CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST DISCARDABLE PURE "kmtest/kmtest.exe.manifest"
index 0000000,9f32614..9f32614
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,309 +1,309 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Loader service control functions
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ #include "kmtest.h"
+ #include <assert.h>
+ #define SERVICE_ACCESS (SERVICE_START | SERVICE_STOP | DELETE)
+ static SC_HANDLE ScmHandle;
+ /**
+  * @name KmtServiceInit
+  *
+  * Initialize service management routines (by opening the service control manager)
+  *
+  * @return Win32 error code
+  */
+ DWORD
+ KmtServiceInit(VOID)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     assert(!ScmHandle);
+     ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
+     if (!ScmHandle)
+         error(Error);
+     return Error;
+ }
+ /**
+  * @name KmtServiceCleanup
+  *
+  * Clean up resources used by service management routines.
+  *
+  * @param IgnoreErrors
+  *        If TRUE, the function will never set ErrorLineAndFile, and always return ERROR_SUCCESS
+  *
+  * @return Win32 error code
+  */
+ DWORD
+ KmtServiceCleanup(
+     BOOLEAN IgnoreErrors)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     if (ScmHandle && !CloseServiceHandle(ScmHandle) && !IgnoreErrors)
+         error(Error);
+     return Error;
+ }
+ /**
+  * @name KmtCreateService
+  *
+  * Create the specified driver service and return a handle to it
+  *
+  * @param ServiceName
+  *        Name of the service to create
+  * @param ServicePath
+  *        File name of the driver, relative to the current directory
+  * @param DisplayName
+  *        Service display name
+  * @param ServiceHandle
+  *        Pointer to a variable to receive the handle to the service
+  *
+  * @return Win32 error code
+  */
+ DWORD
+ KmtCreateService(
+     IN PCWSTR ServiceName,
+     IN PCWSTR ServicePath,
+     IN PCWSTR DisplayName OPTIONAL,
+     OUT SC_HANDLE *ServiceHandle)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     WCHAR DriverPath[MAX_PATH];
+     HRESULT result = S_OK;
+     assert(ServiceHandle);
+     assert(ServiceName && ServicePath);
+     if (!GetCurrentDirectory(sizeof DriverPath / sizeof DriverPath[0], DriverPath))
+         error_goto(Error, cleanup);
+     if (DriverPath[wcslen(DriverPath) - 1] != L'\\')
+     {
+         DriverPath[wcslen(DriverPath) + 1] = L'\0';
+         DriverPath[wcslen(DriverPath)] = L'\\';
+     }
+     result = StringCbCat(DriverPath, sizeof DriverPath, ServicePath);
+     if (FAILED(result))
+         error_value_goto(Error, result, cleanup);
+     *ServiceHandle = CreateService(ScmHandle, ServiceName, DisplayName,
+                             SERVICE_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START,
+                             SERVICE_ERROR_NORMAL, DriverPath, NULL, NULL, NULL, NULL, NULL);
+     if (!*ServiceHandle)
+         error_goto(Error, cleanup);
+ cleanup:
+     return Error;
+ }
+ /**
+  * @name KmtStartService
+  *
+  * Start the specified driver service by handle or name (and return a handle to it)
+  *
+  * @param ServiceName
+  *        If *ServiceHandle is NULL, name of the service to start
+  * @param ServiceHandle
+  *        Pointer to a variable containing the service handle,
+  *        or NULL (in which case it will be filled with a handle to the service)
+  *
+  * @return Win32 error code
+  */
+ DWORD
+ KmtStartService(
+     IN PCWSTR ServiceName OPTIONAL,
+     IN OUT SC_HANDLE *ServiceHandle)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     assert(ServiceHandle);
+     assert(ServiceName || *ServiceHandle);
+     if (!*ServiceHandle)
+         *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
+     if (!*ServiceHandle)
+         error_goto(Error, cleanup);
+     if (!StartService(*ServiceHandle, 0, NULL))
+         error_goto(Error, cleanup);
+ cleanup:
+     return Error;
+ }
+ /**
+  * @name KmtCreateAndStartService
+  *
+  * Create and start the specified driver service and return a handle to it
+  *
+  * @param ServiceName
+  *        Name of the service to create
+  * @param ServicePath
+  *        File name of the driver, relative to the current directory
+  * @param DisplayName
+  *        Service display name
+  * @param ServiceHandle
+  *        Pointer to a variable to receive the handle to the service
+  * @param RestartIfRunning
+  *        TRUE to stop and restart the service if it is already running
+  *
+  * @return Win32 error code
+  */
+ DWORD
+ KmtCreateAndStartService(
+     IN PCWSTR ServiceName,
+     IN PCWSTR ServicePath,
+     IN PCWSTR DisplayName OPTIONAL,
+     OUT SC_HANDLE *ServiceHandle,
+     IN BOOLEAN RestartIfRunning)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     assert(ServiceHandle);
+     Error = KmtCreateService(ServiceName, ServicePath, DisplayName, ServiceHandle);
+     if (Error && Error != ERROR_SERVICE_EXISTS)
+         goto cleanup;
+     Error = KmtStartService(ServiceName, ServiceHandle);
+     if (Error != ERROR_SERVICE_ALREADY_RUNNING)
+         goto cleanup;
+     Error = ERROR_SUCCESS;
+     if (!RestartIfRunning)
+         goto cleanup;
+     Error = KmtStopService(ServiceName, ServiceHandle);
+     if (Error)
+         goto cleanup;
+     Error = KmtStartService(ServiceName, ServiceHandle);
+     if (Error)
+         goto cleanup;
+ cleanup:
+     assert(Error || *ServiceHandle);
+     return Error;
+ }
+ /**
+  * @name KmtStopService
+  *
+  * Stop the specified driver service by handle or name (and return a handle to it)
+  *
+  * @param ServiceName
+  *        If *ServiceHandle is NULL, name of the service to stop
+  * @param ServiceHandle
+  *        Pointer to a variable containing the service handle,
+  *        or NULL (in which case it will be filled with a handle to the service)
+  *
+  * @return Win32 error code
+  */
+ DWORD
+ KmtStopService(
+     IN PCWSTR ServiceName OPTIONAL,
+     IN OUT SC_HANDLE *ServiceHandle)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     SERVICE_STATUS ServiceStatus;
+     assert(ServiceHandle);
+     assert(ServiceName || *ServiceHandle);
+     if (!*ServiceHandle)
+         *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
+     if (!*ServiceHandle)
+         error_goto(Error, cleanup);
+     if (!ControlService(*ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus))
+         error_goto(Error, cleanup);
+ cleanup:
+     return Error;
+ }
+ /**
+  * @name KmtDeleteService
+  *
+  * Delete the specified driver service by handle or name (and return a handle to it)
+  *
+  * @param ServiceName
+  *        If *ServiceHandle is NULL, name of the service to delete
+  * @param ServiceHandle
+  *        Pointer to a variable containing the service handle.
+  *        Will be set to NULL on success
+  *
+  * @return Win32 error code
+  */
+ DWORD
+ KmtDeleteService(
+     IN PCWSTR ServiceName OPTIONAL,
+     IN OUT SC_HANDLE *ServiceHandle)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     assert(ServiceHandle);
+     assert(ServiceName || *ServiceHandle);
+     if (!*ServiceHandle)
+         *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
+     if (!*ServiceHandle)
+         error_goto(Error, cleanup);
+     if (!DeleteService(*ServiceHandle))
+         error_goto(Error, cleanup);
+     if (*ServiceHandle)
+         CloseServiceHandle(*ServiceHandle);
+ cleanup:
+     return Error;
+ }
+ /**
+  * @name KmtCloseService
+  *
+  * Close the specified driver service handle
+  *
+  * @param ServiceHandle
+  *        Pointer to a variable containing the service handle.
+  *        Will be set to NULL on success
+  *
+  * @return Win32 error code
+  */
+ DWORD KmtCloseService(
+     IN OUT SC_HANDLE *ServiceHandle)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     assert(ServiceHandle);
+     if (*ServiceHandle && !CloseServiceHandle(*ServiceHandle))
+         error_goto(Error, cleanup);
+     *ServiceHandle = NULL;
+ cleanup:
+     return Error;
+ }
index 0000000,03c10af..03c10af
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,215 +1,215 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Driver
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ #include "kmtest.h"
+ #include <kmt_public.h>
+ #include <assert.h>
+ extern HANDLE KmtestHandle;
+ /**
+  * @name KmtRunKernelTest
+  *
+  * Run the specified kernel-mode test part
+  *
+  * @param TestName
+  *        Name of the test to run
+  *
+  * @return Win32 error code as returned by DeviceIoControl
+  */
+ DWORD
+ KmtRunKernelTest(
+     IN PCSTR TestName)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     DWORD BytesRead;
+     if (!DeviceIoControl(KmtestHandle, IOCTL_KMTEST_RUN_TEST, (PVOID)TestName, strlen(TestName), NULL, 0, &BytesRead, NULL))
+         error(Error);
+     return Error;
+ }
+ static WCHAR TestServiceName[MAX_PATH];
+ static SC_HANDLE TestServiceHandle;
+ static HANDLE TestDeviceHandle;
+ /**
+  * @name KmtLoadDriver
+  *
+  * Load the specified special-purpose driver (create/start the service)
+  *
+  * @param ServiceName
+  *        Name of the driver service (Kmtest- prefix will be added automatically)
+  * @param RestartIfRunning
+  *        TRUE to stop and restart the service if it is already running
+  */
+ VOID
+ KmtLoadDriver(
+     IN PCWSTR ServiceName,
+     IN BOOLEAN RestartIfRunning)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     WCHAR ServicePath[MAX_PATH];
+     StringCbCopy(ServicePath, sizeof ServicePath, ServiceName);
+     StringCbCat(ServicePath, sizeof ServicePath, L"_drv.sys");
+     StringCbCopy(TestServiceName, sizeof TestServiceName, L"Kmtest-");
+     StringCbCat(TestServiceName, sizeof TestServiceName, ServiceName);
+     Error = KmtCreateAndStartService(TestServiceName, ServicePath, NULL, &TestServiceHandle, RestartIfRunning);
+     if (Error)
+     {
+         // TODO
+         __debugbreak();
+     }
+ }
+ /**
+  * @name KmtUnloadDriver
+  *
+  * Unload special-purpose driver (stop the service)
+  */
+ VOID
+ KmtUnloadDriver(VOID)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     Error = KmtStopService(TestServiceName, &TestServiceHandle);
+     if (Error)
+     {
+         // TODO
+         __debugbreak();
+     }
+ }
+ /**
+  * @name KmtOpenDriver
+  *
+  * Open special-purpose driver (acquire a device handle)
+  */
+ VOID
+ KmtOpenDriver(VOID)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     WCHAR DevicePath[MAX_PATH];
+     StringCbCopy(DevicePath, sizeof DevicePath, L"\\\\.\\Global\\GLOBALROOT\\Device\\");
+     StringCbCat(DevicePath, sizeof DevicePath, TestServiceName);
+     TestDeviceHandle = CreateFile(DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+     if (TestDeviceHandle == INVALID_HANDLE_VALUE)
+         error(Error);
+     if (Error)
+     {
+         // TODO
+         __debugbreak();
+     }
+ }
+ /**
+  * @name KmtCloseDriver
+  *
+  * Close special-purpose driver (close device handle)
+  */
+ VOID
+ KmtCloseDriver(VOID)
+ {
+     DWORD Error = ERROR_SUCCESS;
+     if (TestDeviceHandle && !CloseHandle(TestDeviceHandle))
+         error(Error);
+     if (Error)
+     {
+         // TODO
+         __debugbreak();
+     }
+ }
+ /**
+  * @name KmtSendToDriver
+  *
+  * Unload special-purpose driver (stop the service)
+  *
+  * @param ControlCode
+  *
+  * @return Win32 error code as returned by DeviceIoControl
+  */
+ DWORD
+ KmtSendToDriver(
+     IN DWORD ControlCode)
+ {
+     DWORD BytesRead;
+     assert(ControlCode < 0x400);
+     if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), NULL, 0, NULL, 0, &BytesRead, NULL))
+         return GetLastError();
+     return ERROR_SUCCESS;
+ }
+ /**
+  * @name KmtSendStringToDriver
+  *
+  * Unload special-purpose driver (stop the service)
+  *
+  * @param ControlCode
+  * @param String
+  *
+  * @return Win32 error code as returned by DeviceIoControl
+  */
+ DWORD
+ KmtSendStringToDriver(
+     IN DWORD ControlCode,
+     IN PCSTR String)
+ {
+     DWORD BytesRead;
+     assert(ControlCode < 0x400);
+     if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), (PVOID)String, strlen(String), NULL, 0, &BytesRead, NULL))
+         return GetLastError();
+     return ERROR_SUCCESS;
+ }
+ /**
+  * @name KmtSendBufferToDriver
+  *
+  * @param ControlCode
+  * @param Buffer
+  * @param InLength
+  * @param OutLength
+  *
+  * @return Win32 error code as returned by DeviceIoControl
+  */
+ DWORD
+ KmtSendBufferToDriver(
+     IN DWORD ControlCode,
+     IN OUT PVOID Buffer OPTIONAL,
+     IN DWORD InLength,
+     IN OUT PDWORD OutLength)
+ {
+     assert(OutLength);
+     assert(Buffer || (!InLength && !*OutLength));
+     assert(ControlCode < 0x400);
+     if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), Buffer, InLength, Buffer, *OutLength, OutLength, NULL))
+         return GetLastError();
+     return ERROR_SUCCESS;
+ }
index 0000000,ad017c0..ad017c0
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,25 +1,25 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite user-mode test list
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ KMT_TESTFUNC Test_Example;
+ KMT_TESTFUNC Test_IoDeviceObject;
+ KMT_TESTFUNC Test_RtlAvlTree;
+ KMT_TESTFUNC Test_RtlMemory;
+ KMT_TESTFUNC Test_RtlSplayTree;
+ /* tests with a leading '-' will not be listed */
+ const KMT_TEST TestList[] =
+ {
+     { "Example",            Test_Example },
+     { "IoDeviceObject",     Test_IoDeviceObject },
+     { "RtlAvlTree",         Test_RtlAvlTree },
+     { "RtlMemory",          Test_RtlMemory },
+     { "RtlSplayTree",       Test_RtlSplayTree },
+     { NULL,                 NULL },
+ };
index 0000000,3adc67b..3adc67b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,79 +1,79 @@@
+ <module name="kmtest_drv" type="kernelmodedriver" installbase="bin" installname="kmtest_drv.sys">
+       <include base="kmtest_drv">include</include>
+       <library>ntoskrnl</library>
+       <library>hal</library>
+       <library>pseh</library>
+       <library>kmtest_printf</library>
+       <define name="KMT_KERNEL_MODE" />
+       <define name="NTDDI_VERSION">NTDDI_WS03SP1</define>
+       <directory name="kmtest_drv">
+               <file>kmtest_drv.c</file>
+               <file>testlist.c</file>
+       </directory>
+       <directory name="example">
+               <file>Example.c</file>
+               <file>KernelType.c</file>
+       </directory>
+       <directory name="ntos_ex">
+               <file>ExDoubleList.c</file>
+               <file>ExFastMutex.c</file>
+               <file>ExHardError.c</file>
+               <file>ExInterlocked.c</file>
+               <file>ExPools.c</file>
+               <file>ExResource.c</file>
+               <file>ExSequencedList.c</file>
+               <file>ExSingleList.c</file>
+               <file>ExTimer.c</file>
+       </directory>
+       <directory name="ntos_fsrtl">
+               <file>FsRtlExpression.c</file>
+       </directory>
+       <directory name="ntos_io">
+               <file>IoDeviceInterface.c</file>
+               <file>IoInterrupt.c</file>
+               <file>IoIrp.c</file>
+               <file>IoMdl.c</file>
+       </directory>
+       <directory name="ntos_ke">
+               <file>KeApc.c</file>
+               <file>KeDpc.c</file>
+               <file>KeEvent.c</file>
+               <file>KeGuardedMutex.c</file>
+               <file>KeIrql.c</file>
+               <file>KeProcessor.c</file>
+               <file>KeSpinLock.c</file>
+       </directory>
+       <directory name="ntos_ob">
+               <file>ObReference.c</file>
+               <file>ObType.c</file>
+       </directory>
+       <directory name="rtl">
+               <file>RtlAvlTree.c</file>
+               <file>RtlMemory.c</file>
+               <file>RtlSplayTree.c</file>
+       </directory>
+ </module>
+ <module name="kmtest_printf" type="staticlibrary">
+       <include base="crt">include</include>
+       <define name="_LIBCNT_" />
+       <define name="_USER32_WSPRINTF" />
+       <define name="wctomb">KmtWcToMb</define>
+       <directory name="kmtest_drv">
+               <file>printf_stubs.c</file>
+       </directory>
+       <directory name="..">
+               <directory name="..">
+                       <directory name="..">
+                               <directory name="lib">
+                                       <directory name="sdk">
+                                               <directory name="crt">
+                                                       <directory name="printf">
+                                                               <file>streamout.c</file>
+                                                       </directory>
+                                               </directory>
+                                       </directory>
+                               </directory>
+                       </directory>
+               </directory>
+       </directory>
+ </module>
index 0000000,05b5709..05b5709
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,377 +1,377 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Driver
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <ntddk.h>
+ #include <ntifs.h>
+ #include <ndk/ketypes.h>
+ #include <ntstrsafe.h>
+ #include <limits.h>
+ #include <pseh/pseh2.h>
+ //#define NDEBUG
+ #include <debug.h>
+ #include <kmt_public.h>
+ #define KMT_DEFINE_TEST_FUNCTIONS
+ #include <kmt_test.h>
+ /* Prototypes */
+ DRIVER_INITIALIZE DriverEntry;
+ static DRIVER_UNLOAD DriverUnload;
+ static DRIVER_DISPATCH DriverCreate;
+ static DRIVER_DISPATCH DriverClose;
+ static DRIVER_DISPATCH DriverIoControl;
+ /* Globals */
+ static PDEVICE_OBJECT MainDeviceObject;
+ /* Entry */
+ /**
+  * @name DriverEntry
+  *
+  * Driver Entry point.
+  *
+  * @param DriverObject
+  *        Driver Object
+  * @param RegistryPath
+  *        Driver Registry Path
+  *
+  * @return Status
+  */
+ NTSTATUS
+ NTAPI
+ DriverEntry(
+     IN PDRIVER_OBJECT DriverObject,
+     IN PUNICODE_STRING RegistryPath)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     UNICODE_STRING DeviceName;
+     PKMT_DEVICE_EXTENSION DeviceExtension;
+     PKPRCB Prcb;
+     PAGED_CODE();
+     UNREFERENCED_PARAMETER(RegistryPath);
+     DPRINT("DriverEntry\n");
+     Prcb = KeGetCurrentPrcb();
+     KmtIsCheckedBuild = (Prcb->BuildType & PRCB_BUILD_DEBUG) != 0;
+     KmtIsMultiProcessorBuild = (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) == 0;
+     RtlInitUnicodeString(&DeviceName, KMTEST_DEVICE_DRIVER_PATH);
+     Status = IoCreateDevice(DriverObject, sizeof(KMT_DEVICE_EXTENSION),
+                             &DeviceName,
+                             FILE_DEVICE_UNKNOWN,
+                             FILE_DEVICE_SECURE_OPEN | FILE_READ_ONLY_DEVICE,
+                             FALSE, &MainDeviceObject);
+     if (!NT_SUCCESS(Status))
+         goto cleanup;
+     DPRINT("DriverEntry. Created DeviceObject %p. DeviceExtension %p\n",
+              MainDeviceObject, MainDeviceObject->DeviceExtension);
+     DeviceExtension = MainDeviceObject->DeviceExtension;
+     DeviceExtension->ResultBuffer = NULL;
+     DeviceExtension->Mdl = NULL;
+     DriverObject->DriverUnload = DriverUnload;
+     DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreate;
+     DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverClose;
+     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverIoControl;
+ cleanup:
+     if (MainDeviceObject && !NT_SUCCESS(Status))
+     {
+         IoDeleteDevice(MainDeviceObject);
+         MainDeviceObject = NULL;
+     }
+     return Status;
+ }
+ /* Dispatch functions */
+ /**
+  * @name DriverUnload
+  *
+  * Driver cleanup funtion.
+  *
+  * @param DriverObject
+  *        Driver Object
+  */
+ static
+ VOID
+ NTAPI
+ DriverUnload(
+     IN PDRIVER_OBJECT DriverObject)
+ {
+     PAGED_CODE();
+     UNREFERENCED_PARAMETER(DriverObject);
+     DPRINT("DriverUnload\n");
+     if (MainDeviceObject)
+     {
+         PKMT_DEVICE_EXTENSION DeviceExtension = MainDeviceObject->DeviceExtension;
+         ASSERT(!DeviceExtension->Mdl);
+         ASSERT(!DeviceExtension->ResultBuffer);
+         ASSERT(!ResultBuffer);
+         IoDeleteDevice(MainDeviceObject);
+     }
+ }
+ /**
+  * @name DriverCreate
+  *
+  * Driver Dispatch function for CreateFile
+  *
+  * @param DeviceObject
+  *        Device Object
+  * @param Irp
+  *        I/O request packet
+  *
+  * @return Status
+  */
+ static
+ NTSTATUS
+ NTAPI
+ DriverCreate(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     PIO_STACK_LOCATION IoStackLocation;
+     PAGED_CODE();
+     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+     DPRINT("DriverCreate. DeviceObject=%p, RequestorMode=%d, FileObject=%p, FsContext=%p, FsContext2=%p\n",
+              DeviceObject, Irp->RequestorMode, IoStackLocation->FileObject,
+              IoStackLocation->FileObject->FsContext, IoStackLocation->FileObject->FsContext2);
+     Irp->IoStatus.Status = Status;
+     Irp->IoStatus.Information = 0;
+     IoCompleteRequest(Irp, IO_NO_INCREMENT);
+     return Status;
+ }
+ /**
+  * @name DriverClose
+  *
+  * Driver Dispatch function for CloseHandle.
+  *
+  * @param DeviceObject
+  *        Device Object
+  * @param Irp
+  *        I/O request packet
+  *
+  * @return Status
+  */
+ static
+ NTSTATUS
+ NTAPI
+ DriverClose(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     PIO_STACK_LOCATION IoStackLocation;
+     PKMT_DEVICE_EXTENSION DeviceExtension;
+     PAGED_CODE();
+     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+     DPRINT("DriverClose. DeviceObject=%p, RequestorMode=%d, FileObject=%p, FsContext=%p, FsContext2=%p\n",
+              DeviceObject, Irp->RequestorMode, IoStackLocation->FileObject,
+              IoStackLocation->FileObject->FsContext, IoStackLocation->FileObject->FsContext2);
+     ASSERT(IoStackLocation->FileObject->FsContext2 == NULL);
+     DeviceExtension = DeviceObject->DeviceExtension;
+     if (DeviceExtension->Mdl && IoStackLocation->FileObject->FsContext == DeviceExtension->Mdl)
+     {
+         MmUnlockPages(DeviceExtension->Mdl);
+         IoFreeMdl(DeviceExtension->Mdl);
+         DeviceExtension->Mdl = NULL;
+         ResultBuffer = DeviceExtension->ResultBuffer = NULL;
+     }
+     else
+     {
+         ASSERT(IoStackLocation->FileObject->FsContext == NULL);
+     }
+     Irp->IoStatus.Status = Status;
+     Irp->IoStatus.Information = 0;
+     IoCompleteRequest(Irp, IO_NO_INCREMENT);
+     return Status;
+ }
+ /**
+  * @name DriverIoControl
+  *
+  * Driver Dispatch function for DeviceIoControl.
+  *
+  * @param DeviceObject
+  *        Device Object
+  * @param Irp
+  *        I/O request packet
+  *
+  * @return Status
+  */
+ static
+ NTSTATUS
+ NTAPI
+ DriverIoControl(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     PIO_STACK_LOCATION IoStackLocation;
+     ULONG Length = 0;
+     PAGED_CODE();
+     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+     DPRINT("DriverIoControl. Code=0x%08X, DeviceObject=%p, FileObject=%p, FsContext=%p, FsContext2=%p\n",
+              IoStackLocation->Parameters.DeviceIoControl.IoControlCode,
+              DeviceObject, IoStackLocation->FileObject,
+              IoStackLocation->FileObject->FsContext, IoStackLocation->FileObject->FsContext2);
+     switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode)
+     {
+         case IOCTL_KMTEST_GET_TESTS:
+         {
+             PCKMT_TEST TestEntry;
+             LPSTR OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
+             size_t Remaining = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
+             DPRINT("DriverIoControl. IOCTL_KMTEST_GET_TESTS, outlen=%lu\n",
+                      IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength);
+             for (TestEntry = TestList; TestEntry->TestName; ++TestEntry)
+             {
+                 RtlStringCbCopyExA(OutputBuffer, Remaining, TestEntry->TestName, &OutputBuffer, &Remaining, 0);
+                 if (Remaining)
+                 {
+                     *OutputBuffer++ = '\0';
+                     --Remaining;
+                 }
+             }
+             if (Remaining)
+             {
+                 *OutputBuffer++ = '\0';
+                 --Remaining;
+             }
+             Length = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength - Remaining;
+             break;
+         }
+         case IOCTL_KMTEST_RUN_TEST:
+         {
+             ANSI_STRING TestName;
+             PCKMT_TEST TestEntry;
+             DPRINT("DriverIoControl. IOCTL_KMTEST_RUN_TEST, inlen=%lu, outlen=%lu\n",
+                      IoStackLocation->Parameters.DeviceIoControl.InputBufferLength,
+                      IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength);
+             TestName.Length = TestName.MaximumLength = (USHORT)min(IoStackLocation->Parameters.DeviceIoControl.InputBufferLength, USHRT_MAX);
+             TestName.Buffer = Irp->AssociatedIrp.SystemBuffer;
+             DPRINT("DriverIoControl. Run test: %Z\n", &TestName);
+             for (TestEntry = TestList; TestEntry->TestName; ++TestEntry)
+             {
+                 ANSI_STRING EntryName;
+                 if (TestEntry->TestName[0] == '-')
+                     RtlInitAnsiString(&EntryName, TestEntry->TestName + 1);
+                 else
+                     RtlInitAnsiString(&EntryName, TestEntry->TestName);
+                 if (!RtlCompareString(&TestName, &EntryName, FALSE))
+                 {
+                     DPRINT1("DriverIoControl. Starting test %Z\n", &EntryName);
+                     TestEntry->TestFunction();
+                     DPRINT1("DriverIoControl. Finished test %Z\n", &EntryName);
+                     break;
+                 }
+             }
+             if (!TestEntry->TestName)
+                 Status = STATUS_OBJECT_NAME_INVALID;
+             break;
+         }
+         case IOCTL_KMTEST_SET_RESULTBUFFER:
+         {
+             PKMT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+             DPRINT("DriverIoControl. IOCTL_KMTEST_SET_RESULTBUFFER, buffer=%p, inlen=%lu, outlen=%lu\n",
+                     IoStackLocation->Parameters.DeviceIoControl.Type3InputBuffer,
+                     IoStackLocation->Parameters.DeviceIoControl.InputBufferLength,
+                     IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength);
+             if (DeviceExtension->Mdl)
+             {
+                 if (IoStackLocation->FileObject->FsContext != DeviceExtension->Mdl)
+                 {
+                     Status = STATUS_ACCESS_DENIED;
+                     break;
+                 }
+                 MmUnlockPages(DeviceExtension->Mdl);
+                 IoFreeMdl(DeviceExtension->Mdl);
+                 IoStackLocation->FileObject->FsContext = NULL;
+                 ResultBuffer = DeviceExtension->ResultBuffer = NULL;
+             }
+             DeviceExtension->Mdl = IoAllocateMdl(IoStackLocation->Parameters.DeviceIoControl.Type3InputBuffer,
+                                                     IoStackLocation->Parameters.DeviceIoControl.InputBufferLength,
+                                                     FALSE, FALSE, NULL);
+             if (!DeviceExtension->Mdl)
+             {
+                 Status = STATUS_INSUFFICIENT_RESOURCES;
+                 break;
+             }
+             _SEH2_TRY
+             {
+                 MmProbeAndLockPages(DeviceExtension->Mdl, UserMode, IoModifyAccess);
+             }
+             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+             {
+                 Status = _SEH2_GetExceptionCode();
+                 IoFreeMdl(DeviceExtension->Mdl);
+                 DeviceExtension->Mdl = NULL;
+                 break;
+             } _SEH2_END;
+             ResultBuffer = DeviceExtension->ResultBuffer = MmGetSystemAddressForMdlSafe(DeviceExtension->Mdl, NormalPagePriority);
+             IoStackLocation->FileObject->FsContext = DeviceExtension->Mdl;
+             DPRINT("DriverIoControl. ResultBuffer: %ld %ld %ld %ld\n",
+                     ResultBuffer->Successes, ResultBuffer->Failures,
+                     ResultBuffer->LogBufferLength, ResultBuffer->LogBufferMaxLength);
+             break;
+         }
+         default:
+             DPRINT1("DriverIoControl. Invalid IoCtl code 0x%08X\n",
+                      IoStackLocation->Parameters.DeviceIoControl.IoControlCode);
+             Status = STATUS_INVALID_DEVICE_REQUEST;
+             break;
+     }
+     Irp->IoStatus.Status = Status;
+     Irp->IoStatus.Information = Length;
+     IoCompleteRequest(Irp, IO_NO_INCREMENT);
+     return Status;
+ }
index 0000000,50a28eb..50a28eb
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,15 +1,15 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Driver Resource File
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <windows.h>
+ #define REACTOS_FILETYPE                VFT_DRV
+ #define REACTOS_FILESUBTYPE             VFT2_DRV_SYSTEM
+ #define REACTOS_STR_FILE_DESCRIPTION    "ReactOS Kernel-Mode Test Suite Driver\0"
+ #define REACTOS_STR_INTERNAL_NAME       "kmtest.sys\0"
+ #define REACTOS_STR_ORIGINAL_FILENAME   "kmtest.sys\0"
+ #include <reactos/version.rc>
index 0000000,a8bb707..a8bb707
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,488 +1,488 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Example Test Driver
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <ntddk.h>
+ #include <ntifs.h>
+ #include <ndk/ketypes.h>
+ #define KMT_DEFINE_TEST_FUNCTIONS
+ #include <kmt_test.h>
+ //#define NDEBUG
+ #include <debug.h>
+ #include <kmt_public.h>
+ /* types */
+ typedef struct
+ {
+     UCHAR MajorFunction;
+     PDEVICE_OBJECT DeviceObject;
+     PKMT_IRP_HANDLER IrpHandler;
+ } KMT_IRP_HANDLER_ENTRY, *PKMT_IRP_HANDLER_ENTRY;
+ typedef struct
+ {
+     ULONG ControlCode;
+     PDEVICE_OBJECT DeviceObject;
+     PKMT_MESSAGE_HANDLER MessageHandler;
+ } KMT_MESSAGE_HANDLER_ENTRY, *PKMT_MESSAGE_HANDLER_ENTRY;
+ /* Prototypes */
+ DRIVER_INITIALIZE DriverEntry;
+ static DRIVER_UNLOAD DriverUnload;
+ static DRIVER_DISPATCH DriverDispatch;
+ static KMT_IRP_HANDLER DeviceControlHandler;
+ /* Globals */
+ static PDEVICE_OBJECT TestDeviceObject;
+ static PDEVICE_OBJECT KmtestDeviceObject;
+ #define KMT_MAX_IRP_HANDLERS 256
+ static KMT_IRP_HANDLER_ENTRY IrpHandlers[KMT_MAX_IRP_HANDLERS] = { { 0 } };
+ #define KMT_MAX_MESSAGE_HANDLERS 256
+ static KMT_MESSAGE_HANDLER_ENTRY MessageHandlers[KMT_MAX_MESSAGE_HANDLERS] = { { 0 } };
+ /**
+  * @name DriverEntry
+  *
+  * Driver entry point.
+  *
+  * @param DriverObject
+  *        Driver Object
+  * @param RegistryPath
+  *        Driver Registry Path
+  *
+  * @return Status
+  */
+ NTSTATUS
+ NTAPI
+ DriverEntry(
+     IN PDRIVER_OBJECT DriverObject,
+     IN PUNICODE_STRING RegistryPath)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     WCHAR DeviceNameBuffer[128] = L"\\Device\\Kmtest-";
+     UNICODE_STRING KmtestDeviceName;
+     PFILE_OBJECT KmtestFileObject;
+     PKMT_DEVICE_EXTENSION KmtestDeviceExtension;
+     UNICODE_STRING DeviceName;
+     PCWSTR DeviceNameSuffix;
+     INT Flags = 0;
+     int i;
+     PKPRCB Prcb;
+     PAGED_CODE();
+     DPRINT("DriverEntry\n");
+     Prcb = KeGetCurrentPrcb();
+     KmtIsCheckedBuild = (Prcb->BuildType & PRCB_BUILD_DEBUG) != 0;
+     KmtIsMultiProcessorBuild = (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) == 0;
+     /* get the Kmtest device, so that we get a ResultBuffer pointer */
+     RtlInitUnicodeString(&KmtestDeviceName, KMTEST_DEVICE_DRIVER_PATH);
+     Status = IoGetDeviceObjectPointer(&KmtestDeviceName, FILE_ALL_ACCESS, &KmtestFileObject, &KmtestDeviceObject);
+     if (!NT_SUCCESS(Status))
+     {
+         DPRINT1("Failed to get Kmtest device object pointer\n");
+         goto cleanup;
+     }
+     Status = ObReferenceObjectByPointer(KmtestDeviceObject, FILE_ALL_ACCESS, NULL, KernelMode);
+     if (!NT_SUCCESS(Status))
+     {
+         DPRINT1("Failed to reference Kmtest device object\n");
+         goto cleanup;
+     }
+     ObDereferenceObject(KmtestFileObject);
+     KmtestFileObject = NULL;
+     KmtestDeviceExtension = KmtestDeviceObject->DeviceExtension;
+     ResultBuffer = KmtestDeviceExtension->ResultBuffer;
+     DPRINT("KmtestDeviceObject: %p\n", (PVOID)KmtestDeviceObject);
+     DPRINT("KmtestDeviceExtension: %p\n", (PVOID)KmtestDeviceExtension);
+     DPRINT("Setting ResultBuffer: %p\n", (PVOID)ResultBuffer);
+     /* call TestEntry */
+     RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
+     DeviceName.MaximumLength = sizeof DeviceNameBuffer;
+     TestEntry(DriverObject, RegistryPath, &DeviceNameSuffix, &Flags);
+     /* create test device */
+     if (!(Flags & TESTENTRY_NO_CREATE_DEVICE))
+     {
+         RtlAppendUnicodeToString(&DeviceName, DeviceNameSuffix);
+         Status = IoCreateDevice(DriverObject, 0, &DeviceName,
+                                 FILE_DEVICE_UNKNOWN,
+                                 FILE_DEVICE_SECURE_OPEN | FILE_READ_ONLY_DEVICE,
+                                 TRUE, &TestDeviceObject);
+         if (!NT_SUCCESS(Status))
+         {
+             DPRINT1("Could not create device object %wZ\n", &DeviceName);
+             goto cleanup;
+         }
+         DPRINT("DriverEntry. Created DeviceObject %p\n",
+                  TestDeviceObject);
+     }
+     /* initialize dispatch functions */
+     if (!(Flags & TESTENTRY_NO_REGISTER_UNLOAD))
+         DriverObject->DriverUnload = DriverUnload;
+     if (!(Flags & TESTENTRY_NO_REGISTER_DISPATCH))
+         for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
+             DriverObject->MajorFunction[i] = DriverDispatch;
+ cleanup:
+     if (TestDeviceObject && !NT_SUCCESS(Status))
+     {
+         IoDeleteDevice(TestDeviceObject);
+         TestDeviceObject = NULL;
+     }
+     if (KmtestDeviceObject && !NT_SUCCESS(Status))
+     {
+         ObDereferenceObject(KmtestDeviceObject);
+         KmtestDeviceObject = NULL;
+         if (KmtestFileObject)
+             ObDereferenceObject(KmtestFileObject);
+     }
+     return Status;
+ }
+ /**
+  * @name DriverUnload
+  *
+  * Driver cleanup funtion.
+  *
+  * @param DriverObject
+  *        Driver Object
+  */
+ static
+ VOID
+ NTAPI
+ DriverUnload(
+     IN PDRIVER_OBJECT DriverObject)
+ {
+     PAGED_CODE();
+     UNREFERENCED_PARAMETER(DriverObject);
+     DPRINT("DriverUnload\n");
+     TestUnload(DriverObject);
+     if (TestDeviceObject)
+         IoDeleteDevice(TestDeviceObject);
+     if (KmtestDeviceObject)
+         ObDereferenceObject(KmtestDeviceObject);
+ }
+ /**
+  * @name KmtRegisterIrpHandler
+  *
+  * Register a handler with the IRP Dispatcher.
+  * If multiple registered handlers match an IRP, it is unspecified which of
+  * them is called on IRP reception
+  *
+  * @param MajorFunction
+  *        IRP major function code to be handled
+  * @param DeviceObject
+  *        Device Object to handle IRPs for.
+  *        Can be NULL to indicate any device object
+  * @param IrpHandler
+  *        Handler function to register.
+  *
+  * @return Status
+  */
+ NTSTATUS
+ KmtRegisterIrpHandler(
+     IN UCHAR MajorFunction,
+     IN PDEVICE_OBJECT DeviceObject OPTIONAL,
+     IN PKMT_IRP_HANDLER IrpHandler)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     int i;
+     if (MajorFunction > IRP_MJ_MAXIMUM_FUNCTION)
+     {
+         Status = STATUS_INVALID_PARAMETER_1;
+         goto cleanup;
+     }
+     if (IrpHandler == NULL)
+     {
+         Status = STATUS_INVALID_PARAMETER_3;
+         goto cleanup;
+     }
+     for (i = 0; i < sizeof IrpHandlers / sizeof IrpHandlers[0]; ++i)
+         if (IrpHandlers[i].IrpHandler == NULL)
+         {
+             IrpHandlers[i].MajorFunction = MajorFunction;
+             IrpHandlers[i].DeviceObject = DeviceObject;
+             IrpHandlers[i].IrpHandler = IrpHandler;
+             goto cleanup;
+         }
+     Status = STATUS_ALLOTTED_SPACE_EXCEEDED;
+ cleanup:
+     return Status;
+ }
+ /**
+  * @name KmtUnregisterIrpHandler
+  *
+  * Unregister a handler with the IRP Dispatcher.
+  * Parameters must be specified exactly as in the call to
+  * KmtRegisterIrpHandler. Only the first matching entry will be removed
+  * if multiple exist
+  *
+  * @param MajorFunction
+  *        IRP major function code of the handler to be removed
+  * @param DeviceObject
+  *        Device Object to of the handler to be removed
+  * @param IrpHandler
+  *        Handler function of the handler to be removed
+  *
+  * @return Status
+  */
+ NTSTATUS
+ KmtUnregisterIrpHandler(
+     IN UCHAR MajorFunction,
+     IN PDEVICE_OBJECT DeviceObject OPTIONAL,
+     IN PKMT_IRP_HANDLER IrpHandler)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     int i;
+     for (i = 0; i < sizeof IrpHandlers / sizeof IrpHandlers[0]; ++i)
+         if (IrpHandlers[i].MajorFunction == MajorFunction &&
+                 IrpHandlers[i].DeviceObject == DeviceObject &&
+                 IrpHandlers[i].IrpHandler == IrpHandler)
+         {
+             IrpHandlers[i].IrpHandler = NULL;
+             goto cleanup;
+         }
+     Status = STATUS_NOT_FOUND;
+ cleanup:
+     return Status;
+ }
+ /**
+  * @name DriverDispatch
+  *
+  * Driver Dispatch function
+  *
+  * @param DeviceObject
+  *        Device Object
+  * @param Irp
+  *        I/O request packet
+  *
+  * @return Status
+  */
+ static
+ NTSTATUS
+ NTAPI
+ DriverDispatch(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     PIO_STACK_LOCATION IoStackLocation;
+     int i;
+     PAGED_CODE();
+     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+     DPRINT("DriverDispatch: Function=%s, Device=%p\n",
+             KmtMajorFunctionNames[IoStackLocation->MajorFunction],
+             DeviceObject);
+     for (i = 0; i < sizeof IrpHandlers / sizeof IrpHandlers[0]; ++i)
+     {
+         if (IrpHandlers[i].MajorFunction == IoStackLocation->MajorFunction &&
+                 (IrpHandlers[i].DeviceObject == NULL || IrpHandlers[i].DeviceObject == DeviceObject) &&
+                 IrpHandlers[i].IrpHandler != NULL)
+             return IrpHandlers[i].IrpHandler(DeviceObject, Irp, IoStackLocation);
+     }
+     
+     /* default handler for DeviceControl */
+     if (IoStackLocation->MajorFunction == IRP_MJ_DEVICE_CONTROL ||
+             IoStackLocation->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
+         return DeviceControlHandler(DeviceObject, Irp, IoStackLocation);
+     /* default handler */
+     Irp->IoStatus.Status = Status;
+     Irp->IoStatus.Information = 0;
+     IoCompleteRequest(Irp, IO_NO_INCREMENT);
+     return Status;
+ }
+ /**
+  * @name KmtRegisterMessageHandler
+  *
+  * Register a handler with the DeviceControl Dispatcher.
+  * If multiple registered handlers match a message, it is unspecified which of
+  * them is called on message reception.
+  * NOTE: message handlers registered with this function will not be called
+  *       if a custom IRP handler matching the corresponding IRP is installed!
+  *
+  * @param ControlCode
+  *        Control code to be handled, as passed by the application.
+  *        Can be 0 to indicate any control code
+  * @param DeviceObject
+  *        Device Object to handle IRPs for.
+  *        Can be NULL to indicate any device object
+  * @param MessageHandler
+  *        Handler function to register.
+  *
+  * @return Status
+  */
+ NTSTATUS
+ KmtRegisterMessageHandler(
+     IN ULONG ControlCode OPTIONAL,
+     IN PDEVICE_OBJECT DeviceObject OPTIONAL,
+     IN PKMT_MESSAGE_HANDLER MessageHandler)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     int i;
+     if (ControlCode >= 0x400)
+     {
+         Status = STATUS_INVALID_PARAMETER_1;
+         goto cleanup;
+     }
+     if (MessageHandler == NULL)
+     {
+         Status = STATUS_INVALID_PARAMETER_2;
+         goto cleanup;
+     }
+     for (i = 0; i < sizeof MessageHandlers / sizeof MessageHandlers[0]; ++i)
+         if (MessageHandlers[i].MessageHandler == NULL)
+         {
+             MessageHandlers[i].ControlCode = ControlCode;
+             MessageHandlers[i].DeviceObject = DeviceObject;
+             MessageHandlers[i].MessageHandler = MessageHandler;
+             goto cleanup;
+         }
+     Status = STATUS_ALLOTTED_SPACE_EXCEEDED;
+ cleanup:
+     return Status;
+ }
+ /**
+  * @name KmtUnregisterMessageHandler
+  *
+  * Unregister a handler with the DeviceControl Dispatcher.
+  * Parameters must be specified exactly as in the call to
+  * KmtRegisterMessageHandler. Only the first matching entry will be removed
+  * if multiple exist
+  *
+  * @param ControlCode
+  *        Control code of the handler to be removed
+  * @param DeviceObject
+  *        Device Object to of the handler to be removed
+  * @param MessageHandler
+  *        Handler function of the handler to be removed
+  *
+  * @return Status
+  */
+ NTSTATUS
+ KmtUnregisterMessageHandler(
+     IN ULONG ControlCode OPTIONAL,
+     IN PDEVICE_OBJECT DeviceObject OPTIONAL,
+     IN PKMT_MESSAGE_HANDLER MessageHandler)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     int i;
+     for (i = 0; i < sizeof MessageHandlers / sizeof MessageHandlers[0]; ++i)
+         if (MessageHandlers[i].ControlCode == ControlCode &&
+                 MessageHandlers[i].DeviceObject == DeviceObject &&
+                 MessageHandlers[i].MessageHandler == MessageHandler)
+         {
+             MessageHandlers[i].MessageHandler = NULL;
+             goto cleanup;
+         }
+     Status = STATUS_NOT_FOUND;
+ cleanup:
+     return Status;
+ }
+ /**
+  * @name DeviceControlHandler
+  *
+  * Default IRP_MJ_DEVICE_CONTROL/IRP_MJ_INTERNAL_DEVICE_CONTROL handler
+  *
+  * @param DeviceObject
+  *        Device Object.
+  *        This is guaranteed not to have been touched by the dispatch function
+  *        before the call to the IRP handler
+  * @param Irp
+  *        Device Object.
+  *        This is guaranteed not to have been touched by the dispatch function
+  *        before the call to the IRP handler, except for passing it to
+  *        IoGetCurrentStackLocation
+  * @param IoStackLocation
+  *        Device Object.
+  *        This is guaranteed not to have been touched by the dispatch function
+  *        before the call to the IRP handler
+  *
+  * @return Status
+  */
+ static
+ NTSTATUS
+ DeviceControlHandler(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+     IN PIO_STACK_LOCATION IoStackLocation)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     ULONG ControlCode = (IoStackLocation->Parameters.DeviceIoControl.IoControlCode & 0x00000FFC) >> 2;
+     ULONG OutLength = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
+     int i;
+     for (i = 0; i < sizeof MessageHandlers / sizeof MessageHandlers[0]; ++i)
+     {
+         if ((MessageHandlers[i].ControlCode == 0 ||
+                 MessageHandlers[i].ControlCode == ControlCode) &&
+                 (MessageHandlers[i].DeviceObject == NULL || MessageHandlers[i].DeviceObject == DeviceObject) &&
+                 MessageHandlers[i].MessageHandler != NULL)
+         {
+             Status = MessageHandlers[i].MessageHandler(DeviceObject, ControlCode, Irp->AssociatedIrp.SystemBuffer,
+                                                         IoStackLocation->Parameters.DeviceIoControl.InputBufferLength,
+                                                         &OutLength);
+             break;
+         }
+     }
+     Irp->IoStatus.Status = Status;
+     Irp->IoStatus.Information = OutLength;
+     IoCompleteRequest(Irp, IO_NO_INCREMENT);
+     return Status;
+ }
index 0000000,09e4d2b..09e4d2b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,40 +1,40 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite stub functions for any-IRQL vsnprintf
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #undef wctomb
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <wchar.h>
+ int __cdecl KmtWcToMb(char *mbchar, wchar_t wchar)
+ {
+     *mbchar = (char)wchar;
+     return 1;
+ }
+ int __cdecl streamout(FILE *stream, const char *format, va_list argptr);
+ int __cdecl KmtVSNPrintF(char *buffer, size_t count, const char *format, va_list argptr)
+ {
+     int result;
+     FILE stream;
+     stream._base = (char *)buffer;
+     stream._ptr = stream._base;
+     stream._charbuf = 0;
+     stream._cnt = count;
+     stream._bufsiz = 0;
+     stream._flag = _IOSTRG | _IOWRT;
+     stream._tmpfname = 0;
+     result = streamout(&stream, format, argptr);
+     /* Only zero terminate if there is enough space left */
+     if (stream._cnt) *(char *)stream._ptr = '\0';
+     return result;
+ }
index 0000000,b17ad79..b17ad79
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,74 +1,74 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Driver test list
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ KMT_TESTFUNC Test_Example;
+ KMT_TESTFUNC Test_ExDoubleList;
+ KMT_TESTFUNC Test_ExFastMutex;
+ KMT_TESTFUNC Test_ExHardError;
+ KMT_TESTFUNC Test_ExHardErrorInteractive;
+ KMT_TESTFUNC Test_ExInterlocked;
+ KMT_TESTFUNC Test_ExPools;
+ KMT_TESTFUNC Test_ExResource;
+ KMT_TESTFUNC Test_ExSequencedList;
+ KMT_TESTFUNC Test_ExSingleList;
+ KMT_TESTFUNC Test_ExTimer;
+ KMT_TESTFUNC Test_FsRtlExpression;
+ KMT_TESTFUNC Test_IoDeviceInterface;
+ KMT_TESTFUNC Test_IoInterrupt;
+ KMT_TESTFUNC Test_IoIrp;
+ KMT_TESTFUNC Test_IoMdl;
+ KMT_TESTFUNC Test_KeApc;
+ KMT_TESTFUNC Test_KeDpc;
+ KMT_TESTFUNC Test_KeEvent;
+ KMT_TESTFUNC Test_KeGuardedMutex;
+ KMT_TESTFUNC Test_KeIrql;
+ KMT_TESTFUNC Test_KeProcessor;
+ KMT_TESTFUNC Test_KernelType;
+ KMT_TESTFUNC Test_ObReference;
+ KMT_TESTFUNC Test_ObType;
+ KMT_TESTFUNC Test_ObTypeClean;
+ KMT_TESTFUNC Test_ObTypeNoClean;
+ KMT_TESTFUNC Test_RtlAvlTree;
+ KMT_TESTFUNC Test_RtlMemory;
+ KMT_TESTFUNC Test_RtlSplayTree;
+ const KMT_TEST TestList[] =
+ {
+     { "ExDoubleList",                       Test_ExDoubleList },
+     { "ExFastMutex",                        Test_ExFastMutex },
+     { "ExHardError",                        Test_ExHardError },
+     { "-ExHardErrorInteractive",            Test_ExHardErrorInteractive },
+     { "ExInterlocked",                      Test_ExInterlocked },
+     { "ExPools",                            Test_ExPools },
+     { "ExResource",                         Test_ExResource },
+     { "ExSequencedList",                    Test_ExSequencedList },
+     { "ExSingleList",                       Test_ExSingleList },
+     { "-ExTimer",                           Test_ExTimer },
+     { "Example",                            Test_Example },
+     { "FsRtlExpression",                    Test_FsRtlExpression },
+     { "IoDeviceInterface",                  Test_IoDeviceInterface },
+     { "IoInterrupt",                        Test_IoInterrupt },
+     { "IoIrp",                              Test_IoIrp },
+     { "IoMdl",                              Test_IoMdl },
+     { "KeApc",                              Test_KeApc },
+     { "KeDpc",                              Test_KeDpc },
+     { "KeEvent",                            Test_KeEvent },
+     { "KeGuardedMutex",                     Test_KeGuardedMutex },
+     { "KeIrql",                             Test_KeIrql },
+     { "-KeProcessor",                       Test_KeProcessor },
+     { "-KernelType",                        Test_KernelType },
+     { "ObReference",                        Test_ObReference },
+     { "ObType",                             Test_ObType },
+     { "-ObTypeClean",                       Test_ObTypeClean },
+     { "-ObTypeNoClean",                     Test_ObTypeNoClean },
+     { "RtlAvlTreeKM",                       Test_RtlAvlTree },
+     { "RtlMemoryKM",                        Test_RtlMemory },
+     { "RtlSplayTreeKM",                     Test_RtlSplayTree },
+     { NULL,                                 NULL }
+ };
index 0000000,d27993f..d27993f
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,235 +1,235 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Doubly-linked list test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ struct _LIST_ENTRY;
+ struct _LIST_ENTRY *__stdcall ExInterlockedInsertHeadList(struct _LIST_ENTRY *, struct _LIST_ENTRY *, unsigned long *);
+ struct _LIST_ENTRY *__stdcall ExInterlockedInsertTailList(struct _LIST_ENTRY *, struct _LIST_ENTRY *, unsigned long *);
+ struct _LIST_ENTRY *__stdcall ExInterlockedRemoveHeadList(struct _LIST_ENTRY *, unsigned long *);
+ #include <kmt_test.h>
+ LIST_ENTRY Entries[5];
+ #define ok_eq_free(Value, Expected) do              \
+ {                                                   \
+     if (KmtIsCheckedBuild)                          \
+         ok_eq_pointer(Value, (PVOID)0x0BADD0FF);    \
+     else                                            \
+         ok_eq_pointer(Value, Expected);             \
+ } while (0)
+ #define ok_eq_free2(Value, Expected) do              \
+ {                                                   \
+     if (KmtIsCheckedBuild)                          \
+         ok_eq_pointer(Value, (PVOID)0xBADDD0FF);    \
+     else                                            \
+         ok_eq_pointer(Value, Expected);             \
+ } while (0)
+ START_TEST(ExDoubleList)
+ {
+     KSPIN_LOCK SpinLock;
+     LIST_ENTRY ListHead;
+     PLIST_ENTRY Ret;
+     KeInitializeSpinLock(&SpinLock);
+     memset(&ListHead, 0x55, sizeof ListHead);
+     InitializeListHead(&ListHead);
+     ok_eq_pointer(ListHead.Flink, &ListHead);
+     ok_eq_pointer(ListHead.Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedInsertHeadList(&ListHead, &Entries[0], &SpinLock);
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(ListHead.Flink, &Entries[0]);
+     ok_eq_pointer(ListHead.Blink, &Entries[0]);
+     ok_eq_pointer(Entries[0].Flink, &ListHead);
+     ok_eq_pointer(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_eq_pointer(ListHead.Flink, &ListHead);
+     ok_eq_pointer(ListHead.Blink, &ListHead);
+     ok_eq_free(Entries[0].Flink, &ListHead);
+     ok_eq_free(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(ListHead.Flink, &ListHead);
+     ok_eq_pointer(ListHead.Blink, &ListHead);
+     ok_eq_free(Entries[0].Flink, &ListHead);
+     ok_eq_free(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedInsertTailList(&ListHead, &Entries[0], &SpinLock);
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(ListHead.Flink, &Entries[0]);
+     ok_eq_pointer(ListHead.Blink, &Entries[0]);
+     ok_eq_pointer(Entries[0].Flink, &ListHead);
+     ok_eq_pointer(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_eq_pointer(ListHead.Flink, &ListHead);
+     ok_eq_pointer(ListHead.Blink, &ListHead);
+     ok_eq_free(Entries[0].Flink, &ListHead);
+     ok_eq_free(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(ListHead.Flink, &ListHead);
+     ok_eq_pointer(ListHead.Blink, &ListHead);
+     ok_eq_free(Entries[0].Flink, &ListHead);
+     ok_eq_free(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedInsertTailList(&ListHead, &Entries[0], &SpinLock);
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(ListHead.Flink, &Entries[0]);
+     ok_eq_pointer(ListHead.Blink, &Entries[0]);
+     ok_eq_pointer(Entries[0].Flink, &ListHead);
+     ok_eq_pointer(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedInsertHeadList(&ListHead, &Entries[1], &SpinLock);
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_eq_pointer(ListHead.Flink, &Entries[1]);
+     ok_eq_pointer(ListHead.Blink, &Entries[0]);
+     ok_eq_pointer(Entries[0].Flink, &ListHead);
+     ok_eq_pointer(Entries[0].Blink, &Entries[1]);
+     ok_eq_pointer(Entries[1].Flink, &Entries[0]);
+     ok_eq_pointer(Entries[1].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedInsertTailList(&ListHead, &Entries[2], &SpinLock);
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_eq_pointer(ListHead.Flink, &Entries[1]);
+     ok_eq_pointer(ListHead.Blink, &Entries[2]);
+     ok_eq_pointer(Entries[0].Flink, &Entries[2]);
+     ok_eq_pointer(Entries[0].Blink, &Entries[1]);
+     ok_eq_pointer(Entries[1].Flink, &Entries[0]);
+     ok_eq_pointer(Entries[1].Blink, &ListHead);
+     ok_eq_pointer(Entries[2].Flink, &ListHead);
+     ok_eq_pointer(Entries[2].Blink, &Entries[0]);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     memset(Entries, 0x55, sizeof Entries);
+ #undef ExInterlockedInsertHeadList
+ #undef ExInterlockedInsertTailList
+ #undef ExInterlockedRemoveHeadList
+     memset(&ListHead, 0x55, sizeof ListHead);
+     InitializeListHead(&ListHead);
+     ok_eq_pointer(ListHead.Flink, &ListHead);
+     ok_eq_pointer(ListHead.Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedInsertHeadList(&ListHead, &Entries[0], &SpinLock);
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(ListHead.Flink, &Entries[0]);
+     ok_eq_pointer(ListHead.Blink, &Entries[0]);
+     ok_eq_pointer(Entries[0].Flink, &ListHead);
+     ok_eq_pointer(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_eq_pointer(ListHead.Flink, &ListHead);
+     ok_eq_pointer(ListHead.Blink, &ListHead);
+     ok_eq_free2(Entries[0].Flink, &ListHead);
+     ok_eq_free2(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(ListHead.Flink, &ListHead);
+     ok_eq_pointer(ListHead.Blink, &ListHead);
+     ok_eq_free2(Entries[0].Flink, &ListHead);
+     ok_eq_free2(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedInsertTailList(&ListHead, &Entries[0], &SpinLock);
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(ListHead.Flink, &Entries[0]);
+     ok_eq_pointer(ListHead.Blink, &Entries[0]);
+     ok_eq_pointer(Entries[0].Flink, &ListHead);
+     ok_eq_pointer(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_eq_pointer(ListHead.Flink, &ListHead);
+     ok_eq_pointer(ListHead.Blink, &ListHead);
+     ok_eq_free2(Entries[0].Flink, &ListHead);
+     ok_eq_free2(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(ListHead.Flink, &ListHead);
+     ok_eq_pointer(ListHead.Blink, &ListHead);
+     ok_eq_free2(Entries[0].Flink, &ListHead);
+     ok_eq_free2(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedInsertTailList(&ListHead, &Entries[0], &SpinLock);
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(ListHead.Flink, &Entries[0]);
+     ok_eq_pointer(ListHead.Blink, &Entries[0]);
+     ok_eq_pointer(Entries[0].Flink, &ListHead);
+     ok_eq_pointer(Entries[0].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedInsertHeadList(&ListHead, &Entries[1], &SpinLock);
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_eq_pointer(ListHead.Flink, &Entries[1]);
+     ok_eq_pointer(ListHead.Blink, &Entries[0]);
+     ok_eq_pointer(Entries[0].Flink, &ListHead);
+     ok_eq_pointer(Entries[0].Blink, &Entries[1]);
+     ok_eq_pointer(Entries[1].Flink, &Entries[0]);
+     ok_eq_pointer(Entries[1].Blink, &ListHead);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     Ret = ExInterlockedInsertTailList(&ListHead, &Entries[2], &SpinLock);
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_eq_pointer(ListHead.Flink, &Entries[1]);
+     ok_eq_pointer(ListHead.Blink, &Entries[2]);
+     ok_eq_pointer(Entries[0].Flink, &Entries[2]);
+     ok_eq_pointer(Entries[0].Blink, &Entries[1]);
+     ok_eq_pointer(Entries[1].Flink, &Entries[0]);
+     ok_eq_pointer(Entries[1].Blink, &ListHead);
+     ok_eq_pointer(Entries[2].Flink, &ListHead);
+     ok_eq_pointer(Entries[2].Blink, &Entries[0]);
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+     ok_irql(PASSIVE_LEVEL);
+     KmtSetIrql(PASSIVE_LEVEL);
+ }
index 0000000,1811b27..1811b27
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,309 +1,309 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Fast Mutex test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ //#define NDEBUG
+ #include <debug.h>
+ NTKERNELAPI VOID    FASTCALL ExiAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex);
+ NTKERNELAPI VOID    FASTCALL ExiReleaseFastMutex(IN OUT PFAST_MUTEX FastMutex);
+ NTKERNELAPI BOOLEAN FASTCALL ExiTryToAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex);
+ #define CheckMutex(Mutex, ExpectedCount, ExpectedOwner,                 \
+                    ExpectedContention, ExpectedOldIrql,                 \
+                    ExpectedIrql) do                                     \
+ {                                                                       \
+     ok_eq_long((Mutex)->Count, ExpectedCount);                          \
+     ok_eq_pointer((Mutex)->Owner, ExpectedOwner);                       \
+     ok_eq_ulong((Mutex)->Contention, ExpectedContention);               \
+     ok_eq_ulong((Mutex)->OldIrql, (ULONG)ExpectedOldIrql);              \
+     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");   \
+     ok_irql(ExpectedIrql);                                              \
+ } while (0)
+ static
+ VOID
+ TestFastMutex(
+     PFAST_MUTEX Mutex,
+     KIRQL OriginalIrql)
+ {
+     PKTHREAD Thread = KeGetCurrentThread();
+     ok_irql(OriginalIrql);
+     /* acquire/release normally */
+     ExAcquireFastMutex(Mutex);
+     CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL);
+     ok_bool_false(ExTryToAcquireFastMutex(Mutex), "ExTryToAcquireFastMutex returned");
+     CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL);
+     ExReleaseFastMutex(Mutex);
+     CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
+     /* ntoskrnl's fastcall version */
+     ExiAcquireFastMutex(Mutex);
+     CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL);
+     ok_bool_false(ExiTryToAcquireFastMutex(Mutex), "ExiTryToAcquireFastMutex returned");
+     CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL);
+     ExiReleaseFastMutex(Mutex);
+     CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
+     /* try to acquire */
+     ok_bool_true(ExTryToAcquireFastMutex(Mutex), "ExTryToAcquireFastMutex returned");
+     CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL);
+     ExReleaseFastMutex(Mutex);
+     CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
+     /* shortcut functions with critical region */
+     ExEnterCriticalRegionAndAcquireFastMutexUnsafe(Mutex);
+     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(Mutex);
+     /* acquire/release unsafe */
+     if (!KmtIsCheckedBuild || OriginalIrql == APC_LEVEL)
+     {
+         ExAcquireFastMutexUnsafe(Mutex);
+         CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, OriginalIrql);
+         ExReleaseFastMutexUnsafe(Mutex);
+         CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
+         /* mismatched acquire/release */
+         ExAcquireFastMutex(Mutex);
+         CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL);
+         ExReleaseFastMutexUnsafe(Mutex);
+         CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, APC_LEVEL);
+         KmtSetIrql(OriginalIrql);
+         CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
+         Mutex->OldIrql = 0x55555555LU;
+         ExAcquireFastMutexUnsafe(Mutex);
+         CheckMutex(Mutex, 0L, Thread, 0LU, 0x55555555LU, OriginalIrql);
+         Mutex->OldIrql = PASSIVE_LEVEL;
+         ExReleaseFastMutex(Mutex);
+         CheckMutex(Mutex, 1L, NULL, 0LU, PASSIVE_LEVEL, PASSIVE_LEVEL);
+         KmtSetIrql(OriginalIrql);
+         CheckMutex(Mutex, 1L, NULL, 0LU, PASSIVE_LEVEL, OriginalIrql);
+     }
+     
+     if (!KmtIsCheckedBuild)
+     {
+         /* release without acquire */
+         ExReleaseFastMutexUnsafe(Mutex);
+         CheckMutex(Mutex, 2L, NULL, 0LU, PASSIVE_LEVEL, OriginalIrql);
+         --Mutex->Count;
+         Mutex->OldIrql = OriginalIrql;
+         ExReleaseFastMutex(Mutex);
+         CheckMutex(Mutex, 2L, NULL, 0LU, OriginalIrql, OriginalIrql);
+         ExReleaseFastMutex(Mutex);
+         CheckMutex(Mutex, 3L, NULL, 0LU, OriginalIrql, OriginalIrql);
+         Mutex->Count -= 2;
+     }
+     /* make sure we survive this in case of error */
+     ok_eq_long(Mutex->Count, 1L);
+     Mutex->Count = 1;
+     ok_irql(OriginalIrql);
+     KmtSetIrql(OriginalIrql);
+ }
+ typedef VOID (FASTCALL *PMUTEX_FUNCTION)(PFAST_MUTEX);
+ typedef BOOLEAN (FASTCALL *PMUTEX_TRY_FUNCTION)(PFAST_MUTEX);
+ typedef struct
+ {
+     HANDLE Handle;
+     PKTHREAD Thread;
+     KIRQL Irql;
+     PFAST_MUTEX Mutex;
+     PMUTEX_FUNCTION Acquire;
+     PMUTEX_TRY_FUNCTION TryAcquire;
+     PMUTEX_FUNCTION Release;
+     BOOLEAN Try;
+     BOOLEAN RetExpected;
+     KEVENT InEvent;
+     KEVENT OutEvent;
+ } THREAD_DATA, *PTHREAD_DATA;
+ static
+ VOID
+ NTAPI
+ AcquireMutexThread(
+     PVOID Parameter)
+ {
+     PTHREAD_DATA ThreadData = Parameter;
+     KIRQL Irql;
+     BOOLEAN Ret = FALSE;
+     NTSTATUS Status;
+     KeRaiseIrql(ThreadData->Irql, &Irql);
+     if (ThreadData->Try)
+     {
+         Ret = ThreadData->TryAcquire(ThreadData->Mutex);
+         ok_eq_bool(Ret, ThreadData->RetExpected);
+     }
+     else
+         ThreadData->Acquire(ThreadData->Mutex);
+     ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent returned");
+     Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     if (!ThreadData->Try || Ret)
+         ThreadData->Release(ThreadData->Mutex);
+     KeLowerIrql(Irql);
+ }
+ static
+ VOID
+ InitThreadData(
+     PTHREAD_DATA ThreadData,
+     PFAST_MUTEX Mutex,
+     PMUTEX_FUNCTION Acquire,
+     PMUTEX_TRY_FUNCTION TryAcquire,
+     PMUTEX_FUNCTION Release)
+ {
+     ThreadData->Mutex = Mutex;
+     KeInitializeEvent(&ThreadData->InEvent, NotificationEvent, FALSE);
+     KeInitializeEvent(&ThreadData->OutEvent, NotificationEvent, FALSE);
+     ThreadData->Acquire = Acquire;
+     ThreadData->TryAcquire = TryAcquire;
+     ThreadData->Release = Release;
+ }
+ static
+ NTSTATUS
+ StartThread(
+     PTHREAD_DATA ThreadData,
+     PLARGE_INTEGER Timeout,
+     KIRQL Irql,
+     BOOLEAN Try,
+     BOOLEAN RetExpected)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     OBJECT_ATTRIBUTES Attributes;
+     ThreadData->Try = Try;
+     ThreadData->Irql = Irql;
+     ThreadData->RetExpected = RetExpected;
+     InitializeObjectAttributes(&Attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+     Status = PsCreateSystemThread(&ThreadData->Handle, GENERIC_ALL, &Attributes, NULL, NULL, AcquireMutexThread, ThreadData);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     Status = ObReferenceObjectByHandle(ThreadData->Handle, SYNCHRONIZE, PsThreadType, KernelMode, (PVOID *)&ThreadData->Thread, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     return KeWaitForSingleObject(&ThreadData->OutEvent, Executive, KernelMode, FALSE, Timeout);
+ }
+ static
+ VOID
+ FinishThread(
+     PTHREAD_DATA ThreadData)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     KeSetEvent(&ThreadData->InEvent, 0, TRUE);
+     Status = KeWaitForSingleObject(ThreadData->Thread, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     ObDereferenceObject(ThreadData->Thread);
+     Status = ZwClose(ThreadData->Handle);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeClearEvent(&ThreadData->InEvent);
+     KeClearEvent(&ThreadData->OutEvent);
+ }
+ static
+ VOID
+ TestFastMutexConcurrent(
+     PFAST_MUTEX Mutex)
+ {
+     NTSTATUS Status;
+     THREAD_DATA ThreadData;
+     THREAD_DATA ThreadData2;
+     THREAD_DATA ThreadDataUnsafe;
+     THREAD_DATA ThreadDataTry;
+     LARGE_INTEGER Timeout;
+     Timeout.QuadPart = -10 * 1000 * 10; /* 10 ms */
+     InitThreadData(&ThreadData, Mutex, ExAcquireFastMutex, NULL, ExReleaseFastMutex);
+     InitThreadData(&ThreadData2, Mutex, ExAcquireFastMutex, NULL, ExReleaseFastMutex);
+     InitThreadData(&ThreadDataUnsafe, Mutex, ExAcquireFastMutexUnsafe, NULL, ExReleaseFastMutexUnsafe);
+     InitThreadData(&ThreadDataTry, Mutex, NULL, ExTryToAcquireFastMutex, ExReleaseFastMutex);
+     /* have a thread acquire the mutex */
+     Status = StartThread(&ThreadData, NULL, PASSIVE_LEVEL, FALSE, FALSE);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckMutex(Mutex, 0L, ThreadData.Thread, 0LU, PASSIVE_LEVEL, PASSIVE_LEVEL);
+     /* have a second thread try to acquire it -- should fail */
+     Status = StartThread(&ThreadDataTry, NULL, PASSIVE_LEVEL, TRUE, FALSE);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckMutex(Mutex, 0L, ThreadData.Thread, 0LU, PASSIVE_LEVEL, PASSIVE_LEVEL);
+     FinishThread(&ThreadDataTry);
+     /* have another thread acquire it -- should block */
+     Status = StartThread(&ThreadData2, &Timeout, APC_LEVEL, FALSE, FALSE);
+     ok_eq_hex(Status, STATUS_TIMEOUT);
+     CheckMutex(Mutex, -1L, ThreadData.Thread, 1LU, PASSIVE_LEVEL, PASSIVE_LEVEL);
+     /* finish the first thread -- now the second should become available */
+     FinishThread(&ThreadData);
+     Status = KeWaitForSingleObject(&ThreadData2.OutEvent, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckMutex(Mutex, 0L, ThreadData2.Thread, 1LU, APC_LEVEL, PASSIVE_LEVEL);
+     /* block two more threads */
+     Status = StartThread(&ThreadDataUnsafe, &Timeout, APC_LEVEL, FALSE, FALSE);
+     ok_eq_hex(Status, STATUS_TIMEOUT);
+     CheckMutex(Mutex, -1L, ThreadData2.Thread, 2LU, APC_LEVEL, PASSIVE_LEVEL);
+     Status = StartThread(&ThreadData, &Timeout, PASSIVE_LEVEL, FALSE, FALSE);
+     ok_eq_hex(Status, STATUS_TIMEOUT);
+     CheckMutex(Mutex, -2L, ThreadData2.Thread, 3LU, APC_LEVEL, PASSIVE_LEVEL);
+     /* finish 1 */
+     FinishThread(&ThreadData2);
+     Status = KeWaitForSingleObject(&ThreadDataUnsafe.OutEvent, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckMutex(Mutex, -1L, ThreadDataUnsafe.Thread, 3LU, APC_LEVEL, PASSIVE_LEVEL);
+     /* finish 2 */
+     FinishThread(&ThreadDataUnsafe);
+     Status = KeWaitForSingleObject(&ThreadData.OutEvent, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckMutex(Mutex, 0L, ThreadData.Thread, 3LU, PASSIVE_LEVEL, PASSIVE_LEVEL);
+     /* finish 3 */
+     FinishThread(&ThreadData);
+     CheckMutex(Mutex, 1L, NULL, 3LU, PASSIVE_LEVEL, PASSIVE_LEVEL);
+ }
+ START_TEST(ExFastMutex)
+ {
+     FAST_MUTEX Mutex;
+     KIRQL Irql;
+     memset(&Mutex, 0x55, sizeof Mutex);
+     ExInitializeFastMutex(&Mutex);
+     CheckMutex(&Mutex, 1L, NULL, 0LU, 0x55555555LU, PASSIVE_LEVEL);
+     TestFastMutex(&Mutex, PASSIVE_LEVEL);
+     KeRaiseIrql(APC_LEVEL, &Irql);
+     TestFastMutex(&Mutex, APC_LEVEL);
+     if (!KmtIsCheckedBuild)
+     {
+         KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+         TestFastMutex(&Mutex, DISPATCH_LEVEL);
+         KeRaiseIrql(HIGH_LEVEL, &Irql);
+         TestFastMutex(&Mutex, HIGH_LEVEL);
+     }
+     KeLowerIrql(PASSIVE_LEVEL);
+     TestFastMutexConcurrent(&Mutex);
+ }
index 0000000,39cd0ab..39cd0ab
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,236 +1,236 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Hard error message test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ /* TODO: don't require user interaction, test Io* routines,
+  *       test NTSTATUS values with special handling */
+ static
+ VOID
+ SetParameters(
+     OUT PULONG_PTR Parameters,
+     IN INT Count,
+     ...)
+ {
+     INT i;
+     va_list Arguments;
+     va_start(Arguments, Count);
+     for (i = 0; i < Count; ++i)
+         Parameters[i] = va_arg(Arguments, ULONG_PTR);
+     va_end(Arguments);
+ }
+ #define NoResponse 27
+ #define CheckHardError(ErrStatus, UnicodeStringMask, ResponseOption,    \
+                         ExpectedStatus, ExpectedResponse,               \
+                         NumberOfParameters, ...) do                     \
+ {                                                                       \
+     SetParameters(HardErrorParameters, NumberOfParameters, __VA_ARGS__);\
+     Response = NoResponse;                                              \
+     _SEH2_TRY {                                                         \
+         Status = ExRaiseHardError(ErrStatus,                            \
+                                   NumberOfParameters,                   \
+                                   UnicodeStringMask,                    \
+                                   HardErrorParameters,                  \
+                                   ResponseOption,                       \
+                                   &Response);                           \
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                         \
+         Status = _SEH2_GetExceptionCode();                              \
+     } _SEH2_END;                                                        \
+     ok_eq_hex(Status, ExpectedStatus);                                  \
+     ok_eq_ulong(Response, (ULONG)ExpectedResponse);                     \
+ } while (0)
+ #define CheckInformationalHardError(ErrStatus, String, Thread,          \
+                                         ExpectedStatus, ExpectedRet) do \
+ {                                                                       \
+     Status = STATUS_SUCCESS;                                            \
+     Ret = !ExpectedRet;                                                 \
+     _SEH2_TRY {                                                         \
+         Ret = IoRaiseInformationalHardError(ErrStatus,                  \
+                                             String,                     \
+                                             Thread);                    \
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                         \
+         Status = _SEH2_GetExceptionCode();                              \
+     } _SEH2_END;                                                        \
+     ok_eq_hex(Status, ExpectedStatus);                                  \
+     ok_eq_bool(Ret, ExpectedRet);                                       \
+ } while (0)
+ static
+ VOID
+ TestHardError(
+     BOOLEAN InteractivePart1,
+     BOOLEAN InteractivePart2,
+     BOOLEAN InteractivePart3,
+     BOOLEAN InteractivePart4)
+ {
+     NTSTATUS Status;
+     ULONG Response;
+     WCHAR StringBuffer1[] = L"Parameter1+Garbage";
+     CHAR StringBuffer1Ansi[] = "Parameter1+Garbage";
+     WCHAR StringBuffer2[] = L"Parameter2+Garbage";
+     UNICODE_STRING String1 = RTL_CONSTANT_STRING(StringBuffer1);
+     ANSI_STRING String1Ansi = RTL_CONSTANT_STRING(StringBuffer1Ansi);
+     UNICODE_STRING String2 = RTL_CONSTANT_STRING(StringBuffer2);
+     ULONG_PTR HardErrorParameters[6];
+     BOOLEAN Ret;
+     String1.Length = sizeof L"Parameter1" - sizeof UNICODE_NULL;
+     String1Ansi.Length = sizeof "Parameter1" - sizeof ANSI_NULL;
+     String2.Length = sizeof L"Parameter2" - sizeof UNICODE_NULL;
+     if (InteractivePart1)
+     {
+     CheckHardError(0x40000000,                  0, OptionOk,                STATUS_SUCCESS,            ResponseOk,             0, 0);                          // outputs a box :|
+     CheckHardError(0x40000001,                  0, OptionOk,                STATUS_SUCCESS,            ResponseOk,             4, 1, 2, 3, 4);                 // outputs a box :|
+     CheckHardError(0x40000002,                  0, OptionOk,                STATUS_SUCCESS,            ResponseOk,             5, 1, 2, 3, 4, 5);              // outputs a box :|
+     CheckHardError(0x40000003,                  0, OptionOk,                STATUS_SUCCESS,            ResponseNotHandled,     6, 1, 2, 3, 4, 5, 6);           // TODO: interactive on ROS
+     }
+     CheckHardError(0x40000004,                  0, OptionShutdownSystem,    STATUS_PRIVILEGE_NOT_HELD, ResponseNotHandled,     0, 0);
+     if (InteractivePart1)
+     {
+     // TODO: these 2 are interactive on ROS
+     CheckHardError(0x40000005,                  0, OptionOkNoWait,          STATUS_SUCCESS,            ResponseOk,             0, 0);                          // outputs a balloon notification
+     CheckHardError(0x4000000f,                  0, OptionOkNoWait,          STATUS_SUCCESS,            ResponseOk,             0, 0);                          // outputs a balloon notification
+     CheckHardError(0x40000006,                  0, OptionAbortRetryIgnore,  STATUS_SUCCESS,            ResponseAbort,          0, 0);                          // outputs a box :|
+     CheckHardError(0x40000006,                  0, OptionAbortRetryIgnore,  STATUS_SUCCESS,            ResponseRetry,          0, 0);                          // outputs a box :|
+     CheckHardError(0x40000006,                  0, OptionAbortRetryIgnore,  STATUS_SUCCESS,            ResponseIgnore,         0, 0);                          // outputs a box :|
+     CheckHardError(0x40000008,                  0, OptionCancelTryContinue, STATUS_SUCCESS,            ResponseCancel,         0, 0);                          // outputs a box :|
+     CheckHardError(0x40000008,                  0, OptionCancelTryContinue, STATUS_SUCCESS,            ResponseTryAgain,       0, 0);                          // outputs a box :|
+     CheckHardError(0x40000008,                  0, OptionCancelTryContinue, STATUS_SUCCESS,            ResponseContinue,       0, 0);                          // outputs a box :|
+     CheckHardError(0x40000010,                  0, OptionOkCancel,          STATUS_SUCCESS,            ResponseOk,             0, 0);                          // outputs a box :|
+     CheckHardError(0x40000010,                  0, OptionOkCancel,          STATUS_SUCCESS,            ResponseCancel,         0, 0);                          // outputs a box :|
+     CheckHardError(0x40000011,                  0, OptionRetryCancel,       STATUS_SUCCESS,            ResponseRetry,          0, 0);                          // outputs a box :|
+     CheckHardError(0x40000011,                  0, OptionRetryCancel,       STATUS_SUCCESS,            ResponseCancel,         0, 0);                          // outputs a box :|
+     CheckHardError(0x40000012,                  0, OptionYesNo,             STATUS_SUCCESS,            ResponseYes,            0, 0);                          // outputs a box :|
+     CheckHardError(0x40000012,                  0, OptionYesNo,             STATUS_SUCCESS,            ResponseNo,             0, 0);                          // outputs a box :|
+     CheckHardError(0x40000013,                  0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            0, 0);                          // outputs a box :|
+     CheckHardError(0x40000013,                  0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             0, 0);                          // outputs a box :|
+     CheckHardError(0x40000013,                  0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         0, 0);                          // outputs a box :|
+     }
+     CheckHardError(0x40000009,                  0, 9,                       STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
+     CheckHardError(0x4000000a,                  0, 10,                      STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
+     CheckHardError(0x4000000b,                  0, 11,                      STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
+     CheckHardError(0x4000000c,                  0, 12,                      STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
+     CheckHardError(0x4000000d,                  0, MAXULONG / 2 + 1,        STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
+     CheckHardError(0x4000000d,                  0, MAXULONG,                STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
+     if (InteractivePart2)
+     {
+     /* try a message with one parameter */
+     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            1, &String1);                   // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, &String1);                   // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         0, &String1);                   // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         0, &String1);                   // outputs a box :|
+     /* give too many parameters */
+     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            2, &String1, &String2);         // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        2, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         2, &String1, &String2);         // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            2, &String1, &String2);         // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            4, &String1, &String2, 0, 0);   // outputs a box :|
+     /* try with stuff that's not a UNICODE_STRING */
+     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, &String1Ansi);               // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, L"Parameter1");              // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, "Parameter1");               // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, 1234);                       // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, NULL);                       // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, &String1Ansi);               // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, L"Parameter1");              // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, "Parameter1");               // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, 1234);                       // outputs a box :|
+     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, NULL);                       // outputs a box :|
+     }
+     if (InteractivePart3)
+     {
+     /* try a message with one parameter */
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, &String1);                   // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, &String1);                   // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     0, &String1);                   // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     0, &String1);                   // outputs a box :|
+     /* give too many parameters */
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     2, &String1, &String2);         // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 2, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     2, &String1, &String2);         // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     2, &String1, &String2);         // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseOk,             3, &String1, &String2, 0);      // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseOk,             4, &String1, &String2, 0, 0);   // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 3, OptionOkNoWait,          STATUS_SUCCESS,            ResponseOk,             4, &String1, &String2, 0, 0);   // outputs a balloon notification
+     /* try with stuff that's not a UNICODE_STRING */
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, &String1Ansi);               // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, L"Parameter1");              // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, "Parameter1");               // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, 1234);                       // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, NULL);                       // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, &String1Ansi);               // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, L"Parameter1");              // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, "Parameter1");               // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, 1234);                       // outputs a box :|
+     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, NULL);                       // outputs a box :|
+     }
+     if (InteractivePart4)
+     {
+     /* try a message with one parameter */
+     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            1, &String1);                   // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, &String1);                   // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         0, &String1);                   // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         0, &String1);                   // outputs a box :|
+     /* give too many parameters */
+     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            2, &String1, &String2);         // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       2, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         2, &String1, &String2);         // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            2, &String1, &String2);         // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            4, &String1, &String2, 0, 0);   // outputs a box :|
+     /* try with stuff that's not a UNICODE_STRING */
+     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, &String1Ansi);               // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, L"Parameter1");              // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, "Parameter1");               // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, 1234);                       // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, NULL);                       // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, &String1Ansi);               // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, L"Parameter1");              // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, "Parameter1");               // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, 1234);                       // outputs a box :|
+     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, NULL);                       // outputs a box :|
+     // TODO: these 3 are interactive on ROS
+     CheckInformationalHardError(STATUS_WAIT_0,               NULL,     NULL, STATUS_SUCCESS, TRUE);                                                            // outputs a balloon notification
+     CheckInformationalHardError(STATUS_DLL_NOT_FOUND,        &String1, NULL, STATUS_SUCCESS, TRUE);                                                            // outputs a balloon notification
+     CheckInformationalHardError(STATUS_DLL_NOT_FOUND,        NULL,     NULL, STATUS_SUCCESS, TRUE);                                                            // outputs a balloon notification
+     }
+     CheckInformationalHardError(STATUS_SERVICE_NOTIFICATION, &String1, NULL, STATUS_SUCCESS, FALSE);
+     ok_bool_true(IoSetThreadHardErrorMode(TRUE), "IoSetThreadHardErrorMode returned");
+     ok_bool_true(IoSetThreadHardErrorMode(FALSE), "IoSetThreadHardErrorMode returned");
+     ok_bool_false(IoSetThreadHardErrorMode(FALSE), "IoSetThreadHardErrorMode returned");
+     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseReturnToCaller, 0, 0);
+     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, NULL);
+     CheckInformationalHardError(STATUS_WAIT_0,               NULL,     NULL, STATUS_SUCCESS, FALSE);
+     CheckInformationalHardError(STATUS_DLL_NOT_FOUND,        &String1, NULL, STATUS_SUCCESS, FALSE);
+     CheckInformationalHardError(STATUS_DLL_NOT_FOUND,        NULL,     NULL, STATUS_SUCCESS, FALSE);
+     CheckInformationalHardError(STATUS_SERVICE_NOTIFICATION, &String1, NULL, STATUS_SUCCESS, FALSE);
+     ok_bool_false(IoSetThreadHardErrorMode(TRUE), "IoSetThreadHardErrorMode returned");
+ }
+ START_TEST(ExHardError)
+ {
+     TestHardError(FALSE, FALSE, FALSE, FALSE);
+ }
+ /* Here's how to do the interactive test:
+  * - First there will be a few messages random messages. If there's
+  *   multiple options available, the same box will appear multiple times --
+  *   click the buttons in order from left to right
+  * - After that, you must verify the error parameters. You should always
+  *   see Parameter1 or Parameter2 for strings, and 0x12345678 for numbers.
+  *   if there's a message saying an exception occured during processing,
+  *   click cancel. If there's a bad parameter (Parameter1+, Parameter1+Garbage
+  *   or an empty string for example), click no. Otherwise click yes. */
+ START_TEST(ExHardErrorInteractive)
+ {
+     TestHardError(TRUE, TRUE, TRUE, TRUE);
+ }
index 0000000,6131f03..6131f03
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,399 +1,399 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Interlocked function test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ /* missing prototypes >:| */
+ #ifndef _MSC_VER
+ typedef long long __int64;
+ #endif
+ struct _KSPIN_LOCK;
+ __declspec(dllimport)   long            __fastcall  InterlockedCompareExchange(volatile long *, long, long);
+ __declspec(dllimport)   __int64         __fastcall  ExInterlockedCompareExchange64(volatile __int64 *, __int64 *, __int64 *, void *);
+ __declspec(dllimport)   __int64         __fastcall  ExfInterlockedCompareExchange64(volatile __int64 *, __int64 *, __int64 *);
+ __declspec(dllimport)   long            __fastcall  InterlockedExchange(volatile long *, long);
+ __declspec(dllimport)   unsigned long   __stdcall   ExInterlockedExchangeUlong(unsigned long *, unsigned long, void *);
+ __declspec(dllimport)   long            __fastcall  InterlockedExchangeAdd(volatile long *, long);
+ __declspec(dllimport)   unsigned long   __stdcall   ExInterlockedAddUlong(unsigned long *, unsigned long, void *);
+ __declspec(dllimport)   unsigned long   __stdcall   Exi386InterlockedExchangeUlong(unsigned long *, unsigned long);
+ __declspec(dllimport)   long            __fastcall  InterlockedIncrement(long *);
+ __declspec(dllimport)   long            __fastcall  InterlockedDecrement(long *);
+ __declspec(dllimport)   int             __stdcall   ExInterlockedIncrementLong(long *, void *);
+ __declspec(dllimport)   int             __stdcall   ExInterlockedDecrementLong(long *, void *);
+ __declspec(dllimport)   int             __stdcall   Exi386InterlockedIncrementLong(long *);
+ __declspec(dllimport)   int             __stdcall   Exi386InterlockedDecrementLong(long *);
+ #include <kmt_test.h>
+ /* TODO: There are quite some changes needed for other architectures!
+          ExInterlockedAddLargeInteger, ExInterlockedAddUlong are the only two
+          functions actually exported by my win7/x64 kernel! */
+ /* TODO: stress-testing */
+ static KSPIN_LOCK SpinLock;
+ #ifdef _M_IX86
+ typedef struct
+ {
+     unsigned long esi, edi, ebx, ebp, esp;
+ } PROCESSOR_STATE;
+ #elif defined(_M_AMD64)
+ typedef struct
+ {
+     unsigned long long rsi, rdi, rbx, rbp, rsp, r12, r13, r14, r15;
+ } PROCESSOR_STATE;
+ #else
+ // dummy
+ typedef int PROCESSOR_STATE;
+ #endif
+ #if defined(_MSC_VER) && defined(_M_IX86)
+ #define SaveState(State) do                                                 \
+ {                                                                           \
+     __asm lea ecx,      [State]                                             \
+     __asm mov [ecx],    esi                                                 \
+     __asm mov [ecx+4],  edi                                                 \
+     __asm mov [ecx+8],  ebx                                                 \
+     __asm mov [ecx+12], ebp                                                 \
+     __asm mov [ecx+16], esp                                                 \
+ } while (0)
+ #define CheckState(OldState, NewState) do                                   \
+ {                                                                           \
+     ok_eq_hex((OldState)->esi, (NewState)->esi);                            \
+     ok_eq_hex((OldState)->edi, (NewState)->edi);                            \
+     ok_eq_hex((OldState)->ebx, (NewState)->ebx);                            \
+     ok_eq_hex((OldState)->ebp, (NewState)->ebp);                            \
+     ok_eq_hex((OldState)->esp, (NewState)->esp);                            \
+ } while (0)
+ #elif defined(__GNUC__) && defined(_M_IX86)
+ #define SaveState(State)                                                    \
+     asm volatile(                                                           \
+         ".intel_syntax noprefix\n\t"                                        \
+         "mov\t[ecx], esi\n\t"                                               \
+         "mov\t[ecx+4], edi\n\t"                                             \
+         "mov\t[ecx+8], ebx\n\t"                                             \
+         "mov\t[ecx+12], ebp\n\t"                                            \
+         "mov\t[ecx+16], esp\n\t"                                            \
+         ".att_syntax prefix"                                                \
+         : : "c" (&State) : "memory"                                         \
+     );
+ #define CheckState(OldState, NewState) do                                   \
+ {                                                                           \
+     ok_eq_hex((OldState)->esi, (NewState)->esi);                            \
+     ok_eq_hex((OldState)->edi, (NewState)->edi);                            \
+     ok_eq_hex((OldState)->ebx, (NewState)->ebx);                            \
+     ok_eq_hex((OldState)->ebp, (NewState)->ebp);                            \
+     ok_eq_hex((OldState)->esp, (NewState)->esp);                            \
+ } while (0)
+ #elif defined(__GNUC__) && defined(_M_AMD64)
+ #define SaveState(State)                                                    \
+     asm volatile(                                                           \
+         ".intel_syntax noprefix\n\t"                                        \
+         "mov\t[rcx], rsi\n\t"                                               \
+         "mov\t[rcx+8], rdi\n\t"                                             \
+         "mov\t[rcx+16], rbx\n\t"                                            \
+         "mov\t[rcx+24], rbp\n\t"                                            \
+         "mov\t[rcx+32], rsp\n\t"                                            \
+         "mov\t[rcx+40], r12\n\t"                                            \
+         "mov\t[rcx+48], r13\n\t"                                            \
+         "mov\t[rcx+56], r14\n\t"                                            \
+         "mov\t[rcx+64], r15\n\t"                                            \
+         ".att_syntax prefix"                                                \
+         : : "c" (&State) : "memory"                                         \
+     );
+ #define CheckState(OldState, NewState) do                                   \
+ {                                                                           \
+     ok_eq_hex((OldState)->rsi, (NewState)->rsi);                            \
+     ok_eq_hex((OldState)->rdi, (NewState)->rdi);                            \
+     ok_eq_hex((OldState)->rbx, (NewState)->rbx);                            \
+     ok_eq_hex((OldState)->rbp, (NewState)->rbp);                            \
+     ok_eq_hex((OldState)->rsp, (NewState)->rsp);                            \
+     ok_eq_hex((OldState)->r12, (NewState)->r12);                            \
+     ok_eq_hex((OldState)->r13, (NewState)->r13);                            \
+     ok_eq_hex((OldState)->r14, (NewState)->r14);                            \
+     ok_eq_hex((OldState)->r15, (NewState)->r15);                            \
+ } while (0)
+ #else
+ #define SaveState(State)
+ #define CheckState(OldState, NewState)
+ #endif
+ static
+ LARGE_INTEGER
+ Large(
+     ULONGLONG Value)
+ {
+     LARGE_INTEGER Ret;
+     Ret.QuadPart = Value;
+     return Ret;
+ }
+ #define CheckInterlockedCmpXchg(Function, Type, Print, Val, Cmp, Xchg,      \
+                                 ExpectedValue, ExpectedRet) do              \
+ {                                                                           \
+     Type Ret##Type = 0;                                                     \
+     Type Value##Type = Val;                                                 \
+     Status = STATUS_SUCCESS;                                                \
+     _SEH2_TRY {                                                             \
+         SaveState(OldState);                                                \
+         Ret##Type = Function(&Value##Type, Xchg, Cmp);                      \
+         SaveState(NewState);                                                \
+         CheckState(&OldState, &NewState);                                   \
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                             \
+         Status = _SEH2_GetExceptionCode();                                  \
+     } _SEH2_END;                                                            \
+     ok_eq_hex(Status, STATUS_SUCCESS);                                      \
+     ok_eq_print(Ret##Type, ExpectedRet, Print);                             \
+     ok_eq_print(Value##Type, ExpectedValue, Print);                         \
+ } while (0)
+ #define CheckInterlockedCmpXchgI(Function, Type, Print, Val, Cmp, Xchg,     \
+                                 ExpectedValue, ExpectedRet, ...) do         \
+ {                                                                           \
+     Type Ret##Type = 0;                                                     \
+     Type Value##Type = Val;                                                 \
+     Type Compare##Type = Cmp;                                               \
+     Type Exchange##Type = Xchg;                                             \
+     Status = STATUS_SUCCESS;                                                \
+     _SEH2_TRY {                                                             \
+         SaveState(OldState);                                                \
+         Ret##Type = Function(&Value##Type, &Exchange##Type,                 \
+                                 &Compare##Type, ##__VA_ARGS__);             \
+         SaveState(NewState);                                                \
+         CheckState(&OldState, &NewState);                                   \
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                             \
+         Status = _SEH2_GetExceptionCode();                                  \
+     } _SEH2_END;                                                            \
+     ok_eq_hex(Status, STATUS_SUCCESS);                                      \
+     ok_eq_print(Ret##Type, ExpectedRet, Print);                             \
+     ok_eq_print(Value##Type, ExpectedValue, Print);                         \
+     ok_eq_print(Exchange##Type, Xchg, Print);                               \
+     ok_eq_print(Compare##Type, Cmp, Print);                                 \
+ } while(0)
+ #define CheckInterlockedOp(Function, Type, Print, Val, Op,                  \
+                                 ExpectedValue, ExpectedRet, ...) do         \
+ {                                                                           \
+     Type Ret##Type = 0;                                                     \
+     Type Value##Type = Val;                                                 \
+     Status = STATUS_SUCCESS;                                                \
+     _SEH2_TRY {                                                             \
+         SaveState(OldState);                                                \
+         Ret##Type = Function(&Value##Type, Op, ##__VA_ARGS__);              \
+         SaveState(NewState);                                                \
+         CheckState(&OldState, &NewState);                                   \
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                             \
+         Status = _SEH2_GetExceptionCode();                                  \
+     } _SEH2_END;                                                            \
+     ok_eq_hex(Status, STATUS_SUCCESS);                                      \
+     ok_eq_print(Ret##Type, ExpectedRet, Print);                             \
+     ok_eq_print(Value##Type, ExpectedValue, Print);                         \
+ } while (0)
+ #define CheckInterlockedOpNoArg(Function, Type, Print, Val,                 \
+                                 ExpectedValue, ExpectedRet, ...) do         \
+ {                                                                           \
+     Type Ret##Type = 0;                                                     \
+     Type Value##Type = Val;                                                 \
+     Status = STATUS_SUCCESS;                                                \
+     _SEH2_TRY {                                                             \
+         SaveState(OldState);                                                \
+         Ret##Type = Function(&Value##Type, ##__VA_ARGS__);                  \
+         SaveState(NewState);                                                \
+         CheckState(&OldState, &NewState);                                   \
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                             \
+         Status = _SEH2_GetExceptionCode();                                  \
+     } _SEH2_END;                                                            \
+     ok_eq_hex(Status, STATUS_SUCCESS);                                      \
+     ok_eq_print(Ret##Type, ExpectedRet, Print);                             \
+     ok_eq_print(Value##Type, ExpectedValue, Print);                         \
+ } while (0)
+ #define CheckInterlockedOpLarge(Function, Type, Print, Val, Op,             \
+                                 ExpectedValue, ExpectedRet, ...) do         \
+ {                                                                           \
+     Type Ret##Type = Large(0);                                              \
+     Type Value##Type = Val;                                                 \
+     Status = STATUS_SUCCESS;                                                \
+     _SEH2_TRY {                                                             \
+         SaveState(OldState);                                                \
+         Ret##Type = Function(&Value##Type, Op, ##__VA_ARGS__);              \
+         SaveState(NewState);                                                \
+         CheckState(&OldState, &NewState);                                   \
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                             \
+         Status = _SEH2_GetExceptionCode();                                  \
+     } _SEH2_END;                                                            \
+     ok_eq_hex(Status, STATUS_SUCCESS);                                      \
+     ok_eq_print(Ret##Type.QuadPart, ExpectedRet, Print);                    \
+     ok_eq_print(Value##Type.QuadPart, ExpectedValue, Print);                \
+ } while (0)
+ #define CheckInterlockedOpLargeNoRet(Function, Type, Print, Val, Op,        \
+                                 ExpectedValue) do                           \
+ {                                                                           \
+     Type Value##Type = Val;                                                 \
+     Status = STATUS_SUCCESS;                                                \
+     _SEH2_TRY {                                                             \
+         SaveState(OldState);                                                \
+         Function(&Value##Type, Op);                                         \
+         SaveState(NewState);                                                \
+         CheckState(&OldState, &NewState);                                   \
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                             \
+         Status = _SEH2_GetExceptionCode();                                  \
+     } _SEH2_END;                                                            \
+     ok_eq_hex(Status, STATUS_SUCCESS);                                      \
+     ok_eq_print(Value##Type.QuadPart, ExpectedValue, Print);                \
+ } while (0)
+ /* TODO: missing in wdm.h! */
+ #define InterlockedCompareExchangeAcquire InterlockedCompareExchange
+ #define InterlockedCompareExchangeRelease InterlockedCompareExchange
+ #define InterlockedIncrementAcquire InterlockedIncrement
+ #define InterlockedIncrementRelease InterlockedIncrement
+ #define InterlockedDecrementAcquire InterlockedDecrement
+ #define InterlockedDecrementRelease InterlockedDecrement
+ static
+ VOID
+ TestInterlockedFunctional(VOID)
+ {
+     NTSTATUS Status;
+     PKSPIN_LOCK pSpinLock = &SpinLock;
+     PROCESSOR_STATE OldState, NewState;
+     /* on x86, most of these are supported intrinsically and don't need a spinlock! */
+ #if defined _M_IX86 || defined _M_AMD64
+     pSpinLock = NULL;
+ #endif
+     /* CompareExchange */
+     /* macro version */
+     CheckInterlockedCmpXchg(InterlockedCompareExchange, LONG, "%ld", 5, 6, 8, 5L, 5L);
+     CheckInterlockedCmpXchg(InterlockedCompareExchange, LONG, "%ld", 5, 5, 9, 9L, 5L);
+     /* these only exist as macros on x86 */
+     CheckInterlockedCmpXchg(InterlockedCompareExchangeAcquire, LONG, "%ld", 16, 9, 12, 16L, 16L);
+     CheckInterlockedCmpXchg(InterlockedCompareExchangeAcquire, LONG, "%ld", 16, 16, 4, 4L, 16L);
+     CheckInterlockedCmpXchg(InterlockedCompareExchangeRelease, LONG, "%ld", 27, 123, 38, 27L, 27L);
+     CheckInterlockedCmpXchg(InterlockedCompareExchangeRelease, LONG, "%ld", 27, 27, 39, 39L, 27L);
+     /* exported function */
+ #undef InterlockedCompareExchange
+ #ifdef _M_IX86
+     CheckInterlockedCmpXchg(InterlockedCompareExchange, LONG, "%ld", 5, 6, 8, 5L, 5L);
+     CheckInterlockedCmpXchg(InterlockedCompareExchange, LONG, "%ld", 5, 5, 9, 9L, 5L);
+ #endif
+     /* only exists as a macro */
+     CheckInterlockedCmpXchg(InterlockedCompareExchangePointer, PVOID, "%p", (PVOID)117, (PVOID)711, (PVOID)12, (PVOID)117, (PVOID)117);
+     CheckInterlockedCmpXchg(InterlockedCompareExchangePointer, PVOID, "%p", (PVOID)117, (PVOID)117, (PVOID)228, (PVOID)228, (PVOID)117);
+     /* macro version */
+     CheckInterlockedCmpXchgI(ExInterlockedCompareExchange64, LONGLONG, "%I64d", 17, 4LL, 20LL, 17LL, 17LL, pSpinLock);
+     CheckInterlockedCmpXchgI(ExInterlockedCompareExchange64, LONGLONG, "%I64d", 17, 17LL, 21LL, 21LL, 17LL, pSpinLock);
+ #ifdef _M_IX86
+     /* exported function */
+     CheckInterlockedCmpXchgI((ExInterlockedCompareExchange64), LONGLONG, "%I64d", 17, 4LL, 20LL, 17LL, 17LL, pSpinLock);
+     CheckInterlockedCmpXchgI((ExInterlockedCompareExchange64), LONGLONG, "%I64d", 17, 17LL, 21LL, 21LL, 17LL, pSpinLock);
+     /* fastcall version */
+     CheckInterlockedCmpXchgI(ExfInterlockedCompareExchange64, LONGLONG, "%I64d", 17, 4LL, 20LL, 17LL, 17LL);
+     CheckInterlockedCmpXchgI(ExfInterlockedCompareExchange64, LONGLONG, "%I64d", 17, 17LL, 21LL, 21LL, 17LL);
+ #endif
+     /* Exchange */
+     CheckInterlockedOp(InterlockedExchange, LONG, "%ld", 5, 8, 8L, 5L);
+     CheckInterlockedOpNoArg(InterlockedExchangePointer, PVOID, "%p", (PVOID)700, (PVOID)93, (PVOID)700, (PVOID)93);
+ #undef InterlockedExchange
+ #ifdef _M_IX86
+     CheckInterlockedOp(InterlockedExchange, LONG, "%ld", 5, 8, 8L, 5L);
+     CheckInterlockedOp(ExInterlockedExchangeUlong, ULONG, "%lu", 212, 121, 121LU, 212LU, pSpinLock);
+     CheckInterlockedOp((ExInterlockedExchangeUlong), ULONG, "%lu", 212, 121, 121LU, 212LU, pSpinLock);
+     CheckInterlockedOp(Exi386InterlockedExchangeUlong, ULONG, "%lu", 212, 121, 121LU, 212LU);
+     CheckInterlockedOp(Exfi386InterlockedExchangeUlong, ULONG, "%lu", 212, 121, 121LU, 212LU);
+ #endif
+     /* ExchangeAdd */
+     /* TODO: ExInterlockedExchangeAddLargeInteger? */
+     CheckInterlockedOp(InterlockedExchangeAdd, LONG, "%ld", 312, 7, 319L, 312L);
+ #undef InterlockedExchangeAdd
+ #ifdef _M_IX86
+     CheckInterlockedOp(InterlockedExchangeAdd, LONG, "%ld", 312, 7, 319L, 312L);
+ #endif
+     /* Add */
+     /* these DO need a valid spinlock even on x86 */
+     CheckInterlockedOpLarge(ExInterlockedAddLargeInteger, LARGE_INTEGER, "%I64d", Large(23), Large(7), 30LL, 23LL, &SpinLock);
+     CheckInterlockedOpLargeNoRet(ExInterlockedAddLargeStatistic, LARGE_INTEGER, "%I64d", Large(15), 17LL, 32LL);
+     CheckInterlockedOp(ExInterlockedAddUlong, ULONG, "%lu", 239, 44, 283LU, 239LU, &SpinLock);
+ #undef ExInterlockedAddUlong
+     CheckInterlockedOp(ExInterlockedAddUlong, ULONG, "%lu", 239, 44, 283LU, 239LU, &SpinLock);
+     /* Increment */
+     CheckInterlockedOpNoArg(InterlockedIncrement, LONG, "%ld", 2341L, 2342L, 2342L);
+     CheckInterlockedOpNoArg(InterlockedIncrement, LONG, "%ld", (LONG)MAXLONG, (LONG)MINLONG, (LONG)MINLONG);
+     CheckInterlockedOpNoArg(InterlockedIncrementAcquire, LONG, "%ld", 2341L, 2342L, 2342L);
+     CheckInterlockedOpNoArg(InterlockedIncrementRelease, LONG, "%ld", 2341L, 2342L, 2342L);
+ #undef InterlockedIncrement
+ #ifdef _M_IX86
+     CheckInterlockedOpNoArg(InterlockedIncrement, LONG, "%ld", 2341L, 2342L, 2342L);
+     CheckInterlockedOpNoArg(InterlockedIncrement, LONG, "%ld", (LONG)MAXLONG, (LONG)MINLONG, (LONG)MINLONG);
+     CheckInterlockedOpNoArg(ExInterlockedIncrementLong, LONG, "%ld", -2L, -1L, (LONG)ResultNegative, pSpinLock);
+     CheckInterlockedOpNoArg(ExInterlockedIncrementLong, LONG, "%ld", -1L, 0L, (LONG)ResultZero, pSpinLock);
+     CheckInterlockedOpNoArg(ExInterlockedIncrementLong, LONG, "%ld", 0L, 1L, (LONG)ResultPositive, pSpinLock);
+     CheckInterlockedOpNoArg(ExInterlockedIncrementLong, LONG, "%ld", (LONG)MAXLONG, (LONG)MINLONG, (LONG)ResultNegative, pSpinLock);
+     CheckInterlockedOpNoArg((ExInterlockedIncrementLong), LONG, "%ld", -2L, -1L, (LONG)ResultNegative, pSpinLock);
+     CheckInterlockedOpNoArg((ExInterlockedIncrementLong), LONG, "%ld", -1L, 0L, (LONG)ResultZero, pSpinLock);
+     CheckInterlockedOpNoArg((ExInterlockedIncrementLong), LONG, "%ld", 0L, 1L, (LONG)ResultPositive, pSpinLock);
+     CheckInterlockedOpNoArg((ExInterlockedIncrementLong), LONG, "%ld", (LONG)MAXLONG, (LONG)MINLONG, (LONG)ResultNegative, pSpinLock);
+     CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong, LONG, "%ld", -2L, -1L, (LONG)ResultNegative);
+     CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong, LONG, "%ld", -1L, 0L, (LONG)ResultZero);
+     CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong, LONG, "%ld", 0L, 1L, (LONG)ResultPositive);
+     CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong, LONG, "%ld", (LONG)MAXLONG, (LONG)MINLONG, (LONG)ResultNegative);
+ #endif
+     /* Decrement */
+     CheckInterlockedOpNoArg(InterlockedDecrement, LONG, "%ld", 1745L, 1744L, 1744L);
+     CheckInterlockedOpNoArg(InterlockedDecrement, LONG, "%ld", (LONG)MINLONG, (LONG)MAXLONG, (LONG)MAXLONG);
+     CheckInterlockedOpNoArg(InterlockedDecrementAcquire, LONG, "%ld", 1745L, 1744L, 1744L);
+     CheckInterlockedOpNoArg(InterlockedDecrementRelease, LONG, "%ld", 1745L, 1744L, 1744L);
+ #undef InterlockedDecrement
+ #ifdef _M_IX86
+     CheckInterlockedOpNoArg(InterlockedDecrement, LONG, "%ld", 1745L, 1744L, 1744L);
+     CheckInterlockedOpNoArg(InterlockedDecrement, LONG, "%ld", (LONG)MINLONG, (LONG)MAXLONG, (LONG)MAXLONG);
+     CheckInterlockedOpNoArg(ExInterlockedDecrementLong, LONG, "%ld", (LONG)MINLONG, (LONG)MAXLONG, (LONG)ResultPositive, pSpinLock);
+     CheckInterlockedOpNoArg(ExInterlockedDecrementLong, LONG, "%ld", 0L, -1L, (LONG)ResultNegative, pSpinLock);
+     CheckInterlockedOpNoArg(ExInterlockedDecrementLong, LONG, "%ld", 1L, 0L, (LONG)ResultZero, pSpinLock);
+     CheckInterlockedOpNoArg(ExInterlockedDecrementLong, LONG, "%ld", 2L, 1L, (LONG)ResultPositive, pSpinLock);
+     CheckInterlockedOpNoArg((ExInterlockedDecrementLong), LONG, "%ld", (LONG)MINLONG, (LONG)MAXLONG, (LONG)ResultPositive, pSpinLock);
+     CheckInterlockedOpNoArg((ExInterlockedDecrementLong), LONG, "%ld", 0L, -1L, (LONG)ResultNegative, pSpinLock);
+     CheckInterlockedOpNoArg((ExInterlockedDecrementLong), LONG, "%ld", 1L, 0L, (LONG)ResultZero, pSpinLock);
+     CheckInterlockedOpNoArg((ExInterlockedDecrementLong), LONG, "%ld", 2L, 1L, (LONG)ResultPositive, pSpinLock);
+     CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong, LONG, "%ld", (LONG)MINLONG, (LONG)MAXLONG, (LONG)ResultPositive);
+     CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong, LONG, "%ld", 0L, -1L, (LONG)ResultNegative);
+     CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong, LONG, "%ld", 1L, 0L, (LONG)ResultZero);
+     CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong, LONG, "%ld", 2L, 1L, (LONG)ResultPositive);
+ #endif
+     /* And, Or, Xor */
+     CheckInterlockedOp(InterlockedAnd, LONG, "0x%lx", 0x1234L, 0x1111L, 0x1010L, 0x1234L);
+     CheckInterlockedOp(InterlockedOr, LONG, "0x%lx", 0x1234L, 0x1111L, 0x1335L, 0x1234L);
+     CheckInterlockedOp(InterlockedXor, LONG, "0x%lx", 0x1234L, 0x1111L, 0x0325L, 0x1234L);
+ #ifdef _WIN64
+     CheckInterlockedOp(InterlockedXor64, LONGLONG, "0x%I64x", 0x200001234LL, 0x100001111LL, 0x300000325LL, 0x200001234LL);
+ #endif
+ }
+ START_TEST(ExInterlocked)
+ {
+     KIRQL Irql;
+     KeInitializeSpinLock(&SpinLock);
+     /* functional testing */
+     TestInterlockedFunctional();
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     TestInterlockedFunctional();
+     KeLowerIrql(Irql);
+ }
@@@ -1,50 -1,25 +1,25 @@@
  /*
-  * NTOSKRNL Pools test routines KM-Test
-  * ReactOS Kernel Mode Regression Testing framework
-  *
-  * Copyright 2008 Aleksey Bragin <aleksey@reactos.org>
-  *
-  * 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.
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Pools test routines KM-Test
+  * PROGRAMMER:      Aleksey Bragin <aleksey@reactos.org>
   */
  
- /* INCLUDES *******************************************************************/
+ /* TODO: PoolsCorruption tests fail because accessing invalid memory doesn't necessarily cause an access violation */
  
- #include <ddk/ntddk.h>
- #include <ntifs.h>
- #include <ndk/ntndk.h>
- /* SEH support with PSEH */
- #include <pseh/pseh2.h>
- #include "kmtest.h"
+ #include <kmt_test.h>
  
  #define NDEBUG
- #include "debug.h"
+ #include <debug.h>
  
  #define TAG_POOLTEST 'tstP'
  
- /* PUBLIC FUNCTIONS ***********************************************************/
- VOID
- PoolsTest(HANDLE KeyHandle)
+ static VOID PoolsTest(VOID)
  {
      PVOID Ptr;
      ULONG AllocSize, i, AllocNumber;
      PVOID *Allocs;
  
-     StartTest();
      // Stress-test nonpaged pool
      for (i=1; i<10000; i++)
      {
  
  
      ExFreePoolWithTag(Allocs, TAG_POOLTEST);
-     FinishTest(KeyHandle, L"MmPoolAllocTest");
  }
  
- VOID
- PoolsCorruption(HANDLE KeyHandle)
+ static VOID PoolsCorruption(VOID)
  {
      PULONG Ptr, TestPtr;
      ULONG AllocSize;
      NTSTATUS Status = STATUS_SUCCESS;
  
-     StartTest();
      // start with non-paged pool
      AllocSize = 4096 + 0x10;
      Ptr = ExAllocatePoolWithTag(NonPagedPool, AllocSize, TAG_POOLTEST);
  
      // free the pool
      ExFreePoolWithTag(Ptr, TAG_POOLTEST);
+ }
  
-     FinishTest(KeyHandle, L"MmPoolCorruptionTest");
+ START_TEST(ExPools)
+ {
+     PoolsTest();
+     PoolsCorruption();
  }
index 0000000,16366ab..16366ab
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,460 +1,460 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Executive Resource test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ //#define NDEBUG
+ #include <debug.h>
+ /* TODO: This is getting pretty long, make it somehow easier to read if possible */
+ /* TODO: this is the Windows Server 2003 version! ROS should use this!
+  *       This declaration can be removed once ROS headers are corrected */
+ typedef struct _ERESOURCE_2K3 {
+   LIST_ENTRY SystemResourcesList;
+   POWNER_ENTRY OwnerTable;
+   SHORT ActiveCount;
+   USHORT Flag;
+   volatile PKSEMAPHORE SharedWaiters;
+   volatile PKEVENT ExclusiveWaiters;
+   OWNER_ENTRY OwnerThreads[2];
+   ULONG ContentionCount;
+   USHORT NumberOfSharedWaiters;
+   USHORT NumberOfExclusiveWaiters;
+   _ANONYMOUS_UNION union {
+     PVOID Address;
+     ULONG_PTR CreatorBackTraceIndex;
+   } DUMMYUNIONNAME;
+   KSPIN_LOCK SpinLock;
+ } ERESOURCE_2K3, *PERESOURCE_2K3;
+ #define CheckResourceFields(Res, Reinit) do                                                                     \
+ {                                                                                                               \
+     ok_eq_pointer((Res)->SystemResourcesList.Flink->Blink, &(Res)->SystemResourcesList);                        \
+     ok_eq_pointer((Res)->SystemResourcesList.Blink->Flink, &(Res)->SystemResourcesList);                        \
+     if (!Reinit) ok_eq_pointer((Res)->OwnerTable, NULL);                                                        \
+     ok_eq_int((Res)->ActiveCount, 0);                                                                           \
+     ok_eq_uint((Res)->Flag, 0);                                                                                 \
+     if (!Reinit) ok_eq_pointer((Res)->SharedWaiters, NULL);                                                     \
+     if (!Reinit) ok_eq_pointer((Res)->ExclusiveWaiters, NULL);                                                  \
+     ok_eq_ulongptr((Res)->OwnerThreads[0].OwnerThread, 0);                                                      \
+     ok_eq_ulong((Res)->OwnerThreads[0].TableSize, 0LU);                                                         \
+     ok_eq_ulongptr((Res)->OwnerThreads[1].OwnerThread, 0);                                                      \
+     ok_eq_ulong((Res)->OwnerThreads[1].TableSize, 0LU);                                                         \
+     ok_eq_ulong((Res)->ContentionCount, 0LU);                                                                   \
+     ok_eq_uint((Res)->NumberOfSharedWaiters, 0);                                                                \
+     ok_eq_uint((Res)->NumberOfExclusiveWaiters, 0);                                                             \
+     ok_eq_pointer((Res)->Address, NULL);                                                                        \
+     ok_eq_ulongptr((Res)->SpinLock, 0);                                                                         \
+ } while (0)
+ #define CheckResourceStatus(Res, Exclusive, Shared, ExclusiveWaiters, SharedWaiters) do                         \
+ {                                                                                                               \
+     if (Exclusive)                                                                                              \
+         ok_bool_true(ExIsResourceAcquiredExclusiveLite(Res), "ExIsResourceAcquiredExclusiveLite returned");     \
+     else                                                                                                        \
+         ok_bool_false(ExIsResourceAcquiredExclusiveLite(Res), "ExIsResourceAcquiredExclusiveLite returned");    \
+     ok_eq_ulong(ExIsResourceAcquiredSharedLite(Res), Shared);                                                   \
+     ok_eq_ulong(ExGetExclusiveWaiterCount(Res), ExclusiveWaiters);                                              \
+     ok_eq_ulong(ExGetSharedWaiterCount(Res), SharedWaiters);                                                    \
+ } while (0)
+ static
+ VOID
+ TestResourceSharedAccess(
+     IN PERESOURCE Res)
+ {
+     LONG Count = 0;
+     KeEnterCriticalRegion();
+     ok_bool_true(ExAcquireResourceSharedLite(Res, FALSE), "ExAcquireResourceSharedLite returned"); ++Count;
+     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
+     ok_bool_true(ExAcquireResourceSharedLite(Res, FALSE), "ExAcquireResourceSharedLite returned"); ++Count;
+     ok_bool_true(ExAcquireResourceSharedLite(Res, TRUE), "ExAcquireResourceSharedLite returned"); ++Count;
+     ok_bool_true(ExAcquireSharedStarveExclusive(Res, FALSE), "ExAcquireSharedStarveExclusive returned"); ++Count;
+     ok_bool_true(ExAcquireSharedStarveExclusive(Res, TRUE), "ExAcquireSharedStarveExclusive returned"); ++Count;
+     ok_bool_true(ExAcquireSharedWaitForExclusive(Res, FALSE), "ExAcquireSharedWaitForExclusive returned"); ++Count;
+     ok_bool_true(ExAcquireSharedWaitForExclusive(Res, TRUE), "ExAcquireSharedWaitForExclusive returned"); ++Count;
+     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
+     /* this one fails, TRUE would deadlock */
+     ok_bool_false(ExAcquireResourceExclusiveLite(Res, FALSE), "ExAcquireResourceExclusiveLite returned");
+     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
+     /* this asserts */
+     if (!KmtIsCheckedBuild)
+         ExConvertExclusiveToSharedLite(Res);
+     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
+     while (Count--)
+         ExReleaseResourceLite(Res);
+     KeLeaveCriticalRegion();
+ }
+ static
+ VOID
+ TestResourceExclusiveAccess(
+     IN PERESOURCE Res)
+ {
+     LONG Count = 0;
+     KeEnterCriticalRegion();
+     ok_bool_true(ExAcquireResourceExclusiveLite(Res, FALSE), "ExAcquireResourceExclusiveLite returned"); ++Count;
+     CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
+     ok_bool_true(ExAcquireResourceExclusiveLite(Res, TRUE), "ExAcquireResourceExclusiveLite returned"); ++Count;
+     CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
+     ok_bool_true(ExAcquireResourceSharedLite(Res, FALSE), "ExAcquireResourceSharedLite returned"); ++Count;
+     ok_bool_true(ExAcquireResourceSharedLite(Res, TRUE), "ExAcquireResourceSharedLite returned"); ++Count;
+     ok_bool_true(ExAcquireSharedStarveExclusive(Res, FALSE), "ExAcquireSharedStarveExclusive returned"); ++Count;
+     ok_bool_true(ExAcquireSharedStarveExclusive(Res, TRUE), "ExAcquireSharedStarveExclusive returned"); ++Count;
+     ok_bool_true(ExAcquireSharedWaitForExclusive(Res, FALSE), "ExAcquireSharedWaitForExclusive returned"); ++Count;
+     ok_bool_true(ExAcquireSharedWaitForExclusive(Res, TRUE), "ExAcquireSharedWaitForExclusive returned"); ++Count;
+     CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
+     ExConvertExclusiveToSharedLite(Res);
+     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
+     while (Count--)
+         ExReleaseResourceLite(Res);
+     KeLeaveCriticalRegion();
+ }
+ static
+ VOID
+ TestResourceUndocumentedShortcuts(
+     IN PERESOURCE Res,
+     IN BOOLEAN AreApcsDisabled)
+ {
+     PVOID Ret;
+     LONG Count = 0;
+     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled);
+     /* ExEnterCriticalRegionAndAcquireResourceShared, ExEnterCriticalRegionAndAcquireSharedWaitForExclusive */
+     Count = 0;
+     Ret = ExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count;
+     ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
+     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
+     Ret = ExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count;
+     ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
+     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
+     ExEnterCriticalRegionAndAcquireSharedWaitForExclusive(Res); ++Count;
+     ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
+     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
+     while (Count-- > 1)
+     {
+         ExReleaseResourceAndLeaveCriticalRegion(Res);
+         ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+         ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+         CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
+     }
+     ExReleaseResourceAndLeaveCriticalRegion(Res);
+     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
+     /* ExEnterCriticalRegionAndAcquireResourceExclusive */
+     Count = 0;
+     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+     Ret = ExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count;
+     ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
+     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+     CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
+     Ret = ExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count;
+     ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
+     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+     CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
+     ExReleaseResourceAndLeaveCriticalRegion(Res); --Count;
+     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+     CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
+     ExReleaseResourceAndLeaveCriticalRegion(Res); --Count;
+     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled);
+     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
+ }
+ typedef BOOLEAN (NTAPI *PACQUIRE_FUNCTION)(PERESOURCE, BOOLEAN);
+ typedef struct
+ {
+     HANDLE Handle;
+     PKTHREAD Thread;
+     PERESOURCE Res;
+     KEVENT InEvent;
+     KEVENT OutEvent;
+     PACQUIRE_FUNCTION AcquireResource;
+     BOOLEAN Wait;
+     BOOLEAN RetExpected;
+ } THREAD_DATA, *PTHREAD_DATA;
+ static
+ VOID
+ NTAPI
+ AcquireResourceThread(
+     PVOID Context)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     PTHREAD_DATA ThreadData = Context;
+     BOOLEAN Ret;
+     KeEnterCriticalRegion();
+     Ret = ThreadData->AcquireResource(ThreadData->Res, ThreadData->Wait);
+     if (ThreadData->RetExpected)
+         ok_bool_true(Ret, "AcquireResource returned");
+     else
+         ok_bool_false(Ret, "AcquireResource returned");
+     ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent returned");
+     Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     if (Ret)
+         ExReleaseResource(ThreadData->Res);
+     KeLeaveCriticalRegion();
+ }
+ static
+ VOID
+ InitThreadData(
+     PTHREAD_DATA ThreadData,
+     PERESOURCE Res,
+     PACQUIRE_FUNCTION AcquireFunction)
+ {
+     ThreadData->Res = Res;
+     KeInitializeEvent(&ThreadData->InEvent, NotificationEvent, FALSE);
+     KeInitializeEvent(&ThreadData->OutEvent, NotificationEvent, FALSE);
+     ThreadData->AcquireResource = AcquireFunction;
+ }
+ static
+ NTSTATUS
+ StartThread(
+     PTHREAD_DATA ThreadData,
+     PLARGE_INTEGER Timeout,
+     BOOLEAN Wait,
+     BOOLEAN RetExpected)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     OBJECT_ATTRIBUTES Attributes;
+     ThreadData->Wait = Wait;
+     ThreadData->RetExpected = RetExpected;
+     InitializeObjectAttributes(&Attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+     Status = PsCreateSystemThread(&ThreadData->Handle, GENERIC_ALL, &Attributes, NULL, NULL, AcquireResourceThread, ThreadData);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     Status = ObReferenceObjectByHandle(ThreadData->Handle, SYNCHRONIZE, PsThreadType, KernelMode, (PVOID *)&ThreadData->Thread, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     return KeWaitForSingleObject(&ThreadData->OutEvent, Executive, KernelMode, FALSE, Timeout);
+ }
+ static
+ VOID
+ FinishThread(
+     PTHREAD_DATA ThreadData)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     KeSetEvent(&ThreadData->InEvent, 0, TRUE);
+     Status = KeWaitForSingleObject(ThreadData->Thread, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     ObDereferenceObject(ThreadData->Thread);
+     Status = ZwClose(ThreadData->Handle);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeClearEvent(&ThreadData->InEvent);
+     KeClearEvent(&ThreadData->OutEvent);
+ }
+ static
+ VOID
+ TestResourceWithThreads(
+     IN PERESOURCE Res)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     THREAD_DATA ThreadDataShared;
+     THREAD_DATA ThreadDataShared2;
+     THREAD_DATA ThreadDataExclusive;
+     THREAD_DATA ThreadDataSharedStarve;
+     THREAD_DATA ThreadDataSharedWait;
+     LARGE_INTEGER Timeout;
+     Timeout.QuadPart = -10 * 1000 * 10; /* 10 ms */
+     InitThreadData(&ThreadDataShared, Res, ExAcquireResourceSharedLite);
+     InitThreadData(&ThreadDataShared2, Res, ExAcquireResourceSharedLite);
+     InitThreadData(&ThreadDataExclusive, Res, ExAcquireResourceExclusiveLite);
+     InitThreadData(&ThreadDataSharedStarve, Res, ExAcquireSharedStarveExclusive);
+     InitThreadData(&ThreadDataSharedWait, Res, ExAcquireSharedWaitForExclusive);
+     /* have a thread acquire the resource shared */
+     Status = StartThread(&ThreadDataShared, NULL, FALSE, TRUE);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 1);
+     /* a second thread should be able to acquire the resource shared */
+     Status = StartThread(&ThreadDataShared2, NULL, FALSE, TRUE);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 2);
+     FinishThread(&ThreadDataShared2);
+     CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 1);
+     /* now have a thread that tries to acquire the resource exclusive -- it should fail */
+     Status = StartThread(&ThreadDataExclusive, NULL, FALSE, FALSE);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 1);
+     FinishThread(&ThreadDataExclusive);
+     CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 1);
+     /* as above, but this time it should block */
+     Status = StartThread(&ThreadDataExclusive, &Timeout, TRUE, TRUE);
+     ok_eq_hex(Status, STATUS_TIMEOUT);
+     CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 1);
+     /* now try another shared one -- it should fail */
+     Status = StartThread(&ThreadDataShared2, NULL, FALSE, FALSE);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 1);
+     FinishThread(&ThreadDataShared2);
+     /* same for ExAcquireSharedWaitForExclusive */
+     Status = StartThread(&ThreadDataSharedWait, NULL, FALSE, FALSE);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 1);
+     FinishThread(&ThreadDataSharedWait);
+     /* ExAcquireSharedStarveExclusive must get access though! */
+     Status = StartThread(&ThreadDataSharedStarve, NULL, TRUE, TRUE);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 2);
+     FinishThread(&ThreadDataSharedStarve);
+     CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 1);
+     /* block another shared one */
+     Status = StartThread(&ThreadDataShared2, &Timeout, TRUE, TRUE);
+     ok_eq_hex(Status, STATUS_TIMEOUT);
+     CheckResourceStatus(Res, FALSE, 0LU, 1LU, 1LU);
+     ok_eq_int(Res->ActiveCount, 1);
+     /* finish the very first one */
+     FinishThread(&ThreadDataShared);
+     /* now the blocked exclusive one should get the resource */
+     Status = KeWaitForSingleObject(&ThreadDataExclusive.OutEvent, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckResourceStatus(Res, FALSE, 0LU, 0LU, 1LU);
+     ok_eq_int(Res->ActiveCount, 1);
+     ok_eq_uint((Res->Flag & ResourceOwnedExclusive) != 0, 1);
+     FinishThread(&ThreadDataExclusive);
+     CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+     /* now the blocked shared one should resume */
+     Status = KeWaitForSingleObject(&ThreadDataShared2.OutEvent, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 1);
+     FinishThread(&ThreadDataShared2);
+     CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+     ok_eq_int(Res->ActiveCount, 0);
+ }
+ START_TEST(ExResource)
+ {
+     NTSTATUS Status;
+     ERESOURCE Res;
+     KIRQL Irql;
+     /* this must be true even with the different structure versions */
+     ASSERT(sizeof(ERESOURCE) == sizeof(ERESOURCE_2K3));
+     /* functional tests & internals */
+     Irql = KeRaiseIrqlToDpcLevel();
+       Status = ExInitializeResourceLite(&Res);
+       ok_eq_hex(Status, STATUS_SUCCESS);
+     KeLowerIrql(APC_LEVEL);
+       Status = ExDeleteResourceLite(&Res);
+       ok_eq_hex(Status, STATUS_SUCCESS);
+     KeLowerIrql(Irql);
+     memset(&Res, 0x55, sizeof Res);
+     Status = ExInitializeResourceLite(&Res);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckResourceFields((PERESOURCE_2K3)&Res, FALSE);
+     CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
+     TestResourceSharedAccess(&Res);
+     CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
+     TestResourceExclusiveAccess(&Res);
+     CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
+     TestResourceUndocumentedShortcuts(&Res, FALSE);
+     CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
+     KeRaiseIrql(APC_LEVEL, &Irql);
+       TestResourceUndocumentedShortcuts(&Res, TRUE);
+     KeLowerIrql(Irql);
+     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+     CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
+     TestResourceWithThreads(&Res);
+     /* ExReinitializeResourceLite cleans up after us */
+     Status = ExReinitializeResourceLite(&Res);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckResourceFields((PERESOURCE_2K3)&Res, TRUE);
+     CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
+     Status = ExDeleteResourceLite(&Res);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     /* parameter checks */
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         ExInitializeResourceLite(NULL);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
+     /* these bugcheck
+     ExDeleteResourceLite(NULL);
+     Status = ExDeleteResourceLite(&Res);*/
+ }
index 0000000,1fad761..1fad761
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,79 +1,79 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite sequenced singly-linked list test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ struct _SINGLE_LIST_ENTRY;
+ union _SLIST_HEADER;
+ struct _SINGLE_LIST_ENTRY *__fastcall ExInterlockedPushEntrySList(union _SLIST_HEADER *, struct _SINGLE_LIST_ENTRY *, unsigned long *);
+ struct _SINGLE_LIST_ENTRY *__fastcall ExInterlockedPopEntrySList(union _SLIST_HEADER *, unsigned long *);
+ #include <kmt_test.h>
+ /* TODO: SLIST_HEADER is a lot different for x64 */
+ #define CheckSListHeader(ListHead, ExpectedPointer, ExpectedDepth) do   \
+ {                                                                       \
+     ok_eq_pointer((ListHead)->Next.Next, ExpectedPointer);              \
+     /*ok_eq_pointer(FirstEntrySList(ListHead), ExpectedPointer);*/      \
+     ok_eq_uint((ListHead)->Depth, ExpectedDepth);                       \
+     ok_eq_uint((ListHead)->Sequence, ExpectedSequence);                 \
+     ok_eq_uint(ExQueryDepthSList(ListHead), ExpectedDepth);             \
+     ok_irql(HIGH_LEVEL);                                                \
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");     \
+ } while (0)
+ #define PXLIST_HEADER       PSLIST_HEADER
+ #define PXLIST_ENTRY        PSLIST_ENTRY
+ #define PushXList           ExInterlockedPushEntrySList
+ #define PopXList            ExInterlockedPopEntrySList
+ #define FlushXList          ExInterlockedFlushSList
+ #define ok_free_xlist       ok_eq_pointer
+ #define CheckXListHeader    CheckSListHeader
+ #define TestXListFunctional TestSListFunctional
+ #include "ExXList.h"
+ #undef ExInterlockedPushEntrySList
+ #undef ExInterlockedPopEntrySList
+ #define TestXListFunctional TestSListFunctionalExports
+ #include "ExXList.h"
+ START_TEST(ExSequencedList)
+ {
+     PSLIST_HEADER ListHead;
+     KSPIN_LOCK SpinLock;
+     USHORT ExpectedSequence = 0;
+     PKSPIN_LOCK pSpinLock = &SpinLock;
+     PCHAR Buffer;
+     PSLIST_ENTRY Entries;
+     SIZE_T EntriesSize = 5 * sizeof *Entries;
+     KIRQL Irql;
+     KeInitializeSpinLock(&SpinLock);
+ #ifdef _M_IX86
+     pSpinLock = NULL;
+ #endif
+     /* make sure stuff is as un-aligned as possible ;) */
+     Buffer = ExAllocatePoolWithTag(NonPagedPool, sizeof *ListHead + EntriesSize + 1, 'TLqS');
+     ListHead = (PVOID)&Buffer[1];
+     Entries = (PVOID)&ListHead[1];
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     RtlFillMemory(Entries, EntriesSize, 0x55);
+     RtlFillMemory(ListHead, sizeof *ListHead, 0x55);
+     InitializeSListHead(ListHead);
+     CheckSListHeader(ListHead, NULL, 0);
+     TestSListFunctional(ListHead, Entries, pSpinLock);
+     RtlFillMemory(Entries, EntriesSize, 0x55);
+     RtlFillMemory(ListHead, sizeof *ListHead, 0x55);
+     ExInitializeSListHead(ListHead);
+     CheckSListHeader(ListHead, NULL, 0);
+     TestSListFunctionalExports(ListHead, Entries, pSpinLock);
+     
+     KeLowerIrql(Irql);
+     ExFreePoolWithTag(Buffer, 'TLqS');
+ }
index 0000000,cebf265..cebf265
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,112 +1,112 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Singly-linked list test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ struct _SINGLE_LIST_ENTRY;
+ struct _SINGLE_LIST_ENTRY *__stdcall ExInterlockedPushEntryList(struct _SINGLE_LIST_ENTRY *, struct _SINGLE_LIST_ENTRY *, unsigned long *);
+ struct _SINGLE_LIST_ENTRY *__stdcall ExInterlockedPopEntryList(struct _SINGLE_LIST_ENTRY *, unsigned long *);
+ #include <kmt_test.h>
+ #define ok_eq_free2(Value, Expected) do              \
+ {                                                   \
+     if (KmtIsCheckedBuild)                          \
+         ok_eq_pointer(Value, (PVOID)0xBADDD0FF);    \
+     else                                            \
+         ok_eq_pointer(Value, Expected);             \
+ } while (0)
+ PSINGLE_LIST_ENTRY FlushList(PSINGLE_LIST_ENTRY ListHead)
+ {
+     PSINGLE_LIST_ENTRY Ret = ListHead->Next;
+     ListHead->Next = NULL;
+     return Ret;
+ }
+ USHORT QueryDepthList(PSINGLE_LIST_ENTRY ListHead)
+ {
+     USHORT Depth = 0;
+     while (ListHead->Next)
+     {
+         ++Depth;
+         ListHead = ListHead->Next;
+     }
+     return Depth;
+ }
+ PSINGLE_LIST_ENTRY PushEntryListWrapper(PSINGLE_LIST_ENTRY ListHead, PSINGLE_LIST_ENTRY Entry, PKSPIN_LOCK Lock)
+ {
+     PSINGLE_LIST_ENTRY Ret;
+     UNREFERENCED_PARAMETER(Lock);
+     Ret = ListHead->Next;
+     PushEntryList(ListHead, Entry);
+     return Ret;
+ }
+ #define CheckListHeader(ListHead, ExpectedPointer, ExpectedDepth) do    \
+ {                                                                       \
+     ok_eq_pointer((ListHead)->Next, ExpectedPointer);                   \
+     ok_eq_uint(QueryDepthList(ListHead), ExpectedDepth);                \
+     ok_irql(HIGH_LEVEL);                                                \
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");     \
+ } while (0)
+ #define PXLIST_HEADER       PSINGLE_LIST_ENTRY
+ #define PXLIST_ENTRY        PSINGLE_LIST_ENTRY
+ #define PushXList           ExInterlockedPushEntryList
+ #define PopXList            ExInterlockedPopEntryList
+ #define FlushXList          FlushList
+ #define ok_free_xlist       ok_eq_free2
+ #define CheckXListHeader    CheckListHeader
+ #define TestXListFunctional TestListFunctional
+ #include "ExXList.h"
+ #undef ExInterlockedPushEntryList
+ #undef ExInterlockedPopEntryList
+ #define TestXListFunctional TestListFunctionalExports
+ #include "ExXList.h"
+ #undef  PushXList
+ #define PushXList           PushEntryListWrapper
+ #undef  PopXList
+ #define PopXList(h, s)      PopEntryList(h)
+ #undef  ok_free_xlist
+ #define ok_free_xlist       ok_eq_pointer
+ #define TestXListFunctional TestListFunctionalNoInterlocked
+ #include "ExXList.h"
+ START_TEST(ExSingleList)
+ {
+     KSPIN_LOCK SpinLock;
+     PSINGLE_LIST_ENTRY ListHead;
+     PSINGLE_LIST_ENTRY Entries;
+     SIZE_T EntriesSize = 5 * sizeof *Entries;
+     PCHAR Buffer;
+     KIRQL Irql;
+     KeInitializeSpinLock(&SpinLock);
+     /* make sure stuff is as un-aligned as possible ;) */
+     Buffer = ExAllocatePoolWithTag(NonPagedPool, sizeof *ListHead + EntriesSize + 1, 'TLiS');
+     ListHead = (PVOID)&Buffer[1];
+     Entries = (PVOID)&ListHead[1];
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     
+     RtlFillMemory(Entries, sizeof Entries, 0x55);
+     ListHead->Next = NULL;
+     TestListFunctional(ListHead, Entries, &SpinLock);
+     RtlFillMemory(Entries, sizeof Entries, 0x55);
+     ListHead->Next = NULL;
+     TestListFunctionalExports(ListHead, Entries, &SpinLock);
+     
+     RtlFillMemory(Entries, sizeof Entries, 0x55);
+     ListHead->Next = NULL;
+     TestListFunctionalNoInterlocked(ListHead, Entries, &SpinLock);
+     
+     KeLowerIrql(Irql);
+     ExFreePoolWithTag(Buffer, 'TLiS');
+ }
@@@ -1,37 -1,16 +1,16 @@@
  /*
-  * NTOSKRNL Executive Regressions KM-Test
-  * ReactOS Kernel Mode Regression Testing framework
-  *
-  * Copyright 2006 Aleksey Bragin <aleksey@reactos.org>
-  *
-  * 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.
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Executive Regressions KM-Test
+  * PROGRAMMER:      Aleksey Bragin <aleksey@reactos.org>
   */
  
- /* INCLUDES *******************************************************************/
- #include <ddk/ntddk.h>
- #include <ntifs.h>
- #include <ndk/ntndk.h>
- #include "kmtest.h"
+ #include <kmt_test.h>
  
  #define NDEBUG
- #include "debug.h"
- /* PRIVATE FUNCTIONS ***********************************************************/
+ #include <debug.h>
  
+ static
  VOID
  NTAPI
  TestTimerApcRoutine(IN PVOID TimerContext,
      (*ApcCount)++;
  }
  
- /* PUBLIC FUNCTIONS *************************************************************/
- VOID
- ExTimerTest(HANDLE KeyHandle)
+ START_TEST(ExTimer)
  {
      UNICODE_STRING TimerName;
      OBJECT_ATTRIBUTES ObjectAttributes;
@@@ -58,8 -34,6 +34,6 @@@
      NTSTATUS Status;
      ULONG ApcCount;
  
-     StartTest();
      // Create the timer
      RtlInitUnicodeString(&TimerName, L"\\TestTimer");
      InitializeObjectAttributes(&ObjectAttributes, &TimerName, 0, NULL, NULL);
  
      Status = ZwClose(TimerHandle);
      ok(Status == STATUS_SUCCESS, "ZwClose failed with Status=0x%08lX", Status);
-     FinishTest(KeyHandle, L"ExTimerTest");
  }
index 0000000,f5928c9..f5928c9
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,91 +1,91 @@@
+ /* used by ExSingleList and ExSequencedList tests */
+ static
+ VOID
+ TestXListFunctional(
+     IN PXLIST_HEADER ListHead,
+     IN PXLIST_ENTRY Entries,
+     IN PKSPIN_LOCK pSpinLock)
+ {
+     USHORT ExpectedSequence = 0;
+     PXLIST_ENTRY Ret;
+     Ret = FlushXList(ListHead);
+     ok_eq_pointer(Ret, NULL);
+     CheckXListHeader(ListHead, NULL, 0);
+     
+     Ret = PopXList(ListHead, pSpinLock);
+     ok_eq_pointer(Ret, NULL);
+     CheckXListHeader(ListHead, NULL, 0);
+     Ret = PushXList(ListHead, &Entries[0], pSpinLock);
+     ++ExpectedSequence;
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(Entries[0].Next, NULL);
+     CheckXListHeader(ListHead, &Entries[0], 1);
+     Ret = PushXList(ListHead, &Entries[1], pSpinLock);
+     ++ExpectedSequence;
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_eq_pointer(Entries[0].Next, NULL);
+     ok_eq_pointer(Entries[1].Next, &Entries[0]);
+     CheckXListHeader(ListHead, &Entries[1], 2);
+     Ret = PopXList(ListHead, pSpinLock);
+     ok_eq_pointer(Ret, &Entries[1]);
+     ok_eq_pointer(Entries[0].Next, NULL);
+     ok_free_xlist(Entries[1].Next, &Entries[0]);
+     CheckXListHeader(ListHead, &Entries[0], 1);
+     Ret = PopXList(ListHead, pSpinLock);
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_free_xlist(Entries[0].Next, NULL);
+     ok_free_xlist(Entries[1].Next, &Entries[0]);
+     CheckXListHeader(ListHead, NULL, 0);
+     
+     Ret = PopXList(ListHead, pSpinLock);
+     ok_eq_pointer(Ret, NULL);
+     ok_free_xlist(Entries[0].Next, NULL);
+     ok_free_xlist(Entries[1].Next, &Entries[0]);
+     CheckXListHeader(ListHead, NULL, 0);
+     /* add entries again */
+     Ret = PushXList(ListHead, &Entries[0], pSpinLock);
+     ++ExpectedSequence;
+     ok_eq_pointer(Ret, NULL);
+     ok_eq_pointer(Entries[0].Next, NULL);
+     CheckXListHeader(ListHead, &Entries[0], 1);
+     Ret = PushXList(ListHead, &Entries[1], pSpinLock);
+     ++ExpectedSequence;
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_eq_pointer(Entries[0].Next, NULL);
+     ok_eq_pointer(Entries[1].Next, &Entries[0]);
+     CheckXListHeader(ListHead, &Entries[1], 2);
+     Ret = PopXList(ListHead, pSpinLock);
+     ok_eq_pointer(Ret, &Entries[1]);
+     ok_eq_pointer(Entries[0].Next, NULL);
+     ok_free_xlist(Entries[1].Next, &Entries[0]);
+     CheckXListHeader(ListHead, &Entries[0], 1);
+     Ret = PushXList(ListHead, &Entries[1], pSpinLock);
+     ++ExpectedSequence;
+     ok_eq_pointer(Ret, &Entries[0]);
+     ok_eq_pointer(Entries[0].Next, NULL);
+     ok_eq_pointer(Entries[1].Next, &Entries[0]);
+     CheckXListHeader(ListHead, &Entries[1], 2);
+     Ret = PushXList(ListHead, &Entries[2], pSpinLock);
+     ++ExpectedSequence;
+     ok_eq_pointer(Ret, &Entries[1]);
+     ok_eq_pointer(Entries[0].Next, NULL);
+     ok_eq_pointer(Entries[1].Next, &Entries[0]);
+     ok_eq_pointer(Entries[2].Next, &Entries[1]);
+     CheckXListHeader(ListHead, &Entries[2], 3);
+     Ret = FlushXList(ListHead);
+     ok_eq_pointer(Ret, &Entries[2]);
+     CheckXListHeader(ListHead, NULL, 0);
+ }
+ #undef TestXListFunctional
@@@ -1,43 -1,30 +1,30 @@@
  /*
-  * FsRtl Test
-  *
-  * Copyright 2010 Pierre Schweitzer <pierre.schweitzer@reactos.org>
-  *
-  * 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.
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite FsRtl Test
+  * PROGRAMMER:      Pierre Schweitzer <pierre.schweitzer@reactos.org>
   */
  
- /* INCLUDES *******************************************************************/
+ /* TODO: most of these calls fail the Windows checked build's !islower assertion and others */
  
- #include "kmtest.h"
- #include <ntifs.h>
+ #include <kmt_test.h>
  
  #define NDEBUG
- #include "debug.h"
+ #include <debug.h>
  
- /* PRIVATE FUNCTIONS **********************************************************/
- VOID FsRtlIsNameInExpressionTest()
+ static VOID FsRtlIsNameInExpressionTest()
  {
      UNICODE_STRING Expression, Name;
  
-     RtlInitUnicodeString(&Expression, L"*");
-     RtlInitUnicodeString(&Name, L"");
-     ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == FALSE, "expected FALSE, got TRUE");
-     RtlInitUnicodeString(&Expression, L"");
-     ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == TRUE, "expected TRUE, got FALSE");
+     /* !Name->Length || !Expression->Length asserts */
+     if (!KmtIsCheckedBuild)
+     {
+         RtlInitUnicodeString(&Expression, L"*");
+         RtlInitUnicodeString(&Name, L"");
+         ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == FALSE, "expected FALSE, got TRUE");
+         RtlInitUnicodeString(&Expression, L"");
+         ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == TRUE, "expected TRUE, got FALSE");
+     }
  
      RtlInitUnicodeString(&Expression, L"ntdll.dll");
      RtlInitUnicodeString(&Name, L".");
      RtlInitUnicodeString(&Expression, L"*.?.c.d");
      ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == TRUE, "expected TRUE, got FALSE");
      RtlInitUnicodeString(&Expression, L"*?");
-     RtlInitUnicodeString(&Name, L"");
-     ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == FALSE, "expected FALSE, got TRUE");
+     if (!KmtIsCheckedBuild)
+     {
+         RtlInitUnicodeString(&Name, L"");
+         ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == FALSE, "expected FALSE, got TRUE");
+     }
      RtlInitUnicodeString(&Name, L"a");
      ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == TRUE, "expected TRUE, got FALSE");
      RtlInitUnicodeString(&Name, L"aa");
      RtlInitUnicodeString(&Name, L"aaa");
      ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == TRUE, "expected TRUE, got FALSE");
      RtlInitUnicodeString(&Expression, L"?*?");
-     RtlInitUnicodeString(&Name, L"");
-     ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == FALSE, "expected FALSE, got TRUE");
+     if (!KmtIsCheckedBuild)
+     {
+         RtlInitUnicodeString(&Name, L"");
+         ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == FALSE, "expected FALSE, got TRUE");
+     }
      RtlInitUnicodeString(&Name, L"a");
      ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == FALSE, "expected FALSE, got TRUE");
      RtlInitUnicodeString(&Name, L"aa");
      ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == FALSE, "expected FALSE, got TRUE");
  }
  
- VOID FsRtlIsDbcsInExpressionTest()
static VOID FsRtlIsDbcsInExpressionTest()
  {
      ANSI_STRING Expression, Name;
  
-     RtlInitAnsiString(&Expression, "*");
-     RtlInitAnsiString(&Name, "");
-     ok(FsRtlIsDbcsInExpression(&Expression, &Name) == FALSE, "expected FALSE, got TRUE");
-     RtlInitAnsiString(&Expression, "");
-     ok(FsRtlIsDbcsInExpression(&Expression, &Name) == TRUE, "expected TRUE, got FALSE");
+     if (!KmtIsCheckedBuild)
+     {
+         RtlInitAnsiString(&Expression, "*");
+         RtlInitAnsiString(&Name, "");
+         ok(FsRtlIsDbcsInExpression(&Expression, &Name) == FALSE, "expected FALSE, got TRUE");
+         RtlInitAnsiString(&Expression, "");
+         ok(FsRtlIsDbcsInExpression(&Expression, &Name) == TRUE, "expected TRUE, got FALSE");
+     }
  
      RtlInitAnsiString(&Expression, "ntdll.dll");
      RtlInitAnsiString(&Name, ".");
      RtlInitAnsiString(&Expression, "*.?.c.d");
      ok(FsRtlIsDbcsInExpression(&Expression, &Name) == TRUE, "expected TRUE, got FALSE");
      RtlInitAnsiString(&Expression, "*?");
-     RtlInitAnsiString(&Name, "");
-     ok(FsRtlIsDbcsInExpression(&Expression, &Name) == FALSE, "expected FALSE, got TRUE");
+     if (!KmtIsCheckedBuild)
+     {
+         RtlInitAnsiString(&Name, "");
+         ok(FsRtlIsDbcsInExpression(&Expression, &Name) == FALSE, "expected FALSE, got TRUE");
+     }
      RtlInitAnsiString(&Name, "a");
      ok(FsRtlIsDbcsInExpression(&Expression, &Name) == TRUE, "expected TRUE, got FALSE");
      RtlInitAnsiString(&Name, "aa");
      RtlInitAnsiString(&Name, "aaa");
      ok(FsRtlIsDbcsInExpression(&Expression, &Name) == TRUE, "expected TRUE, got FALSE");
      RtlInitAnsiString(&Expression, "?*?");
-     RtlInitAnsiString(&Name, "");
-     ok(FsRtlIsDbcsInExpression(&Expression, &Name) == FALSE, "expected FALSE, got TRUE");
+     if (!KmtIsCheckedBuild)
+     {
+         RtlInitAnsiString(&Name, "");
+         ok(FsRtlIsDbcsInExpression(&Expression, &Name) == FALSE, "expected FALSE, got TRUE");
+     }
      RtlInitAnsiString(&Name, "a");
      ok(FsRtlIsDbcsInExpression(&Expression, &Name) == FALSE, "expected FALSE, got TRUE");
      RtlInitAnsiString(&Name, "aa");
      ok(FsRtlIsDbcsInExpression(&Expression, &Name) == FALSE, "expected FALSE, got TRUE");
  }
  
- /* PUBLIC FUNCTIONS ***********************************************************/
- VOID
- NtoskrnlFsRtlTest(HANDLE KeyHandle)
+ START_TEST(FsRtlExpression)
  {
-     StartTest();
      FsRtlIsNameInExpressionTest();
      FsRtlIsDbcsInExpressionTest();
-     FinishTest(KeyHandle, L"FsRtlTest");
  }
index 0000000,af43acf..af43acf
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,36 +1,36 @@@
+ include_directories(
+     ../include)
+ #
+ # IoDeviceObject
+ #
+ list(APPEND IODEVICEOBJECT_DRV_SOURCE
+     ../kmtest_drv/kmtest_standalone.c
+     IoDeviceObject_drv.c)
+ add_library(iodeviceobject_drv SHARED ${IODEVICEOBJECT_DRV_SOURCE})
+ set_module_type(iodeviceobject_drv kernelmodedriver)
+ target_link_libraries(iodeviceobject_drv kmtest_printf ${PSEH_LIB})
+ add_importlibs(iodeviceobject_drv ntoskrnl hal)
+ add_target_compile_definitions(iodeviceobject_drv KMT_STANDALONE_DRIVER)
+ #add_pch(iodeviceobject_drv ../include/kmt_test.h)
+ add_cd_file(TARGET iodeviceobject_drv DESTINATION reactos/bin FOR all)
+ #
+ # IoHelper
+ #
+ list(APPEND IOHELPER_DRV_SOURCE
+     ../kmtest_drv/kmtest_standalone.c
+     IoHelper_drv.c)
+ add_library(iohelper_drv SHARED ${IOHELPER_DRV_SOURCE})
+ set_module_type(iohelper_drv kernelmodedriver)
+ target_link_libraries(iohelper_drv kmtest_printf ${PSEH_LIB})
+ add_importlibs(iohelper_drv ntoskrnl hal)
+ add_target_compile_definitions(iohelper_drv KMT_STANDALONE_DRIVER)
+ #add_pch(iohelper_drv ../include/kmt_test.h)
+ add_cd_file(TARGET iohelper_drv DESTINATION reactos/bin FOR all)
@@@ -1,36 -1,18 +1,18 @@@
  /*
-  * PnP Test
-  * Device Interface functions test
-  *
-  * Copyright 2004 Filip Navara <xnavara@volny.cz>
-  *
-  * 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.
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Device Interface functions test
+  * PROGRAMMER:      Filip Navara <xnavara@volny.cz>
   */
  
- /* INCLUDES *******************************************************************/
+ /* TODO: what's with the prototypes at the top, what's with the if-ed out part? Doesn't process most results */
  
- #include <ddk/ntifs.h>
- #include <ndk/iotypes.h>
- #include "kmtest.h"
+ #include <kmt_test.h>
  
  #define NDEBUG
- #include "debug.h"
- /* PRIVATE FUNCTIONS **********************************************************/
+ #include <debug.h>
  
+ #if 0
  NTSTATUS
  (NTAPI *IoGetDeviceInterfaces_Func)(
     IN CONST GUID *InterfaceClassGuid,
@@@ -44,8 -26,9 +26,9 @@@ ReactOS_IoGetDeviceInterfaces
     IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
     IN ULONG Flags,
     OUT PWSTR *SymbolicLinkList);
+ #endif /* 0 */
  
- VOID DeviceInterfaceTest_Func()
static VOID DeviceInterfaceTest_Func()
  {
     NTSTATUS Status;
     PWSTR SymbolicLinkList;
     ExFreePool(SymbolicLinkList);
  }
  
VOID RegisterDI_Test(HANDLE KeyHandle)
START_TEST(IoDeviceInterface)
  {
      GUID Guid = {0x378de44c, 0x56ef, 0x11d1, {0xbc, 0x8c, 0x00, 0xa0, 0xc9, 0x14, 0x05, 0xdd}};
      DEVICE_OBJECT DeviceObject;
      UNICODE_STRING SymbolicLinkName;
      NTSTATUS Status;
  
-     StartTest();
      RtlInitUnicodeString(&SymbolicLinkName, L"");
  
      // Prepare our surrogate of a Device Object
          "IoRegisterDeviceInterface returned 0x%08lX\n", Status);
  
      DeviceInterfaceTest_Func();
-     FinishTest(KeyHandle, L"IoDeviceInterfaceTest");
  }
index 0000000,688f308..688f308
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,495 +1,495 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Driver Object Test Driver
+  * PROGRAMMER:      Michael Martin <martinmnet@hotmail.com>
+  *                  Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ //#define NDEBUG
+ #include <debug.h>
+ typedef enum
+ {
+     DriverEntry,
+     DriverIrp,
+     DriverUnload
+ } DRIVER_STATUS;
+ static DRIVER_DISPATCH TestDispatch;
+ static VOID TestDriverObject(IN PDRIVER_OBJECT DriverObject, IN DRIVER_STATUS DriverStatus);
+ static BOOLEAN TestZwLoad(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING DriverRegistryPath, IN PWCHAR NewDriverRegPath);
+ static BOOLEAN TestZwUnload(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING DriverRegistryPath, IN PWCHAR NewDriverRegPath);
+ static VOID TestLowerDeviceKernelAPI(IN PDEVICE_OBJECT DeviceObject);
+ static VOID TestDeviceCreated(IN PDEVICE_OBJECT DeviceObject, IN BOOLEAN ExclusiveAccess);
+ static VOID TestDeviceDeletion(IN PDEVICE_OBJECT DeviceObject, IN BOOLEAN Lower, IN BOOLEAN Attached);
+ static VOID TestDeviceCreateDelete(IN PDRIVER_OBJECT DriverObject);
+ static VOID TestAttachDevice(IN PDEVICE_OBJECT DeviceObject, IN PWCHAR NewDriverRegPath);
+ static VOID TestDetachDevice(IN PDEVICE_OBJECT AttachedDevice);
+ static PDEVICE_OBJECT MainDeviceObject;
+ static PDEVICE_OBJECT AttachDeviceObject;
+ static PDRIVER_OBJECT ThisDriverObject;
+ NTSTATUS
+ TestEntry(
+     IN PDRIVER_OBJECT DriverObject,
+     IN PCUNICODE_STRING RegistryPath,
+     OUT PCWSTR *DeviceName,
+     IN OUT INT *Flags)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     BOOLEAN Ret;
+     INT i;
+     PAGED_CODE();
+     UNREFERENCED_PARAMETER(DeviceName);
+     *Flags = TESTENTRY_NO_CREATE_DEVICE | TESTENTRY_NO_REGISTER_DISPATCH;
+     ThisDriverObject = DriverObject;
+     TestDriverObject(DriverObject, DriverEntry);
+     /* Create and delete device, on return MainDeviceObject has been created */
+     TestDeviceCreateDelete(DriverObject);
+     /* Make sure a device object was created */
+     if (!skip(MainDeviceObject != NULL, "Device object creation failed\n"))
+     {
+         PWCHAR LowerDriverRegPath = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Kmtest-IoHelper";
+         /* Load driver test and load the lower driver */
+         Ret = TestZwLoad(DriverObject, RegistryPath, LowerDriverRegPath);
+         if (!skip(Ret, "Failed to load helper driver\n"))
+         {
+             TestAttachDevice(MainDeviceObject, L"\\Device\\Kmtest-IoHelper");
+             if (!skip(AttachDeviceObject != NULL, "No attached device object\n"))
+                 TestLowerDeviceKernelAPI(MainDeviceObject);
+             /* Unload lower driver without detaching from its device */
+             TestZwUnload(DriverObject, RegistryPath, LowerDriverRegPath);
+             TestLowerDeviceKernelAPI(MainDeviceObject);
+         }
+     }
+     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
+         DriverObject->MajorFunction[i] = NULL;
+     DriverObject->MajorFunction[IRP_MJ_CREATE] = TestDispatch;
+     DriverObject->MajorFunction[IRP_MJ_CLOSE] = TestDispatch;
+     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TestDispatch;
+     return Status;
+ }
+ VOID
+ TestUnload(
+     IN PDRIVER_OBJECT DriverObject)
+ {
+     PAGED_CODE();
+     if (!skip(AttachDeviceObject != NULL, "no attached device object\n"))
+     {
+         TestDeviceDeletion(MainDeviceObject, FALSE, TRUE);
+         TestDeviceDeletion(AttachDeviceObject, TRUE, FALSE);
+         TestDetachDevice(AttachDeviceObject);
+     }
+     TestDeviceDeletion(MainDeviceObject, FALSE, FALSE);
+     TestDriverObject(DriverObject, DriverUnload);
+     if (MainDeviceObject)
+         IoDeleteDevice(MainDeviceObject);
+ }
+ static
+ NTSTATUS
+ NTAPI
+ TestDispatch(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     PIO_STACK_LOCATION IoStackLocation;
+     PAGED_CODE();
+     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+     DPRINT("TestIrpHandler. Function=%s, DeviceObject=%p, AttachDeviceObject=%p\n",
+         KmtMajorFunctionNames[IoStackLocation->MajorFunction],
+         DeviceObject,
+         AttachDeviceObject);
+     if (AttachDeviceObject)
+     {
+         IoSkipCurrentIrpStackLocation(Irp);
+         Status = IoCallDriver(AttachDeviceObject, Irp);
+         return Status;
+     }
+     TestDriverObject(DeviceObject->DriverObject, DriverIrp);
+     Irp->IoStatus.Status = Status;
+     Irp->IoStatus.Information = 0;
+     IoCompleteRequest(Irp, IO_NO_INCREMENT);
+     return Status;
+ }
+ static
+ VOID
+ TestDriverObject(
+     IN PDRIVER_OBJECT DriverObject,
+     IN DRIVER_STATUS DriverStatus)
+ {
+     BOOLEAN CheckThisDispatchRoutine;
+     PVOID FirstMajorFunc;
+     int i;
+     ok(DriverObject->Size == sizeof(DRIVER_OBJECT), "Size does not match, got %x\n",DriverObject->Size);
+     ok(DriverObject->Type == 4, "Type does not match 4. got %d\n", DriverObject->Type);
+     if (DriverStatus == DriverEntry)
+     {
+         ok(DriverObject->DeviceObject == NULL, "Expected DeviceObject pointer to be 0, got %p\n",
+             DriverObject->DeviceObject);
+         ok (DriverObject->Flags == DRVO_LEGACY_DRIVER,
+             "Expected Flags to be DRVO_LEGACY_DRIVER, got %lu\n",
+             DriverObject->Flags);
+     }
+     else if (DriverStatus == DriverIrp)
+     {
+         ok(DriverObject->DeviceObject != NULL, "Expected DeviceObject pointer to non null\n");
+         ok (DriverObject->Flags == (DRVO_LEGACY_DRIVER | DRVO_INITIALIZED),
+             "Expected Flags to be DRVO_LEGACY_DRIVER | DRVO_INITIALIZED, got %lu\n",
+             DriverObject->Flags);
+     }
+     else if (DriverStatus == DriverUnload)
+     {
+         ok(DriverObject->DeviceObject != NULL, "Expected DeviceObject pointer to non null\n");
+         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\n",
+             DriverObject->Flags);
+     }
+     else
+         ASSERT(FALSE);
+     /* Select a routine that was not changed */
+     FirstMajorFunc = DriverObject->MajorFunction[1];
+     ok(FirstMajorFunc != 0, "Expected MajorFunction[1] to be non NULL\n");
+     if (!skip(FirstMajorFunc != NULL, "First major function not set!\n"))
+     {
+         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\n",
+                     i, FirstMajorFunc);
+             }
+         }
+     }
+ }
+ static
+ BOOLEAN
+ TestZwLoad(
+     IN PDRIVER_OBJECT DriverObject,
+     IN PCUNICODE_STRING DriverRegistryPath,
+     IN PWCHAR NewDriverRegPath)
+ {
+     UNICODE_STRING RegPath;
+     NTSTATUS Status;
+     /* Try to load ourself */
+     Status = ZwLoadDriver((PUNICODE_STRING)DriverRegistryPath);
+     ok (Status == STATUS_IMAGE_ALREADY_LOADED, "Expected NTSTATUS STATUS_IMAGE_ALREADY_LOADED, got 0x%lX\n", 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\n", Status);
+     /* Load the driver */
+     RtlInitUnicodeString(&RegPath, NewDriverRegPath);
+     Status = ZwLoadDriver(&RegPath);
+     ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX\n", Status);
+     return NT_SUCCESS(Status);
+ }
+ static
+ BOOLEAN
+ TestZwUnload(
+     IN PDRIVER_OBJECT DriverObject,
+     IN PCUNICODE_STRING DriverRegistryPath,
+     IN PWCHAR NewDriverRegPath)
+ {
+     UNICODE_STRING RegPath;
+     NTSTATUS Status;
+     /* Try to unload ourself, which should fail as our Unload routine hasnt been set yet. */
+     Status = ZwUnloadDriver((PUNICODE_STRING)DriverRegistryPath);
+     ok (Status == STATUS_INVALID_DEVICE_REQUEST, "Expected NTSTATUS STATUS_INVALID_DEVICE_REQUEST, got 0x%lX\n", 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\n", Status);
+     /* Unload the driver */
+     RtlInitUnicodeString(&RegPath, NewDriverRegPath);
+     Status = ZwUnloadDriver(&RegPath);
+     ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX\n", Status);
+     return NT_SUCCESS(Status);
+ }
+ static
+ VOID
+ TestLowerDeviceKernelAPI(
+     IN PDEVICE_OBJECT DeviceObject)
+ {
+     PDEVICE_OBJECT RetObject;
+     RetObject = IoGetLowerDeviceObject(DeviceObject);
+     ok(RetObject == AttachDeviceObject,
+         "Expected an Attached DeviceObject %p, got %p\n", AttachDeviceObject, RetObject);
+     if (RetObject)
+     {
+         ObDereferenceObject(RetObject);
+     }
+     RetObject = IoGetDeviceAttachmentBaseRef(DeviceObject);
+     ok(RetObject == AttachDeviceObject,
+         "Expected an Attached DeviceObject %p, got %p\n", AttachDeviceObject, RetObject);
+     if (RetObject)
+     {
+         ObDereferenceObject(RetObject);
+     }
+ }
+ static
+ VOID
+ TestDeviceCreated(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN BOOLEAN ExclusiveAccess)
+ {
+     PEXTENDED_DEVOBJ_EXTENSION extdev;
+     /* Check the device object members */
+     ok(DeviceObject->Type == 3, "Expected Type = 3, got %x\n", DeviceObject->Type);
+     ok(DeviceObject->Size == 0xb8, "Expected Size = 0xb8, got %x\n", DeviceObject->Size);
+     ok(DeviceObject->ReferenceCount == 0, "Expected ReferenceCount = 0, got %lu\n",
+         DeviceObject->ReferenceCount);
+     ok(DeviceObject->DriverObject == ThisDriverObject,
+         "Expected DriverObject member to match this DriverObject %p, got %p\n",
+         ThisDriverObject, DeviceObject->DriverObject);
+     ok(DeviceObject->NextDevice == NULL, "Expected NextDevice to be NULL, got %p\n", DeviceObject->NextDevice);
+     ok(DeviceObject->AttachedDevice == NULL, "Expected AttachDevice to be NULL, got %p\n", DeviceObject->AttachedDevice);
+     ok(DeviceObject->Characteristics == 0, "Expected Characteristics to be 0\n");
+     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\n", DeviceObject->Flags);
+     }
+     else
+     {
+         ok((DeviceObject->Flags == (DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING)),
+             "Expected Flags DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING, got %lu\n", DeviceObject->Flags);
+     }
+     ok(DeviceObject->DeviceType == FILE_DEVICE_UNKNOWN,
+         "Expected DeviceType to match creation parameter FILE_DEVICE_UNKNWOWN, got %lu\n",
+         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\n", extdev->ExtensionFlags);
+     ok (extdev->Type == 13, "Expected Type of 13, got %d\n", extdev->Type);
+     ok (extdev->Size == 0, "Expected Size of 0, got %d\n", extdev->Size);
+     ok (extdev->DeviceObject == DeviceObject, "Expected DeviceOject to match newly created device %p, got %p\n",
+         DeviceObject, extdev->DeviceObject);
+     ok(extdev->AttachedTo == NULL, "Expected AttachTo to be NULL, got %p\n", extdev->AttachedTo);
+     ok(extdev->StartIoCount == 0, "Expected StartIoCount = 0, got %lu\n", extdev->StartIoCount);
+     ok(extdev->StartIoKey == 0, "Expected StartIoKey = 0, got %lu\n", extdev->StartIoKey);
+     ok(extdev->StartIoFlags == 0, "Expected StartIoFlags = 0, got %lu\n", extdev->StartIoFlags);
+ }
+ static
+ VOID
+ TestDeviceDeletion(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN BOOLEAN Lower,
+     IN BOOLEAN Attached)
+ {
+     PEXTENDED_DEVOBJ_EXTENSION extdev;
+     /* Check the device object members */
+     ok(DeviceObject->Type == 3, "Expected Type = 3, got %d\n", DeviceObject->Type);
+     ok(DeviceObject->Size == 0xb8, "Expected Size = 0xb8, got %d\n", DeviceObject->Size);
+     ok(DeviceObject->ReferenceCount == 0, "Expected ReferenceCount = 0, got %lu\n",
+         DeviceObject->ReferenceCount);
+     if (!Lower)
+     {
+         ok(DeviceObject->DriverObject == ThisDriverObject,
+             "Expected DriverObject member to match this DriverObject %p, got %p\n",
+             ThisDriverObject, DeviceObject->DriverObject);
+     }
+     ok(DeviceObject->NextDevice == NULL, "Expected NextDevice to be NULL, got %p\n", DeviceObject->NextDevice);
+     if (Lower)
+     {
+         ok(DeviceObject->AttachedDevice == MainDeviceObject,
+             "Expected AttachDevice to be %p, got %p\n", MainDeviceObject, DeviceObject->AttachedDevice);
+     }
+     else
+     {
+         ok(DeviceObject->AttachedDevice == NULL, "Expected AttachDevice to be NULL, got %p\n", DeviceObject->AttachedDevice);
+     }
+     ok(DeviceObject->Flags == (DO_DEVICE_HAS_NAME | (Lower ? DO_EXCLUSIVE : 0)),
+         "Expected Flags DO_DEVICE_HAS_NAME, got %lu\n", DeviceObject->Flags);
+     ok(DeviceObject->DeviceType == FILE_DEVICE_UNKNOWN,
+         "Expected DeviceType to match creation parameter FILE_DEVICE_UNKNWOWN, got %lu\n",
+         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\n", extdev->ExtensionFlags);
+     ok (extdev->Type == 13, "Expected Type of 13, got %d\n", extdev->Type);
+     ok (extdev->Size == 0, "Expected Size of 0, got %d\n", extdev->Size);
+     ok (extdev->DeviceObject == DeviceObject, "Expected DeviceOject to match newly created device %p, got %p\n",
+         DeviceObject, extdev->DeviceObject);
+     if (Lower || !Attached)
+     {
+         ok(extdev->AttachedTo == NULL, "Expected AttachTo to be NULL, got %p\n", extdev->AttachedTo);
+     }
+     else
+     {
+         ok(extdev->AttachedTo == AttachDeviceObject, "Expected AttachTo to %p, got %p\n", AttachDeviceObject, extdev->AttachedTo);
+     }
+     ok(extdev->StartIoCount == 0, "Expected StartIoCount = 0, got %lu\n", extdev->StartIoCount);
+     ok(extdev->StartIoKey == 0, "Expected StartIoKey = 0, got %lu\n", extdev->StartIoKey);
+     ok(extdev->StartIoFlags == 0, "Expected StartIoFlags = 0, got %lu\n", extdev->StartIoFlags);
+ }
+ static
+ VOID
+ TestDeviceCreateDelete(
+     IN PDRIVER_OBJECT DriverObject)
+ {
+     NTSTATUS Status;
+     UNICODE_STRING DeviceString;
+     PDEVICE_OBJECT DeviceObject;
+     /* Create using wrong directory */
+     RtlInitUnicodeString(&DeviceString, L"\\Device1\\Kmtest-IoDeviceObject");
+     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\n", Status);
+     /* Create using correct params with exclusice access */
+     RtlInitUnicodeString(&DeviceString, L"\\Device\\Kmtest-IoDeviceObject");
+     Status = IoCreateDevice(DriverObject,
+                             0,
+                             &DeviceString,
+                             FILE_DEVICE_UNKNOWN,
+                             0,
+                             TRUE,
+                             &DeviceObject);
+     ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX\n", Status);
+     TestDeviceCreated(DeviceObject, TRUE);
+     /* Delete the device */
+     if (NT_SUCCESS(Status))
+     {
+         IoDeleteDevice(DeviceObject);
+         ok(DriverObject->DeviceObject == 0, "Expected DriverObject->DeviceObject to be NULL, got %p\n",
+             DriverObject->DeviceObject);
+     }
+     /* Create using correct params without exclusice access */
+     Status = IoCreateDevice(DriverObject,
+                             0,
+                             &DeviceString,
+                             FILE_DEVICE_UNKNOWN,
+                             0,
+                             FALSE,
+                             &DeviceObject);
+     ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX\n", Status);
+     TestDeviceCreated(DeviceObject, FALSE);
+     /* Delete the device */
+     if (NT_SUCCESS(Status))
+     {
+         IoDeleteDevice(DeviceObject);
+         ok(DriverObject->DeviceObject == 0, "Expected DriverObject->DeviceObject to be NULL, got %p\n",
+             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\n", Status);
+     if (NT_SUCCESS(Status))
+         MainDeviceObject = DeviceObject;
+ }
+ static
+ VOID
+ TestAttachDevice(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PWCHAR NewDriverRegPath)
+ {
+     NTSTATUS Status;
+     UNICODE_STRING LowerDeviceName;
+     RtlInitUnicodeString(&LowerDeviceName, NewDriverRegPath);
+     Status = IoAttachDevice(DeviceObject, &LowerDeviceName, &AttachDeviceObject);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     /* TODO: Add more tests */
+ }
+ static
+ VOID
+ TestDetachDevice(
+     IN PDEVICE_OBJECT AttachedDevice)
+ {
+     IoDetachDevice(AttachedDevice);
+     /* TODO: Add more tests */
+ }
index 0000000,5ce1ac8..5ce1ac8
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,20 +1,20 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Driver Object test user-mode part
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ START_TEST(IoDeviceObject)
+ {
+     /* make sure IoHelper has an existing service key, but is not started */
+     KmtLoadDriver(L"IoHelper", FALSE);
+     KmtUnloadDriver();
+     KmtLoadDriver(L"IoDeviceObject", TRUE);
+     KmtOpenDriver();
+     KmtCloseDriver();
+     KmtUnloadDriver();
+ }
index 0000000,fc7b116..fc7b116
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,71 +1,71 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite I/O Test Helper driver
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ //#define NDEBUG
+ #include <debug.h>
+ static KMT_IRP_HANDLER TestIrpHandler;
+ NTSTATUS
+ TestEntry(
+     IN PDRIVER_OBJECT DriverObject,
+     IN PCUNICODE_STRING RegistryPath,
+     OUT PCWSTR *DeviceName,
+     IN OUT INT *Flags)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     INT i;
+     PAGED_CODE();
+     UNREFERENCED_PARAMETER(DriverObject);
+     UNREFERENCED_PARAMETER(RegistryPath);
+     UNREFERENCED_PARAMETER(Flags);
+     DPRINT("TestEntry. DriverObject=%p, RegistryPath=%wZ\n", DriverObject, RegistryPath);
+     *DeviceName = L"IoHelper";
+     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
+         KmtRegisterIrpHandler(i, NULL, TestIrpHandler);
+     return Status;
+ }
+ VOID
+ TestUnload(
+     IN PDRIVER_OBJECT DriverObject)
+ {
+     PAGED_CODE();
+     UNREFERENCED_PARAMETER(DriverObject);
+     DPRINT("TestUnload. DriverObject=%p\n", DriverObject);
+ }
+ static
+ NTSTATUS
+ TestIrpHandler(
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+     IN PIO_STACK_LOCATION IoStackLocation)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     DPRINT("TestIrpHandler. Function=%s, DeviceObject=%p\n",
+         KmtMajorFunctionNames[IoStackLocation->MajorFunction],
+         DeviceObject);
+     Irp->IoStatus.Status = Status;
+     Irp->IoStatus.Information = 0;
+     IoCompleteRequest(Irp, IO_NO_INCREMENT);
+     return Status;
+ }
index 0000000,0f4d8de..0f4d8de
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,95 +1,95 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Interrupt test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ #define NDEBUG
+ #include <debug.h>
+ #define CheckSpinLock(Lock, Locked) do                  \
+ {                                                       \
+     if (KmtIsMultiProcessorBuild)                       \
+         ok_eq_ulongptr(*(Lock), (Locked) != 0);         \
+     else                                                \
+         ok_eq_ulongptr(*(Lock), 0);                     \
+ } while (0)
+ typedef struct
+ {
+     BOOLEAN ReturnValue;
+     KIRQL ExpectedIrql;
+     PKINTERRUPT Interrupt;
+ } TEST_CONTEXT, *PTEST_CONTEXT;
+ static KSYNCHRONIZE_ROUTINE SynchronizeRoutine;
+ static
+ BOOLEAN
+ NTAPI
+ SynchronizeRoutine(
+     IN PVOID Context)
+ {
+     PTEST_CONTEXT TestContext = Context;
+     ok_irql(TestContext->ExpectedIrql);
+     CheckSpinLock(TestContext->Interrupt->ActualLock, TRUE);
+     return TestContext->ReturnValue;
+ }
+ static
+ VOID
+ TestSynchronizeExecution(VOID)
+ {
+     KINTERRUPT Interrupt;
+     TEST_CONTEXT TestContext;
+     KIRQL SynchIrql;
+     KIRQL OriginalIrql;
+     KIRQL Irql;
+     KSPIN_LOCK ActualLock;
+     BOOLEAN Ret;
+     RtlFillMemory(&Interrupt, sizeof Interrupt, 0x55);
+     Interrupt.ActualLock = &ActualLock;
+     KeInitializeSpinLock(Interrupt.ActualLock);
+     CheckSpinLock(Interrupt.ActualLock, FALSE);
+     TestContext.Interrupt = &Interrupt;
+     TestContext.ReturnValue = TRUE;
+     for (TestContext.ReturnValue = 0; TestContext.ReturnValue <= 2; ++TestContext.ReturnValue)
+     {
+         for (OriginalIrql = PASSIVE_LEVEL; OriginalIrql <= HIGH_LEVEL; ++OriginalIrql)
+         {
+             /* TODO: don't hardcode this :| */
+             if (OriginalIrql == 3 || (OriginalIrql >= 11 && OriginalIrql <= 26) || OriginalIrql == 30)
+                 continue;
+             KeRaiseIrql(OriginalIrql, &Irql);
+             for (SynchIrql = max(DISPATCH_LEVEL, OriginalIrql); SynchIrql <= HIGH_LEVEL; ++SynchIrql)
+             {
+                 if (SynchIrql == 3 || (SynchIrql >= 11 && SynchIrql <= 26) || SynchIrql == 30)
+                     continue;
+                 Interrupt.SynchronizeIrql = SynchIrql;
+                 ok_irql(OriginalIrql);
+                 CheckSpinLock(Interrupt.ActualLock, FALSE);
+                 TestContext.ExpectedIrql = SynchIrql;
+                 Ret = KeSynchronizeExecution(&Interrupt, SynchronizeRoutine, &TestContext);
+                 ok_eq_int(Ret, TestContext.ReturnValue);
+                 ok_irql(OriginalIrql);
+                 CheckSpinLock(Interrupt.ActualLock, FALSE);
+                 /* TODO: Check that all other fields of the interrupt are untouched */
+             }
+             KeLowerIrql(Irql);
+         }
+     }
+ }
+ START_TEST(IoInterrupt)
+ {
+     TestSynchronizeExecution();
+ }
@@@ -1,94 -1,21 +1,21 @@@
  /*
-  * NTOSKRNL Io Regressions KM-Test
-  * ReactOS Kernel Mode Regression Testing framework
-  *
-  * Copyright 2006 Aleksey Bragin <aleksey@reactos.org>
-  * Copyright 2008 Etersoft (Alexander Morozov)
-  *
-  * 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.
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Io Regressions KM-Test (Irp)
+  * PROGRAMMER:      Aleksey Bragin <aleksey@reactos.org>
   */
+ /* Based on code Copyright 2008 Etersoft (Alexander Morozov) */
  
- /* INCLUDES *******************************************************************/
- #include <ddk/ntddk.h>
- #include "kmtest.h"
+ #include <kmt_test.h>
  
  #define NDEBUG
- #include "debug.h"
- /* PUBLIC FUNCTIONS ***********************************************************/
- VOID NtoskrnlIoMdlTest(HANDLE KeyHandle)
- {
-     PMDL Mdl;
-     PIRP Irp;
-     PVOID VirtualAddress;
-     ULONG MdlSize = 2*4096+184; // 2 pages and some random value
-     StartTest();
-     // Try to alloc 2Gb MDL
-     Mdl = IoAllocateMdl(NULL, 2048UL*0x100000, FALSE, FALSE, NULL);
-     ok(Mdl == NULL,
-       "IoAllocateMdl should fail allocation of 2Gb or more, but got Mdl=0x%X",
-       (UINT_PTR)Mdl);
-     if (Mdl)
-         IoFreeMdl(Mdl);
+ #include <debug.h>
  
-     // Now create a valid MDL
-     VirtualAddress = ExAllocatePool(NonPagedPool, MdlSize);
-     Mdl = IoAllocateMdl(VirtualAddress, MdlSize, FALSE, FALSE, NULL);
-     ok(Mdl != NULL, "Mdl allocation failed");
-     // Check fields of the allocated struct
-     ok(Mdl->Next == NULL, "Mdl->Next should be NULL, but is 0x%X",
-         (UINT_PTR)Mdl->Next);
-     ok(Mdl->ByteCount == MdlSize,
-         "Mdl->ByteCount should be equal to MdlSize, but is 0x%X",
-         (UINT_PTR)Mdl->ByteCount);
-     // TODO: Check other fields of MDL struct
-     IoFreeMdl(Mdl);
-     // Allocate now with pointer to an Irp
-     Irp = IoAllocateIrp(1, FALSE);
-     ok(Irp != NULL, "IRP allocation failed");
-     Mdl = IoAllocateMdl(VirtualAddress, MdlSize, FALSE, FALSE, Irp);
-     ok(Mdl != NULL, "Mdl allocation failed");
-     ok(Irp->MdlAddress == Mdl, "Irp->MdlAddress should be 0x%X, but is 0x%X",
-         (UINT_PTR)Mdl, (UINT_PTR)Irp->MdlAddress);
-     IoFreeMdl(Mdl);
-     // TODO: Check a case when SecondaryBuffer == TRUE
-     IoFreeIrp(Irp);
-     ExFreePool(VirtualAddress);
-     FinishTest(KeyHandle, L"IoMdlTest");
- }
- VOID NtoskrnlIoIrpTest(HANDLE KeyHandle)
+ START_TEST(IoIrp)
  {
      USHORT size;
      IRP *iorp;
  
-     StartTest();
      // 1st test
      size = sizeof(IRP) + 5 * sizeof(IO_STACK_LOCATION);
      iorp = ExAllocatePool(NonPagedPool, size);
  
          IoFreeIrp(iorp);
      }
-     FinishTest(KeyHandle, L"IoIrpTest");
  }
index 0000000,898761c..898761c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,57 +1,57 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Io Regressions KM-Test (Mdl)
+  * PROGRAMMER:      Aleksey Bragin <aleksey@reactos.org>
+  */
+ #include <kmt_test.h>
+ #define NDEBUG
+ #include <debug.h>
+ START_TEST(IoMdl)
+ {
+     PMDL Mdl;
+     PIRP Irp;
+     PVOID VirtualAddress;
+     ULONG MdlSize = 2*4096+184; // 2 pages and some random value
+     // Try to alloc 2Gb MDL
+     Mdl = IoAllocateMdl(NULL, 2048UL*0x100000, FALSE, FALSE, NULL);
+     ok(Mdl == NULL,
+       "IoAllocateMdl should fail allocation of 2Gb or more, but got Mdl=0x%X",
+       (UINT_PTR)Mdl);
+     if (Mdl)
+         IoFreeMdl(Mdl);
+     // Now create a valid MDL
+     VirtualAddress = ExAllocatePool(NonPagedPool, MdlSize);
+     Mdl = IoAllocateMdl(VirtualAddress, MdlSize, FALSE, FALSE, NULL);
+     ok(Mdl != NULL, "Mdl allocation failed");
+     // Check fields of the allocated struct
+     ok(Mdl->Next == NULL, "Mdl->Next should be NULL, but is 0x%X",
+         (UINT_PTR)Mdl->Next);
+     ok(Mdl->ByteCount == MdlSize,
+         "Mdl->ByteCount should be equal to MdlSize, but is 0x%X",
+         (UINT_PTR)Mdl->ByteCount);
+     // TODO: Check other fields of MDL struct
+     IoFreeMdl(Mdl);
+     // Allocate now with pointer to an Irp
+     Irp = IoAllocateIrp(1, FALSE);
+     ok(Irp != NULL, "IRP allocation failed");
+     Mdl = IoAllocateMdl(VirtualAddress, MdlSize, FALSE, FALSE, Irp);
+     ok(Mdl != NULL, "Mdl allocation failed");
+     ok(Irp->MdlAddress == Mdl, "Irp->MdlAddress should be 0x%X, but is 0x%X",
+         (UINT_PTR)Mdl, (UINT_PTR)Irp->MdlAddress);
+     IoFreeMdl(Mdl);
+     // TODO: Check a case when SecondaryBuffer == TRUE
+     IoFreeIrp(Irp);
+     ExFreePool(VirtualAddress);
+ }
index 0000000,037d838..037d838
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,14 +1,14 @@@
+ <module name="iodeviceobject_drv" type="kernelmodedriver" installbase="bin" installname="iodeviceobject_drv.sys">
+       <include base="kmtest_drv">include</include>
+       <library>ntoskrnl</library>
+       <library>hal</library>
+       <library>pseh</library>
+       <library>kmtest_printf</library>
+       <define name="KMT_STANDALONE_DRIVER" />
+       <file>IoDeviceObject_drv.c</file>
+       <directory name="..">
+               <directory name="kmtest_drv">
+                       <file>kmtest_standalone.c</file>
+               </directory>
+       </directory>
+ </module>
index 0000000,5d0b554..5d0b554
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,14 +1,14 @@@
+ <module name="iohelper_drv" type="kernelmodedriver" installbase="bin" installname="iohelper_drv.sys">
+       <include base="kmtest_drv">include</include>
+       <library>ntoskrnl</library>
+       <library>hal</library>
+       <library>pseh</library>
+       <library>kmtest_printf</library>
+       <define name="KMT_STANDALONE_DRIVER" />
+       <file>IoHelper_drv.c</file>
+       <directory name="..">
+               <directory name="kmtest_drv">
+                       <file>kmtest_standalone.c</file>
+               </directory>
+       </directory>
+ </module>
index 0000000,3b00c53..3b00c53
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,193 +1,193 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Asynchronous Procedure Call test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ #define CheckApcs(KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, Irql) do    \
+ {                                                                                       \
+     ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled);         \
+     ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled);                            \
+     ok_eq_bool(KeAreAllApcsDisabled(), AllApcsDisabled);                                \
+     ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled);                          \
+     ok_irql(Irql);                                                                      \
+ } while (0)
+ START_TEST(KeApc)
+ {
+     KIRQL Irql;
+     PKTHREAD Thread = KeGetCurrentThread();
+     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     /* critical region */
+     KeEnterCriticalRegion();
+       CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
+       KeEnterCriticalRegion();
+         CheckApcs(-2, 0, FALSE, PASSIVE_LEVEL);
+         KeEnterCriticalRegion();
+           CheckApcs(-3, 0, FALSE, PASSIVE_LEVEL);
+         KeLeaveCriticalRegion();
+         CheckApcs(-2, 0, FALSE, PASSIVE_LEVEL);
+       KeLeaveCriticalRegion();
+       CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
+     KeLeaveCriticalRegion();
+     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     /* guarded region */
+     KeEnterGuardedRegion();
+       CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
+       KeEnterGuardedRegion();
+         CheckApcs(0, -2, TRUE, PASSIVE_LEVEL);
+         KeEnterGuardedRegion();
+           CheckApcs(0, -3, TRUE, PASSIVE_LEVEL);
+         KeLeaveGuardedRegion();
+         CheckApcs(0, -2, TRUE, PASSIVE_LEVEL);
+       KeLeaveGuardedRegion();
+       CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
+     KeLeaveGuardedRegion();
+     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     /* mix them */
+     KeEnterGuardedRegion();
+       CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
+       KeEnterCriticalRegion();
+         CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL);
+       KeLeaveCriticalRegion();
+       CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
+     KeLeaveGuardedRegion();
+     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     KeEnterCriticalRegion();
+       CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
+       KeEnterGuardedRegion();
+         CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL);
+       KeLeaveGuardedRegion();
+       CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
+     KeLeaveCriticalRegion();
+     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     /* leave without entering */
+     if (!KmtIsCheckedBuild)
+     {
+         KeLeaveCriticalRegion();
+         CheckApcs(1, 0, FALSE, PASSIVE_LEVEL);
+         KeEnterCriticalRegion();
+         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+         KeLeaveGuardedRegion();
+         CheckApcs(0, 1, TRUE, PASSIVE_LEVEL);
+         KeEnterGuardedRegion();
+         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+         KeLeaveCriticalRegion();
+         CheckApcs(1, 0, FALSE, PASSIVE_LEVEL);
+         KeLeaveGuardedRegion();
+         CheckApcs(1, 1, TRUE, PASSIVE_LEVEL);
+         KeEnterCriticalRegion();
+         CheckApcs(0, 1, TRUE, PASSIVE_LEVEL);
+         KeEnterGuardedRegion();
+         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     }
+     /* manually disable APCs */
+     Thread->KernelApcDisable = -1;
+     CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
+     Thread->SpecialApcDisable = -1;
+     CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL);
+     Thread->KernelApcDisable = 0;
+     CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
+     Thread->SpecialApcDisable = 0;
+     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     /* raised irql - APC_LEVEL should disable APCs */
+     KeRaiseIrql(APC_LEVEL, &Irql);
+       CheckApcs(0, 0, TRUE, APC_LEVEL);
+     KeLowerIrql(Irql);
+     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     /* KeAre*ApcsDisabled are documented to work up to DISPATCH_LEVEL... */
+     KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+       CheckApcs(0, 0, TRUE, DISPATCH_LEVEL);
+     KeLowerIrql(Irql);
+     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     /* ... but also work on higher levels! */
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+       CheckApcs(0, 0, TRUE, HIGH_LEVEL);
+     KeLowerIrql(Irql);
+     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     /* now comes the crazy stuff */
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+       CheckApcs(0, 0, TRUE, HIGH_LEVEL);
+       KeEnterCriticalRegion();
+         CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
+       KeLeaveCriticalRegion();
+       CheckApcs(0, 0, TRUE, HIGH_LEVEL);
+       /* Ke*GuardedRegion assert at > APC_LEVEL */
+       if (!KmtIsCheckedBuild)
+       {
+           KeEnterGuardedRegion();
+             CheckApcs(0, -1, TRUE, HIGH_LEVEL);
+           KeLeaveGuardedRegion();
+       }
+       CheckApcs(0, 0, TRUE, HIGH_LEVEL);
+     KeLowerIrql(Irql);
+     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     if (!KmtIsCheckedBuild)
+     {
+         KeRaiseIrql(HIGH_LEVEL, &Irql);
+         CheckApcs(0, 0, TRUE, HIGH_LEVEL);
+         KeEnterCriticalRegion();
+         CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
+         KeEnterGuardedRegion();
+         CheckApcs(-1, -1, TRUE, HIGH_LEVEL);
+         KeLowerIrql(Irql);
+         CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL);
+         KeLeaveCriticalRegion();
+         CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
+         KeLeaveGuardedRegion();
+         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+         KeEnterGuardedRegion();
+         CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
+         KeRaiseIrql(HIGH_LEVEL, &Irql);
+         CheckApcs(0, -1, TRUE, HIGH_LEVEL);
+         KeEnterCriticalRegion();
+         CheckApcs(-1, -1, TRUE, HIGH_LEVEL);
+         KeLeaveGuardedRegion();
+         CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
+         KeLowerIrql(Irql);
+         CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
+         KeLeaveCriticalRegion();
+         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+         KeEnterCriticalRegion();
+         CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
+         KeRaiseIrql(HIGH_LEVEL, &Irql);
+         CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
+         KeEnterGuardedRegion();
+         CheckApcs(-1, -1, TRUE, HIGH_LEVEL);
+         KeLeaveCriticalRegion();
+         CheckApcs(0, -1, TRUE, HIGH_LEVEL);
+         KeLowerIrql(Irql);
+         CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
+         KeLeaveGuardedRegion();
+         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+     }
+     KeEnterCriticalRegion();
+     CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
+     KeLeaveCriticalRegion();
+     CheckApcs(0, 0, TRUE, HIGH_LEVEL);
+     KeLowerIrql(Irql);
+     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
+ }
index 0000000,b52c0db..b52c0db
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,181 +1,181 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Deferred Procedure Call test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ //#define NDEBUG
+ #include <debug.h>
+ /* TODO: DPC importance */
+ static volatile LONG DpcCount;
+ static volatile UCHAR DpcImportance;
+ static KDEFERRED_ROUTINE DpcHandler;
+ static
+ VOID
+ NTAPI
+ DpcHandler(
+     IN PRKDPC Dpc,
+     IN PVOID DeferredContext,
+     IN PVOID SystemArgument1,
+     IN PVOID SystemArgument2)
+ {
+     PKPRCB Prcb = KeGetCurrentPrcb();
+     ok_irql(DISPATCH_LEVEL);
+     InterlockedIncrement(&DpcCount);
+     ok(DeferredContext == Dpc, "DeferredContext = %p, Dpc = %p, expected equal\n", DeferredContext, Dpc);
+     ok_eq_pointer(SystemArgument1, (PVOID)0xabc123);
+     ok_eq_pointer(SystemArgument2, (PVOID)0x5678);
+     /* KDPC object contents */
+     ok_eq_uint(Dpc->Type, DpcObject);
+     ok_eq_uint(Dpc->Importance, DpcImportance);
+     ok_eq_uint(Dpc->Number, 0);
+     ok(Dpc->DpcListEntry.Blink != NULL, "\n");
+     ok(Dpc->DpcListEntry.Blink != &Dpc->DpcListEntry, "\n");
+     if (!skip(Dpc->DpcListEntry.Blink != NULL, "DpcListEntry.Blink == NULL\n"))
+         ok_eq_pointer(Dpc->DpcListEntry.Flink, Dpc->DpcListEntry.Blink->Flink);
+     ok(Dpc->DpcListEntry.Flink != NULL, "\n");
+     ok(Dpc->DpcListEntry.Flink != &Dpc->DpcListEntry, "\n");
+     if (!skip(Dpc->DpcListEntry.Flink != NULL, "DpcListEntry.Flink == NULL\n"))
+         ok_eq_pointer(Dpc->DpcListEntry.Blink, Dpc->DpcListEntry.Flink->Blink);
+     ok_eq_pointer(Dpc->DeferredRoutine, DpcHandler);
+     ok_eq_pointer(Dpc->DeferredContext, DeferredContext);
+     ok_eq_pointer(Dpc->SystemArgument1, SystemArgument1);
+     ok_eq_pointer(Dpc->SystemArgument2, SystemArgument2);
+     ok_eq_pointer(Dpc->DpcData, NULL);
+     ok_eq_uint(Prcb->DpcRoutineActive, 1);
+     /* this DPC is not in the list anymore, but it was at the head! */
+     ok_eq_pointer(Prcb->DpcData[DPC_NORMAL].DpcListHead.Flink, Dpc->DpcListEntry.Flink);
+     ok_eq_pointer(Prcb->DpcData[DPC_NORMAL].DpcListHead.Blink, Dpc->DpcListEntry.Blink);
+ }
+ START_TEST(KeDpc)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     KDPC Dpc;
+     KIRQL Irql, Irql2, Irql3;
+     LONG ExpectedDpcCount = 0;
+     BOOLEAN Ret;
+     int i;
+     DpcCount = 0;
+     DpcImportance = MediumImportance;
+ #define ok_dpccount() ok(DpcCount == ExpectedDpcCount, "DpcCount = %ld, expected %ld\n", DpcCount, ExpectedDpcCount);
+     trace("Dpc = %p\n", &Dpc);
+     memset(&Dpc, 0x55, sizeof Dpc);
+     KeInitializeDpc(&Dpc, DpcHandler, &Dpc);
+     /* check the Dpc object's fields */
+     ok_eq_uint(Dpc.Type, DpcObject);
+     ok_eq_uint(Dpc.Importance, DpcImportance);
+     ok_eq_uint(Dpc.Number, 0);
+     ok_eq_pointer(Dpc.DpcListEntry.Flink, (LIST_ENTRY *)0x5555555555555555LL);
+     ok_eq_pointer(Dpc.DpcListEntry.Blink, (LIST_ENTRY *)0x5555555555555555LL);
+     ok_eq_pointer(Dpc.DeferredRoutine, DpcHandler);
+     ok_eq_pointer(Dpc.DeferredContext, &Dpc);
+     ok_eq_pointer(Dpc.SystemArgument1, (PVOID)0x5555555555555555LL);
+     ok_eq_pointer(Dpc.SystemArgument2, (PVOID)0x5555555555555555LL);
+     ok_eq_pointer(Dpc.DpcData, NULL);
+     /* simply run the Dpc a few times */
+     for (i = 0; i < 5; ++i)
+     {
+         ok_dpccount();
+         Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xabc123, (PVOID)0x5678);
+         ok_bool_true(Ret, "KeInsertQueueDpc returned");
+         ++ExpectedDpcCount;
+         ok_dpccount();
+     }
+     /* insert into queue at high irql
+      * -> should only run when lowered to APC_LEVEL,
+      *    inserting a second time should fail
+      */
+     KeRaiseIrql(APC_LEVEL, &Irql);
+     for (i = 0; i < 5; ++i)
+     {
+         KeRaiseIrql(DISPATCH_LEVEL, &Irql2);
+           ok_dpccount();
+           Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xabc123, (PVOID)0x5678);
+           ok_bool_true(Ret, "KeInsertQueueDpc returned");
+           Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xdef, (PVOID)0x123);
+           ok_bool_false(Ret, "KeInsertQueueDpc returned");
+           ok_dpccount();
+           KeRaiseIrql(HIGH_LEVEL, &Irql3);
+             ok_dpccount();
+           KeLowerIrql(Irql3);
+           ok_dpccount();
+         KeLowerIrql(Irql2);
+         ++ExpectedDpcCount;
+         ok_dpccount();
+     }
+     KeLowerIrql(Irql);
+     /* now test removing from the queue */
+     KeRaiseIrql(APC_LEVEL, &Irql);
+     for (i = 0; i < 5; ++i)
+     {
+         KeRaiseIrql(DISPATCH_LEVEL, &Irql2);
+           ok_dpccount();
+           Ret = KeRemoveQueueDpc(&Dpc);
+           ok_bool_false(Ret, "KeRemoveQueueDpc returned");
+           Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xabc123, (PVOID)0x5678);
+           ok_bool_true(Ret, "KeInsertQueueDpc returned");
+           ok_dpccount();
+           KeRaiseIrql(HIGH_LEVEL, &Irql3);
+             ok_dpccount();
+           KeLowerIrql(Irql3);
+           ok_dpccount();
+           Ret = KeRemoveQueueDpc(&Dpc);
+           ok_bool_true(Ret, "KeRemoveQueueDpc returned");
+         KeLowerIrql(Irql2);
+         ok_dpccount();
+     }
+     KeLowerIrql(Irql);
+     /* parameter checks */
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         KeInitializeDpc(&Dpc, NULL, NULL);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     if (!skip(Status == STATUS_SUCCESS, "KeInitializeDpc failed\n"))
+     {
+         KeRaiseIrql(HIGH_LEVEL, &Irql);
+           Ret = KeInsertQueueDpc(&Dpc, NULL, NULL);
+           ok_bool_true(Ret, "KeInsertQueueDpc returned");
+           Ret = KeRemoveQueueDpc(&Dpc);
+           ok_bool_true(Ret, "KeRemoveQueueDpc returned");
+         KeLowerIrql(Irql);
+     }
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         KeInitializeDpc(NULL, NULL, NULL);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
+     /* These result in IRQL_NOT_LESS_OR_EQUAL on 2k3 -- IRQLs 0x1f and 0xff (?)
+     Ret = KeInsertQueueDpc(NULL, NULL, NULL);
+     Ret = KeRemoveQueueDpc(NULL);*/
+     ok_dpccount();
+     ok_irql(PASSIVE_LEVEL);
+     trace("Final Dpc count: %ld, expected %ld\n", DpcCount, ExpectedDpcCount);
+ }
index 0000000,2446ef6..2446ef6
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,267 +1,267 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Event test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ /* TODO: why does GCC have 3 tests less than MSVC?! */
+ #define CheckEvent(Event, ExpectedType, State, ExpectedWaitNext,                \
+                             Irql, ThreadList, ThreadCount) do                   \
+ {                                                                               \
+     INT TheIndex;                                                               \
+     PLIST_ENTRY TheEntry;                                                       \
+     PKTHREAD TheThread;                                                         \
+     ok_eq_uint((Event)->Header.Type, ExpectedType);                             \
+     ok_eq_uint((Event)->Header.Hand, sizeof *(Event) / sizeof(ULONG));          \
+     ok_eq_hex((Event)->Header.Lock & 0xFF00FF00L, 0x55005500L);                 \
+     ok_eq_long((Event)->Header.SignalState, State);                             \
+     TheEntry = (Event)->Header.WaitListHead.Flink;                              \
+     for (TheIndex = 0; TheIndex < (ThreadCount); ++TheIndex)                    \
+     {                                                                           \
+         TheThread = CONTAINING_RECORD(TheEntry, KTHREAD,                        \
+                                         WaitBlock[0].WaitListEntry);            \
+         ok_eq_pointer(TheThread, (ThreadList)[TheIndex]);                       \
+         ok_eq_pointer(TheEntry->Flink->Blink, TheEntry);                        \
+         TheEntry = TheEntry->Flink;                                             \
+     }                                                                           \
+     ok_eq_pointer(TheEntry, &(Event)->Header.WaitListHead);                     \
+     ok_eq_pointer(TheEntry->Flink->Blink, TheEntry);                            \
+     ok_eq_long(KeReadStateEvent(Event), State);                                 \
+     ok_eq_bool(Thread->WaitNext, ExpectedWaitNext);                             \
+     ok_irql(Irql);                                                              \
+ } while (0)
+ static
+ VOID
+ TestEventFunctional(
+     IN PKEVENT Event,
+     IN EVENT_TYPE Type,
+     IN KIRQL OriginalIrql)
+ {
+     LONG State;
+     PKTHREAD Thread = KeGetCurrentThread();
+     memset(Event, 0x55, sizeof *Event);
+     KeInitializeEvent(Event, Type, FALSE);
+     CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
+     memset(Event, 0x55, sizeof *Event);
+     KeInitializeEvent(Event, Type, TRUE);
+     CheckEvent(Event, Type, 1L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
+     Event->Header.SignalState = 0x12345678L;
+     CheckEvent(Event, Type, 0x12345678L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
+     State = KePulseEvent(Event, 0, FALSE);
+     CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
+     ok_eq_long(State, 0x12345678L);
+     Event->Header.SignalState = 0x12345678L;
+     KeClearEvent(Event);
+     CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
+     State = KeSetEvent(Event, 0, FALSE);
+     CheckEvent(Event, Type, 1L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
+     ok_eq_long(State, 0L);
+     State = KeResetEvent(Event);
+     CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
+     ok_eq_long(State, 1L);
+     Event->Header.SignalState = 0x23456789L;
+     State = KeSetEvent(Event, 0, FALSE);
+     CheckEvent(Event, Type, 1L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
+     ok_eq_long(State, 0x23456789L);
+     Event->Header.SignalState = 0x3456789AL;
+     State = KeResetEvent(Event);
+     CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
+     ok_eq_long(State, 0x3456789AL);
+     /* Irql is raised to DISPATCH_LEVEL here, which kills checked build,
+      * a spinlock is acquired and never released, which kills MP build */
+     if ((OriginalIrql <= DISPATCH_LEVEL || !KmtIsCheckedBuild) &&
+         !KmtIsMultiProcessorBuild)
+     {
+         Event->Header.SignalState = 0x456789ABL;
+         State = KeSetEvent(Event, 0, TRUE);
+         CheckEvent(Event, Type, 1L, TRUE, DISPATCH_LEVEL, (PVOID *)NULL, 0);
+         ok_eq_long(State, 0x456789ABL);
+         ok_eq_uint(Thread->WaitIrql, OriginalIrql);
+         /* repair the "damage" */
+         Thread->WaitNext = FALSE;
+         KmtSetIrql(OriginalIrql);
+         Event->Header.SignalState = 0x56789ABCL;
+         State = KePulseEvent(Event, 0, TRUE);
+         CheckEvent(Event, Type, 0L, TRUE, DISPATCH_LEVEL, (PVOID *)NULL, 0);
+         ok_eq_long(State, 0x56789ABCL);
+         ok_eq_uint(Thread->WaitIrql, OriginalIrql);
+         /* repair the "damage" */
+         Thread->WaitNext = FALSE;
+         KmtSetIrql(OriginalIrql);
+     }
+     ok_irql(OriginalIrql);
+     KmtSetIrql(OriginalIrql);
+ }
+ typedef struct
+ {
+     HANDLE Handle;
+     PKTHREAD Thread;
+     PKEVENT Event;
+     volatile BOOLEAN Signal;
+ } THREAD_DATA, *PTHREAD_DATA;
+ static
+ VOID
+ NTAPI
+ WaitForEventThread(
+     IN OUT PVOID Context)
+ {
+     NTSTATUS Status;
+     PTHREAD_DATA ThreadData = Context;
+     ok_irql(PASSIVE_LEVEL);
+     ThreadData->Signal = TRUE;
+     Status = KeWaitForSingleObject(ThreadData->Event, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     ok_irql(PASSIVE_LEVEL);
+ }
+ typedef LONG (NTAPI *PSET_EVENT_FUNCTION)(PRKEVENT, KPRIORITY, BOOLEAN);
+ static
+ VOID
+ TestEventConcurrent(
+     IN PKEVENT Event,
+     IN EVENT_TYPE Type,
+     IN KIRQL OriginalIrql,
+     PSET_EVENT_FUNCTION SetEvent,
+     KPRIORITY PriorityIncrement,
+     LONG ExpectedState,
+     BOOLEAN SatisfiesAll)
+ {
+     NTSTATUS Status;
+     THREAD_DATA Threads[5];
+     const INT ThreadCount = sizeof Threads / sizeof Threads[0];
+     KPRIORITY Priority;
+     LARGE_INTEGER LongTimeout, ShortTimeout;
+     INT i;
+     KWAIT_BLOCK WaitBlock[MAXIMUM_WAIT_OBJECTS];
+     PVOID ThreadObjects[MAXIMUM_WAIT_OBJECTS];
+     LONG State;
+     PKTHREAD Thread = KeGetCurrentThread();
+     LongTimeout.QuadPart = -100 * MILLISECOND;
+     ShortTimeout.QuadPart = -1 * MILLISECOND;
+     KeInitializeEvent(Event, Type, FALSE);
+     for (i = 0; i < ThreadCount; ++i)
+     {
+         Threads[i].Event = Event;
+         Threads[i].Signal = FALSE;
+         Status = PsCreateSystemThread(&Threads[i].Handle, GENERIC_ALL, NULL, NULL, NULL, WaitForEventThread, &Threads[i]);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         Status = ObReferenceObjectByHandle(Threads[i].Handle, SYNCHRONIZE, PsThreadType, KernelMode, (PVOID *)&Threads[i].Thread, NULL);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         ThreadObjects[i] = Threads[i].Thread;
+         Priority = KeQueryPriorityThread(Threads[i].Thread);
+         ok_eq_long(Priority, 8L);
+         while (!Threads[i].Signal)
+         {
+             Status = KeDelayExecutionThread(KernelMode, FALSE, &ShortTimeout);
+             ok_eq_hex(Status, STATUS_SUCCESS);
+         }
+         CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, ThreadObjects, i + 1);
+     }
+     /* the threads shouldn't wake up on their own */
+     Status = KeDelayExecutionThread(KernelMode, FALSE, &ShortTimeout);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     for (i = 0; i < ThreadCount; ++i)
+     {
+         CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, ThreadObjects + i, ThreadCount - i);
+         State = SetEvent(Event, PriorityIncrement + i, FALSE);
+         ok_eq_long(State, 0L);
+         CheckEvent(Event, Type, ExpectedState, FALSE, OriginalIrql, ThreadObjects + i + 1, SatisfiesAll ? 0 : ThreadCount - i - 1);
+         Status = KeWaitForMultipleObjects(ThreadCount, ThreadObjects, SatisfiesAll ? WaitAll : WaitAny, Executive, KernelMode, FALSE, &LongTimeout, WaitBlock);
+         ok_eq_hex(Status, STATUS_WAIT_0 + i);
+         if (SatisfiesAll)
+         {
+             for (; i < ThreadCount; ++i)
+             {
+                 Priority = KeQueryPriorityThread(Threads[i].Thread);
+                 ok_eq_long(Priority, max(min(8L + PriorityIncrement, 15L), 8L));
+             }
+             break;
+         }
+         Priority = KeQueryPriorityThread(Threads[i].Thread);
+         ok_eq_long(Priority, max(min(8L + PriorityIncrement + i, 15L), 8L));
+         /* replace the thread with the current thread - which will never signal */
+         if (!skip((Status & 0x3F) < ThreadCount, "Index out of bounds"))
+             ThreadObjects[Status & 0x3F] = Thread;
+         Status = KeWaitForMultipleObjects(ThreadCount, ThreadObjects, WaitAny, Executive, KernelMode, FALSE, &ShortTimeout, WaitBlock);
+         ok_eq_hex(Status, STATUS_TIMEOUT);
+     }
+     for (i = 0; i < ThreadCount; ++i)
+     {
+         ObDereferenceObject(Threads[i].Thread);
+         Status = ZwClose(Threads[i].Handle);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+     }
+ }
+ START_TEST(KeEvent)
+ {
+     KEVENT Event;
+     KIRQL Irql;
+     KIRQL Irqls[] = { PASSIVE_LEVEL, APC_LEVEL, DISPATCH_LEVEL, HIGH_LEVEL };
+     INT i;
+     KPRIORITY PriorityIncrement;
+     for (i = 0; i < sizeof Irqls / sizeof Irqls[0]; ++i)
+     {
+         /* DRIVER_IRQL_NOT_LESS_OR_EQUAL (TODO: on MP only?) */
+         if (Irqls[i] > DISPATCH_LEVEL && KmtIsCheckedBuild)
+             return;
+         KeRaiseIrql(Irqls[i], &Irql);
+         TestEventFunctional(&Event, NotificationEvent, Irqls[i]);
+         TestEventFunctional(&Event, SynchronizationEvent, Irqls[i]);
+         KeLowerIrql(Irql);
+     }
+     for (i = 0; i < sizeof Irqls / sizeof Irqls[0]; ++i)
+     {
+         /* creating threads above DISPATCH_LEVEL... nope */
+         if (Irqls[i] >= DISPATCH_LEVEL && KmtIsCheckedBuild)
+             continue;
+         KeRaiseIrql(Irqls[i], &Irql);
+         trace("IRQL: %u\n", Irqls[i]);
+         for (PriorityIncrement = -1; PriorityIncrement <= 8; ++PriorityIncrement)
+         {
+             trace("PriorityIncrement: %ld\n", PriorityIncrement);
+             trace("-> Checking KeSetEvent, NotificationEvent\n");
+             TestEventConcurrent(&Event, NotificationEvent, Irqls[i], KeSetEvent, PriorityIncrement, 1, TRUE);
+             trace("-> Checking KeSetEvent, SynchronizationEvent\n");
+             TestEventConcurrent(&Event, SynchronizationEvent, Irqls[i], KeSetEvent, PriorityIncrement, 0, FALSE);
+             trace("-> Checking KePulseEvent, NotificationEvent\n");
+             TestEventConcurrent(&Event, NotificationEvent, Irqls[i], KePulseEvent, PriorityIncrement, 0, TRUE);
+             trace("-> Checking KePulseEvent, SynchronizationEvent\n");
+             TestEventConcurrent(&Event, SynchronizationEvent, Irqls[i], KePulseEvent, PriorityIncrement, 0, FALSE);
+         }
+         KeLowerIrql(Irql);
+     }
+     ok_irql(PASSIVE_LEVEL);
+     KmtSetIrql(PASSIVE_LEVEL);
+ }
index 0000000,6f4101e..6f4101e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,361 +1,361 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Guarded Mutex test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ #define NDEBUG
+ #include <debug.h>
+ #define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, ExpectedContention,     \
+                    ExpectedKernelApcDisable, ExpectedSpecialApcDisable,         \
+                    KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled,    \
+                    ExpectedIrql) do                                             \
+ {                                                                               \
+     ok_eq_long((Mutex)->Count, ExpectedCount);                                  \
+     ok_eq_pointer((Mutex)->Owner, ExpectedOwner);                               \
+     ok_eq_ulong((Mutex)->Contention, ExpectedContention);                       \
+     ok_eq_int((Mutex)->KernelApcDisable, ExpectedKernelApcDisable);             \
+     if (KmtIsCheckedBuild)                                                      \
+         ok_eq_int((Mutex)->SpecialApcDisable, ExpectedSpecialApcDisable);       \
+     else                                                                        \
+         ok_eq_int((Mutex)->SpecialApcDisable, 0x5555);                          \
+     ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \
+     ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled);                    \
+     ok_eq_bool(KeAreAllApcsDisabled(), AllApcsDisabled);                        \
+     ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled);                  \
+     ok_irql(ExpectedIrql);                                                      \
+ } while (0)
+ static
+ VOID
+ TestGuardedMutex(
+     PKGUARDED_MUTEX Mutex,
+     SHORT KernelApcsDisabled,
+     SHORT SpecialApcsDisabled,
+     SHORT AllApcsDisabled,
+     KIRQL OriginalIrql)
+ {
+     PKTHREAD Thread = KeGetCurrentThread();
+     ok_irql(OriginalIrql);
+     CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, 0x5555, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
+     /* these ASSERT */
+     if (!KmtIsCheckedBuild || OriginalIrql <= APC_LEVEL)
+     {
+         /* acquire/release normally */
+         KeAcquireGuardedMutex(Mutex);
+         CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
+         ok_bool_false(KeTryToAcquireGuardedMutex(Mutex), "KeTryToAcquireGuardedMutex returned");
+         CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
+         KeReleaseGuardedMutex(Mutex);
+         CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
+         /* try to acquire */
+         ok_bool_true(KeTryToAcquireGuardedMutex(Mutex), "KeTryToAcquireGuardedMutex returned");
+         CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
+         KeReleaseGuardedMutex(Mutex);
+         CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
+     }
+     else
+         /* Make the following test happy */
+         Mutex->SpecialApcDisable = SpecialApcsDisabled - 1;
+     /* ASSERT */
+     if (!KmtIsCheckedBuild || OriginalIrql == APC_LEVEL || SpecialApcsDisabled < 0)
+     {
+         /* acquire/release unsafe */
+         KeAcquireGuardedMutexUnsafe(Mutex);
+         CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
+         KeReleaseGuardedMutexUnsafe(Mutex);
+         CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
+     }
+     /* Bugchecks >= DISPATCH_LEVEL */
+     if (!KmtIsCheckedBuild)
+     {
+         /* mismatched acquire/release */
+         KeAcquireGuardedMutex(Mutex);
+         CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
+         KeReleaseGuardedMutexUnsafe(Mutex);
+         CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
+         KeLeaveGuardedRegion();
+         CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
+         KeAcquireGuardedMutexUnsafe(Mutex);
+         CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
+         KeReleaseGuardedMutex(Mutex);
+         CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled + 1, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -1, OriginalIrql);
+         KeEnterGuardedRegion();
+         CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
+         /* release without acquire */
+         KeReleaseGuardedMutexUnsafe(Mutex);
+         CheckMutex(Mutex, 0L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
+         KeReleaseGuardedMutex(Mutex);
+         CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 1, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -1, OriginalIrql);
+         KeReleaseGuardedMutex(Mutex);
+         /* TODO: here we see that Mutex->Count isn't actually just a count. Test the bits correctly! */
+         CheckMutex(Mutex, 0L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 2, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -2, OriginalIrql);
+         KeReleaseGuardedMutex(Mutex);
+         CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 3, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -3, OriginalIrql);
+         Thread->SpecialApcDisable -= 3;
+     }
+     /* make sure we survive this in case of error */
+     ok_eq_long(Mutex->Count, 1L);
+     Mutex->Count = 1;
+     ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled);
+     Thread->KernelApcDisable = KernelApcsDisabled;
+     ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled);
+     Thread->SpecialApcDisable = SpecialApcsDisabled;
+     ok_irql(OriginalIrql);
+ }
+ typedef VOID (FASTCALL *PMUTEX_FUNCTION)(PKGUARDED_MUTEX);
+ typedef BOOLEAN (FASTCALL *PMUTEX_TRY_FUNCTION)(PKGUARDED_MUTEX);
+ typedef struct
+ {
+     HANDLE Handle;
+     PKTHREAD Thread;
+     KIRQL Irql;
+     PKGUARDED_MUTEX Mutex;
+     PMUTEX_FUNCTION Acquire;
+     PMUTEX_TRY_FUNCTION TryAcquire;
+     PMUTEX_FUNCTION Release;
+     BOOLEAN Try;
+     BOOLEAN RetExpected;
+     KEVENT InEvent;
+     KEVENT OutEvent;
+ } THREAD_DATA, *PTHREAD_DATA;
+ static
+ VOID
+ NTAPI
+ AcquireMutexThread(
+     PVOID Parameter)
+ {
+     PTHREAD_DATA ThreadData = Parameter;
+     KIRQL Irql;
+     BOOLEAN Ret = FALSE;
+     NTSTATUS Status;
+     DPRINT("Thread starting\n");
+     KeRaiseIrql(ThreadData->Irql, &Irql);
+     if (ThreadData->Try)
+     {
+         Ret = ThreadData->TryAcquire(ThreadData->Mutex);
+         ok_eq_bool(Ret, ThreadData->RetExpected);
+     }
+     else
+         ThreadData->Acquire(ThreadData->Mutex);
+     ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent returned");
+     DPRINT("Thread now waiting\n");
+     Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode, FALSE, NULL);
+     DPRINT("Thread done waiting\n");
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     if (!ThreadData->Try || Ret)
+         ThreadData->Release(ThreadData->Mutex);
+     KeLowerIrql(Irql);
+     DPRINT("Thread exiting\n");
+ }
+ static
+ VOID
+ InitThreadData(
+     PTHREAD_DATA ThreadData,
+     PKGUARDED_MUTEX Mutex,
+     PMUTEX_FUNCTION Acquire,
+     PMUTEX_TRY_FUNCTION TryAcquire,
+     PMUTEX_FUNCTION Release)
+ {
+     ThreadData->Mutex = Mutex;
+     KeInitializeEvent(&ThreadData->InEvent, NotificationEvent, FALSE);
+     KeInitializeEvent(&ThreadData->OutEvent, NotificationEvent, FALSE);
+     ThreadData->Acquire = Acquire;
+     ThreadData->TryAcquire = TryAcquire;
+     ThreadData->Release = Release;
+ }
+ static
+ NTSTATUS
+ StartThread(
+     PTHREAD_DATA ThreadData,
+     PLARGE_INTEGER Timeout,
+     KIRQL Irql,
+     BOOLEAN Try,
+     BOOLEAN RetExpected)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     OBJECT_ATTRIBUTES Attributes;
+     ThreadData->Try = Try;
+     ThreadData->Irql = Irql;
+     ThreadData->RetExpected = RetExpected;
+     InitializeObjectAttributes(&Attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+     Status = PsCreateSystemThread(&ThreadData->Handle, GENERIC_ALL, &Attributes, NULL, NULL, AcquireMutexThread, ThreadData);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     Status = ObReferenceObjectByHandle(ThreadData->Handle, SYNCHRONIZE, PsThreadType, KernelMode, (PVOID *)&ThreadData->Thread, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     return KeWaitForSingleObject(&ThreadData->OutEvent, Executive, KernelMode, FALSE, Timeout);
+ }
+ static
+ VOID
+ FinishThread(
+     PTHREAD_DATA ThreadData)
+ {
+     NTSTATUS Status = STATUS_SUCCESS;
+     KeSetEvent(&ThreadData->InEvent, 0, TRUE);
+     Status = KeWaitForSingleObject(ThreadData->Thread, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     ObDereferenceObject(ThreadData->Thread);
+     Status = ZwClose(ThreadData->Handle);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeClearEvent(&ThreadData->InEvent);
+     KeClearEvent(&ThreadData->OutEvent);
+ }
+ static
+ VOID
+ TestGuardedMutexConcurrent(
+     PKGUARDED_MUTEX Mutex)
+ {
+     NTSTATUS Status;
+     THREAD_DATA ThreadData;
+     THREAD_DATA ThreadData2;
+     THREAD_DATA ThreadDataUnsafe;
+     THREAD_DATA ThreadDataTry;
+     PKTHREAD Thread = KeGetCurrentThread();
+     LARGE_INTEGER Timeout;
+     Timeout.QuadPart = -10 * 1000 * 10; /* 10 ms */
+     InitThreadData(&ThreadData, Mutex, KeAcquireGuardedMutex, NULL, KeReleaseGuardedMutex);
+     InitThreadData(&ThreadData2, Mutex, KeAcquireGuardedMutex, NULL, KeReleaseGuardedMutex);
+     InitThreadData(&ThreadDataUnsafe, Mutex, KeAcquireGuardedMutexUnsafe, NULL, KeReleaseGuardedMutexUnsafe);
+     InitThreadData(&ThreadDataTry, Mutex, NULL, KeTryToAcquireGuardedMutex, KeReleaseGuardedMutex);
+     /* have a thread acquire the mutex */
+     Status = StartThread(&ThreadData, NULL, PASSIVE_LEVEL, FALSE, FALSE);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckMutex(Mutex, 0L, ThreadData.Thread, 0LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL);
+     /* have a second thread try to acquire it -- should fail */
+     Status = StartThread(&ThreadDataTry, NULL, PASSIVE_LEVEL, TRUE, FALSE);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckMutex(Mutex, 0L, ThreadData.Thread, 0LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL);
+     FinishThread(&ThreadDataTry);
+     /* have another thread acquire it -- should block */
+     Status = StartThread(&ThreadData2, &Timeout, APC_LEVEL, FALSE, FALSE);
+     ok_eq_hex(Status, STATUS_TIMEOUT);
+     CheckMutex(Mutex, 4L, ThreadData.Thread, 1LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL);
+     /* finish the first thread -- now the second should become available */
+     FinishThread(&ThreadData);
+     Status = KeWaitForSingleObject(&ThreadData2.OutEvent, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckMutex(Mutex, 0L, ThreadData2.Thread, 1LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL);
+     /* block two more threads */
+     Status = StartThread(&ThreadDataUnsafe, &Timeout, APC_LEVEL, FALSE, FALSE);
+     ok_eq_hex(Status, STATUS_TIMEOUT);
+     CheckMutex(Mutex, 4L, ThreadData2.Thread, 2LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL);
+     Status = StartThread(&ThreadData, &Timeout, PASSIVE_LEVEL, FALSE, FALSE);
+     ok_eq_hex(Status, STATUS_TIMEOUT);
+     CheckMutex(Mutex, 8L, ThreadData2.Thread, 3LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL);
+     /* finish 1 */
+     FinishThread(&ThreadData2);
+     Status = KeWaitForSingleObject(&ThreadDataUnsafe.OutEvent, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckMutex(Mutex, 4L, ThreadDataUnsafe.Thread, 3LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL);
+     /* finish 2 */
+     FinishThread(&ThreadDataUnsafe);
+     Status = KeWaitForSingleObject(&ThreadData.OutEvent, Executive, KernelMode, FALSE, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckMutex(Mutex, 0L, ThreadData.Thread, 3LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL);
+     /* finish 3 */
+     FinishThread(&ThreadData);
+     CheckMutex(Mutex, 1L, NULL, 3LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL);
+ }
+ START_TEST(KeGuardedMutex)
+ {
+     KGUARDED_MUTEX Mutex;
+     KIRQL OldIrql;
+     PKTHREAD Thread = KeGetCurrentThread();
+     struct {
+         KIRQL Irql;
+         SHORT KernelApcsDisabled;
+         SHORT SpecialApcsDisabled;
+         BOOLEAN AllApcsDisabled;
+     } TestIterations[] =
+     {
+         { PASSIVE_LEVEL,   0,  0, FALSE },
+         { PASSIVE_LEVEL,  -1,  0, FALSE },
+         { PASSIVE_LEVEL,  -3,  0, FALSE },
+         { PASSIVE_LEVEL,   0, -1, TRUE },
+         { PASSIVE_LEVEL,  -1, -1, TRUE },
+         { PASSIVE_LEVEL,  -3, -2, TRUE },
+         // 6
+         { APC_LEVEL,       0,  0, TRUE },
+         { APC_LEVEL,      -1,  0, TRUE },
+         { APC_LEVEL,      -3,  0, TRUE },
+         { APC_LEVEL,       0, -1, TRUE },
+         { APC_LEVEL,      -1, -1, TRUE },
+         { APC_LEVEL,      -3, -2, TRUE },
+         // 12
+         { DISPATCH_LEVEL,  0,  0, TRUE },
+         { DISPATCH_LEVEL, -1,  0, TRUE },
+         { DISPATCH_LEVEL, -3,  0, TRUE },
+         { DISPATCH_LEVEL,  0, -1, TRUE },
+         { DISPATCH_LEVEL, -1, -1, TRUE },
+         { DISPATCH_LEVEL, -3, -2, TRUE },
+         // 18
+         { HIGH_LEVEL,      0,  0, TRUE },
+         { HIGH_LEVEL,     -1,  0, TRUE },
+         { HIGH_LEVEL,     -3,  0, TRUE },
+         { HIGH_LEVEL,      0, -1, TRUE },
+         { HIGH_LEVEL,     -1, -1, TRUE },
+         { HIGH_LEVEL,     -3, -2, TRUE },
+     };
+     int i;
+     for (i = 0; i < sizeof TestIterations / sizeof TestIterations[0]; ++i)
+     {
+         trace("Run %d\n", i);
+         KeRaiseIrql(TestIterations[i].Irql, &OldIrql);
+         Thread->KernelApcDisable = TestIterations[i].KernelApcsDisabled;
+         Thread->SpecialApcDisable = TestIterations[i].SpecialApcsDisabled;
+         RtlFillMemory(&Mutex, sizeof Mutex, 0x55);
+         KeInitializeGuardedMutex(&Mutex);
+         CheckMutex(&Mutex, 1L, NULL, 0LU, 0x5555, 0x5555, TestIterations[i].KernelApcsDisabled, TestIterations[i].SpecialApcsDisabled, TestIterations[i].AllApcsDisabled, TestIterations[i].Irql);
+         TestGuardedMutex(&Mutex, TestIterations[i].KernelApcsDisabled, TestIterations[i].SpecialApcsDisabled, TestIterations[i].AllApcsDisabled, TestIterations[i].Irql);
+         Thread->SpecialApcDisable = 0;
+         Thread->KernelApcDisable = 0;
+         KeLowerIrql(OldIrql);
+     }
+     trace("Concurrent test\n");
+     RtlFillMemory(&Mutex, sizeof Mutex, 0x55);
+     KeInitializeGuardedMutex(&Mutex);
+     TestGuardedMutexConcurrent(&Mutex);
+ }
index 0000000,27c4d36..27c4d36
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,147 +1,147 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Interrupt Request Level test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ __declspec(dllimport) void __stdcall KeRaiseIrql(unsigned char, unsigned char *);
+ __declspec(dllimport) void __stdcall KeLowerIrql(unsigned char);
+ #include <kmt_test.h>
+ #define NDEBUG
+ #include <debug.h>
+ START_TEST(KeIrql)
+ {
+     KIRQL Irql, Irql2, PrevIrql, SynchIrql;
+     /* we should be called at PASSIVE_LEVEL */
+     ok_irql(PASSIVE_LEVEL);
+     PrevIrql = KeGetCurrentIrql();
+     /* SYNCH_LEVEL is different for UP/MP */
+     if (KmtIsMultiProcessorBuild)
+         SynchIrql = IPI_LEVEL - 2;
+     else
+         SynchIrql = DISPATCH_LEVEL;
+     /* some Irqls MUST work */
+     {
+     const KIRQL Irqls[] = { LOW_LEVEL, PASSIVE_LEVEL, APC_LEVEL, DISPATCH_LEVEL,
+                             CMCI_LEVEL, CLOCK1_LEVEL, CLOCK2_LEVEL, CLOCK_LEVEL,
+                             PROFILE_LEVEL, IPI_LEVEL, /*POWER_LEVEL,*/ SynchIrql, HIGH_LEVEL };
+     int i;
+     for (i = 0; i < sizeof Irqls / sizeof Irqls[0]; ++i)
+     {
+         KeRaiseIrql(Irqls[i], &Irql2);
+         ok_eq_uint(Irql2, PrevIrql);
+         ok_irql(Irqls[i]);
+         KeLowerIrql(Irql2);
+         ok_irql(PrevIrql);
+     }
+     }
+     /* raising/lowering to the current level should have no effect */
+     ok_irql(PASSIVE_LEVEL);
+     KeRaiseIrql(PASSIVE_LEVEL, &Irql);
+     ok_eq_uint(Irql, PASSIVE_LEVEL);
+     KeLowerIrql(PASSIVE_LEVEL);
+     ok_irql(PASSIVE_LEVEL);
+     /* try to raise to each Irql and back */
+     for (Irql = PASSIVE_LEVEL; Irql <= HIGH_LEVEL; ++Irql)
+     {
+         DPRINT("Raising to %u\n", Irql);
+         KeRaiseIrql(Irql, &Irql2);
+         ok_eq_uint(Irql2, PrevIrql);
+         KeLowerIrql(Irql2);
+         ok_irql(PrevIrql);
+     }
+     /* go through all Irqls in order, skip the ones that the system doesn't accept */
+     for (Irql = PASSIVE_LEVEL; Irql <= HIGH_LEVEL; ++Irql)
+     {
+         DPRINT("Raising to %u\n", Irql);
+         KeRaiseIrql(Irql, &Irql2);
+         ok_eq_uint(Irql2, PrevIrql);
+         Irql2 = KeGetCurrentIrql();
+         ok(Irql2 <= Irql, "New Irql is %u, expected <= requested value of %u\n", Irql2, Irql);
+         PrevIrql = Irql2;
+     }
+     ok_irql(HIGH_LEVEL);
+     /* now go back again, skipping the ones that don't work */
+     for (Irql = HIGH_LEVEL; Irql > PASSIVE_LEVEL;)
+     {
+         DPRINT("Lowering to %u\n", Irql - 1);
+         KeLowerIrql(Irql - 1);
+         Irql2 = KeGetCurrentIrql();
+         ok(Irql2 < Irql, "New Irql is %u, expected <= requested value of %u\n", Irql2, Irql - 1);
+         if (Irql2 < Irql)
+             Irql = Irql2;
+         else
+             --Irql;
+     }
+     DPRINT("Alive!\n");
+     /* on x86, you can raise to _any_ possible KIRQL value */
+     /* on x64, anything with more than the least significant 4 bits set bugchecked, last time I tried */
+     /* TODO: other platforms? */
+ #if defined _M_X86
+     for (Irql = PASSIVE_LEVEL; Irql <= (KIRQL)-1; ++Irql)
+     {
+         DPRINT("Raising to %u\n", Irql);
+         KeRaiseIrql(Irql, &Irql2);
+         ok_eq_uint(Irql2, PrevIrql);
+         KeLowerIrql(Irql2);
+         ok_irql(PrevIrql);
+     }
+ #endif /* defined _M_X86 */
+     /* test KeRaiseIrqlToDpcLevel */
+     ok_irql(PASSIVE_LEVEL);
+     Irql = KeRaiseIrqlToDpcLevel();
+     ok_irql(DISPATCH_LEVEL);
+     ok_eq_uint(Irql, PASSIVE_LEVEL);
+     Irql = KeRaiseIrqlToDpcLevel();
+     ok_irql(DISPATCH_LEVEL);
+     ok_eq_uint(Irql, DISPATCH_LEVEL);
+     KeLowerIrql(PASSIVE_LEVEL);
+     /* test KeRaiseIrqlToSynchLevel */
+     ok_irql(PASSIVE_LEVEL);
+     Irql = KeRaiseIrqlToSynchLevel();
+     ok_irql(SynchIrql);
+     ok_eq_uint(Irql, PASSIVE_LEVEL);
+     Irql = KeRaiseIrqlToSynchLevel();
+     ok_irql(SynchIrql);
+     ok_eq_uint(Irql, SynchIrql);
+     KeLowerIrql(PASSIVE_LEVEL);
+     /* these bugcheck on a checked build but run fine on free! */
+     if (!KmtIsCheckedBuild)
+     {
+         KeRaiseIrql(HIGH_LEVEL, &Irql);
+         KeRaiseIrql(APC_LEVEL, &Irql);
+         ok_irql(APC_LEVEL);
+         KeLowerIrql(HIGH_LEVEL);
+         ok_irql(HIGH_LEVEL);
+         KeLowerIrql(PASSIVE_LEVEL);
+     }
+     /* try the actual exports, not only the fastcall versions */
+     ok_irql(PASSIVE_LEVEL);
+     (KeRaiseIrql)(HIGH_LEVEL, &Irql);
+     ok_irql(HIGH_LEVEL);
+     ok_eq_uint(Irql, PASSIVE_LEVEL);
+     (KeLowerIrql)(Irql);
+     ok_irql(PASSIVE_LEVEL);
+     /* make sure we exit gracefully */
+     ok_irql(PASSIVE_LEVEL);
+     KeLowerIrql(PASSIVE_LEVEL);
+ }
@@@ -1,45 -1,22 +1,22 @@@
  /*
-  * NTOSKRNL Executive Regressions KM-Test
-  * ReactOS Kernel Mode Regression Testing framework
-  *
-  * Copyright 2006 Aleksey Bragin <aleksey@reactos.org>
-  *
-  * 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.
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Executive Regressions KM-Test
+  * PROGRAMMER:      Aleksey Bragin <aleksey@reactos.org>
   */
  
- /* INCLUDES *******************************************************************/
+ /* TODO: this test doesn't process any test results; it also takes very long */
  
- #include <ddk/ntddk.h>
- #include <ntifs.h>
- #include <ndk/ntndk.h>
- #include "kmtest.h"
+ #include <kmt_test.h>
  
  #define NDEBUG
- #include "debug.h"
+ #include <debug.h>
  
- /* PUBLIC FUNCTIONS ***********************************************************/
- VOID
- KeStallTest(HANDLE KeyHandle)
+ static VOID KeStallExecutionProcessorTest(VOID)
  {
      ULONG i;
      LARGE_INTEGER TimeStart, TimeFinish;
  
-     StartTest();
      DPRINT1("Waiting for 30 secs with 50us stalls...\n");
      KeQuerySystemTime(&TimeStart);
      for (i = 0; i < (30*1000*20); i++)
@@@ -72,6 -49,9 +49,9 @@@
      KeStallExecutionProcessor(30*1000000);
      KeQuerySystemTime(&TimeFinish);
      DPRINT1("Time elapsed: %d secs\n", (TimeFinish.QuadPart - TimeStart.QuadPart) / 10000000); // 30
-     FinishTest(KeyHandle, L"KeStallmanExecutionTest");
  }
+ START_TEST(KeProcessor)
+ {
+     KeStallExecutionProcessorTest();
+ }
index 0000000,79e799b..79e799b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,364 +1,364 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Spin lock test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #ifndef _WIN64
+ __declspec(dllimport) void __stdcall KeAcquireSpinLock(unsigned long *, unsigned char *);
+ __declspec(dllimport) void __stdcall KeReleaseSpinLock(unsigned long *, unsigned char);
+ __declspec(dllimport) void __stdcall KeAcquireSpinLockAtDpcLevel(unsigned long *);
+ __declspec(dllimport) void __stdcall KeReleaseSpinLockFromDpcLevel(unsigned long *);
+ #endif
+ /* this define makes KeInitializeSpinLock not use the inlined version */
+ #define WIN9X_COMPAT_SPINLOCK
+ #include <kmt_test.h>
+ #include <limits.h>
+ //#define NDEBUG
+ #include <debug.h>
+ /* TODO: these are documented for Vista+ */
+ NTKERNELAPI
+ VOID
+ FASTCALL
+ KeAcquireInStackQueuedSpinLockForDpc(
+   IN OUT PKSPIN_LOCK SpinLock,
+   OUT PKLOCK_QUEUE_HANDLE LockHandle);
+ NTKERNELAPI
+ VOID
+ FASTCALL
+ KeReleaseInStackQueuedSpinLockForDpc(
+   IN PKLOCK_QUEUE_HANDLE LockHandle);
+ /* TODO: multiprocessor testing */
+ struct _CHECK_DATA;
+ typedef struct _CHECK_DATA CHECK_DATA, *PCHECK_DATA;
+ typedef VOID (*PACQUIRE_FUNCTION)(PKSPIN_LOCK, PCHECK_DATA);
+ typedef VOID (*PRELEASE_FUNCTION)(PKSPIN_LOCK, PCHECK_DATA);
+ typedef BOOLEAN (*PTRY_FUNCTION)(PKSPIN_LOCK, PCHECK_DATA);
+ struct _CHECK_DATA
+ {
+     enum
+     {
+         CheckQueueHandle,
+         CheckQueue,
+         CheckLock
+     } Check;
+     KIRQL IrqlWhenAcquired;
+     PACQUIRE_FUNCTION Acquire;
+     PRELEASE_FUNCTION Release;
+     PTRY_FUNCTION TryAcquire;
+     PACQUIRE_FUNCTION AcquireNoRaise;
+     PRELEASE_FUNCTION ReleaseNoLower;
+     PTRY_FUNCTION TryAcquireNoRaise;
+     KSPIN_LOCK_QUEUE_NUMBER QueueNumber;
+     BOOLEAN TryRetOnFailure;
+     KIRQL OriginalIrql;
+     BOOLEAN IsAcquired;
+     _ANONYMOUS_UNION union
+     {
+         KLOCK_QUEUE_HANDLE QueueHandle;
+         PKSPIN_LOCK_QUEUE Queue;
+         KIRQL Irql;
+     } DUMMYUNIONNAME;
+     PVOID UntouchedValue;
+ };
+ #define DEFINE_ACQUIRE(LocalName, SetIsAcquired, DoCall)            \
+ static VOID LocalName(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData)  \
+ {                                                                   \
+     ASSERT(!CheckData->IsAcquired);                                 \
+     DoCall;                                                         \
+     if (SetIsAcquired) CheckData->IsAcquired = TRUE;                \
+ }
+ #define DEFINE_RELEASE(LocalName, SetIsAcquired, DoCall)            \
+ static VOID LocalName(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData)  \
+ {                                                                   \
+     DoCall;                                                         \
+     if (SetIsAcquired) CheckData->IsAcquired = FALSE;               \
+ }
+ DEFINE_ACQUIRE(AcquireNormal,         TRUE,  KeAcquireSpinLock(SpinLock, &CheckData->Irql))
+ DEFINE_RELEASE(ReleaseNormal,         TRUE,  KeReleaseSpinLock(SpinLock, CheckData->Irql))
+ DEFINE_ACQUIRE(AcquireExp,            TRUE,  (KeAcquireSpinLock)(SpinLock, &CheckData->Irql))
+ DEFINE_RELEASE(ReleaseExp,            TRUE,  (KeReleaseSpinLock)(SpinLock, CheckData->Irql))
+ DEFINE_ACQUIRE(AcquireSynch,          TRUE,  CheckData->Irql = KeAcquireSpinLockRaiseToSynch(SpinLock))
+ DEFINE_ACQUIRE(AcquireInStackQueued,  TRUE,  KeAcquireInStackQueuedSpinLock(SpinLock, &CheckData->QueueHandle))
+ DEFINE_ACQUIRE(AcquireInStackSynch,   TRUE,  KeAcquireInStackQueuedSpinLockRaiseToSynch(SpinLock, &CheckData->QueueHandle))
+ DEFINE_RELEASE(ReleaseInStackQueued,  TRUE,  KeReleaseInStackQueuedSpinLock(&CheckData->QueueHandle))
+ DEFINE_ACQUIRE(AcquireQueued,         TRUE,  CheckData->Irql = KeAcquireQueuedSpinLock(CheckData->QueueNumber))
+ DEFINE_ACQUIRE(AcquireQueuedSynch,    TRUE,  CheckData->Irql = KeAcquireQueuedSpinLockRaiseToSynch(CheckData->QueueNumber))
+ DEFINE_RELEASE(ReleaseQueued,         TRUE,  KeReleaseQueuedSpinLock(CheckData->QueueNumber, CheckData->Irql))
+ DEFINE_ACQUIRE(AcquireNoRaise,        FALSE, KeAcquireSpinLockAtDpcLevel(SpinLock))
+ DEFINE_RELEASE(ReleaseNoLower,        FALSE, KeReleaseSpinLockFromDpcLevel(SpinLock))
+ DEFINE_ACQUIRE(AcquireExpNoRaise,     FALSE, (KeAcquireSpinLockAtDpcLevel)(SpinLock))
+ DEFINE_RELEASE(ReleaseExpNoLower,     FALSE, (KeReleaseSpinLockFromDpcLevel)(SpinLock))
+ DEFINE_ACQUIRE(AcquireInStackNoRaise, FALSE, KeAcquireInStackQueuedSpinLockAtDpcLevel(SpinLock, &CheckData->QueueHandle))
+ DEFINE_RELEASE(ReleaseInStackNoRaise, FALSE, KeReleaseInStackQueuedSpinLockFromDpcLevel(&CheckData->QueueHandle))
+ /* TODO: test these functions. They behave weirdly, though */
+ #if 0
+ DEFINE_ACQUIRE(AcquireForDpc,         TRUE,  CheckData->Irql = KeAcquireSpinLockForDpc(SpinLock))
+ DEFINE_RELEASE(ReleaseForDpc,         TRUE,  KeReleaseSpinLockForDpc(SpinLock, CheckData->Irql))
+ #endif
+ DEFINE_ACQUIRE(AcquireInStackForDpc,  FALSE, KeAcquireInStackQueuedSpinLockForDpc(SpinLock, &CheckData->QueueHandle))
+ DEFINE_RELEASE(ReleaseInStackForDpc,  FALSE, KeReleaseInStackQueuedSpinLockForDpc(&CheckData->QueueHandle))
+ DEFINE_ACQUIRE(AcquireInt,            FALSE, KiAcquireSpinLock(SpinLock))
+ DEFINE_RELEASE(ReleaseInt,            FALSE, KiReleaseSpinLock(SpinLock))
+ BOOLEAN TryQueued(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData) {
+     LOGICAL Ret = KeTryToAcquireQueuedSpinLock(CheckData->QueueNumber, &CheckData->Irql);
+     CheckData->IsAcquired = TRUE;
+     ASSERT(Ret == FALSE || Ret == TRUE);
+     return (BOOLEAN)Ret;
+ }
+ BOOLEAN TryQueuedSynch(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData) {
+     BOOLEAN Ret = KeTryToAcquireQueuedSpinLockRaiseToSynch(CheckData->QueueNumber, &CheckData->Irql);
+     CheckData->IsAcquired = TRUE;
+     return Ret;
+ }
+ BOOLEAN TryNoRaise(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData) {
+     BOOLEAN Ret = KeTryToAcquireSpinLockAtDpcLevel(SpinLock);
+     return Ret;
+ }
+ #define CheckSpinLockLock(SpinLock, CheckData, Value) do                            \
+ {                                                                                   \
+     PKTHREAD Thread = KeGetCurrentThread();                                         \
+     if (KmtIsMultiProcessorBuild)                                                   \
+     {                                                                               \
+         ok_eq_bool(Ret, (Value) == 0);                                              \
+         if (SpinLock)                                                               \
+             ok_eq_ulongptr(*(SpinLock),                                             \
+                         (Value) ? (ULONG_PTR)Thread | 1 : 0);                       \
+     }                                                                               \
+     else                                                                            \
+     {                                                                               \
+         ok_bool_true(Ret, "KeTestSpinLock returned");                               \
+         if (SpinLock)                                                               \
+             ok_eq_ulongptr(*(SpinLock), 0);                                         \
+     }                                                                               \
+     ok_eq_uint((CheckData)->Irql, (CheckData)->OriginalIrql);                       \
+ } while (0)
+ #define CheckSpinLockQueue(SpinLock, CheckData, Value) do                           \
+ {                                                                                   \
+     ok_eq_pointer((CheckData)->Queue->Next, NULL);                                  \
+     ok_eq_pointer((CheckData)->Queue->Lock, NULL);                                  \
+     ok_eq_uint((CheckData)->Irql, (CheckData)->OriginalIrql);                       \
+ } while (0)
+ #define CheckSpinLockQueueHandle(SpinLock, CheckData, Value) do                     \
+ {                                                                                   \
+     if (KmtIsMultiProcessorBuild)                                                   \
+     {                                                                               \
+         ok_eq_bool(Ret, (Value) == 0);                                              \
+         if (SpinLock)                                                               \
+             ok_eq_ulongptr(*(SpinLock),                                             \
+                         (Value) ? &(CheckData)->QueueHandle : 0);                   \
+         ok_eq_pointer((CheckData)->QueueHandle.LockQueue.Next, NULL);               \
+         ok_eq_pointer((CheckData)->QueueHandle.LockQueue.Lock,                      \
+                 (PVOID)((ULONG_PTR)SpinLock | ((Value) ? 2 : 0)));                  \
+     }                                                                               \
+     else                                                                            \
+     {                                                                               \
+         ok_bool_true(Ret, "KeTestSpinLock returned");                               \
+         if (SpinLock)                                                               \
+             ok_eq_ulongptr(*(SpinLock), 0);                                         \
+         ok_eq_pointer((CheckData)->QueueHandle.LockQueue.Next, (CheckData)->UntouchedValue);                \
+         ok_eq_pointer((CheckData)->QueueHandle.LockQueue.Lock, (CheckData)->UntouchedValue);                \
+     }                                                                               \
+     ok_eq_uint((CheckData)->QueueHandle.OldIrql, (CheckData)->OriginalIrql);        \
+ } while (0)
+ #define CheckSpinLock(SpinLock, CheckData, Value) do                                \
+ {                                                                                   \
+     BOOLEAN Ret = SpinLock ? KeTestSpinLock(SpinLock) : TRUE;                       \
+     KIRQL ExpectedIrql = (CheckData)->OriginalIrql;                                 \
+                                                                                     \
+     switch ((CheckData)->Check)                                                     \
+     {                                                                               \
+         case CheckLock:                                                             \
+             CheckSpinLockLock(SpinLock, CheckData, Value);                          \
+             break;                                                                  \
+         case CheckQueue:                                                            \
+             CheckSpinLockQueue(SpinLock, CheckData, Value);                         \
+             break;                                                                  \
+         case CheckQueueHandle:                                                      \
+             CheckSpinLockQueueHandle(SpinLock, CheckData, Value);                   \
+             break;                                                                  \
+     }                                                                               \
+                                                                                     \
+     if ((CheckData)->IsAcquired)                                                    \
+         ExpectedIrql = (CheckData)->IrqlWhenAcquired;                               \
+     ok_irql(ExpectedIrql);                                                          \
+     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");               \
+     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");                 \
+ } while (0)
+ static
+ VOID
+ TestSpinLock(
+     PKSPIN_LOCK SpinLock,
+     PCHECK_DATA CheckData)
+ {
+     static INT Run = 0;
+     trace("Test SpinLock run %d\n", Run++);
+     ok_irql(CheckData->OriginalIrql);
+     if (SpinLock)
+         ok_eq_ulongptr(*SpinLock, 0);
+     CheckData->Acquire(SpinLock, CheckData);
+     CheckSpinLock(SpinLock, CheckData, 1);
+     CheckData->Release(SpinLock, CheckData);
+     CheckSpinLock(SpinLock, CheckData, 0);
+     if (CheckData->TryAcquire)
+     {
+         CheckSpinLock(SpinLock, CheckData, 0);
+         ok_bool_true(CheckData->TryAcquire(SpinLock, CheckData), "TryAcquire returned");
+         CheckSpinLock(SpinLock, CheckData, 1);
+         if (!KmtIsCheckedBuild)
+         {
+             /* SPINLOCK_ALREADY_OWNED on checked build */
+             ok_bool_true(CheckData->TryAcquire(SpinLock, CheckData), "TryAcquire returned");
+             /* even a failing acquire sets irql */
+             ok_eq_uint(CheckData->Irql, CheckData->IrqlWhenAcquired);
+             CheckData->Irql = CheckData->OriginalIrql;
+             CheckSpinLock(SpinLock, CheckData, 1);
+         }
+         CheckData->Release(SpinLock, CheckData);
+         CheckSpinLock(SpinLock, CheckData, 0);
+     }
+     if (CheckData->AcquireNoRaise &&
+             (CheckData->OriginalIrql >= DISPATCH_LEVEL || !KmtIsCheckedBuild))
+     {
+         /* acquire/release without irql change */
+         CheckData->AcquireNoRaise(SpinLock, CheckData);
+         CheckSpinLock(SpinLock, CheckData, 1);
+         CheckData->ReleaseNoLower(SpinLock, CheckData);
+         CheckSpinLock(SpinLock, CheckData, 0);
+         /* acquire without raise, but normal release */
+         CheckData->AcquireNoRaise(SpinLock, CheckData);
+         CheckSpinLock(SpinLock, CheckData, 1);
+         CheckData->Release(SpinLock, CheckData);
+         CheckSpinLock(SpinLock, CheckData, 0);
+         /* acquire normally but release without lower */
+         CheckData->Acquire(SpinLock, CheckData);
+         CheckSpinLock(SpinLock, CheckData, 1);
+         CheckData->ReleaseNoLower(SpinLock, CheckData);
+         CheckSpinLock(SpinLock, CheckData, 0);
+         CheckData->IsAcquired = FALSE;
+         KmtSetIrql(CheckData->OriginalIrql);
+         if (CheckData->TryAcquireNoRaise)
+         {
+             CheckSpinLock(SpinLock, CheckData, 0);
+             ok_bool_true(CheckData->TryAcquireNoRaise(SpinLock, CheckData), "TryAcquireNoRaise returned");
+             CheckSpinLock(SpinLock, CheckData, 1);
+             if (!KmtIsCheckedBuild)
+             {
+                 ok_bool_true(CheckData->TryAcquireNoRaise(SpinLock, CheckData), "TryAcquireNoRaise returned");
+                 CheckSpinLock(SpinLock, CheckData, 1);
+             }
+             CheckData->ReleaseNoLower(SpinLock, CheckData);
+             CheckSpinLock(SpinLock, CheckData, 0);
+         }
+     }
+     ok_irql(CheckData->OriginalIrql);
+     /* make sure we survive this in case of error */
+     KmtSetIrql(CheckData->OriginalIrql);
+ }
+ START_TEST(KeSpinLock)
+ {
+     KSPIN_LOCK SpinLock = (KSPIN_LOCK)0x5555555555555555LL;
+     PKSPIN_LOCK pSpinLock = &SpinLock;
+     KIRQL Irql, SynchIrql = KmtIsMultiProcessorBuild ? IPI_LEVEL - 2 : DISPATCH_LEVEL;
+     KIRQL OriginalIrqls[] = { PASSIVE_LEVEL, APC_LEVEL, DISPATCH_LEVEL, HIGH_LEVEL };
+     CHECK_DATA TestData[] =
+     {
+         { CheckLock,        DISPATCH_LEVEL, AcquireNormal,        ReleaseNormal,        NULL,           AcquireNoRaise,        ReleaseNoLower,        TryNoRaise },
+         { CheckLock,        DISPATCH_LEVEL, AcquireExp,           ReleaseExp,           NULL,           AcquireExpNoRaise,     ReleaseExpNoLower,     NULL },
+         /* TODO: this one is just weird!
+         { CheckLock,        DISPATCH_LEVEL, AcquireNormal,        ReleaseNormal,        NULL,           AcquireForDpc,         ReleaseForDpc,         NULL },*/
+         { CheckLock,        DISPATCH_LEVEL, AcquireNormal,        ReleaseNormal,        NULL,           AcquireInt,            ReleaseInt,            NULL },
+         { CheckLock,        SynchIrql,      AcquireSynch,         ReleaseNormal,        NULL,           NULL,                  NULL,                  NULL },
+         { CheckQueueHandle, DISPATCH_LEVEL, AcquireInStackQueued, ReleaseInStackQueued, NULL,           AcquireInStackNoRaise, ReleaseInStackNoRaise, NULL },
+         { CheckQueueHandle, SynchIrql,      AcquireInStackSynch,  ReleaseInStackQueued, NULL,           NULL,                  NULL,                  NULL },
+         { CheckQueueHandle, DISPATCH_LEVEL, AcquireInStackQueued, ReleaseInStackQueued, NULL,           AcquireInStackForDpc,  ReleaseInStackForDpc,  NULL },
+         { CheckQueue,       DISPATCH_LEVEL, AcquireQueued,        ReleaseQueued,        TryQueued,      NULL,                  NULL,                  NULL,       LockQueuePfnLock },
+         { CheckQueue,       SynchIrql,      AcquireQueuedSynch,   ReleaseQueued,        TryQueuedSynch, NULL,                  NULL,                  NULL,       LockQueuePfnLock },
+     };
+     int i, iIrql;
+     PKPRCB Prcb = KeGetCurrentPrcb();
+     /* KeInitializeSpinLock */
+     memset(&SpinLock, 0x55, sizeof SpinLock);
+     KeInitializeSpinLock(&SpinLock);
+     ok_eq_ulongptr(SpinLock, 0);
+     /* KeTestSpinLock */
+     ok_bool_true(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
+     SpinLock = 1;
+     ok_bool_false(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
+     SpinLock = 2;
+     ok_bool_false(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
+     SpinLock = (ULONG_PTR)-1;
+     ok_bool_false(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
+     SpinLock = (ULONG_PTR)1 << (sizeof(ULONG_PTR) * CHAR_BIT - 1);
+     ok_bool_false(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
+     SpinLock = 0;
+     ok_bool_true(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
+     /* on UP none of the following functions actually looks at the spinlock! */
+     if (!KmtIsMultiProcessorBuild && !KmtIsCheckedBuild)
+         pSpinLock = NULL;
+     for (i = 0; i < sizeof TestData / sizeof TestData[0]; ++i)
+     {
+         memset(&SpinLock, 0x55, sizeof SpinLock);
+         KeInitializeSpinLock(&SpinLock);
+         if (TestData[i].Check == CheckQueueHandle)
+             memset(&TestData[i].QueueHandle, 0x55, sizeof TestData[i].QueueHandle);
+         if (TestData[i].Check == CheckQueue)
+         {
+             TestData[i].Queue = &Prcb->LockQueue[TestData[i].QueueNumber];
+             TestData[i].UntouchedValue = NULL;
+         }
+         else
+             TestData[i].UntouchedValue = (PVOID)0x5555555555555555LL;
+         for (iIrql = 0; iIrql < sizeof OriginalIrqls / sizeof OriginalIrqls[0]; ++iIrql)
+         {
+             if (KmtIsCheckedBuild && OriginalIrqls[iIrql] > DISPATCH_LEVEL)
+                 continue;
+             KeRaiseIrql(OriginalIrqls[iIrql], &Irql);
+             TestData[i].OriginalIrql = OriginalIrqls[iIrql];
+             TestData[i].IsAcquired = FALSE;
+             TestSpinLock(pSpinLock, &TestData[i]);
+             KeLowerIrql(Irql);
+         }
+     }
+     KmtSetIrql(PASSIVE_LEVEL);
+ }
index 0000000,68b9a32..68b9a32
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,327 +1,327 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Object Referencing test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <kmt_test.h>
+ #define NDEBUG
+ #include <debug.h>
+ #define CheckObject(Handle, Pointers, Handles) do                   \
+ {                                                                   \
+     PUBLIC_OBJECT_BASIC_INFORMATION ObjectInfo;                     \
+     Status = ZwQueryObject(Handle, ObjectBasicInformation,          \
+                             &ObjectInfo, sizeof ObjectInfo, NULL);  \
+     ok_eq_hex(Status, STATUS_SUCCESS);                              \
+     ok_eq_ulong(ObjectInfo.PointerCount, Pointers);                 \
+     ok_eq_ulong(ObjectInfo.HandleCount, Handles);                   \
+ } while (0)
+ static POBJECT_TYPE ObDirectoryObjectType;
+ static
+ VOID
+ TestReference(
+     IN HANDLE Handle,
+     IN PUNICODE_STRING Name OPTIONAL,
+     IN PUNICODE_STRING NameUpper OPTIONAL,
+     IN BOOLEAN CaseSensitive,
+     IN ULONG AdditionalReferences,
+     IN BOOLEAN Permanent)
+ {
+     NTSTATUS Status;
+     LONG_PTR Ret;
+     PVOID Object = NULL;
+     PVOID Object2 = NULL;
+     PVOID Object3 = NULL;
+     PVOID Object4 = NULL;
+     CheckObject(Handle, 2LU + AdditionalReferences, 1LU);
+     Status = ObReferenceObjectByHandle(Handle, DIRECTORY_ALL_ACCESS, NULL, KernelMode, &Object, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     ok(Object != NULL, "ObReferenceObjectByHandle returned NULL object\n");
+     CheckObject(Handle, 3LU + AdditionalReferences, 1LU);
+     Status = ObReferenceObjectByHandle(Handle, DIRECTORY_ALL_ACCESS, NULL, KernelMode, &Object2, NULL);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     ok(Object != NULL, "ObReferenceObjectByHandle returned NULL object\n");
+     ok_eq_pointer(Object, Object2);
+     CheckObject(Handle, 4LU + AdditionalReferences, 1LU);
+     if (!skip(Object != NULL, "No object to reference!\n"))
+     {
+         Ret = ObReferenceObject(Object);
+         ok_eq_longptr(Ret, (LONG_PTR)4 + AdditionalReferences);
+         CheckObject(Handle, 5LU + AdditionalReferences, 1LU);
+         Ret = ObReferenceObject(Object);
+         ok_eq_longptr(Ret, (LONG_PTR)5 + AdditionalReferences);
+         CheckObject(Handle, 6LU + AdditionalReferences, 1LU);
+         Status = ObReferenceObjectByPointer(Object, DIRECTORY_ALL_ACCESS, NULL, KernelMode);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         CheckObject(Handle, 7LU + AdditionalReferences, 1LU);
+         Status = ObReferenceObjectByPointer(Object, DIRECTORY_ALL_ACCESS, NULL, KernelMode);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         CheckObject(Handle, 8LU + AdditionalReferences, 1LU);
+         Ret = ObDereferenceObject(Object);
+         ok_eq_longptr(Ret, (LONG_PTR)6 + AdditionalReferences);
+         CheckObject(Handle, 7LU + AdditionalReferences, 1LU);
+         Ret = ObDereferenceObject(Object);
+         ok_eq_longptr(Ret, (LONG_PTR)5 + AdditionalReferences);
+         CheckObject(Handle, 6LU + AdditionalReferences, 1LU);
+         Ret = ObDereferenceObject(Object);
+         ok_eq_longptr(Ret, (LONG_PTR)4 + AdditionalReferences);
+         CheckObject(Handle, 5LU + AdditionalReferences, 1LU);
+         Ret = ObDereferenceObject(Object);
+         ok_eq_longptr(Ret, (LONG_PTR)3 + AdditionalReferences);
+         CheckObject(Handle, 4LU + AdditionalReferences, 1LU);
+     }
+     if (Name && !skip(ObDirectoryObjectType != NULL, "No directory object type\n"))
+     {
+         Status = ObReferenceObjectByName(Name, 0, NULL, DIRECTORY_ALL_ACCESS, ObDirectoryObjectType, KernelMode, NULL, &Object3);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         CheckObject(Handle, 5LU + AdditionalReferences, 1LU);
+     }
+     if (NameUpper && !skip(ObDirectoryObjectType != NULL, "No directory object type\n"))
+     {
+         Status = ObReferenceObjectByName(NameUpper, 0, NULL, DIRECTORY_ALL_ACCESS, ObDirectoryObjectType, KernelMode, NULL, &Object4);
+         ok_eq_hex(Status, CaseSensitive ? STATUS_OBJECT_NAME_NOT_FOUND : STATUS_SUCCESS);
+         CheckObject(Handle, 5LU + AdditionalReferences + !CaseSensitive, 1LU);
+     }
+     if (NameUpper && !skip(Object4 != NULL, "No object to dereference\n"))
+     {
+         Ret = ObDereferenceObject(Object4);
+         ok_eq_longptr(Ret, (LONG_PTR)4 + AdditionalReferences);
+         CheckObject(Handle, 5LU + AdditionalReferences, 1LU);
+     }
+     if (Name && !skip(Object3 != NULL, "No object to dereference\n"))
+     {
+         Ret = ObDereferenceObject(Object3);
+         ok_eq_longptr(Ret, (LONG_PTR)3 + AdditionalReferences);
+         CheckObject(Handle, 4LU + AdditionalReferences, 1LU);
+     }
+     if (!skip(Object2 != NULL, "No object to dereference\n"))
+     {
+         Ret = ObDereferenceObject(Object2);
+         ok_eq_longptr(Ret, (LONG_PTR)2 + AdditionalReferences);
+         CheckObject(Handle, 3LU + AdditionalReferences, 1LU);
+     }
+     if (!skip(Object != NULL, "No object to dereference\n"))
+     {
+         Ret = ObDereferenceObject(Object);
+         ok_eq_longptr(Ret, (LONG_PTR)1 + AdditionalReferences);
+         CheckObject(Handle, 2LU + AdditionalReferences, 1LU);
+     }
+     CheckObject(Handle, 2LU + AdditionalReferences, 1LU);
+     if (Permanent)
+     {
+         Status = ZwMakeTemporaryObject(Handle);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         CheckObject(Handle, 2LU + AdditionalReferences, 1LU);
+         Status = ZwMakeTemporaryObject(Handle);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         CheckObject(Handle, 2LU + AdditionalReferences, 1LU);
+     }
+ }
+ START_TEST(ObReference)
+ {
+     NTSTATUS Status;
+     NTSTATUS ExceptionStatus;
+     HANDLE DirectoryHandle = NULL;
+     OBJECT_ATTRIBUTES ObjectAttributes;
+     UNICODE_STRING Name, *pName;
+     UNICODE_STRING NameUpper, *pNameUpper;
+     ULONG i;
+     struct
+     {
+         PWSTR Name;
+         ULONG Flags;
+         ULONG AdditionalReferences;
+     } Tests[] =
+     {
+         { NULL,                 0,                                                          0 },
+         { NULL,                 OBJ_CASE_INSENSITIVE,                                       0 },
+         { NULL,                 OBJ_KERNEL_HANDLE,                                          0 },
+         { NULL,                 OBJ_PERMANENT,                                              0 },
+         { NULL,                 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,                       0 },
+         { NULL,                 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,                   0 },
+         { NULL,                 OBJ_KERNEL_HANDLE | OBJ_PERMANENT,                          0 },
+         { NULL,                 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_PERMANENT,   0 },
+         { L"\\YayDirectory0",   0,                                                          1 },
+         { L"\\YayDirectory1",   OBJ_CASE_INSENSITIVE,                                       1 },
+         { L"\\YayDirectory2",   OBJ_KERNEL_HANDLE,                                          1 },
+         { L"\\YayDirectory3",   OBJ_PERMANENT,                                              1 },
+         { L"\\YayDirectory4",   OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,                       1 },
+         { L"\\YayDirectory5",   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,                   1 },
+         { L"\\YayDirectory6",   OBJ_KERNEL_HANDLE | OBJ_PERMANENT,                          1 },
+         { L"\\YayDirectory7",   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_PERMANENT,   1 },
+     };
+     HANDLE ObjectTypeHandle;
+     /* ObReferenceObjectByName needs the object type... so get it... */
+     RtlInitUnicodeString(&Name, L"\\ObjectTypes\\Directory");
+     InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_KERNEL_HANDLE, NULL, NULL);
+     Status = ObOpenObjectByName(&ObjectAttributes, NULL, KernelMode, NULL, 0, NULL, &ObjectTypeHandle);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     ok(ObjectTypeHandle != NULL, "ObjectTypeHandle = NULL\n");
+     if (!skip(Status == STATUS_SUCCESS && ObjectTypeHandle, "No handle\n"))
+     {
+         Status = ObReferenceObjectByHandle(ObjectTypeHandle, 0, NULL, KernelMode, (PVOID)&ObDirectoryObjectType, NULL);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         ok(ObDirectoryObjectType != NULL, "ObDirectoryObjectType = NULL\n");
+         Status = ZwClose(ObjectTypeHandle);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+     }
+     for (i = 0; i < sizeof Tests / sizeof Tests[0]; ++i)
+     {
+         DPRINT("Run %d\n", i);
+         if (Tests[i].Name)
+         {
+             RtlInitUnicodeString(&Name, Tests[i].Name);
+             pName = &Name;
+             Status = RtlUpcaseUnicodeString(&NameUpper, &Name, TRUE);
+             ok_eq_hex(Status, STATUS_SUCCESS);
+             if (skip(Status == STATUS_SUCCESS, "No upper case name\n"))
+                 pNameUpper = NULL;
+             else
+                 pNameUpper = &NameUpper;
+         }
+         else
+         {
+             pName = NULL;
+             pNameUpper = NULL;
+         }
+         InitializeObjectAttributes(&ObjectAttributes, pName, Tests[i].Flags, NULL, NULL);
+         Status = ZwCreateDirectoryObject(&DirectoryHandle, DIRECTORY_ALL_ACCESS, &ObjectAttributes);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         ok(DirectoryHandle != NULL, "DirectoryHandle = NULL\n");
+         if (!skip(Status == STATUS_SUCCESS && DirectoryHandle, "Cannot proceed without an object"))
+         {
+             TestReference(DirectoryHandle, pName, pNameUpper, FALSE, Tests[i].AdditionalReferences, (Tests[i].Flags & OBJ_PERMANENT) != 0);
+             /* try again for good measure */
+             TestReference(DirectoryHandle, pName, pNameUpper, FALSE, Tests[i].AdditionalReferences, FALSE);
+             Status = ZwClose(DirectoryHandle);
+             ok_eq_hex(Status, STATUS_SUCCESS);
+             DirectoryHandle = NULL;
+         }
+         if (pNameUpper)
+             RtlFreeUnicodeString(pNameUpper);
+     }
+     if (DirectoryHandle)
+     {
+         Status = ZwClose(DirectoryHandle);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+     }
+     /* parameter tests */
+     /* bugcheck at APC_LEVEL
+     Status = ObReferenceObject(NULL);
+     Status = ObReferenceObjectByPointer(NULL, 0, NULL, UserMode);
+     Status = ObReferenceObjectByPointer(NULL, 0, NULL, KernelMode);*/
+     ExceptionStatus = STATUS_SUCCESS;
+     _SEH2_TRY {
+         /* TODO: this belongs in an ObHandle test if we ever have one */
+         /* NtClose must accept everything */
+         DPRINT("Closing null handle (NtClose)\n");
+         Status = NtClose(NULL);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing null kernel handle (NtClose)\n");
+         Status = NtClose((HANDLE)0x80000000);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing -1 handle (NtClose)\n");
+         Status = NtClose((HANDLE)0x7FFFFFFF);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing -1 kernel handle (NtClose)\n");
+         Status = NtClose((HANDLE)0xFFFFFFFF);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing 123 handle (NtClose)\n");
+         Status = NtClose((HANDLE)123);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing 123 kernel handle (NtClose)\n");
+         Status = NtClose((HANDLE)(123 | 0x80000000));
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         /* ObCloseHandle with UserMode accepts everything */
+         DPRINT("Closing null handle (ObCloseHandle, UserMode)\n");
+         Status = ObCloseHandle(NULL, UserMode);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing null kernel handle (ObCloseHandle, UserMode)\n");
+         Status = ObCloseHandle((HANDLE)0x80000000, UserMode);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing -1 handle (ObCloseHandle, UserMode)\n");
+         Status = ObCloseHandle((HANDLE)0x7FFFFFFF, UserMode);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing -1 kernel handle (ObCloseHandle, UserMode)\n");
+         Status = ObCloseHandle((HANDLE)0xFFFFFFFF, UserMode);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing 123 handle (ObCloseHandle, UserMode)\n");
+         Status = ObCloseHandle((HANDLE)123, UserMode);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing 123 kernel handle (ObCloseHandle, UserMode)\n");
+         Status = ObCloseHandle((HANDLE)(123 | 0x80000000), UserMode);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         /* ZwClose only accepts 0 and -1 */
+         DPRINT("Closing null handle (ZwClose)\n");
+         Status = ZwClose(NULL);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing null kernel handle (ZwClose)\n");
+         Status = ZwClose((HANDLE)0x80000000);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         /* INVALID_KERNEL_HANDLE, 0x7FFFFFFF
+         Status = ZwClose((HANDLE)0x7FFFFFFF);*/
+         DPRINT("Closing -1 kernel handle (ZwClose)\n");
+         Status = ZwClose((HANDLE)0xFFFFFFFF);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         /* INVALID_KERNEL_HANDLE, 0x7B, 1, 0, 0
+         Status = ZwClose((HANDLE)123);
+         Status = ZwClose((HANDLE)(123 | 0x80000000));*/
+         /* ObCloseHandle with KernelMode accepts only 0 and -1 */
+         DPRINT("Closing null handle (ObCloseHandle, KernelMode)\n");
+         Status = ObCloseHandle(NULL, KernelMode);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         DPRINT("Closing null kernel handle (ObCloseHandle, KernelMode)\n");
+         Status = ObCloseHandle((HANDLE)0x80000000, KernelMode);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         /* INVALID_KERNEL_HANDLE, 0x7FFFFFFF, 1, 0, 0
+         Status = ObCloseHandle((HANDLE)0x7FFFFFFF, KernelMode);*/
+         DPRINT("Closing -1 kernel handle (ObCloseHandle, KernelMode)\n");
+         Status = ObCloseHandle((HANDLE)0xFFFFFFFF, KernelMode);
+         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
+         /* INVALID_KERNEL_HANDLE, 0x7B, 1, 0, 0
+         Status = ObCloseHandle((HANDLE)123, KernelMode);
+         Status = ObCloseHandle((HANDLE)(123 | 0x80000000), KernelMode);*/
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         ExceptionStatus = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(ExceptionStatus, STATUS_SUCCESS);
+     if (ObDirectoryObjectType)
+     {
+         ObDereferenceObject(ObDirectoryObjectType);
+         ObDirectoryObjectType = NULL;
+     }
+ }
index 0000000,e428aa0..e428aa0
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,446 +1,446 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Ob Regressions KM-Test
+  * PROGRAMMER:      Aleksey Bragin <aleksey@reactos.org>
+  *                  Thomas Faber <thfabba@gmx.de>
+  */
+ /* TODO: split this into multiple tests! ObLife, ObHandle, ObName, ... */
+ #include <kmt_test.h>
+ #define NDEBUG
+ #include <debug.h>
+ #define CheckObject(Handle, Pointers, Handles) do                   \
+ {                                                                   \
+     PUBLIC_OBJECT_BASIC_INFORMATION ObjectInfo;                     \
+     Status = ZwQueryObject(Handle, ObjectBasicInformation,          \
+                             &ObjectInfo, sizeof ObjectInfo, NULL);  \
+     ok_eq_hex(Status, STATUS_SUCCESS);                              \
+     ok_eq_ulong(ObjectInfo.PointerCount, Pointers);                 \
+     ok_eq_ulong(ObjectInfo.HandleCount, Handles);                   \
+ } while (0)
+ #define NUM_OBTYPES 5
+ typedef struct _MY_OBJECT1
+ {
+     ULONG Something1;
+ } MY_OBJECT1, *PMY_OBJECT1;
+ typedef struct _MY_OBJECT2
+ {
+     ULONG Something1;
+     ULONG SomeLong[10];
+ } MY_OBJECT2, *PMY_OBJECT2;
+ static POBJECT_TYPE            ObTypes[NUM_OBTYPES];
+ static UNICODE_STRING          ObTypeName[NUM_OBTYPES];
+ static UNICODE_STRING          ObName[NUM_OBTYPES];
+ static OBJECT_TYPE_INITIALIZER ObTypeInitializer[NUM_OBTYPES];
+ static UNICODE_STRING          ObDirectoryName;
+ static OBJECT_ATTRIBUTES       ObDirectoryAttributes;
+ static OBJECT_ATTRIBUTES       ObAttributes[NUM_OBTYPES];
+ static PVOID                   ObBody[NUM_OBTYPES];
+ static HANDLE                  ObHandle1[NUM_OBTYPES];
+ static HANDLE                  DirectoryHandle;
+ typedef struct _COUNTS
+ {
+     USHORT Dump;
+     USHORT Open;
+     USHORT Close;
+     USHORT Delete;
+     USHORT Parse;
+     USHORT OkayToClose;
+     USHORT QueryName;
+ } COUNTS, *PCOUNTS;
+ static COUNTS Counts;
+ static
+ VOID
+ NTAPI
+ DumpProc(
+     IN PVOID Object,
+     IN POB_DUMP_CONTROL DumpControl)
+ {
+     DPRINT("DumpProc() called\n");
+     ++Counts.Dump;
+ }
+ static
+ NTSTATUS
+ NTAPI
+ OpenProc(
+     IN OB_OPEN_REASON OpenReason,
+     IN PEPROCESS Process,
+     IN PVOID Object,
+     IN ACCESS_MASK GrantedAccess,
+     IN ULONG HandleCount)
+ {
+     DPRINT("OpenProc() 0x%p, OpenReason %d, HandleCount %lu, AccessMask 0x%lX\n",
+         Object, OpenReason, HandleCount, GrantedAccess);
+     ++Counts.Open;
+     return STATUS_SUCCESS;
+ }
+ static
+ VOID
+ NTAPI
+ CloseProc(
+     IN PEPROCESS Process,
+     IN PVOID Object,
+     IN ACCESS_MASK GrantedAccess,
+     IN ULONG ProcessHandleCount,
+     IN ULONG SystemHandleCount)
+ {
+     DPRINT("CloseProc() 0x%p, ProcessHandleCount %lu, SystemHandleCount %lu, AccessMask 0x%lX\n",
+         Object, ProcessHandleCount, SystemHandleCount, GrantedAccess);
+     ++Counts.Close;
+ }
+ static
+ VOID
+ NTAPI
+ DeleteProc(
+     IN PVOID Object)
+ {
+     DPRINT("DeleteProc() 0x%p\n", Object);
+     ++Counts.Delete;
+ }
+ static
+ NTSTATUS
+ NTAPI
+ ParseProc(
+     IN PVOID ParseObject,
+     IN PVOID ObjectType,
+     IN OUT PACCESS_STATE AccessState,
+     IN KPROCESSOR_MODE AccessMode,
+     IN ULONG Attributes,
+     IN OUT PUNICODE_STRING CompleteName,
+     IN OUT PUNICODE_STRING RemainingName,
+     IN OUT PVOID Context OPTIONAL,
+     IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
+     OUT PVOID *Object)
+ {
+     DPRINT("ParseProc() called\n");
+     *Object = NULL;
+     ++Counts.Parse;
+     return STATUS_OBJECT_NAME_NOT_FOUND;//STATUS_SUCCESS;
+ }
+ static
+ BOOLEAN
+ NTAPI
+ OkayToCloseProc(
+     IN PEPROCESS Process OPTIONAL,
+     IN PVOID Object,
+     IN HANDLE Handle,
+     IN KPROCESSOR_MODE AccessMode)
+ {
+     DPRINT("OkayToCloseProc() 0x%p, Handle 0x%p, AccessMask 0x%lX\n",
+         Object, Handle, AccessMode);
+     ++Counts.OkayToClose;
+     return TRUE;
+ }
+ static
+ NTSTATUS
+ NTAPI
+ QueryNameProc(
+     IN PVOID Object,
+     IN BOOLEAN HasObjectName,
+     OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
+     IN ULONG Length,
+     OUT PULONG ReturnLength,
+     IN KPROCESSOR_MODE AccessMode)
+ {
+     DPRINT("QueryNameProc() 0x%p, HasObjectName %d, Len %lu, AccessMask 0x%lX\n",
+         Object, HasObjectName, Length, AccessMode);
+     ++Counts.QueryName;
+     ObjectNameInfo = NULL;
+     ReturnLength = 0;
+     return STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ static
+ VOID
+ ObtCreateObjectTypes(VOID)
+ {
+     INT i;
+     NTSTATUS Status;
+     struct
+     {
+         WCHAR DirectoryName[sizeof "\\ObjectTypes\\" - 1];
+         WCHAR TypeName[15];
+     } Name;
+     OBJECT_ATTRIBUTES ObjectAttributes;
+     HANDLE ObjectTypeHandle;
+     UNICODE_STRING ObjectPath;
+     RtlCopyMemory(&Name.DirectoryName, L"\\ObjectTypes\\", sizeof Name.DirectoryName);
+     for (i = 0; i < NUM_OBTYPES; ++i)
+     {
+         Status = RtlStringCbPrintfW(Name.TypeName, sizeof Name.TypeName, L"MyObjectType%x", i);
+         ASSERT(NT_SUCCESS(Status));
+         RtlInitUnicodeString(&ObTypeName[i], Name.TypeName);
+         DPRINT("Creating object type %wZ\n", &ObTypeName[i]);
+         RtlZeroMemory(&ObTypeInitializer[i], sizeof ObTypeInitializer[i]);
+         ObTypeInitializer[i].Length = sizeof ObTypeInitializer[i];
+         ObTypeInitializer[i].PoolType = NonPagedPool;
+         ObTypeInitializer[i].MaintainHandleCount = TRUE;
+         ObTypeInitializer[i].ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
+         // Test for invalid parameter
+         // FIXME: Make it more exact, to see which params Win2k3 checks
+         // existence of
+         Status = ObCreateObjectType(&ObTypeName[i], &ObTypeInitializer[i], NULL, &ObTypes[i]);
+         ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
+         ObTypeInitializer[i].CloseProcedure = CloseProc;
+         ObTypeInitializer[i].DeleteProcedure = DeleteProc;
+         ObTypeInitializer[i].DumpProcedure = DumpProc;
+         ObTypeInitializer[i].OpenProcedure = OpenProc;
+         ObTypeInitializer[i].ParseProcedure = ParseProc;
+         ObTypeInitializer[i].OkayToCloseProcedure = OkayToCloseProc;
+         ObTypeInitializer[i].QueryNameProcedure = QueryNameProc;
+         //ObTypeInitializer[i].SecurityProcedure = SecurityProc;
+         Status = ObCreateObjectType(&ObTypeName[i], &ObTypeInitializer[i], NULL, &ObTypes[i]);
+         if (Status == STATUS_OBJECT_NAME_COLLISION)
+         {
+             /* as we cannot delete the object types, get a pointer if they
+              * already exist */
+             RtlInitUnicodeString(&ObjectPath, Name.DirectoryName);
+             InitializeObjectAttributes(&ObjectAttributes, &ObjectPath, OBJ_KERNEL_HANDLE, NULL, NULL);
+             Status = ObOpenObjectByName(&ObjectAttributes, NULL, KernelMode, NULL, 0, NULL, &ObjectTypeHandle);
+             ok_eq_hex(Status, STATUS_SUCCESS);
+             ok(ObjectTypeHandle != NULL, "ObjectTypeHandle = NULL\n");
+             if (!skip(Status == STATUS_SUCCESS && ObjectTypeHandle, "No handle\n"))
+             {
+                 Status = ObReferenceObjectByHandle(ObjectTypeHandle, 0, NULL, KernelMode, (PVOID)&ObTypes[i], NULL);
+                 ok_eq_hex(Status, STATUS_SUCCESS);
+                 if (!skip(Status == STATUS_SUCCESS && ObTypes[i], "blah\n"))
+                 {
+                     ObTypes[i]->TypeInfo.CloseProcedure = CloseProc;
+                     ObTypes[i]->TypeInfo.DeleteProcedure = DeleteProc;
+                     ObTypes[i]->TypeInfo.DumpProcedure = DumpProc;
+                     ObTypes[i]->TypeInfo.OpenProcedure = OpenProc;
+                     ObTypes[i]->TypeInfo.ParseProcedure = ParseProc;
+                     ObTypes[i]->TypeInfo.OkayToCloseProcedure = OkayToCloseProc;
+                     ObTypes[i]->TypeInfo.QueryNameProcedure = QueryNameProc;
+                 }
+                 Status = ZwClose(ObjectTypeHandle);
+             }
+         }
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         ok(ObTypes[i] != NULL, "ObType = NULL\n");
+     }
+ }
+ static
+ VOID
+ ObtCreateDirectory(VOID)
+ {
+     NTSTATUS Status;
+     RtlInitUnicodeString(&ObDirectoryName, L"\\ObtDirectory");
+     InitializeObjectAttributes(&ObDirectoryAttributes, &ObDirectoryName, OBJ_KERNEL_HANDLE | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, NULL, NULL);
+     Status = ZwCreateDirectoryObject(&DirectoryHandle, DELETE, &ObDirectoryAttributes);
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     CheckObject(DirectoryHandle, 3LU, 1LU);
+ }
+ #define CheckCounts(OpenCount, CloseCount, DeleteCount, ParseCount, \
+                         OkayToCloseCount, QueryNameCount) do        \
+ {                                                                   \
+     ok_eq_uint(Counts.Open, OpenCount);                             \
+     ok_eq_uint(Counts.Close, CloseCount);                           \
+     ok_eq_uint(Counts.Delete, DeleteCount);                         \
+     ok_eq_uint(Counts.Parse, ParseCount);                           \
+     ok_eq_uint(Counts.OkayToClose, OkayToCloseCount);               \
+     ok_eq_uint(Counts.QueryName, QueryNameCount);                   \
+ } while (0)
+ #define SaveCounts(Save) memcpy(&Save, &Counts, sizeof Counts)
+ /* TODO: make this the same as NUM_OBTYPES */
+ #define NUM_OBTYPES2 2
+ static
+ VOID
+ ObtCreateObjects(VOID)
+ {
+     NTSTATUS Status;
+     WCHAR Name[NUM_OBTYPES2][MAX_PATH];
+     COUNTS SaveCounts;
+     INT i;
+     ACCESS_MASK Access[NUM_OBTYPES2] = { STANDARD_RIGHTS_ALL, GENERIC_ALL };
+     ULONG ObjectSize[NUM_OBTYPES2] = { sizeof(MY_OBJECT1), sizeof(MY_OBJECT2) };
+     // Create two objects
+     for (i = 0; i < NUM_OBTYPES2; ++i)
+     {
+         ASSERT(sizeof Name[i] == MAX_PATH * sizeof(WCHAR));
+         Status = RtlStringCbPrintfW(Name[i], sizeof Name[i], L"\\ObtDirectory\\MyObject%d", i + 1);
+         ASSERT(Status == STATUS_SUCCESS);
+         RtlInitUnicodeString(&ObName[i], Name[i]);
+         InitializeObjectAttributes(&ObAttributes[i], &ObName[i], OBJ_CASE_INSENSITIVE, NULL, NULL);
+     }
+     CheckObject(DirectoryHandle, 3LU, 1LU);
+     for (i = 0; i < NUM_OBTYPES2; ++i)
+     {
+         Status = ObCreateObject(KernelMode, ObTypes[i], &ObAttributes[i], KernelMode, NULL, ObjectSize[i], 0L, 0L, &ObBody[i]);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+     }
+     SaveCounts(SaveCounts);
+     // Insert them
+     for (i = 0; i < NUM_OBTYPES2; ++i)
+     {
+         CheckObject(DirectoryHandle, 3LU + i, 1LU);
+         Status = ObInsertObject(ObBody[i], NULL, Access[i], 0, &ObBody[i], &ObHandle1[i]);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         ok(ObBody[i] != NULL, "Object body = NULL\n");
+         ok(ObHandle1[i] != NULL, "Handle = NULL\n");
+         CheckObject(ObHandle1[i], 3LU, 1LU);
+         CheckCounts(SaveCounts.Open + 1, SaveCounts.Close, SaveCounts.Delete, SaveCounts.Parse, SaveCounts.OkayToClose, SaveCounts.QueryName);
+         SaveCounts(SaveCounts);
+         CheckObject(DirectoryHandle, 4LU + i, 1LU);
+     }
+     //DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
+     CheckCounts(SaveCounts.Open, SaveCounts.Close, SaveCounts.Delete, SaveCounts.Parse, SaveCounts.OkayToClose, SaveCounts.QueryName);
+ }
+ static
+ VOID
+ ObtClose(
+     BOOLEAN Clean,
+     BOOLEAN AlternativeMethod)
+ {
+     NTSTATUS Status;
+     LONG_PTR Ret;
+     PVOID TypeObject;
+     INT i;
+     UNICODE_STRING ObPathName[NUM_OBTYPES];
+     WCHAR Name[MAX_PATH];
+     // Close what we have opened and free what we allocated
+     for (i = 0; i < NUM_OBTYPES2; ++i)
+     {
+         if (!skip(ObBody[i] != NULL, "Nothing to dereference\n"))
+         {
+             if (ObHandle1[i]) CheckObject(ObHandle1[i], 3LU, 1LU);
+             Ret = ObDereferenceObject(ObBody[i]);
+             ok_eq_longptr(Ret, (LONG_PTR)1);
+             if (ObHandle1[i]) CheckObject(ObHandle1[i], 2LU, 1LU);
+             ObBody[i] = NULL;
+         }
+         if (!skip(ObHandle1[i] != NULL, "Nothing to close\n"))
+         {
+             Status = ZwClose(ObHandle1[i]);
+             ok_eq_hex(Status, STATUS_SUCCESS);
+             ObHandle1[i] = NULL;
+         }
+     }
+     if (skip(Clean, "Not cleaning up, as requested. Use ObTypeClean to clean up\n"))
+         return;
+     // Now we have to get rid of a directory object
+     // Since it is permanent, we have to firstly make it temporary
+     // and only then kill
+     // (this procedure is described in DDK)
+     if (!skip(DirectoryHandle != NULL, "No directory handle\n"))
+     {
+         CheckObject(DirectoryHandle, 3LU, 1LU);
+         Status = ZwMakeTemporaryObject(DirectoryHandle);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+         CheckObject(DirectoryHandle, 3LU, 1LU);
+         Status = ZwClose(DirectoryHandle);
+         ok_eq_hex(Status, STATUS_SUCCESS);
+     }
+     /* we don't delete the object types we created. It makes Windows unstable.
+      * TODO: perhaps make it work in ROS anyway */
+     return;
+     if (!AlternativeMethod)
+     {
+         for (i = 0; i < NUM_OBTYPES; ++i)
+             if (!skip(ObTypes[i] != NULL, "No object type to delete\n"))
+             {
+                 Ret = ObDereferenceObject(ObTypes[i]);
+                 ok_eq_longptr(Ret, (LONG_PTR)0);
+                 ObTypes[i] = NULL;
+             }
+     }
+     else
+     {
+         for (i = 0; i < NUM_OBTYPES; ++i)
+         {
+             if (!skip(ObTypes[i] != NULL, "No object type to delete\n"))
+             {
+                 Status = RtlStringCbPrintfW(Name, sizeof Name, L"\\ObjectTypes\\MyObjectType%d", i);
+                 RtlInitUnicodeString(&ObPathName[i], Name);
+                 Status = ObReferenceObjectByName(&ObPathName[i], OBJ_CASE_INSENSITIVE, NULL, 0L, NULL, KernelMode, NULL, &TypeObject);
+                 Ret = ObDereferenceObject(TypeObject);
+                 ok_eq_longptr(Ret, (LONG_PTR)2);
+                 Ret = ObDereferenceObject(TypeObject);
+                 ok_eq_longptr(Ret, (LONG_PTR)1);
+                 DPRINT("Reference Name %wZ = %p, ObTypes[%d] = %p\n",
+                     ObPathName[i], TypeObject, i, ObTypes[i]);
+                 ObTypes[i] = NULL;
+             }
+         }
+     }
+ }
+ static
+ VOID
+ TestObjectType(
+     IN BOOLEAN Clean)
+ {
+     RtlZeroMemory(&Counts, sizeof Counts);
+     ObtCreateObjectTypes();
+     DPRINT("ObtCreateObjectTypes() done\n");
+     ObtCreateDirectory();
+     DPRINT("ObtCreateDirectory() done\n");
+     if (!skip(ObTypes[0] != NULL, "No object types!\n"))
+         ObtCreateObjects();
+     DPRINT("ObtCreateObjects() done\n");
+     ObtClose(Clean, FALSE);
+ }
+ START_TEST(ObType)
+ {
+     TestObjectType(TRUE);
+ }
+ /* run this to see the objects created in user mode */
+ START_TEST(ObTypeNoClean)
+ {
+     TestObjectType(FALSE);
+ }
+ /* run this to clean up after ObTypeNoClean */
+ START_TEST(ObTypeClean)
+ {
+     ObtClose(TRUE, FALSE);
+ }
index 0000000,fa9a66b..fa9a66b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,11 +1,11 @@@
+ This directory contains the ReactOS Kernel-Mode Test Suite.
+ The kmtest, kmtest_drv and include subdirectories contain the
+ testing framework infrastructure, other directories contain tests.
+ The example subdirectory contains a set of small tests that can be used as
+ examples and templates.
+ See http://www.reactos.org/wiki/User:ThFabba/KmtestsHowto for more
+ information and a guide on how to use the framework.
index 0000000,999245a..999245a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,4 +1,4 @@@
+ /* this is a little hacky, but better than duplicating the code (for now) */
+ #define RTL_USE_AVL_TABLES
+ #define Test_RtlSplayTree Test_RtlAvlTree
+ #include "RtlSplayTree.c"
index 0000000,49dcf3e..49dcf3e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,498 +1,498 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         GPLv2+ - See COPYING in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite Runtime library memory functions test
+  * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+  */
+ #include <stddef.h>
+ __declspec(dllimport) void __stdcall RtlMoveMemory(void *, const void *, size_t);
+ __declspec(dllimport) void __stdcall RtlFillMemory(void *, size_t, unsigned char);
+ #define KMT_EMULATE_KERNEL
+ #include <kmt_test.h>
+ #ifdef __GNUC__
+ #pragma GCC diagnostic ignored "-Wnonnull"
+ #endif /* defined __GNUC__ */
+ static
+ VOID
+ MakeBuffer(
+     OUT PVOID Buffer,
+     ...)
+ {
+     PUCHAR OutBuffer = Buffer;
+     INT Count;
+     INT Value;
+     va_list Arguments;
+     va_start(Arguments, Buffer);
+     while (1)
+     {
+         Count = va_arg(Arguments, INT);
+         if (!Count)
+             break;
+         ASSERT(Count > 0);
+         Value = va_arg(Arguments, INT);
+         while (Count--)
+             *OutBuffer++ = Value;
+     }
+     va_end(Arguments);
+ }
+ static
+ BOOLEAN
+ CheckBuffer(
+     IN const VOID *Buffer,
+     ...)
+ {
+     PCUCHAR OutBuffer = Buffer;
+     INT Count;
+     INT Value;
+     va_list Arguments;
+     va_start(Arguments, Buffer);
+     while (1)
+     {
+         Count = va_arg(Arguments, INT);
+         if (!Count)
+             break;
+         ASSERT(Count > 0);
+         Value = va_arg(Arguments, INT);
+         while (Count--)
+             if (*OutBuffer++ != Value)
+             {
+                 --OutBuffer;
+                 trace("CheckBuffer failed at offset %d, value %x, expected %x\n", OutBuffer - (PCUCHAR)Buffer, *OutBuffer, Value);
+                 return FALSE;
+             }
+     }
+     va_end(Arguments);
+     return TRUE;
+ }
+ static
+ VOID
+ MakePattern(
+     OUT PVOID Buffer,
+     ...)
+ {
+     PUCHAR OutBuffer = Buffer;
+     INT Count, Repeat, i;
+     INT Values[16];
+     va_list Arguments;
+     va_start(Arguments, Buffer);
+     while (1)
+     {
+         Count = va_arg(Arguments, INT);
+         if (!Count)
+             break;
+         ASSERT(Count > 0 && Count < sizeof Values / sizeof Values[0]);
+         Repeat = va_arg(Arguments, INT);
+         ASSERT(Repeat > 0);
+         for (i = 0; i < Count; ++i)
+             Values[i] = va_arg(Arguments, INT);
+         while (Repeat--)
+             for (i = 0; i < Count; ++i)
+                 *OutBuffer++ = Values[i];
+     }
+     va_end(Arguments);
+ }
+ static
+ BOOLEAN
+ CheckPattern(
+     IN const VOID *Buffer,
+     ...)
+ {
+     PCUCHAR OutBuffer = Buffer;
+     INT Count, Repeat, i;
+     INT Values[16];
+     va_list Arguments;
+     va_start(Arguments, Buffer);
+     while (1)
+     {
+         Count = va_arg(Arguments, INT);
+         if (!Count)
+             break;
+         ASSERT(Count > 0 && Count < sizeof Values / sizeof Values[0]);
+         Repeat = va_arg(Arguments, INT);
+         ASSERT(Repeat > 0);
+         for (i = 0; i < Count; ++i)
+             Values[i] = va_arg(Arguments, INT);
+         while (Repeat--)
+             for (i = 0; i < Count; ++i)
+                 if (*OutBuffer++ != Values[i])
+                 {
+                     --OutBuffer;
+                     trace("CheckPattern failed at offset %d, value %x, expected %x\n", OutBuffer - (PCUCHAR)Buffer, *OutBuffer, Values[i]);
+                     return FALSE;
+                 }
+     }
+     va_end(Arguments);
+     return TRUE;
+ }
+ START_TEST(RtlMemory)
+ {
+     NTSTATUS Status;
+     UCHAR Buffer[513];
+     const SIZE_T Size = 512;
+     const SIZE_T HalfSize = Size / 2;
+     SIZE_T RetSize;
+     KIRQL Irql;
+     ULONG i;
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* zero everything behind 'Size'. Tests will check that this wasn't changed.
+      * TODO: use guarded memory for this! */
+     MakeBuffer(Buffer + Size, sizeof Buffer - Size, 0, 0);
+     /* test our helper functions first */
+     MakeBuffer(Buffer, HalfSize, 0x55, HalfSize, 0xAA, 0);
+     for (i = 0; i < HalfSize; ++i)
+         ok_eq_uint(Buffer[i], 0x55);
+     for (i = HalfSize; i < Size; ++i)
+         ok_eq_uint(Buffer[i], 0xAA);
+     ok_bool_true(CheckBuffer(Buffer, HalfSize, 0x55, HalfSize, 0xAA, 1, 0, 0), "CheckBuffer");
+     MakePattern(Buffer, 3, 20, 0x11, 0x22, 0x33, 1, 4, 0x44, 0);
+     for (i = 0; i < 60; i += 3)
+     {
+         ok_eq_uint(Buffer[i+0], 0x11);
+         ok_eq_uint(Buffer[i+1], 0x22);
+         ok_eq_uint(Buffer[i+2], 0x33);
+     }
+     for (i = 60; i < 64; ++i)
+         ok_eq_uint(Buffer[i], 0x44);
+     for (i = 64; i < HalfSize; ++i)
+         ok_eq_uint(Buffer[i], 0x55);
+     for (i = HalfSize; i < Size; ++i)
+         ok_eq_uint(Buffer[i], 0xAA);
+     ok_bool_true(CheckPattern(Buffer, 3, 20, 0x11, 0x22, 0x33, 1, 4, 0x44, 0), "CheckPattern");
+     /* RtlMoveMemory */
+     MakePattern(Buffer, 2, 64, 0x12, 0x34, 2, 192, 0x56, 0x78, 0);
+     RtlMoveMemory(Buffer + 13, Buffer + 62, 95);
+     ok_bool_true(CheckPattern(Buffer, 2, 6, 0x12, 0x34, 1, 1, 0x12, 2, 33, 0x12, 0x34, 2, 14, 0x56, 0x78, 1, 1, 0x56, 2, 10, 0x12, 0x34, 2, 192, 0x56, 0x78, 1, 1, 0, 0), "CheckPattern");
+     MakePattern(Buffer, 2, 32, 0x12, 0x34, 2, 32, 0x56, 0x78, 2, 192, 0x9A, 0xAB, 0);
+     RtlMoveMemory(Buffer + 78, Buffer + 43, 107);
+     ok_bool_true(CheckPattern(Buffer, 2, 32, 0x12, 0x34, 2, 7, 0x56, 0x78, 1, 1, 0x34, 2, 10, 0x12, 0x34, 2, 32, 0x56, 0x78, 2, 11, 0x9A, 0xAB, 1, 1, 0xAB, 2, 163, 0x9A, 0xAB, 1, 1, 0, 0), "CheckPattern");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlMoveMemory(NULL, NULL, 0);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+ #undef RtlMoveMemory
+     /* RtlMoveMemory export */
+     MakePattern(Buffer, 2, 64, 0x12, 0x34, 2, 192, 0x56, 0x78, 0);
+     RtlMoveMemory(Buffer + 13, Buffer + 62, 95);
+     ok_bool_true(CheckPattern(Buffer, 2, 6, 0x12, 0x34, 1, 1, 0x12, 2, 33, 0x12, 0x34, 2, 14, 0x56, 0x78, 1, 1, 0x56, 2, 10, 0x12, 0x34, 2, 192, 0x56, 0x78, 1, 1, 0, 0), "CheckPattern");
+     MakePattern(Buffer, 2, 32, 0x12, 0x34, 2, 32, 0x56, 0x78, 2, 192, 0x9A, 0xAB, 0);
+     RtlMoveMemory(Buffer + 78, Buffer + 43, 107);
+     ok_bool_true(CheckPattern(Buffer, 2, 32, 0x12, 0x34, 2, 7, 0x56, 0x78, 1, 1, 0x34, 2, 10, 0x12, 0x34, 2, 32, 0x56, 0x78, 2, 11, 0x9A, 0xAB, 1, 1, 0xAB, 2, 163, 0x9A, 0xAB, 1, 1, 0, 0), "CheckPattern");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlMoveMemory(NULL, NULL, 0);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlCopyMemory */
+     MakePattern(Buffer, 2, 64, 0x12, 0x34, 2, 192, 0x56, 0x78, 0);
+     RtlCopyMemory(Buffer + 13, Buffer + 62, 95);
+     ok_bool_true(CheckPattern(Buffer, 2, 6, 0x12, 0x34, 1, 1, 0x12, 2, 33, 0x12, 0x34, 2, 14, 0x56, 0x78, 1, 1, 0x56, 2, 10, 0x12, 0x34, 2, 192, 0x56, 0x78, 1, 1, 0, 0), "CheckPattern");
+     MakePattern(Buffer, 2, 32, 0x12, 0x34, 2, 32, 0x56, 0x78, 2, 192, 0x9A, 0xAB, 0);
+     RtlCopyMemory(Buffer + 78, Buffer + 43, 107);
+     ok_bool_true(CheckPattern(Buffer, 2, 32, 0x12, 0x34, 2, 7, 0x56, 0x78, 1, 1, 0x34, 2, 10, 0x12, 0x34, 2, 32, 0x56, 0x78, 2, 11, 0x9A, 0xAB, 1, 1, 0xAB, 2, 163, 0x9A, 0xAB, 1, 1, 0, 0), "CheckPattern");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlCopyMemory(NULL, NULL, 0);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlCopyMemoryNonTemporal */
+     MakePattern(Buffer, 2, 64, 0x12, 0x34, 2, 192, 0x56, 0x78, 0);
+     RtlCopyMemoryNonTemporal(Buffer + 13, Buffer + 62, 95);
+     ok_bool_true(CheckPattern(Buffer, 2, 6, 0x12, 0x34, 1, 1, 0x12, 2, 33, 0x12, 0x34, 2, 14, 0x56, 0x78, 1, 1, 0x56, 2, 10, 0x12, 0x34, 2, 192, 0x56, 0x78, 1, 1, 0, 0), "CheckPattern");
+     MakePattern(Buffer, 2, 32, 0x12, 0x34, 2, 32, 0x56, 0x78, 2, 192, 0x9A, 0xAB, 0);
+     RtlCopyMemoryNonTemporal(Buffer + 78, Buffer + 43, 107);
+     ok_bool_true(CheckPattern(Buffer, 2, 32, 0x12, 0x34, 2, 7, 0x56, 0x78, 1, 1, 0x34, 2, 10, 0x12, 0x34, 2, 32, 0x56, 0x78, 2, 11, 0x9A, 0xAB, 1, 1, 0xAB, 2, 163, 0x9A, 0xAB, 1, 1, 0, 0), "CheckPattern");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlCopyMemoryNonTemporal(NULL, NULL, 0);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlCopyBytes */
+     MakePattern(Buffer, 2, 64, 0x12, 0x34, 2, 192, 0x56, 0x78, 0);
+     RtlCopyBytes(Buffer + 13, Buffer + 62, 95);
+     ok_bool_true(CheckPattern(Buffer, 2, 6, 0x12, 0x34, 1, 1, 0x12, 2, 33, 0x12, 0x34, 2, 14, 0x56, 0x78, 1, 1, 0x56, 2, 10, 0x12, 0x34, 2, 192, 0x56, 0x78, 1, 1, 0, 0), "CheckPattern");
+     MakePattern(Buffer, 2, 32, 0x12, 0x34, 2, 32, 0x56, 0x78, 2, 192, 0x9A, 0xAB, 0);
+     RtlCopyBytes(Buffer + 78, Buffer + 43, 107);
+     ok_bool_true(CheckPattern(Buffer, 2, 32, 0x12, 0x34, 2, 7, 0x56, 0x78, 1, 1, 0x34, 2, 10, 0x12, 0x34, 2, 32, 0x56, 0x78, 2, 11, 0x9A, 0xAB, 1, 1, 0xAB, 2, 163, 0x9A, 0xAB, 1, 1, 0, 0), "CheckPattern");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlCopyBytes(NULL, NULL, 0);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlEqualMemory */
+     /* TODO: where is memcmp? */
+     /* RtlCompareMemory */
+     MakePattern(Buffer, 8, HalfSize / 8 - 1, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
+                         1, 1,                0x12,
+                         8, HalfSize / 8,     0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
+                         1, 7,                0x12, 0);
+     RetSize = RtlCompareMemory(Buffer, Buffer + HalfSize - 7, HalfSize - 8);
+     ok_eq_size(RetSize, HalfSize - 8);
+     RetSize = RtlCompareMemory(Buffer, Buffer + HalfSize - 7, HalfSize - 8 + 1);
+     ok_eq_size(RetSize, HalfSize - 8 + 1);
+     RetSize = RtlCompareMemory(Buffer, Buffer + HalfSize - 7, HalfSize - 8 + 2);
+     ok_eq_size(RetSize, HalfSize - 8 + 1);
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RetSize = RtlCompareMemory(Buffer, Buffer + HalfSize - 7, SIZE_MAX);
+         ok_eq_size(RetSize, HalfSize - 8 + 1);
+         RetSize = RtlCompareMemory(NULL, NULL, 0);
+         ok_eq_size(RetSize, 0);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlCompareMemoryUlong */
+     MakeBuffer(Buffer, 8, 0x55, Size - 4, 0, 0);
+     RetSize = RtlCompareMemoryUlong(Buffer, sizeof(ULONG), 0x55555555LU);
+     ok_eq_size(RetSize, 4);
+     RetSize = RtlCompareMemoryUlong(Buffer + 1, sizeof(ULONG), 0x55555555LU);
+     ok_eq_size(RetSize, 4);
+     RetSize = RtlCompareMemoryUlong(Buffer + 2, sizeof(ULONG), 0x55555555LU);
+     ok_eq_size(RetSize, 4);
+     RetSize = RtlCompareMemoryUlong(Buffer + 3, sizeof(ULONG), 0x55555555LU);
+     ok_eq_size(RetSize, 4);
+     RetSize = RtlCompareMemoryUlong(Buffer + 5, sizeof(ULONG), 0x55555555LU);
+     ok_eq_size(RetSize, 0);
+     RetSize = RtlCompareMemoryUlong(Buffer + 5, sizeof(ULONG), 0x00555555LU);
+     ok_eq_size(RetSize, 4);
+     RetSize = RtlCompareMemoryUlong(Buffer, 1, 0x55555555LU);
+     ok_eq_size(RetSize, 0);
+     RetSize = RtlCompareMemoryUlong(Buffer, 2, 0x55555555LU);
+     ok_eq_size(RetSize, 0);
+     RetSize = RtlCompareMemoryUlong(Buffer, 3, 0x55555555LU);
+     ok_eq_size(RetSize, 0);
+     RetSize = RtlCompareMemoryUlong(Buffer, 5, 0x55555555LU);
+     ok_eq_size(RetSize, 4);
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RetSize = RtlCompareMemoryUlong(NULL, 0, 0x55555555LU);
+         ok_eq_size(RetSize, 0);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlZeroMemory */
+     MakeBuffer(Buffer, Size, 0x11, 0);
+     RtlZeroMemory(Buffer, 1);
+     ok_bool_true(CheckBuffer(Buffer, 1, 0, Size - 1, 0x11, 1, 0, 0), "CheckBuffer");
+     Buffer[0] = 0x11;
+     RtlZeroMemory(Buffer, Size - 1);
+     ok_bool_true(CheckBuffer(Buffer, Size - 1, 0, 1, 0x11, 1, 0, 0), "CheckBuffer");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlZeroMemory(NULL, 0);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlSecureZeroMemory */
+     MakeBuffer(Buffer, Size, 0x11, 0);
+     RtlSecureZeroMemory(Buffer, 1);
+     ok_bool_true(CheckBuffer(Buffer, 1, 0, Size - 1, 0x11, 1, 0, 0), "CheckBuffer");
+     Buffer[0] = 0x11;
+     RtlSecureZeroMemory(Buffer, Size - 1);
+     ok_bool_true(CheckBuffer(Buffer, Size - 1, 0, 1, 0x11, 1, 0, 0), "CheckBuffer");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlSecureZeroMemory(NULL, 0);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlZeroBytes */
+     MakeBuffer(Buffer, Size, 0x11, 0);
+     RtlZeroBytes(Buffer, 1);
+     ok_bool_true(CheckBuffer(Buffer, 1, 0, Size - 1, 0x11, 1, 0, 0), "CheckBuffer");
+     Buffer[0] = 0x11;
+     RtlZeroBytes(Buffer, Size - 1);
+     ok_bool_true(CheckBuffer(Buffer, Size - 1, 0, 1, 0x11, 1, 0, 0), "CheckBuffer");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlZeroBytes(NULL, 0);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlFillMemory */
+     MakeBuffer(Buffer, Size, 0, 0);
+     RtlFillMemory(Buffer, HalfSize, 0x55);
+     RtlFillMemory(Buffer + HalfSize, HalfSize, 0xAA);
+     ok_bool_true(CheckBuffer(Buffer, HalfSize, 0x55, HalfSize, 0xAA, 1, 0, 0), "CheckBuffer");
+     RtlFillMemory(Buffer + 3, 7, 0x88);
+     ok_bool_true(CheckBuffer(Buffer, 3, 0x55, 7, 0x88, HalfSize - 10, 0x55, HalfSize, 0xAA, 1, 0, 0), "CheckBuffer");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlFillMemory(NULL, 0, 0x55);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+ #undef RtlFillMemory
+     /* RtlFillMemory export */
+     MakeBuffer(Buffer, Size, 0, 0);
+     RtlFillMemory(Buffer, HalfSize, 0x55);
+     RtlFillMemory(Buffer + HalfSize, HalfSize, 0xAA);
+     ok_bool_true(CheckBuffer(Buffer, HalfSize, 0x55, HalfSize, 0xAA, 1, 0, 0), "CheckBuffer");
+     RtlFillMemory(Buffer + 3, 7, 0x88);
+     ok_bool_true(CheckBuffer(Buffer, 3, 0x55, 7, 0x88, HalfSize - 10, 0x55, HalfSize, 0xAA, 1, 0, 0), "CheckBuffer");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlFillMemory(NULL, 0, 0x55);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlFillMemoryUlong */
+     MakeBuffer(Buffer, Size, 0, 0);
+     RtlFillMemoryUlong(Buffer, HalfSize, 0x01234567LU);
+     RtlFillMemoryUlong(Buffer + HalfSize, HalfSize, 0x89ABCDEFLU);
+     ok_bool_true(CheckPattern(Buffer, 4, HalfSize / 4, 0x67, 0x45, 0x23, 0x01, 4, HalfSize / 4, 0xEF, 0xCD, 0xAB, 0x89, 1, 1, 0, 0), "CheckPattern");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         MakeBuffer(Buffer, Size, 0, 0);
+         RtlFillMemoryUlong(Buffer + 1, sizeof(ULONG), 0xAAAAAAAALU);
+         ok_bool_true(CheckBuffer(Buffer, 1, 0, sizeof(ULONG), 0xAA, Size - sizeof(ULONG) - 1, 0, 1, 0, 0), "CheckBuffer");
+         RtlFillMemoryUlong(NULL, 0, 0x55555555LU);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlFillMemoryUlonglong */
+     /* TODO: this function doesn't exist in 2k3/x86? wdm.h error? */
+     /* RtlFillBytes */
+     MakeBuffer(Buffer, Size, 0, 0);
+     RtlFillBytes(Buffer, HalfSize, 0x55);
+     RtlFillBytes(Buffer + HalfSize, HalfSize, 0xAA);
+     ok_bool_true(CheckBuffer(Buffer, HalfSize, 0x55, HalfSize, 0xAA, 1, 0, 0), "CheckBuffer");
+     RtlFillBytes(Buffer + 3, 7, 0x88);
+     ok_bool_true(CheckBuffer(Buffer, 3, 0x55, 7, 0x88, HalfSize - 10, 0x55, HalfSize, 0xAA, 1, 0, 0), "CheckBuffer");
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlFillBytes(NULL, 0, 0x55);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     /* RtlPrefetchMemoryNonTemporal */
+     RtlPrefetchMemoryNonTemporal(Buffer, Size);
+     KeLowerIrql(Irql);
+     Status = STATUS_SUCCESS;
+     _SEH2_TRY {
+         RtlPrefetchMemoryNonTemporal(NULL, 0);
+     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+         Status = _SEH2_GetExceptionCode();
+     } _SEH2_END;
+     ok_eq_hex(Status, STATUS_SUCCESS);
+     KeRaiseIrql(HIGH_LEVEL, &Irql);
+     KeLowerIrql(Irql);
+ }
index 0000000,1e4b739..1e4b739
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,92 +1,92 @@@
+ /*
+  * PROJECT:         ReactOS kernel-mode tests
+  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
+  * PURPOSE:         Kernel-Mode Test Suite RtlGenericTable
+  * PROGRAMMER:      arty
+  */
+ #define KMT_EMULATE_KERNEL
+ #include <kmt_test.h>
+ #define NDEBUG
+ #include <debug.h>
+ static LIST_ENTRY Allocations;
+ static RTL_GENERIC_COMPARE_RESULTS NTAPI
+ CompareCharTable(PRTL_GENERIC_TABLE Table, PVOID A, PVOID B)
+ {
+     RTL_GENERIC_COMPARE_RESULTS Result = (*((PCHAR)A) < *((PCHAR)B)) ? GenericLessThan :
+         (*((PCHAR)A) > *((PCHAR)B)) ? GenericGreaterThan :
+         GenericEqual;
+     return Result;
+ }
+ static PVOID NTAPI
+ AllocRoutine(PRTL_GENERIC_TABLE Table, CLONG ByteSize)
+ {
+     PLIST_ENTRY Entry = ExAllocatePool
+         (NonPagedPool, sizeof(LIST_ENTRY) + ByteSize);
+     InsertTailList(&Allocations, Entry);
+     return &Entry[1];
+ }
+ static VOID NTAPI
+ FreeRoutine(PRTL_GENERIC_TABLE Table, PVOID Buffer)
+ {
+     PLIST_ENTRY Entry = (PLIST_ENTRY)(((PCHAR)Buffer) - sizeof(LIST_ENTRY));
+     RemoveEntryList(Entry);
+     ExFreePool(Entry);
+ }
+ static void RtlSplayTreeTest()
+ {
+     ULONG i, del;
+     PCHAR Ch;
+     CHAR Text[] = "the quick_brown!fOx-jUmp3d/0vER+THe^lazy.D@g";
+     CHAR NewE[] = "11111111111111111111111111111111110111111111";
+     RTL_GENERIC_TABLE Table;
+     RtlInitializeGenericTable
+         (&Table,
+          CompareCharTable,
+          AllocRoutine,
+          FreeRoutine,
+          NULL);
+     for (i = 0; Text[i]; i++) {
+         BOOLEAN WasNew;
+         Ch = (PCHAR)RtlInsertElementGenericTable
+             (&Table,
+              &Text[i],
+              sizeof(Text[i]),
+              &WasNew);
+         ok(Ch && *Ch == Text[i], "Copy character into node\n");
+         ok(WasNew == (NewE[i] == '1'), "Character newness didn't match\n");
+     }
+     for (Ch = (PCHAR)RtlEnumerateGenericTable(&Table, TRUE), i = 0;
+          Ch;
+          Ch = (PCHAR)RtlEnumerateGenericTable(&Table, FALSE), i++) {
+         ok(strchr(Text, *Ch) != NULL, "Nonexistent character\n");
+     }
+     ok(RtlNumberGenericTableElements(&Table) == strlen(Text) - 1, "Not the right number of elements\n");
+     ok(RtlLookupElementGenericTable(&Table, "q") != NULL, "Could not lookup q\n");
+     ok(!RtlLookupElementGenericTable(&Table, "#"), "Found a character that shouldn't appear\n");
+     ok(strlen(Text) == i + 1, "Didn't enumerate enough characters\n");
+     del = 0;
+     for (i = 0; Text[i]; i++) {
+         if (NewE[i] == '1') {
+             BOOLEAN WasDeleted;
+             WasDeleted = RtlDeleteElementGenericTable(&Table, &Text[i]);
+             del += WasDeleted;
+         }
+     }
+     ok(!RtlNumberGenericTableElements(&Table), "Not zero elements\n");
+     ok(!RtlGetElementGenericTable(&Table, 0), "Elements left when we removed them all\n");
+     ok(strlen(Text) == del + 1, "Deleted too many times\n");
+     ok(IsListEmpty(&Allocations), "Didn't free all memory\n");
+ }
+ START_TEST(RtlSplayTree)
+ {
+     InitializeListHead(&Allocations);
+     RtlSplayTreeTest();
+ }
@@@ -4,9 -4,6 +4,6 @@@
        <directory name="kernel32">
                <xi:include href="kernel32/directory.rbuild" />
        </directory>
-       <directory name="kmtloader">
-               <xi:include href="kmtloader/kmtloader.rbuild" />
-       </directory>
        <directory name="smss">
                <xi:include href="smss/smss.rbuild" />
        </directory>