mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 22:23:01 +00:00
[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:
commit
454f222ade
76 changed files with 8871 additions and 2239 deletions
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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>
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -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");
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
105
rostests/kmtests/CMakeLists.txt
Normal file
105
rostests/kmtests/CMakeLists.txt
Normal 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)
|
13
rostests/kmtests/directory.rbuild
Normal file
13
rostests/kmtests/directory.rbuild
Normal 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>
|
16
rostests/kmtests/example/CMakeLists.txt
Normal file
16
rostests/kmtests/example/CMakeLists.txt
Normal 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)
|
43
rostests/kmtests/example/Example.c
Normal file
43
rostests/kmtests/example/Example.c
Normal 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);
|
||||
}
|
21
rostests/kmtests/example/Example.h
Normal file
21
rostests/kmtests/example/Example.h
Normal 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_ */
|
245
rostests/kmtests/example/Example_drv.c
Normal file
245
rostests/kmtests/example/Example_drv.c
Normal 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;
|
||||
}
|
44
rostests/kmtests/example/Example_user.c
Normal file
44
rostests/kmtests/example/Example_user.c
Normal 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");
|
||||
}
|
20
rostests/kmtests/example/KernelType.c
Normal file
20
rostests/kmtests/example/KernelType.c
Normal 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");
|
||||
}
|
14
rostests/kmtests/example/example_drv.rbuild
Normal file
14
rostests/kmtests/example/example_drv.rbuild
Normal 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>
|
54
rostests/kmtests/include/kmt_platform.h
Normal file
54
rostests/kmtests/include/kmt_platform.h
Normal 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_ */
|
24
rostests/kmtests/include/kmt_public.h
Normal file
24
rostests/kmtests/include/kmt_public.h
Normal 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_ */
|
416
rostests/kmtests/include/kmt_test.h
Normal file
416
rostests/kmtests/include/kmt_test.h
Normal 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_ */
|
24
rostests/kmtests/kmtest.rbuild
Normal file
24
rostests/kmtests/kmtest.rbuild
Normal 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>
|
395
rostests/kmtests/kmtest/kmtest.c
Normal file
395
rostests/kmtests/kmtest/kmtest.c
Normal 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;
|
||||
}
|
12
rostests/kmtests/kmtest/kmtest.exe.manifest
Normal file
12
rostests/kmtests/kmtest/kmtest.exe.manifest
Normal 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>
|
64
rostests/kmtests/kmtest/kmtest.h
Normal file
64
rostests/kmtests/kmtest/kmtest.h
Normal 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_ */
|
15
rostests/kmtests/kmtest/kmtest.rc
Normal file
15
rostests/kmtests/kmtest/kmtest.rc
Normal 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"
|
309
rostests/kmtests/kmtest/service.c
Normal file
309
rostests/kmtests/kmtest/service.c
Normal 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;
|
||||
}
|
215
rostests/kmtests/kmtest/support.c
Normal file
215
rostests/kmtests/kmtest/support.c
Normal 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;
|
||||
}
|
25
rostests/kmtests/kmtest/testlist.c
Normal file
25
rostests/kmtests/kmtest/testlist.c
Normal 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 },
|
||||
};
|
79
rostests/kmtests/kmtest_drv.rbuild
Normal file
79
rostests/kmtests/kmtest_drv.rbuild
Normal 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>
|
377
rostests/kmtests/kmtest_drv/kmtest_drv.c
Normal file
377
rostests/kmtests/kmtest_drv/kmtest_drv.c
Normal 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;
|
||||
}
|
15
rostests/kmtests/kmtest_drv/kmtest_drv.rc
Normal file
15
rostests/kmtests/kmtest_drv/kmtest_drv.rc
Normal 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>
|
488
rostests/kmtests/kmtest_drv/kmtest_standalone.c
Normal file
488
rostests/kmtests/kmtest_drv/kmtest_standalone.c
Normal 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;
|
||||
}
|
40
rostests/kmtests/kmtest_drv/printf_stubs.c
Normal file
40
rostests/kmtests/kmtest_drv/printf_stubs.c
Normal 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;
|
||||
}
|
74
rostests/kmtests/kmtest_drv/testlist.c
Normal file
74
rostests/kmtests/kmtest_drv/testlist.c
Normal 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 }
|
||||
};
|
235
rostests/kmtests/ntos_ex/ExDoubleList.c
Normal file
235
rostests/kmtests/ntos_ex/ExDoubleList.c
Normal 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);
|
||||
}
|
309
rostests/kmtests/ntos_ex/ExFastMutex.c
Normal file
309
rostests/kmtests/ntos_ex/ExFastMutex.c
Normal 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);
|
||||
}
|
236
rostests/kmtests/ntos_ex/ExHardError.c
Normal file
236
rostests/kmtests/ntos_ex/ExHardError.c
Normal 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);
|
||||
}
|
399
rostests/kmtests/ntos_ex/ExInterlocked.c
Normal file
399
rostests/kmtests/ntos_ex/ExInterlocked.c
Normal 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);
|
||||
}
|
|
@ -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();
|
||||
}
|
460
rostests/kmtests/ntos_ex/ExResource.c
Normal file
460
rostests/kmtests/ntos_ex/ExResource.c
Normal 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);*/
|
||||
}
|
79
rostests/kmtests/ntos_ex/ExSequencedList.c
Normal file
79
rostests/kmtests/ntos_ex/ExSequencedList.c
Normal 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');
|
||||
}
|
112
rostests/kmtests/ntos_ex/ExSingleList.c
Normal file
112
rostests/kmtests/ntos_ex/ExSingleList.c
Normal 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');
|
||||
}
|
|
@ -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");
|
||||
}
|
91
rostests/kmtests/ntos_ex/ExXList.h
Normal file
91
rostests/kmtests/ntos_ex/ExXList.h
Normal 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
|
|
@ -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");
|
||||
}
|
36
rostests/kmtests/ntos_io/CMakeLists.txt
Normal file
36
rostests/kmtests/ntos_io/CMakeLists.txt
Normal 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)
|
|
@ -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");
|
||||
}
|
495
rostests/kmtests/ntos_io/IoDeviceObject_drv.c
Normal file
495
rostests/kmtests/ntos_io/IoDeviceObject_drv.c
Normal 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 */
|
||||
}
|
20
rostests/kmtests/ntos_io/IoDeviceObject_user.c
Normal file
20
rostests/kmtests/ntos_io/IoDeviceObject_user.c
Normal 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();
|
||||
}
|
71
rostests/kmtests/ntos_io/IoHelper_drv.c
Normal file
71
rostests/kmtests/ntos_io/IoHelper_drv.c
Normal 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;
|
||||
}
|
95
rostests/kmtests/ntos_io/IoInterrupt.c
Normal file
95
rostests/kmtests/ntos_io/IoInterrupt.c
Normal 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();
|
||||
}
|
|
@ -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");
|
||||
}
|
57
rostests/kmtests/ntos_io/IoMdl.c
Normal file
57
rostests/kmtests/ntos_io/IoMdl.c
Normal 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);
|
||||
}
|
14
rostests/kmtests/ntos_io/iodeviceobject_drv.rbuild
Normal file
14
rostests/kmtests/ntos_io/iodeviceobject_drv.rbuild
Normal 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>
|
14
rostests/kmtests/ntos_io/iohelper_drv.rbuild
Normal file
14
rostests/kmtests/ntos_io/iohelper_drv.rbuild
Normal 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>
|
193
rostests/kmtests/ntos_ke/KeApc.c
Normal file
193
rostests/kmtests/ntos_ke/KeApc.c
Normal 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);
|
||||
}
|
181
rostests/kmtests/ntos_ke/KeDpc.c
Normal file
181
rostests/kmtests/ntos_ke/KeDpc.c
Normal 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);
|
||||
}
|
267
rostests/kmtests/ntos_ke/KeEvent.c
Normal file
267
rostests/kmtests/ntos_ke/KeEvent.c
Normal 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);
|
||||
}
|
361
rostests/kmtests/ntos_ke/KeGuardedMutex.c
Normal file
361
rostests/kmtests/ntos_ke/KeGuardedMutex.c
Normal 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);
|
||||
}
|
147
rostests/kmtests/ntos_ke/KeIrql.c
Normal file
147
rostests/kmtests/ntos_ke/KeIrql.c
Normal 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);
|
||||
}
|
|
@ -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();
|
||||
}
|
364
rostests/kmtests/ntos_ke/KeSpinLock.c
Normal file
364
rostests/kmtests/ntos_ke/KeSpinLock.c
Normal 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);
|
||||
}
|
327
rostests/kmtests/ntos_ob/ObReference.c
Normal file
327
rostests/kmtests/ntos_ob/ObReference.c
Normal 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;
|
||||
}
|
||||
}
|
446
rostests/kmtests/ntos_ob/ObType.c
Normal file
446
rostests/kmtests/ntos_ob/ObType.c
Normal 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);
|
||||
}
|
11
rostests/kmtests/readme.txt
Normal file
11
rostests/kmtests/readme.txt
Normal 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.
|
4
rostests/kmtests/rtl/RtlAvlTree.c
Normal file
4
rostests/kmtests/rtl/RtlAvlTree.c
Normal 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"
|
498
rostests/kmtests/rtl/RtlMemory.c
Normal file
498
rostests/kmtests/rtl/RtlMemory.c
Normal 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);
|
||||
}
|
92
rostests/kmtests/rtl/RtlSplayTree.c
Normal file
92
rostests/kmtests/rtl/RtlSplayTree.c
Normal 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();
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
<module name="kmtloader" type="win32cui" installbase="system32" installname="kmtloader.exe">
|
||||
<library>advapi32</library>
|
||||
<file>kmtloader.c</file>
|
||||
</module>
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue