[KMTESTS]

- add basic driver that can list/run tests and log messages

svn path=/branches/GSoC_2011/KMTestSuite/; revision=52168
This commit is contained in:
Thomas Faber 2011-06-10 05:34:00 +00:00
parent 22216d2eb7
commit e95992c699
9 changed files with 547 additions and 0 deletions

View file

@ -1,6 +1,32 @@
include_directories(
include)
#
# subdirectories containing special-purpose drivers
#
#add_subdirectory(something)
#
# kmtest_drv.sys driver
#
list(APPEND KMTEST_DRV_SOURCE
kmtest_drv/kmtest_drv.c
kmtest_drv/log.c
kmtest_drv/testlist.c
kmtest_drv/kmtest_drv.rc)
add_library(kmtest_drv SHARED ${KMTEST_DRV_SOURCE})
set_module_type(kmtest_drv kernelmodedriver)
target_link_libraries(kmtest_drv ${PSEH_LIB})
add_importlibs(kmtest_drv ntoskrnl hal)
add_cd_file(TARGET kmtest_drv DESTINATION reactos/system32/drivers FOR all)
#
# kmtest.exe loader application
#
set_rc_compiler()
add_definitions(-D_DLL -D__USE_CRTIMP)

View file

@ -5,4 +5,5 @@
<xi:include href="something/something_drv.rbuild" />
</directory>-->
<xi:include href="kmtest.rbuild" />
<xi:include href="kmtest_drv.rbuild" />
</group>

21
kmtests/include/kmt_log.h Normal file
View file

@ -0,0 +1,21 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite Driver logging function declarations
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
#ifndef _KMTEST_LOG_H_
#define _KMTEST_LOG_H_
#include <ntddk.h>
NTSTATUS LogInit(VOID);
VOID LogFree(VOID);
VOID LogPrint(IN PCSTR Message);
VOID LogPrintF(IN PCSTR Format, ...);
VOID LogVPrintF(IN PCSTR Format, va_list Arguments);
SIZE_T LogRead(OUT PVOID Buffer, IN SIZE_T BufferSize);
#endif /* !defined _KMTEST_LOG_H_ */

View file

@ -0,0 +1,25 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite test declarations
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
#ifndef _KMTEST_TEST_H_
#define _KMTEST_TEST_H_
#include <kmt_log.h>
typedef void KMT_TESTFUNC(void);
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[];
#endif /* !defined _KMTEST_TEST_H_ */

12
kmtests/kmtest_drv.rbuild Normal file
View file

@ -0,0 +1,12 @@
<module name="kmtest_drv" type="kernelmodedriver" installbase="system32/drivers" installname="kmtest_drv.sys">
<include base="kmtest_drv">include</include>
<library>ntoskrnl</library>
<library>ntdll</library>
<library>hal</library>
<library>pseh</library>
<directory name="kmtest_drv">
<file>kmtest_drv.c</file>
<file>log.c</file>
<file>testlist.c</file>
</directory>
</module>

View file

@ -0,0 +1,282 @@
/*
* 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 <ntstrsafe.h>
#include <limits.h>
//#define NDEBUG
#include <debug.h>
#include <kmt_public.h>
#include <kmt_log.h>
#include <kmt_test.h>
/* Prototypes */
DRIVER_INITIALIZE DriverEntry;
static DRIVER_UNLOAD DriverUnload;
static DRIVER_DISPATCH DriverCreateClose;
static DRIVER_DISPATCH DriverIoControl;
static DRIVER_DISPATCH DriverRead;
/* 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;
PAGED_CODE();
UNREFERENCED_PARAMETER(RegistryPath);
DPRINT("DriverEntry\n");
Status = LogInit();
if (!NT_SUCCESS(Status))
goto cleanup;
RtlInitUnicodeString(&DeviceName, L"\\Device\\Kmtest");
Status = IoCreateDevice(DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN | FILE_READ_ONLY_DEVICE,
TRUE, &MainDeviceObject);
if (!NT_SUCCESS(Status))
goto cleanup;
DPRINT("DriverEntry. Created DeviceObject %p\n",
MainDeviceObject);
MainDeviceObject->Flags |= DO_DIRECT_IO;
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverIoControl;
DriverObject->MajorFunction[IRP_MJ_READ] = DriverRead;
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)
IoDeleteDevice(MainDeviceObject);
LogFree();
}
/**
* @name DriverCreateClose
*
* Driver Dispatch function for CreateFile/CloseHandle.
*
* @param DeviceObject
* Device Object
* @param Irp
* I/O request packet
*
* @return Status
*/
static NTSTATUS NTAPI DriverCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION IoStackLocation;
PAGED_CODE();
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
DPRINT("DriverCreateClose. Function=%s, DeviceObject=%p\n",
IoStackLocation->MajorFunction == IRP_MJ_CREATE ? "Create" : "Close",
DeviceObject);
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\n",
IoStackLocation->Parameters.DeviceIoControl.IoControlCode,
DeviceObject);
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;
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;
}
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;
}
/**
* @name DriverRead
*
* Driver Dispatch function for ReadFile.
*
* @param DeviceObject
* Device Object
* @param Irp
* I/O request packet
*
* @return Status
*/
static NTSTATUS NTAPI DriverRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION IoStackLocation;
PVOID ReadBuffer;
SIZE_T Length;
PAGED_CODE();
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
DPRINT("DriverRead. Offset=%I64u, Length=%lu, DeviceObject=%p\n",
IoStackLocation->Parameters.Read.ByteOffset.QuadPart,
IoStackLocation->Parameters.Read.Length,
DeviceObject);
ReadBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
Length = LogRead(ReadBuffer, IoStackLocation->Parameters.Read.Length);
DPRINT("DriverRead. Length of data read: %lu\n",
Length);
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = Length;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}

View file

@ -0,0 +1,15 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite Driver Resource File
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
#include <windows.h>
#define REACTOS_FILETYPE VFT_DRV
#define REACTOS_FILESUBTYPE VFT2_DRV_SYSTEM
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Kernel-Mode Test Suite Driver\0"
#define REACTOS_STR_INTERNAL_NAME "kmtest.sys\0"
#define REACTOS_STR_ORIGINAL_FILENAME "kmtest.sys\0"
#include <reactos/version.rc>

151
kmtests/kmtest_drv/log.c Normal file
View file

@ -0,0 +1,151 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite Driver logging functions
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
#include <ntddk.h>
#include <ntstrsafe.h>
#include <kmt_log.h>
#define LOGBUFFER_MAX (1024UL * 1024)
static PCHAR LogBuffer;
static SIZE_T LogOffset;
#define LOG_TAG 'LtmK'
/* TODO: allow concurrent log buffer access */
/**
* @name LogInit
*
* Initialize logging mechanism. Call from DriverEntry.
*
* @return Status
*/
NTSTATUS LogInit(VOID)
{
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
LogBuffer = ExAllocatePoolWithTag(NonPagedPool, LOGBUFFER_MAX, LOG_TAG);
if (!LogBuffer)
Status = STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
/**
* @name LogFree
*
* Clean up logging mechanism. Call from Unload.
*
* @return None
*/
VOID LogFree(VOID)
{
PAGED_CODE();
ExFreePoolWithTag(LogBuffer, LOG_TAG);
}
/**
* @name LogPrint
*
* Print a log message.
*
* @param Message
* Ansi string to be logged
*
* @return None
*/
VOID LogPrint(IN PCSTR Message)
{
SIZE_T MessageLength = strlen(Message);
ASSERT(LogOffset + MessageLength + 1 < LOGBUFFER_MAX);
RtlCopyMemory(&LogBuffer[LogOffset], Message, MessageLength + 1);
LogOffset += MessageLength;
}
/**
* @name LogPrintF
*
* Print a formatted log message.
*
* @param Format
* printf-like format string
* @param ...
* Arguments corresponding to the format
*
* @return None
*/
VOID LogPrintF(IN PCSTR Format, ...)
{
va_list Arguments;
PAGED_CODE();
va_start(Arguments, Format);
LogVPrintF(Format, Arguments);
va_end(Arguments);
}
/**
* @name LogVPrintF
*
* Print a formatted log message.
*
* @param Format
* printf-like format string
* @param Arguments
* Arguments corresponding to the format
*
* @return None
*/
VOID LogVPrintF(IN PCSTR Format, va_list Arguments)
{
CHAR Buffer[1024];
SIZE_T BufferLength;
/* TODO: make this work from any IRQL */
PAGED_CODE();
RtlStringCbVPrintfA(Buffer, sizeof Buffer, Format, Arguments);
BufferLength = strlen(Buffer);
ASSERT(LogOffset + BufferLength + 1 < LOGBUFFER_MAX);
RtlCopyMemory(&LogBuffer[LogOffset], Buffer, BufferLength + 1);
LogOffset += BufferLength;
}
/**
* @name LogRead
*
* Retrieve data from the log buffer.
*
* @param Buffer
* Buffer to copy log data to
* @param BufferSize
* Maximum number of bytes to copy
*
* @return Number of bytes copied
*/
SIZE_T LogRead(OUT PVOID Buffer, IN SIZE_T BufferSize)
{
SIZE_T Size;
PAGED_CODE();
Size = min(BufferSize, LogOffset);
RtlCopyMemory(Buffer, LogBuffer, Size);
if (BufferSize < LogOffset)
{
SIZE_T SizeLeft = LogOffset - BufferSize;
RtlMoveMemory(LogBuffer, &LogBuffer[LogOffset], SizeLeft);
LogOffset = SizeLeft;
}
else
LogOffset = 0;
return Size;
}

View file

@ -0,0 +1,14 @@
/*
* 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 <stddef.h>
#include <kmt_test.h>
const KMT_TEST TestList[] =
{
{ NULL, NULL }
};