[ROSTESTS]

- Merge the Kernel Mode Test Suite Google Summer of Code project
- Happy testing, everyone ;)

svn path=/trunk/; revision=53671
This commit is contained in:
Thomas Faber 2011-09-10 11:41:33 +00:00
commit 454f222ade
76 changed files with 8871 additions and 2239 deletions

View file

@ -1,7 +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)

View file

@ -1,6 +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 @@
<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 @@
<directory name="winetests">
<xi:include href="winetests/directory.rbuild" />
</directory>
<directory name="apitests">
<xi:include href="apitests/directory.rbuild" />
</directory>
</group>

View file

@ -4,12 +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>

View file

@ -1,266 +0,0 @@
/*
* Driver Regression Tests
*
* Copyright 2009 Michael Martin <martinmnet@hotmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; see the file COPYING.LIB.
* If not, write to the Free Software Foundation,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* INCLUDES *******************************************************************/
#include "kmtest.h"
#include <ddk/ntddk.h>
#include <ddk/ntifs.h>
#include "ntddser.h"
#include "ntndk.h"
VOID LowerDeviceKernelAPITest(PDEVICE_OBJECT DeviceObject, BOOLEAN UnLoading)
{
PDEVICE_OBJECT RetObject;
RetObject = IoGetLowerDeviceObject(DeviceObject);
if (UnLoading)
{
ok(RetObject == 0,
"Expected no Lower DeviceObject, got %p", RetObject);
}
else
{
ok(RetObject == AttachDeviceObject,
"Expected an Attached DeviceObject %p, got %p", AttachDeviceObject, RetObject);
}
if (RetObject)
{
ObDereferenceObject(RetObject);
}
RetObject = IoGetDeviceAttachmentBaseRef(DeviceObject);
ok(RetObject == DeviceObject,
"Expected an Attached DeviceObject %p, got %p", DeviceObject, RetObject);
if (RetObject)
{
ObDereferenceObject(RetObject);
}
}
VOID DeviceCreatedTest(PDEVICE_OBJECT DeviceObject, BOOLEAN ExclusiveAccess)
{
PEXTENDED_DEVOBJ_EXTENSION extdev;
/*Check the device object members */
ok(DeviceObject->Type==3, "Expected Type = 3, got %x", DeviceObject->Type);
ok(DeviceObject->Size = 0xb8, "Expected Size = 0xba, got %x", DeviceObject->Size);
ok(DeviceObject->ReferenceCount == 0, "Expected ReferenceCount = 0, got %lu",
DeviceObject->ReferenceCount);
ok(DeviceObject->DriverObject == ThisDriverObject,
"Expected DriverObject member to match this DriverObject %p, got %p",
ThisDriverObject, DeviceObject->DriverObject);
ok(DeviceObject->NextDevice == NULL, "Expected NextDevice to be NULL, got %p", DeviceObject->NextDevice);
ok(DeviceObject->AttachedDevice == NULL, "Expected AttachDevice to be NULL, got %p", DeviceObject->AttachedDevice);
ok(DeviceObject->Characteristics == 0, "Expected Characteristics to be 0");
if (ExclusiveAccess)
{
ok((DeviceObject->Flags == (DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING | DO_EXCLUSIVE)),
"Expected Flags DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING | DO_EXCLUSIVE, got %lu", DeviceObject->Flags);
}
else
{
ok((DeviceObject->Flags == (DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING)),
"Expected Flags DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING, got %lu", DeviceObject->Flags);
}
ok(DeviceObject->DeviceType == FILE_DEVICE_UNKNOWN,
"Expected DeviceType to match creation parameter FILE_DEVICE_UNKNWOWN, got %lu",
DeviceObject->DeviceType);
ok(DeviceObject->ActiveThreadCount == 0, "Expected ActiveThreadCount = 0, got %lu\n", DeviceObject->ActiveThreadCount);
/*Check the extended extension */
extdev = (PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension;
ok(extdev->ExtensionFlags == 0, "Expected Extended ExtensionFlags to be 0, got %lu", extdev->ExtensionFlags);
ok (extdev->Type == 13, "Expected Type of 13, got %d", extdev->Type);
ok (extdev->Size == 0, "Expected Size of 0, got %d", extdev->Size);
ok (extdev->DeviceObject == DeviceObject, "Expected DeviceOject to match newly created device %p, got %p",
DeviceObject, extdev->DeviceObject);
ok(extdev->AttachedTo == NULL, "Expected AttachTo to be NULL, got %p", extdev->AttachedTo);
ok(extdev->StartIoCount == 0, "Expected StartIoCount = 0, got %lu", extdev->StartIoCount);
ok(extdev->StartIoKey == 0, "Expected StartIoKey = 0, got %lu", extdev->StartIoKey);
ok(extdev->StartIoFlags == 0, "Expected StartIoFlags = 0, got %lu", extdev->StartIoFlags);
}
VOID DeviceDeletionTest(PDEVICE_OBJECT DeviceObject, BOOLEAN Lower)
{
PEXTENDED_DEVOBJ_EXTENSION extdev;
/*Check the device object members */
ok(DeviceObject->Type==3, "Expected Type = 3, got %d", DeviceObject->Type);
ok(DeviceObject->Size = 0xb8, "Expected Size = 0xba, got %d", DeviceObject->Size);
ok(DeviceObject->ReferenceCount == 0, "Expected ReferenceCount = 0, got %lu",
DeviceObject->ReferenceCount);
if (!Lower)
{
ok(DeviceObject->DriverObject == ThisDriverObject,
"Expected DriverObject member to match this DriverObject %p, got %p",
ThisDriverObject, DeviceObject->DriverObject);
}
ok(DeviceObject->NextDevice == NULL, "Expected NextDevice to be NULL, got %p", DeviceObject->NextDevice);
if (Lower)
{
ok(DeviceObject->AttachedDevice == MainDeviceObject,
"Expected AttachDevice to be %p, got %p", MainDeviceObject, DeviceObject->AttachedDevice);
}
else
{
ok(DeviceObject->AttachedDevice == NULL, "Expected AttachDevice to be NULL, got %p", DeviceObject->AttachedDevice);
}
ok(DeviceObject->Flags ==FILE_VIRTUAL_VOLUME,
"Expected Flags FILE_VIRTUAL_VOLUME, got %lu", DeviceObject->Flags);
ok(DeviceObject->DeviceType == FILE_DEVICE_UNKNOWN,
"Expected DeviceType to match creation parameter FILE_DEVICE_UNKNWOWN, got %lu",
DeviceObject->DeviceType);
ok(DeviceObject->ActiveThreadCount == 0, "Expected ActiveThreadCount = 0, got %lu\n", DeviceObject->ActiveThreadCount);
/*Check the extended extension */
extdev = (PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension;
ok(extdev->ExtensionFlags == DOE_UNLOAD_PENDING,
"Expected Extended ExtensionFlags to be DOE_UNLOAD_PENDING, got %lu", extdev->ExtensionFlags);
ok (extdev->Type == 13, "Expected Type of 13, got %d", extdev->Type);
ok (extdev->Size == 0, "Expected Size of 0, got %d", extdev->Size);
ok (extdev->DeviceObject == DeviceObject, "Expected DeviceOject to match newly created device %p, got %p",
DeviceObject, extdev->DeviceObject);
if (Lower)
{
/* Skip this for now */
//ok(extdev->AttachedTo == MainDeviceObject, "Expected AttachTo to %p, got %p", MainDeviceObject, extdev->AttachedTo);
}
else
{
ok(extdev->AttachedTo == NULL, "Expected AttachTo to be NULL, got %p", extdev->AttachedTo);
}
ok(extdev->StartIoCount == 0, "Expected StartIoCount = 0, got %lu", extdev->StartIoCount);
ok(extdev->StartIoKey == 0, "Expected StartIoKey = 0, got %lu", extdev->StartIoKey);
ok(extdev->StartIoFlags == 0, "Expected StartIoFlags = 0, got %lu", extdev->StartIoFlags);
}
VOID DeviceCreateDeleteTest(PDRIVER_OBJECT DriverObject)
{
NTSTATUS Status;
UNICODE_STRING DeviceString;
UNICODE_STRING DosDeviceString;
PDEVICE_OBJECT DeviceObject;
/* Create using wrong directory */
RtlInitUnicodeString(&DeviceString, L"\\Device1\\Kmtest");
Status = IoCreateDevice(DriverObject,
0,
&DeviceString,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&DeviceObject);
ok(Status == STATUS_OBJECT_PATH_NOT_FOUND, "Expected STATUS_OBJECT_PATH_NOT_FOUND, got 0x%lX", Status);
/* Create using correct params with exlusice access */
RtlInitUnicodeString(&DeviceString, L"\\Device\\Kmtest");
Status = IoCreateDevice(DriverObject,
0,
&DeviceString,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&DeviceObject);
ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status);
DeviceCreatedTest(DeviceObject, TRUE);
/* Delete the device */
if (NT_SUCCESS(Status))
{
IoDeleteDevice(DeviceObject);
ok(DriverObject->DeviceObject == 0, "Expected DriverObject->DeviceObject to be NULL, got %p",
DriverObject->DeviceObject);
}
/* Create using correct params with exlusice access */
Status = IoCreateDevice(DriverObject,
0,
&DeviceString,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&DeviceObject);
ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status);
DeviceCreatedTest(DeviceObject, FALSE);
/* Delete the device */
if (NT_SUCCESS(Status))
{
IoDeleteDevice(DeviceObject);
ok(DriverObject->DeviceObject == 0, "Expected DriverObject->DeviceObject to be NULL, got %p",
DriverObject->DeviceObject);
}
/* Recreate device */
Status = IoCreateDevice(DriverObject,
0,
&DeviceString,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&DeviceObject);
ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status);
RtlInitUnicodeString(&DosDeviceString, L"\\DosDevices\\kmtest");
Status = IoCreateSymbolicLink(&DosDeviceString, &DeviceString);
if (!NT_SUCCESS(Status))
{
/* Delete device object if not successful */
IoDeleteDevice(DeviceObject);
return;
}
MainDeviceObject = DeviceObject;
return;
}
BOOLEAN AttachDeviceTest(PDEVICE_OBJECT DeviceObject, PWCHAR NewDriverRegPath)
{
NTSTATUS Status;
UNICODE_STRING LowerDeviceName;
RtlInitUnicodeString(&LowerDeviceName, NewDriverRegPath);
Status = IoAttachDevice(DeviceObject, &LowerDeviceName, &AttachDeviceObject);
/* TODO: Add more tests */
return TRUE;
}
BOOLEAN DetachDeviceTest(PDEVICE_OBJECT AttachedDevice)
{
IoDetachDevice(AttachedDevice);
/* TODO: Add more tests */
return TRUE;
}

View file

@ -1,141 +0,0 @@
/*
* Driver Regression Tests
*
* Copyright 2009 Michael Martin <martinmnet@hotmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; see the file COPYING.LIB.
* If not, write to the Free Software Foundation,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* INCLUDES *******************************************************************/
#include "kmtest.h"
#include <ddk/ntddk.h>
#include <ddk/ntifs.h>
VOID DriverObjectTest(PDRIVER_OBJECT DriverObject, int DriverStatus)
{
BOOLEAN CheckThisDispatchRoutine;
PVOID FirstMajorFunc;
int i;
ok(DriverObject->Size == sizeof(DRIVER_OBJECT), "Size does not match, got %x",DriverObject->Size);
ok(DriverObject->Type == 4, "Type does not match 4. got %d",DriverObject->Type);
if (DriverStatus == 0)
{
ok(DriverObject->DeviceObject == NULL, "Expected DeviceObject pointer to be 0, got %p",
DriverObject->DeviceObject);
ok (DriverObject->Flags == DRVO_LEGACY_DRIVER,
"Expected Flags to be DRVO_LEGACY_DRIVER, got %lu",
DriverObject->Flags);
}
else if (DriverStatus == 1)
{
ok(DriverObject->DeviceObject != NULL, "Expected DeviceObject pointer to non null");
ok (DriverObject->Flags == (DRVO_LEGACY_DRIVER | DRVO_INITIALIZED),
"Expected Flags to be DRVO_LEGACY_DRIVER | DRVO_INITIALIZED, got %lu",
DriverObject->Flags);
}
else
{
ok(DriverObject->DeviceObject != NULL, "Expected DeviceObject pointer to non null");
ok (DriverObject->Flags == (DRVO_LEGACY_DRIVER | DRVO_INITIALIZED | DRVO_UNLOAD_INVOKED),
"Expected Flags to be DRVO_LEGACY_DRIVER | DRVO_INITIALIZED | DRVO_UNLOAD_INVOKED, got %lu",
DriverObject->Flags);
}
/* Select a routine that was not changed */
FirstMajorFunc = DriverObject->MajorFunction[1];
ok(FirstMajorFunc != 0, "Expected MajorFunction[1] to be non NULL");
if (FirstMajorFunc)
{
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
{
if (DriverStatus > 0) CheckThisDispatchRoutine = (i > 3) && (i != 14);
else CheckThisDispatchRoutine = TRUE;
if (CheckThisDispatchRoutine)
{
ok(DriverObject->MajorFunction[i] == FirstMajorFunc, "Expected MajorFunction[%d] to match %p",
i, FirstMajorFunc);
}
}
}
else
{
ok(TRUE, "Skipped testing for all MajorFunction");
}
}
BOOLEAN ZwLoadTest(PDRIVER_OBJECT DriverObject, PUNICODE_STRING DriverRegistryPath, PWCHAR NewDriverRegPath)
{
UNICODE_STRING RegPath;
NTSTATUS Status;
/* Try to load ourself */
Status = ZwLoadDriver(DriverRegistryPath);
ok (Status == STATUS_IMAGE_ALREADY_LOADED, "Expected NTSTATUS STATUS_IMAGE_ALREADY_LOADED, got 0x%lX", Status);
if (Status != STATUS_IMAGE_ALREADY_LOADED)
{
DbgPrint("WARNING: Loading this a second time will cause BUGCHECK!\n");
}
/* Try to load with a Registry Path that doesnt exist */
RtlInitUnicodeString(&RegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\deadbeef");
Status = ZwLoadDriver(&RegPath);
ok (Status == STATUS_OBJECT_NAME_NOT_FOUND, "Expected NTSTATUS STATUS_OBJECT_NAME_NOT_FOUND, got 0x%lX", Status);
/* Load the driver */
RtlInitUnicodeString(&RegPath, NewDriverRegPath);
Status = ZwLoadDriver(&RegPath);
ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
return TRUE;
}
BOOLEAN ZwUnloadTest(PDRIVER_OBJECT DriverObject, PUNICODE_STRING DriverRegistryPath, PWCHAR NewDriverRegPath)
{
UNICODE_STRING RegPath;
NTSTATUS Status;
/* Try to unload ourself, which should fail as our Unload routine hasnt been set yet. */
Status = ZwUnloadDriver(DriverRegistryPath);
ok (Status == STATUS_INVALID_DEVICE_REQUEST, "Expected NTSTATUS STATUS_INVALID_DEVICE_REQUEST, got 0x%lX", Status);
/* Try to unload with a Registry Path that doesnt exist */
RtlInitUnicodeString(&RegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\deadbeef");
Status = ZwUnloadDriver(&RegPath);
ok (Status == STATUS_OBJECT_NAME_NOT_FOUND, "Expected NTSTATUS STATUS_OBJECT_NAME_NOT_FOUND, got 0x%lX", Status);
/* Unload the driver */
RtlInitUnicodeString(&RegPath, NewDriverRegPath);
Status = ZwUnloadDriver(&RegPath);
ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
return TRUE;
}

View file

@ -1,526 +0,0 @@
/*
* Kernel Mode regression Test
* Driver Core
*
* 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.
*/
/* INCLUDES *******************************************************************/
#include <ddk/ntddk.h>
#include "kmtest.h"
#define NDEBUG
#include <debug.h>
LONG successes;
LONG failures;
LONG skipped;
tls_data glob_data;
/* PRIVATE FUNCTIONS ***********************************************************/
VOID
StartTest()
{
successes = 0;
failures = 0;
skipped = 0;
}
VOID
FinishTest(HANDLE KeyHandle, LPWSTR TestName)
{
WCHAR KeyName[100];
LONG total = successes + failures;
UNICODE_STRING KeyNameU;
wcscpy(KeyName, TestName);
wcscat(KeyName, L"SuccessCount");
RtlInitUnicodeString(&KeyNameU, KeyName);
ZwSetValueKey(KeyHandle,
&KeyNameU,
0,
REG_DWORD,
&successes,
sizeof(ULONG));
wcscpy(KeyName, TestName);
wcscat(KeyName, L"FailureCount");
RtlInitUnicodeString(&KeyNameU, KeyName);
ZwSetValueKey(KeyHandle,
&KeyNameU,
0,
REG_DWORD,
&failures,
sizeof(ULONG));
wcscpy(KeyName, TestName);
wcscat(KeyName, L"TotalCount");
RtlInitUnicodeString(&KeyNameU, KeyName);
ZwSetValueKey(KeyHandle,
&KeyNameU,
0,
REG_DWORD,
&total,
sizeof(ULONG));
wcscpy(KeyName, TestName);
wcscat(KeyName, L"SkipCount");
RtlInitUnicodeString(&KeyNameU, KeyName);
ZwSetValueKey(KeyHandle,
&KeyNameU,
0,
REG_DWORD,
&skipped,
sizeof(ULONG));
DbgPrint("%S: %d test executed (0 marked as todo, %d failures), %d skipped.\n", TestName, total, failures, skipped);
}
void kmtest_set_location(const char* file, int line)
{
glob_data.current_file=strrchr(file,'/');
if (glob_data.current_file==NULL)
glob_data.current_file=strrchr(file,'\\');
if (glob_data.current_file==NULL)
glob_data.current_file=file;
else
glob_data.current_file++;
glob_data.current_line=line;
}
/*
* Checks condition.
* Parameters:
* - condition - condition to check;
* - msg test description;
* - file - test application source code file name of the check
* - line - test application source code file line number of the check
* Return:
* 0 if condition does not have the expected value, 1 otherwise
*/
int kmtest_ok(int condition, const char *msg, ... )
{
va_list valist;
if (!condition)
{
if (msg[0])
{
char string[1024];
va_start(valist, msg);
vsprintf(string, msg, valist);
DbgPrint( "%s:%d: Test failed: %s\n",
glob_data.current_file, glob_data.current_line, string );
va_end(valist);
}
else
{
DbgPrint( "%s:%d: Test failed\n",
glob_data.current_file, glob_data.current_line );
}
InterlockedIncrement(&failures);
return 0;
}
else
{/*
if (report_success)
fprintf( stdout, "%s:%d: Test succeeded\n",
glob_data.current_file, glob_data.current_line);*/
InterlockedIncrement(&successes);
}
return 1;
}
/* PUBLIC FUNCTIONS ***********************************************************/
PWCHAR CreateLowerDeviceRegistryKey(PUNICODE_STRING RegistryPath, PWCHAR NewDriver);
/*
* Test Declarations
*/
VOID RegisterDI_Test(HANDLE KeyHandle);
VOID NtoskrnlIoMdlTest(HANDLE KeyHandle);
VOID NtoskrnlIoIrpTest(HANDLE KeyHandle);
VOID NtoskrnlObTest(HANDLE KeyHandle);
VOID ExTimerTest(HANDLE KeyHandle);
VOID PoolsTest(HANDLE KeyHandle);
VOID PoolsCorruption(HANDLE KeyHandle);
VOID KeStallTest(HANDLE KeyHandle);
VOID DriverObjectTest(PDRIVER_OBJECT, int);
VOID DeviceCreateDeleteTest(PDRIVER_OBJECT);
VOID DeviceObjectTest(PDEVICE_OBJECT);
BOOLEAN ZwLoadTest(PDRIVER_OBJECT, PUNICODE_STRING, PWCHAR);
BOOLEAN ZwUnloadTest(PDRIVER_OBJECT, PUNICODE_STRING, PWCHAR);
BOOLEAN DetachDeviceTest(PDEVICE_OBJECT);
BOOLEAN AttachDeviceTest(PDEVICE_OBJECT, PWCHAR);
VOID LowerDeviceKernelAPITest(PDEVICE_OBJECT, BOOLEAN);
VOID NtoskrnlFsRtlTest(HANDLE KeyHandle);
typedef enum {
TestStageExTimer = 0,
TestStageIoMdl,
TestStageIoDi,
TestStageIoIrp,
TestStageMmPoolTest,
TestStageMmPoolCorruption,
TestStageOb,
TestStageKeStall,
TestStageDrv,
TestStageFsRtl,
TestStageMax
} TEST_STAGE;
/*
* KmtestDispatch
*/
NTSTATUS
NTAPI
KmtestDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS Status = STATUS_SUCCESS;
if (AttachDeviceObject)
{
IoSkipCurrentIrpStackLocation(Irp);
Status = IoCallDriver(AttachDeviceObject, Irp);
return Status;
}
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
/*
* KmtestCreateClose
*/
NTSTATUS
NTAPI
KmtestCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS Status = STATUS_SUCCESS;
if (AttachDeviceObject)
{
IoSkipCurrentIrpStackLocation(Irp);
Status = IoCallDriver(AttachDeviceObject, Irp);
return Status;
}
/* Do DriverObject Test with Driver Initialized */
DriverObjectTest(DeviceObject->DriverObject, 1);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information=0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
/*
* KmtestUnload
*/
VOID
NTAPI
KmtestUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING DosDeviceString;
if(AttachDeviceObject)
{
IoDetachDevice(AttachDeviceObject);
}
/* Do DriverObject Test for Unload */
DriverObjectTest(DriverObject, 2);
if (MainDeviceObject)
{
RtlInitUnicodeString(&DosDeviceString, L"\\DosDevices\\Kmtest");
IoDeleteSymbolicLink(&DosDeviceString);
IoDeleteDevice(MainDeviceObject);
}
}
static
PKEY_VALUE_PARTIAL_INFORMATION
NTAPI
ReadRegistryValue(HANDLE KeyHandle, PWCHAR ValueName)
{
NTSTATUS Status;
PKEY_VALUE_PARTIAL_INFORMATION InformationBuffer = NULL;
ULONG AllocatedLength = 0, RequiredLength = 0;
UNICODE_STRING ValueNameU;
RtlInitUnicodeString(&ValueNameU, ValueName);
Status = ZwQueryValueKey(KeyHandle,
&ValueNameU,
KeyValuePartialInformation,
NULL,
0,
&RequiredLength);
if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW)
{
InformationBuffer = ExAllocatePool(PagedPool, RequiredLength);
AllocatedLength = RequiredLength;
if (!InformationBuffer) return NULL;
Status = ZwQueryValueKey(KeyHandle,
&ValueNameU,
KeyValuePartialInformation,
InformationBuffer,
AllocatedLength,
&RequiredLength);
}
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to read %S (0x%x)\n", ValueName, Status);
if (InformationBuffer != NULL)
ExFreePool(InformationBuffer);
return NULL;
}
return InformationBuffer;
}
static
VOID
RunKernelModeTest(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath,
HANDLE KeyHandle,
TEST_STAGE Stage)
{
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"CurrentStage");
PWCHAR LowerDriverRegPath;
DPRINT1("Running stage %d test...\n", Stage);
ZwSetValueKey(KeyHandle,
&KeyName,
0,
REG_DWORD,
&Stage,
sizeof(ULONG));
switch (Stage)
{
case TestStageExTimer:
ExTimerTest(KeyHandle);
break;
case TestStageIoMdl:
NtoskrnlIoMdlTest(KeyHandle);
break;
case TestStageIoDi:
RegisterDI_Test(KeyHandle);
break;
case TestStageIoIrp:
NtoskrnlIoIrpTest(KeyHandle);
break;
case TestStageMmPoolTest:
PoolsTest(KeyHandle);
break;
case TestStageMmPoolCorruption:
PoolsCorruption(KeyHandle);
break;
case TestStageOb:
NtoskrnlObTest(KeyHandle);
break;
case TestStageKeStall:
KeStallTest(KeyHandle);
break;
case TestStageDrv:
/* Start the tests for the driver routines */
StartTest();
/* Do DriverObject Test for Driver Entry */
DriverObjectTest(DriverObject, 0);
/* Create and delete device, on return MainDeviceObject has been created */
DeviceCreateDeleteTest(DriverObject);
/* Make sure a device object was created */
if (MainDeviceObject)
{
LowerDriverRegPath = CreateLowerDeviceRegistryKey(RegistryPath, L"kmtestassist");
if (LowerDriverRegPath)
{
/* Load driver test and load the lower driver */
if (ZwLoadTest(DriverObject, RegistryPath, LowerDriverRegPath))
{
AttachDeviceTest(MainDeviceObject, L"kmtestassists");
if (AttachDeviceObject)
{
LowerDeviceKernelAPITest(MainDeviceObject, FALSE);
}
/* Unload lower driver without detaching from its device */
ZwUnloadTest(DriverObject, RegistryPath, LowerDriverRegPath);
LowerDeviceKernelAPITest(MainDeviceObject, TRUE);
}
else
{
DbgPrint("Failed to load kmtestassist driver\n");
}
}
}
FinishTest(KeyHandle, L"DriverTest");
break;
case TestStageFsRtl:
NtoskrnlFsRtlTest(KeyHandle);
break;
default:
ASSERT(FALSE);
break;
}
}
/*
* DriverEntry
*/
NTSTATUS
NTAPI
DriverEntry(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
{
int i;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING ParameterKeyName = RTL_CONSTANT_STRING(L"Parameters");
PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
PULONG KeyValue;
TEST_STAGE CurrentStage;
HANDLE DriverKeyHandle, ParameterKeyHandle;
DbgPrint("\n===============================================\n");
DbgPrint("Kernel Mode Regression Driver Test starting...\n");
DbgPrint("===============================================\n");
InitializeObjectAttributes(&ObjectAttributes,
RegistryPath,
OBJ_CASE_INSENSITIVE,
0,
NULL);
Status = ZwOpenKey(&DriverKeyHandle,
KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to open %wZ\n", RegistryPath);
return Status;
}
InitializeObjectAttributes(&ObjectAttributes,
&ParameterKeyName,
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
DriverKeyHandle,
NULL);
Status = ZwCreateKey(&ParameterKeyHandle,
KEY_SET_VALUE | KEY_QUERY_VALUE,
&ObjectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
ZwClose(DriverKeyHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create %wZ\\%wZ\n", RegistryPath, &ParameterKeyName);
return Status;
}
KeyInfo = ReadRegistryValue(ParameterKeyHandle, L"CurrentStage");
if (KeyInfo)
{
if (KeyInfo->DataLength != sizeof(ULONG))
{
DPRINT1("Invalid data length for CurrentStage: %d\n", KeyInfo->DataLength);
ExFreePool(KeyInfo);
return STATUS_UNSUCCESSFUL;
}
KeyValue = (PULONG)KeyInfo->Data;
if ((*KeyValue) + 1 < TestStageMax)
{
DPRINT1("Resuming testing after a crash at stage %d\n", (*KeyValue));
CurrentStage = (TEST_STAGE)((*KeyValue) + 1);
}
else
{
DPRINT1("Testing was completed on a previous boot\n");
ExFreePool(KeyInfo);
return STATUS_UNSUCCESSFUL;
}
ExFreePool(KeyInfo);
}
else
{
DPRINT1("Starting a fresh test\n");
CurrentStage = (TEST_STAGE)0;
}
/* Run the tests */
while (CurrentStage < TestStageMax)
{
RunKernelModeTest(DriverObject,
RegistryPath,
ParameterKeyHandle,
CurrentStage);
CurrentStage++;
}
DPRINT1("Testing is complete!\n");
ZwClose(ParameterKeyHandle);
/* Set all MajorFunctions to NULL to verify that kernel fixes them */
for (i = 1; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = NULL;
/* Set necessary routines */
DriverObject->DriverUnload = KmtestUnload;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KmtestDispatch;
DriverObject->MajorFunction[IRP_MJ_CREATE] = KmtestCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KmtestCreateClose;
return STATUS_SUCCESS;
}

View file

@ -1,54 +0,0 @@
#ifndef KMTEST_H
#define KMTEST_H
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "ntddk.h"
/*
Some macros, structs, and vars are based or inspired from the great
Wine regression tests Copyright (C) 2002 Alexandre Julliard.
Everything else is done by Aleksey Bragin based on PnPTest by Filip Navara
*/
extern LONG successes; /* number of successful tests */
extern LONG failures; /* number of failures */
//static ULONG todo_successes; /* number of successful tests inside todo block */
//static ULONG todo_failures; /* number of failures inside todo block */
// We don't do multithreading, so we just keep this struct in a global var
typedef struct
{
const char* current_file; /* file of current check */
int current_line; /* line of current check */
int todo_level; /* current todo nesting level */
int todo_do_loop;
} tls_data;
extern tls_data glob_data;
VOID StartTest(VOID);
VOID FinishTest(HANDLE KeyHandle, LPWSTR TestName);
void kmtest_set_location(const char* file, int line);
#ifdef __GNUC__
extern int kmtest_ok( int condition, const char *msg, ... ) __attribute__((format (printf,2,3) ));
#else /* __GNUC__ */
extern int kmtest_ok( int condition, const char *msg, ... );
#endif /* __GNUC__ */
#define ok_(file, line) (kmtest_set_location(file, line), 0) ? (void)0 : kmtest_ok
#define ok ok_(__FILE__, __LINE__)
PDEVICE_OBJECT AttachDeviceObject;
PDEVICE_OBJECT MainDeviceObject;
PDRIVER_OBJECT ThisDriverObject;
#endif /* KMTEST_H */

View file

@ -1,19 +0,0 @@
<module name="kmtest" type="kernelmodedriver" installbase="system32/drivers" installname="kmtest.sys">
<bootstrap base="$(CDOUTPUT)" />
<include base="ReactOS">include/reactos/drivers</include>
<library>ntoskrnl</library>
<library>hal</library>
<library>pseh</library>
<file>kmtest.c</file>
<file>deviface_test.c</file>
<file>drvobj_test.c</file>
<file>devobj_test.c</file>
<file>reghelper.c</file>
<file>ntos_ex.c</file>
<file>ntos_io.c</file>
<file>ntos_ke.c</file>
<file>ntos_ob.c</file>
<file>ntos_pools.c</file>
<file>ntos_fsrtl.c</file>
<file>kmtest.rc</file>
</module>

View file

@ -1,7 +0,0 @@
/* $Id: csqtest.rc 21842 2006-05-07 19:16:11Z ion $ */
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "Kernel Mode Regression Tests\0"
#define REACTOS_STR_INTERNAL_NAME "kmtest\0"
#define REACTOS_STR_ORIGINAL_FILENAME "kmtest.sys\0"
#include <reactos/version.rc>

View file

@ -1,97 +0,0 @@
/*
* Driver Regression Tests
*
* Copyright 2009 Michael Martin <martinmnet@hotmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; see the file COPYING.LIB.
* If not, write to the Free Software Foundation,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* INCLUDES *******************************************************************/
#include "ntddk.h"
#include "ntddser.h"
NTSTATUS
NTAPI
DriverDispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
DbgPrint(" ControlCode %x\n",IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information=0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
DriverCreateClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID
NTAPI
DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING DeviceString;
RtlInitUnicodeString(&DeviceString, L"\\DosDevices\\kmtestassist");
IoDeleteSymbolicLink(&DeviceString);
IoDeleteDevice(DriverObject->DeviceObject);
}
NTSTATUS
NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING path)
{
PDEVICE_OBJECT pDeviceObject;
UNICODE_STRING DriverString;
UNICODE_STRING DeviceString;
NTSTATUS Status= STATUS_DEVICE_CONFIGURATION_ERROR;
RtlInitUnicodeString(&DriverString, L"\\Device\\kmtestassist");
Status = IoCreateDevice(DriverObject,0,&DriverString,FILE_DEVICE_UNKNOWN,0,FALSE,&pDeviceObject);
if (!NT_SUCCESS(Status))
{
return Status;
}
RtlInitUnicodeString(&DeviceString, L"\\DosDevices\\kmtestassist");
Status = IoCreateSymbolicLink(&DeviceString, &DriverString);
if (!NT_SUCCESS(Status))
{
// Delete device object if not successful
IoDeleteDevice(pDeviceObject);
return Status;
}
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDispatch;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverCreateClose;
return Status;
}

View file

@ -1,7 +0,0 @@
<module name="kmtestassist" type="kernelmodedriver" installbase="system32/drivers" installname="kmtestassist.sys">
<bootstrap base="$(CDOUTPUT)" />
<include base="ReactOS">include/reactos/drivers</include>
<library>ntoskrnl</library>
<library>hal</library>
<file>kmtestassist.c</file>
</module>

View file

@ -1,519 +0,0 @@
/*
* NTOSKRNL Ob 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.
*/
/* INCLUDES *******************************************************************/
#include <ddk/ntddk.h>
#include <ddk/ntifs.h>
#include "kmtest.h"
#define NDEBUG
#include "debug.h"
#include "ntndk.h"
// I ment to make this test scalable, but for now
// we work with two object types only
#define NUM_OBTYPES 2
typedef struct _MY_OBJECT1
{
ULONG Something1;
} MY_OBJECT1, *PMY_OBJECT1;
typedef struct _MY_OBJECT2
{
ULONG Something1;
ULONG SomeLong[10];
} MY_OBJECT2, *PMY_OBJECT2;
POBJECT_TYPE ObTypes[NUM_OBTYPES];
UNICODE_STRING ObTypeName[NUM_OBTYPES];
UNICODE_STRING ObName[NUM_OBTYPES];
OBJECT_TYPE_INITIALIZER ObTypeInitializer[NUM_OBTYPES];
UNICODE_STRING ObDirectoryName;
OBJECT_ATTRIBUTES ObDirectoryAttributes;
OBJECT_ATTRIBUTES ObAttributes[NUM_OBTYPES];
PVOID ObBody[NUM_OBTYPES];
PMY_OBJECT1 ObObject1;
PMY_OBJECT2 ObObject2;
HANDLE ObHandle1[NUM_OBTYPES];
HANDLE ObHandle2[NUM_OBTYPES];
HANDLE DirectoryHandle;
USHORT DumpCount, OpenCount, CloseCount, DeleteCount,
ParseCount, OkayToCloseCount, QueryNameCount;
/* PRIVATE FUNCTIONS **********************************************************/
VOID
NTAPI
DumpProc(IN PVOID Object,
IN POB_DUMP_CONTROL DumpControl)
{
DbgPrint("DumpProc() called\n");
DumpCount++;
}
// Tested in Win2k3
VOID
NTAPI
OpenProc(IN OB_OPEN_REASON OpenReason,
IN PEPROCESS Process,
IN PVOID Object,
IN ACCESS_MASK GrantedAccess,
IN ULONG HandleCount)
{
DbgPrint("OpenProc() 0x%p, OpenReason %d, HC %d, AM 0x%X\n",
Object, OpenReason, HandleCount, GrantedAccess);
OpenCount++;
}
// Tested in Win2k3
VOID
NTAPI
CloseProc(IN PEPROCESS Process,
IN PVOID Object,
IN ACCESS_MASK GrantedAccess,
IN ULONG ProcessHandleCount,
IN ULONG SystemHandleCount)
{
DbgPrint("CloseProc() 0x%p, PHC %d, SHC %d, AM 0x%X\n", Object,
ProcessHandleCount, SystemHandleCount, GrantedAccess);
CloseCount++;
}
// Tested in Win2k3
VOID
NTAPI
DeleteProc(IN PVOID Object)
{
DbgPrint("DeleteProc() 0x%p\n", Object);
DeleteCount++;
}
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)
{
DbgPrint("ParseProc() called\n");
*Object = NULL;
ParseCount++;
return STATUS_OBJECT_NAME_NOT_FOUND;//STATUS_SUCCESS;
}
// Tested in Win2k3
NTSTATUS
NTAPI
OkayToCloseProc(IN PEPROCESS Process OPTIONAL,
IN PVOID Object,
IN HANDLE Handle,
IN KPROCESSOR_MODE AccessMode)
{
DbgPrint("OkayToCloseProc() 0x%p, H 0x%p, AM 0x%X\n", Object, Handle,
AccessMode);
OkayToCloseCount++;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
QueryNameProc(IN PVOID Object,
IN BOOLEAN HasObjectName,
OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
IN ULONG Length,
OUT PULONG ReturnLength,
IN KPROCESSOR_MODE AccessMode)
{
DbgPrint("QueryNameProc() 0x%p, HON %d, Len %d, AM 0x%X\n",
Object, HasObjectName, Length, AccessMode);
QueryNameCount++;
ObjectNameInfo = NULL;
ReturnLength = 0;
return STATUS_OBJECT_NAME_NOT_FOUND;
}
VOID
ObtCreateObjectTypes()
{
USHORT i;
NTSTATUS Status;
WCHAR Name[15];
for (i=0; i<NUM_OBTYPES; i++)
{
// Prepare object type name
// TODO: Generate type names and don't use this unprofessional,
swprintf(Name, L"MyObjectType%lx", i);
RtlInitUnicodeString(&ObTypeName[i], Name);
// Prepare initializer
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],
(PSECURITY_DESCRIPTOR)NULL, &ObTypes[i]);
ok(Status == STATUS_INVALID_PARAMETER,
"ObCreateObjectType returned 0x%lX", Status);
// Object procedures
ObTypeInitializer[i].CloseProcedure = (OB_CLOSE_METHOD)CloseProc;
ObTypeInitializer[i].DeleteProcedure = (OB_DELETE_METHOD)DeleteProc;
ObTypeInitializer[i].DumpProcedure = (OB_DUMP_METHOD)DumpProc;
ObTypeInitializer[i].OpenProcedure = (OB_OPEN_METHOD)OpenProc;
ObTypeInitializer[i].ParseProcedure = (OB_PARSE_METHOD)ParseProc;
//ObTypeInitializer[i].OkayToCloseProcedure =
// (OB_OKAYTOCLOSE_METHOD)OkayToCloseProc;
//ObTypeInitializer[i].QueryNameProcedure =
// (OB_QUERYNAME_METHOD)QueryNameProc;
//ObTypeInitializer[i].SecurityProcedure =
// (OB_SECURITY_METHOD)SecurityProc;
Status = ObCreateObjectType(&ObTypeName[i], &ObTypeInitializer[i],
(PSECURITY_DESCRIPTOR)NULL, &ObTypes[i]);
ok(Status == STATUS_SUCCESS,
"Failed to create object type with status=0x%lX", Status);
}
}
VOID
ObtCreateDirectory()
{
NTSTATUS Status;
// Directory will have permanent and case insensitive flags
RtlInitUnicodeString(&ObDirectoryName, L"\\ObtDirectory");
InitializeObjectAttributes(&ObDirectoryAttributes, &ObDirectoryName,
OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwCreateDirectoryObject(&DirectoryHandle, 0, &ObDirectoryAttributes);
ok(Status == STATUS_SUCCESS,
"Failed to create directory object with status=0x%lX", Status);
}
VOID
ObtCreateObjects()
{
PVOID ObBody1[2];
NTSTATUS Status;
USHORT OpenSave, CloseSave, DeleteSave, ParseSave,
OkayToCloseSave, QueryNameSave;
// Create two objects
RtlInitUnicodeString(&ObName[0], L"\\ObtDirectory\\MyObject1");
InitializeObjectAttributes(&ObAttributes[0], &ObName[0],
OBJ_CASE_INSENSITIVE, NULL, NULL);
RtlInitUnicodeString(&ObName[1], L"\\ObtDirectory\\MyObject2");
InitializeObjectAttributes(&ObAttributes[1], &ObName[1],
OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ObCreateObject(KernelMode, ObTypes[0], &ObAttributes[0],
KernelMode, NULL, (ULONG)sizeof(MY_OBJECT1), 0L, 0L,
(PVOID *)&ObBody[0]);
ok(Status == STATUS_SUCCESS,
"Failed to create object with status=0x%lX", Status);
Status = ObCreateObject(KernelMode, ObTypes[1], &ObAttributes[1],
KernelMode, NULL, (ULONG)sizeof(MY_OBJECT2), 0L, 0L,
(PVOID *)&ObBody[1]);
ok(Status == STATUS_SUCCESS,
"Failed to create object with status=0x%lX", Status);
// save counters
OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
QueryNameSave=QueryNameCount;
// Insert them
Status = ObInsertObject(ObBody[0], NULL, STANDARD_RIGHTS_ALL, 0,
&ObBody[0], &ObHandle1[0]);
ok(Status == STATUS_SUCCESS,
"Failed to insert object 0 with status=0x%lX", Status);
ok(ObBody[0] != NULL, "Object body = NULL");
ok(ObHandle1[0] != NULL, "Handle = NULL");
// check counters
ok(OpenSave+1 == OpenCount, "Open method calls mismatch\n");
ok(CloseSave == CloseCount, "Excessive Close method call\n");
ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
ok(ParseSave == ParseCount, "Excessive Parse method call\n");
// save counters
OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
QueryNameSave=QueryNameCount;
Status = ObInsertObject(ObBody[1], NULL, GENERIC_ALL, 0,
&ObBody[1], &ObHandle1[1]);
ok(Status == STATUS_SUCCESS,
"Failed to insert object 1 with status=0x%lX", Status);
ok(ObBody[1] != NULL, "Object body = NULL");
ok(ObHandle1[1] != NULL, "Handle = NULL");
// check counters
ok(OpenSave+1 == OpenCount, "Open method calls mismatch\n");
ok(CloseSave == CloseCount, "Excessive Close method call\n");
ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
ok(ParseSave == ParseCount, "Excessive Parse method call\n");
// save counters
OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
QueryNameSave=QueryNameCount;
// Now create an object of type 0, of the same name and expect it to fail
// inserting, but success creation
RtlInitUnicodeString(&ObName[0], L"\\ObtDirectory\\MyObject1");
InitializeObjectAttributes(&ObAttributes[0], &ObName[0], OBJ_OPENIF,
NULL, NULL);
Status = ObCreateObject(KernelMode, ObTypes[0], &ObAttributes[0], KernelMode,
NULL, (ULONG)sizeof(MY_OBJECT1), 0L, 0L, (PVOID *)&ObBody1[0]);
ok(Status == STATUS_SUCCESS,
"Failed to create object with status=0x%lX", Status);
// check counters
ok(OpenSave == OpenCount, "Excessive Open method call\n");
ok(CloseSave == CloseCount, "Excessive Close method call\n");
ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
ok(ParseSave == ParseCount, "Excessive Parse method call\n");
Status = ObInsertObject(ObBody1[0], NULL, GENERIC_ALL, 0,
&ObBody1[1], &ObHandle2[0]);
ok(Status == STATUS_OBJECT_NAME_EXISTS,
"Object insertion should have failed, but got 0x%lX", Status);
ok(ObBody[0] == ObBody1[1],
"Object bodies doesn't match, 0x%p != 0x%p", ObBody[0], ObBody1[1]);
ok(ObHandle2[0] != NULL, "Bad handle returned 0x%lX", (ULONG_PTR)ObHandle2[0]);
DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, // deletecount+1
CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
// check counters and then save
ok(OpenSave+1 == OpenCount, "Excessive Open method call\n");
ok(CloseSave == CloseCount, "Excessive Close method call\n");
ok(DeleteSave+1 == DeleteCount, "Delete method call mismatch\n");
ok(ParseSave == ParseCount, "Excessive Parse method call\n");
OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
QueryNameSave=QueryNameCount;
// Close its handle
Status = ZwClose(ObHandle2[0]);
ok(Status == STATUS_SUCCESS,
"Failed to close handle status=0x%lX", Status);
// check counters and then save
ok(OpenSave == OpenCount, "Excessive Open method call\n");
ok(CloseSave+1 == CloseCount, "Close method call mismatch\n");
ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
ok(ParseSave == ParseCount, "Excessive Parse method call\n");
OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
QueryNameSave=QueryNameCount;
// Object referenced 2 times:
// 1) ObInsertObject
// 2) AdditionalReferences
ObDereferenceObject(ObBody1[1]);
//DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, // no change
// CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
ok(OpenSave == OpenCount, "Open method call mismatch\n");
ok(CloseSave == CloseCount, "Close method call mismatch\n");
ok(DeleteSave == DeleteCount, "Delete method call mismatch\n");
ok(ParseSave == ParseCount, "Parse method call mismatch\n");
}
VOID
ObtClose()
{
PVOID DirObject;
NTSTATUS Status;
//PVOID TypeObject;
USHORT i;
//UNICODE_STRING ObPathName[NUM_OBTYPES];
// Close what we have opened and free what we allocated
ZwClose(ObHandle1[0]);
ZwClose(ObHandle1[1]);
ZwClose(ObHandle2[0]);
ZwClose(ObHandle2[1]);
// 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)
Status = ObReferenceObjectByHandle(DirectoryHandle, 0L, NULL,
KernelMode, &DirObject, NULL);
ok(Status == STATUS_SUCCESS,
"Failed to reference object by handle with status=0x%lX", Status);
// Dereference 2 times - first for just previous referencing
// and 2nd time for creation of permanent object itself
ObDereferenceObject(DirObject);
ObDereferenceObject(DirObject);
Status = ZwMakeTemporaryObject(DirectoryHandle);
ok(Status == STATUS_SUCCESS,
"Failed to make temp object with status=0x%lX", Status);
// Close the handle now and we are done
Status = ZwClose(DirectoryHandle);
ok(Status == STATUS_SUCCESS,
"Failed to close handle with status=0x%lX", Status);
// Now delete the last piece - object types
// In fact, it's weird to get rid of object types, especially the way,
// how it's done in the commented section below
for (i=0; i<NUM_OBTYPES; i++)
ObDereferenceObject(ObTypes[i]);
/*
RtlInitUnicodeString(&ObPathName[0], L"\\ObjectTypes\\MyObjectType1");
RtlInitUnicodeString(&ObPathName[1], L"\\ObjectTypes\\MyObjectType2");
for (i=0; i<NUM_OBTYPES; i++)
{
Status = ObReferenceObjectByName(&ObPathName[i],
OBJ_CASE_INSENSITIVE, NULL, 0L, NULL, KernelMode, NULL,
&TypeObject);
ObDereferenceObject(TypeObject);
ObDereferenceObject(TypeObject);
DPRINT("Reference Name %S = %p, ObTypes[%d] = %p\n",
ObPathName[i], TypeObject, i, ObTypes[i]);
}
*/
}
VOID
ObtReferenceTests()
{
USHORT i;
NTSTATUS Status;
UNICODE_STRING ObPathName[NUM_OBTYPES];
// Reference them by handle
for (i=0; i<NUM_OBTYPES; i++)
{
Status = ObReferenceObjectByHandle(ObHandle1[i], 0L, ObTypes[i],
KernelMode, &ObBody[i], NULL);
ok(Status == STATUS_SUCCESS,
"Failed to reference object by handle, status=0x%lX", Status);
DPRINT("Ref by handle %lx = %p\n", ObHandle1[i], ObBody[i]);
}
// Reference them by pointer
for (i=0; i<NUM_OBTYPES; i++)
{
Status = ObReferenceObjectByPointer(ObBody[i], 0L, ObTypes[i], KernelMode);
ok(Status == STATUS_SUCCESS,
"Failed to reference object by pointer, status=0x%lX", Status);
}
// Reference them by name
RtlInitUnicodeString(&ObPathName[0], L"\\ObtDirectory\\MyObject1");
RtlInitUnicodeString(&ObPathName[1], L"\\ObtDirectory\\MyObject2");
for (i=0; i<NUM_OBTYPES; i++)
{
Status = ObReferenceObjectByName(&ObPathName[i],
OBJ_CASE_INSENSITIVE, NULL, 0L, ObTypes[i], KernelMode, NULL,
&ObBody[0]);
DPRINT("Ref by name %wZ = %p\n", &ObPathName[i], ObBody[i]);
}
// Dereference now all of them
// For ObInsertObject, AdditionalReference
ObDereferenceObject(ObBody[0]);
ObDereferenceObject(ObBody[1]);
// For ByHandle
ObDereferenceObject(ObBody[0]);
ObDereferenceObject(ObBody[1]);
// For ByPointer
ObDereferenceObject(ObBody[0]);
ObDereferenceObject(ObBody[1]);
// For ByName
ObDereferenceObject(ObBody[0]);
ObDereferenceObject(ObBody[1]);
}
/* PUBLIC FUNCTIONS ***********************************************************/
VOID
NtoskrnlObTest(HANDLE KeyHandle)
{
StartTest();
DumpCount = 0; OpenCount = 0; CloseCount = 0;
DeleteCount = 0; ParseCount = 0;
// Create object-types to use in tests
ObtCreateObjectTypes();
DPRINT("ObtCreateObjectTypes() done\n");
// Create Directory
ObtCreateDirectory();
DPRINT("ObtCreateDirectory() done\n");
// Create and insert objects
ObtCreateObjects();
DPRINT("ObtCreateObjects() done\n");
// Reference them in a variety of ways
//ObtReferenceTests();
// Clean up
// FIXME: Disable to see results of creating objects in usermode.
// Also it has problems with object types removal
ObtClose();
DPRINT("Cleanup done\n");
FinishTest(KeyHandle, L"ObMgrTest");
}

View file

@ -1,219 +0,0 @@
/*
* Driver Regression Tests
*
* Copyright 2009 Michael Martin <martinmnet@hotmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; see the file COPYING.LIB.
* If not, write to the Free Software Foundation,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* INCLUDES *******************************************************************/
#include "kmtest.h"
/*
Adds a service registry entry for a driver
The driver must reside in the same path as this loaded driver
The caller is resposible for releasing memory
*/
PWCHAR CreateLowerDeviceRegistryKey(PUNICODE_STRING RegistryPath, PWCHAR NewDriver)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING Name;
UNICODE_STRING Value;
UNICODE_STRING NewDriverRegPath;
PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInfo = NULL;
HANDLE ServiceKey;
NTSTATUS Status;
ULONG Disposition;
ULONG ServiceDWordValue;
ULONG ResultLength = 0;
ULONG Length = 0;
PWCHAR ReturnPath = NULL;
/* Now lets find out where we were loaded from by using registry */
InitializeObjectAttributes(&ObjectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&ServiceKey, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwOpenKey () failed (Status %x)\n", Status);
return NULL;
}
RtlInitUnicodeString(&Name, L"ImagePath");
/* First query how much memory we need */
Status = ZwQueryValueKey(ServiceKey, &Name, KeyValuePartialInformation, 0, 0, &ResultLength);
ResultLength += sizeof(KEY_VALUE_PARTIAL_INFORMATION);
ValuePartialInfo = ExAllocatePool(PagedPool, ResultLength);
if (!ValuePartialInfo)
{
DbgPrint("Out of memory!\n");
goto cleanup;
}
Length = ResultLength;
Status = ZwQueryValueKey(ServiceKey, &Name, KeyValuePartialInformation, (PVOID)ValuePartialInfo, Length, &ResultLength);
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwQueryValueKey() failed (Status %lx)\n", Status);
goto cleanup;
}
/* Remove the current driver name from the string */
/* FIXME: Dont use hard coded driver name, determine it from the string returned from the above Query */
Length = (wcslen((PWCHAR)ValuePartialInfo->Data) * 2) - (wcslen(L"kmtest.sys") * 2);
RtlZeroMemory((PVOID)((ULONG_PTR)ValuePartialInfo->Data + Length),
wcslen(L"drvtests.sys") * 2);
ZwClose(ServiceKey);
/* Now add a registry entry for the driver */
NewDriverRegPath.Length = 0;
NewDriverRegPath.MaximumLength = (wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") +
wcslen(NewDriver) + 1) * sizeof(WCHAR);
NewDriverRegPath.Buffer = ExAllocatePool(PagedPool, NewDriverRegPath.MaximumLength);
if (!NewDriverRegPath.Buffer)
{
DbgPrint("Out of memory!\n");
ExFreePool(NewDriverRegPath.Buffer);
goto cleanup;
}
RtlAppendUnicodeToString(&NewDriverRegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
RtlAppendUnicodeToString(&NewDriverRegPath, NewDriver);
InitializeObjectAttributes(&ObjectAttributes,
&NewDriverRegPath,
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
0,
NULL);
Status = ZwCreateKey(&ServiceKey,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
&Disposition);
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status);
ExFreePool(NewDriverRegPath.Buffer);
goto cleanup;
}
ReturnPath = NewDriverRegPath.Buffer;
RtlInitUnicodeString(&Name, L"ImagePath");
Value.Length = 0;
Value.MaximumLength = (wcslen((PWCHAR)ValuePartialInfo->Data) +
wcslen(NewDriver) + 5) * sizeof(WCHAR);
Value.Buffer = ExAllocatePool(PagedPool, Value.MaximumLength);
if (!Value.Buffer)
{
DbgPrint("Out of memory!\n");
ExFreePool(Value.Buffer);
goto cleanup;
}
RtlAppendUnicodeToString(&Value, (PWCHAR)ValuePartialInfo->Data);
RtlAppendUnicodeToString(&Value, NewDriver);
RtlAppendUnicodeToString(&Value, L".sys");
Status = ZwSetValueKey(ServiceKey,
&Name,
0,
REG_SZ,
Value.Buffer,
(wcslen(Value.Buffer)+1) * sizeof(WCHAR));
ExFreePool(Value.Buffer);
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status);
goto cleanup;
}
RtlInitUnicodeString(&Name, L"DisplayName");
RtlInitUnicodeString(&Value, NewDriver);
Status = ZwSetValueKey(ServiceKey,
&Name,
0,
REG_SZ,
Value.Buffer,
(wcslen(Value.Buffer)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status);
goto cleanup;
}
RtlInitUnicodeString(&Name, L"ErrorControl");
ServiceDWordValue = 0;
Status = ZwSetValueKey(ServiceKey,
&Name,
0,
REG_DWORD,
&ServiceDWordValue,
sizeof(ULONG));
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status);
goto cleanup;
}
RtlInitUnicodeString(&Name, L"Start");
ServiceDWordValue = 3;
Status = ZwSetValueKey(ServiceKey,
&Name,
0,
REG_DWORD,
&ServiceDWordValue,
sizeof(ULONG));
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status);
goto cleanup;
}
RtlInitUnicodeString(&Name, L"Type");
ServiceDWordValue = 0;
Status = ZwSetValueKey(ServiceKey,
&Name,
0,
REG_DWORD,
&ServiceDWordValue,
sizeof(ULONG));
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status);
goto cleanup;
}
cleanup:
ZwClose(ServiceKey);
if (ValuePartialInfo) ExFreePool(ValuePartialInfo);
return ReturnPath;
}

View file

@ -0,0 +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)

View file

@ -0,0 +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>

View file

@ -0,0 +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)

View file

@ -0,0 +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);
}

View file

@ -0,0 +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_ */

View file

@ -0,0 +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;
}

View file

@ -0,0 +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");
}

View file

@ -0,0 +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");
}

View file

@ -0,0 +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>

View file

@ -0,0 +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_ */

View file

@ -0,0 +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_ */

View file

@ -0,0 +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_ */

View file

@ -0,0 +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>

View file

@ -0,0 +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;
}

View file

@ -0,0 +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>

View file

@ -0,0 +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_ */

View file

@ -0,0 +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"

View file

@ -0,0 +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;
}

View file

@ -0,0 +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;
}

View file

@ -0,0 +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 },
};

View file

@ -0,0 +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>

View file

@ -0,0 +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;
}

View file

@ -0,0 +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>

View file

@ -0,0 +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;
}

View file

@ -0,0 +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;
}

View file

@ -0,0 +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 }
};

View file

@ -0,0 +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);
}

View file

@ -0,0 +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);
}

View file

@ -0,0 +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);
}

View file

@ -0,0 +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);
}

View file

@ -1,50 +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++)
{
@ -122,20 +97,14 @@ PoolsTest(HANDLE KeyHandle)
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);
@ -173,6 +142,10 @@ PoolsCorruption(HANDLE KeyHandle)
// free the pool
ExFreePoolWithTag(Ptr, TAG_POOLTEST);
FinishTest(KeyHandle, L"MmPoolCorruptionTest");
}
START_TEST(ExPools)
{
PoolsTest();
PoolsCorruption();
}

View file

@ -0,0 +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);*/
}

View file

@ -0,0 +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');
}

View file

@ -0,0 +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');
}

View file

@ -1,37 +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,
@ -44,10 +23,7 @@ TestTimerApcRoutine(IN PVOID TimerContext,
(*ApcCount)++;
}
/* PUBLIC FUNCTIONS *************************************************************/
VOID
ExTimerTest(HANDLE KeyHandle)
START_TEST(ExTimer)
{
UNICODE_STRING TimerName;
OBJECT_ATTRIBUTES ObjectAttributes;
@ -58,8 +34,6 @@ ExTimerTest(HANDLE KeyHandle)
NTSTATUS Status;
ULONG ApcCount;
StartTest();
// Create the timer
RtlInitUnicodeString(&TimerName, L"\\TestTimer");
InitializeObjectAttributes(&ObjectAttributes, &TimerName, 0, NULL, NULL);
@ -167,6 +141,4 @@ ExTimerTest(HANDLE KeyHandle)
Status = ZwClose(TimerHandle);
ok(Status == STATUS_SUCCESS, "ZwClose failed with Status=0x%08lX", Status);
FinishTest(KeyHandle, L"ExTimerTest");
}

View file

@ -0,0 +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

View file

@ -1,43 +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;
/* !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".");
@ -142,8 +129,11 @@ VOID FsRtlIsNameInExpressionTest()
RtlInitUnicodeString(&Expression, L"*.?.c.d");
ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == TRUE, "expected TRUE, got FALSE");
RtlInitUnicodeString(&Expression, L"*?");
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");
@ -151,8 +141,11 @@ VOID FsRtlIsNameInExpressionTest()
RtlInitUnicodeString(&Name, L"aaa");
ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == TRUE, "expected TRUE, got FALSE");
RtlInitUnicodeString(&Expression, L"?*?");
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");
@ -179,15 +172,18 @@ VOID FsRtlIsNameInExpressionTest()
ok(FsRtlIsNameInExpression(&Expression, &Name, FALSE, NULL) == FALSE, "expected FALSE, got TRUE");
}
VOID FsRtlIsDbcsInExpressionTest()
static VOID FsRtlIsDbcsInExpressionTest()
{
ANSI_STRING Expression, Name;
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, ".");
@ -292,8 +288,11 @@ VOID FsRtlIsDbcsInExpressionTest()
RtlInitAnsiString(&Expression, "*.?.c.d");
ok(FsRtlIsDbcsInExpression(&Expression, &Name) == TRUE, "expected TRUE, got FALSE");
RtlInitAnsiString(&Expression, "*?");
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");
@ -301,8 +300,11 @@ VOID FsRtlIsDbcsInExpressionTest()
RtlInitAnsiString(&Name, "aaa");
ok(FsRtlIsDbcsInExpression(&Expression, &Name) == TRUE, "expected TRUE, got FALSE");
RtlInitAnsiString(&Expression, "?*?");
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");
@ -329,15 +331,8 @@ VOID FsRtlIsDbcsInExpressionTest()
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");
}

View file

@ -0,0 +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)

View file

@ -1,36 +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 @@ 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;
@ -102,7 +85,7 @@ VOID DeviceInterfaceTest_Func()
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;
@ -111,8 +94,6 @@ VOID RegisterDI_Test(HANDLE KeyHandle)
UNICODE_STRING SymbolicLinkName;
NTSTATUS Status;
StartTest();
RtlInitUnicodeString(&SymbolicLinkName, L"");
// Prepare our surrogate of a Device Object
@ -136,6 +117,4 @@ VOID RegisterDI_Test(HANDLE KeyHandle)
"IoRegisterDeviceInterface returned 0x%08lX\n", Status);
DeviceInterfaceTest_Func();
FinishTest(KeyHandle, L"IoDeviceInterfaceTest");
}

View file

@ -0,0 +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 */
}

View file

@ -0,0 +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();
}

View file

@ -0,0 +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;
}

View file

@ -0,0 +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();
}

View file

@ -1,94 +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"
#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);
// 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);
@ -163,6 +90,4 @@ VOID NtoskrnlIoIrpTest(HANDLE KeyHandle)
IoFreeIrp(iorp);
}
FinishTest(KeyHandle, L"IoIrpTest");
}

View file

@ -0,0 +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);
}

View file

@ -0,0 +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>

View file

@ -0,0 +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>

View file

@ -0,0 +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);
}

View file

@ -0,0 +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);
}

View file

@ -0,0 +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);
}

View file

@ -0,0 +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);
}

View file

@ -0,0 +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);
}

View file

@ -1,45 +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 @@ KeStallTest(HANDLE KeyHandle)
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();
}

View file

@ -0,0 +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);
}

View file

@ -0,0 +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;
}
}

View file

@ -0,0 +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);
}

View file

@ -0,0 +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.

View file

@ -0,0 +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"

View file

@ -0,0 +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);
}

View file

@ -0,0 +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();
}

View file

@ -1,90 +0,0 @@
/*
* Kernel-Mode Tests Loader (based on PnP Test Driver Loader by Filip Navara)
*
* 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.
*/
/* INCLUDES *******************************************************************/
#include <windows.h>
#include <stdio.h>
/* PUBLIC FUNCTIONS ***********************************************************/
int main()
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
PWCHAR DriverName = L"KMTEST";
WCHAR ServiceExe[MAX_PATH];
printf("Kernel Mode Tests loader\n\n");
GetCurrentDirectoryW(MAX_PATH, ServiceExe);
wcscat(ServiceExe, L"\\kmtest.sys");
printf("Opening SC Manager...\n");
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL)
{
DWORD Err = GetLastError();
printf("OpenSCManager failed with error 0x%lx\n", Err);
return 0;
}
printf("Creating service...\n");
schService = CreateServiceW(
schSCManager,
DriverName,
DriverName,
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
ServiceExe,
NULL,
NULL,
NULL,
NULL,
NULL);
if (schService == NULL)
{
printf("Opening service...\n");
schService = OpenServiceW(schSCManager, DriverName, SERVICE_ALL_ACCESS);
}
if (schService == NULL)
{
DWORD Err = GetLastError();
printf("Create/OpenService failed with error 0x%lx\n", Err);
CloseServiceHandle(schSCManager);
return 0;
}
//for (;;) ;
printf("Starting service...\n");
StartService(schService, 0, NULL);
printf("Cleaning up and exiting\n");
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return 0;
}

View file

@ -1,4 +0,0 @@
<module name="kmtloader" type="win32cui" installbase="system32" installname="kmtloader.exe">
<library>advapi32</library>
<file>kmtloader.c</file>
</module>

View file

@ -4,9 +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>