- use a shared memory buffer for storing test results to provide seamless communication between all test parts
- Now user mode code can easily add messages to the buffer
svn path=/branches/GSoC_2011/KMTestSuite/; revision=52216
set_module_type(kmtest_drv kernelmodedriver)
target_link_libraries(kmtest_drv ${PSEH_LIB})
add_importlibs(kmtest_drv ntoskrnl hal)
+set_property(TARGET kmtest_drv PROPERTY COMPILE_DEFINITIONS KMT_KERNEL_MODE)
add_cd_file(TARGET kmtest_drv DESTINATION reactos/system32/drivers FOR all)
add_executable(kmtest ${KMTEST_SOURCE})
set_module_type(kmtest win32cui)
add_importlibs(kmtest advapi32 msvcrt kernel32)
+set_property(TARGET kmtest PROPERTY COMPILE_DEFINITIONS KMT_USER_MODE)
add_cd_file(TARGET kmtest DESTINATION reactos/bin FOR all)
#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_PATH (L"\\\\.\\Global\\GLOBALROOT\\Device\\" KMTEST_DEVICE_NAME)
#ifndef _KMTEST_TEST_H_
#define _KMTEST_TEST_H_
-#include <kmt_log.h>
-
typedef void KMT_TESTFUNC(void);
typedef struct
extern const KMT_TEST TestList[];
+typedef struct {
+ volatile LONG Successes;
+ volatile LONG Failures;
+ volatile LONG LogBufferLength;
+ LONG LogBufferMaxLength;
+ CHAR LogBuffer[ANYSIZE_ARRAY];
+} KMT_RESULTBUFFER, *PKMT_RESULTBUFFER;
+
+extern PKMT_RESULTBUFFER ResultBuffer;
+
+#if defined KMT_DEFINE_TEST_FUNCTIONS
+PKMT_RESULTBUFFER ResultBuffer = NULL;
+
+#if defined KMT_USER_MODE
+static PKMT_RESULTBUFFER KmtAllocateResultBuffer(SIZE_T LogBufferMaxLength)
+{
+ PKMT_RESULTBUFFER Buffer = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer[LogBufferMaxLength]));
+
+ Buffer->Successes = 0;
+ Buffer->Failures = 0;
+ Buffer->LogBufferLength = 0;
+ Buffer->LogBufferMaxLength = LogBufferMaxLength;
+
+ return Buffer;
+}
+
+static VOID KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer)
+{
+ HeapFree(GetProcessHeap(), 0, Buffer);
+}
+#endif /* defined KMT_USER_MODE */
+
+#define KmtMemCpy memcpy
+
+static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
+{
+ LONG OldLength;
+ LONG NewLength;
+
+ do
+ {
+ OldLength = Buffer->LogBufferLength;
+ NewLength = OldLength + Length;
+ if (NewLength > Buffer->LogBufferMaxLength)
+ {
+ /* TODO: indicate failure somehow */
+ __debugbreak();
+ return;
+ }
+ } while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
+
+ KmtMemCpy(&Buffer->LogBuffer[OldLength], String, Length);
+}
+
+#endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
+
#endif /* !defined _KMTEST_TEST_H_ */
<module name="kmtest" type="win32cui" installbase="system32" installname="kmtest.exe">
<include base="kmtest">include</include>
<library>advapi32</library>
+ <define name="KMT_USER_MODE" />
<directory name="kmtest">
<file>kmtest.c</file>
<file>service.c</file>
#include "kmtest.h"
#include <winioctl.h>
#include <kmt_public.h>
+#define KMT_DEFINE_TEST_FUNCTIONS
+#include <kmt_test.h>
+
+#define LOGBUFFER_SIZE 65000
static void OutputError(FILE *fp, DWORD error);
static DWORD RunTest(char *testName);
{
DWORD error = ERROR_SUCCESS;
HANDLE hDevice = INVALID_HANDLE_VALUE;
- DWORD bytesRead;
- char buffer[1024];
- BOOL ret;
+ DWORD bytesRead, bytesWritten;
+
+ ResultBuffer = KmtAllocateResultBuffer(LOGBUFFER_SIZE);
+ if (!ResultBuffer)
+ {
+ error = GetLastError();
+ goto cleanup;
+ }
hDevice = CreateFile(KMTEST_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, NULL);
goto cleanup;
}
- if (!DeviceIoControl(hDevice, IOCTL_KMTEST_RUN_TEST, testName, strlen(testName), NULL, 0, &bytesRead, NULL))
+ if (!DeviceIoControl(hDevice, IOCTL_KMTEST_SET_RESULTBUFFER, ResultBuffer, FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer[LOGBUFFER_SIZE]), NULL, 0, &bytesRead, NULL))
{
error = GetLastError();
goto cleanup;
}
- while ((ret = ReadFile(hDevice, buffer, sizeof buffer - 1, &bytesRead, NULL)) != 0)
+ if (!DeviceIoControl(hDevice, IOCTL_KMTEST_RUN_TEST, testName, strlen(testName), NULL, 0, &bytesRead, NULL))
{
- if (!bytesRead)
- break;
-
- assert(bytesRead < sizeof buffer);
- buffer[bytesRead] = '\0';
-
- fputs(buffer, stdout);
+ error = GetLastError();
+ goto cleanup;
}
- if (!ret)
+
+ if (!WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), ResultBuffer->LogBuffer, ResultBuffer->LogBufferLength, &bytesWritten, NULL))
{
error = GetLastError();
goto cleanup;
if (hDevice != INVALID_HANDLE_VALUE)
CloseHandle(hDevice);
+ if (ResultBuffer)
+ KmtFreeResultBuffer(ResultBuffer);
+
return error;
}
DWORD bytesRead;
PSTR buffer = NULL;
DWORD bufferSize;
-
+
if (!testList)
{
error = ERROR_INVALID_PARAMETER;
error = GetLastError();
goto cleanup;
}
-
+
bufferSize = 1024;
buffer = HeapAlloc(GetProcessHeap(), 0, bufferSize);
if (!buffer)
HeapFree(GetProcessHeap(), 0, buffer);
buffer = NULL;
}
-
+
if (hDevice != INVALID_HANDLE_VALUE)
CloseHandle(hDevice);
-
+
if (testList)
*testList = buffer;
printf(" %s\n", testName);
testName += len + 1;
}
-
+
/* TODO: user-mode test parts */
if (error)
else
{
char *testName = argv[1];
-
+
if (argc > 2)
fputs("Excess arguments ignored\n", stderr);
<library>ntdll</library>
<library>hal</library>
<library>pseh</library>
+ <define name="KMT_KERNEL_MODE" />
<directory name="kmtest_drv">
<file>kmtest_drv.c</file>
<file>log.c</file>
#include <ntddk.h>
#include <ntstrsafe.h>
#include <limits.h>
+#include <pseh/pseh2.h>
//#define NDEBUG
#include <debug.h>
/* Prototypes */
DRIVER_INITIALIZE DriverEntry;
static DRIVER_UNLOAD DriverUnload;
-static DRIVER_DISPATCH DriverCreateClose;
+static DRIVER_DISPATCH DriverCreate;
+static DRIVER_DISPATCH DriverClose;
static DRIVER_DISPATCH DriverIoControl;
-static DRIVER_DISPATCH DriverRead;
+
+/* Device Extension layout */
+typedef struct
+{
+ PKMT_RESULTBUFFER ResultBuffer;
+ PMDL Mdl;
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
/* Globals */
static PDEVICE_OBJECT MainDeviceObject;
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING DeviceName;
+ PDEVICE_EXTENSION DeviceExtension;
+
PAGED_CODE();
UNREFERENCED_PARAMETER(RegistryPath);
goto cleanup;
RtlInitUnicodeString(&DeviceName, L"\\Device\\Kmtest");
- Status = IoCreateDevice(DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN,
+ Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &DeviceName,
+ FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN | FILE_READ_ONLY_DEVICE,
TRUE, &MainDeviceObject);
DPRINT("DriverEntry. Created DeviceObject %p\n",
MainDeviceObject);
- MainDeviceObject->Flags |= DO_DIRECT_IO;
+ DeviceExtension = MainDeviceObject->DeviceExtension;
+ DeviceExtension->ResultBuffer = NULL;
+ DeviceExtension->Mdl = NULL;
DriverObject->DriverUnload = DriverUnload;
- DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreateClose;
- DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverCreateClose;
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreate;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverIoControl;
- DriverObject->MajorFunction[IRP_MJ_READ] = DriverRead;
cleanup:
if (MainDeviceObject && !NT_SUCCESS(Status))
DPRINT("DriverUnload\n");
if (MainDeviceObject)
+ {
+ PDEVICE_EXTENSION DeviceExtension = MainDeviceObject->DeviceExtension;
+ ASSERT(!DeviceExtension->Mdl);
+ ASSERT(!DeviceExtension->ResultBuffer);
+ ASSERT(!ResultBuffer);
IoDeleteDevice(MainDeviceObject);
+ }
LogFree();
}
/**
- * @name DriverCreateClose
+ * @name DriverCreate
*
- * Driver Dispatch function for CreateFile/CloseHandle.
+ * Driver Dispatch function for CreateFile
*
* @param DeviceObject
* Device Object
*
* @return Status
*/
-static NTSTATUS NTAPI DriverCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+static NTSTATUS NTAPI DriverCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION IoStackLocation;
+ PDEVICE_EXTENSION DeviceExtension;
PAGED_CODE();
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
- DPRINT("DriverCreateClose. Function=%s, DeviceObject=%p\n",
- IoStackLocation->MajorFunction == IRP_MJ_CREATE ? "Create" : "Close",
+ DPRINT("DriverCreate. DeviceObject=%p\n",
DeviceObject);
+ DeviceExtension = DeviceObject->DeviceExtension;
+ ASSERT(!DeviceExtension->Mdl);
+ ASSERT(!DeviceExtension->ResultBuffer);
+ ASSERT(!ResultBuffer);
+
+ 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;
+ PDEVICE_EXTENSION DeviceExtension;
+
+ PAGED_CODE();
+
+ IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ DPRINT("DriverClose. DeviceObject=%p\n",
+ DeviceObject);
+
+ DeviceExtension = DeviceObject->DeviceExtension;
+ if (DeviceExtension->Mdl)
+ {
+ MmUnlockPages(DeviceExtension->Mdl);
+ IoFreeMdl(DeviceExtension->Mdl);
+ DeviceExtension->Mdl = NULL;
+ ResultBuffer = DeviceExtension->ResultBuffer = NULL;
+ }
+
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
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;
+ case IOCTL_KMTEST_SET_RESULTBUFFER:
+ {
+ PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
- PAGED_CODE();
+ DPRINT("DriverIoControl. IOCTL_KMTEST_SET_RESULTBUFFER, inlen=%lu, outlen=%lu\n",
+ IoStackLocation->Parameters.DeviceIoControl.InputBufferLength,
+ IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength);
- IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+ if (DeviceExtension->Mdl)
+ {
+ MmUnlockPages(DeviceExtension->Mdl);
+ IoFreeMdl(DeviceExtension->Mdl);
+ }
- DPRINT("DriverRead. Offset=%I64u, Length=%lu, DeviceObject=%p\n",
- IoStackLocation->Parameters.Read.ByteOffset.QuadPart,
- IoStackLocation->Parameters.Read.Length,
- DeviceObject);
+ DeviceExtension->Mdl = IoAllocateMdl(IoStackLocation->Parameters.DeviceIoControl.Type3InputBuffer,
+ IoStackLocation->Parameters.DeviceIoControl.InputBufferLength,
+ FALSE, FALSE, NULL);
+ if (!DeviceExtension->Mdl)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
- ReadBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ _SEH2_TRY
+ {
+ MmProbeAndLockPages(DeviceExtension->Mdl, KernelMode, IoModifyAccess);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ IoFreeMdl(DeviceExtension->Mdl);
+ DeviceExtension->Mdl = NULL;
+ break;
+ } _SEH2_END;
- Length = LogRead(ReadBuffer, IoStackLocation->Parameters.Read.Length);
+ ResultBuffer = DeviceExtension->ResultBuffer = MmGetSystemAddressForMdlSafe(DeviceExtension->Mdl, NormalPagePriority);
- DPRINT("DriverRead. Length of data read: %lu\n",
- Length);
+ 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;
#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 */
+#define KMT_DEFINE_TEST_FUNCTIONS
+#include <kmt_test.h>
/**
* @name LogInit
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
- LogBuffer = ExAllocatePoolWithTag(NonPagedPool, LOGBUFFER_MAX, LOG_TAG);
-
- if (!LogBuffer)
- Status = STATUS_INSUFFICIENT_RESOURCES;
-
return Status;
}
VOID LogFree(VOID)
{
PAGED_CODE();
-
- ExFreePoolWithTag(LogBuffer, LOG_TAG);
}
/**
*/
VOID LogPrint(IN PCSTR Message)
{
- SIZE_T MessageLength = strlen(Message);
- ASSERT(LogOffset + MessageLength + 1 < LOGBUFFER_MAX);
- RtlCopyMemory(&LogBuffer[LogOffset], Message, MessageLength + 1);
- LogOffset += MessageLength;
+ size_t MessageLength;
+ ASSERT(NT_SUCCESS(RtlStringCbLengthA(Message, 512, &MessageLength)));
+
+ KmtAddToLogBuffer(ResultBuffer, Message, MessageLength);
}
/**
*/
VOID LogVPrintF(IN PCSTR Format, va_list Arguments)
{
- CHAR Buffer[1024];
- SIZE_T BufferLength;
+ CHAR Buffer[512];
/* 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;
+ LogPrint(Buffer);
}
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
-#include <stddef.h>
+#include <ntddk.h>
#include <kmt_test.h>
KMT_TESTFUNC Test_Example;