From a6b4eba33503abd52f4b668da5cf5b91b5662b74 Mon Sep 17 00:00:00 2001 From: Thomas Faber Date: Mon, 13 Jun 2011 17:50:07 +0000 Subject: [PATCH] [KMTESTS] - 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 --- kmtests/CMakeLists.txt | 2 + kmtests/include/kmt_public.h | 3 + kmtests/include/kmt_test.h | 58 ++++++++++- kmtests/kmtest.rbuild | 1 + kmtests/kmtest/kmtest.c | 46 +++++---- kmtests/kmtest_drv.rbuild | 1 + kmtests/kmtest_drv/kmtest_drv.c | 174 ++++++++++++++++++++++---------- kmtests/kmtest_drv/log.c | 65 ++---------- kmtests/kmtest_drv/testlist.c | 2 +- 9 files changed, 218 insertions(+), 134 deletions(-) diff --git a/kmtests/CMakeLists.txt b/kmtests/CMakeLists.txt index 0d355f569de..6708c966169 100644 --- a/kmtests/CMakeLists.txt +++ b/kmtests/CMakeLists.txt @@ -23,6 +23,7 @@ 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) +set_property(TARGET kmtest_drv PROPERTY COMPILE_DEFINITIONS KMT_KERNEL_MODE) add_cd_file(TARGET kmtest_drv DESTINATION reactos/system32/drivers FOR all) @@ -39,5 +40,6 @@ list(APPEND KMTEST_SOURCE 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) diff --git a/kmtests/include/kmt_public.h b/kmtests/include/kmt_public.h index 1c1b5dcbc5e..284cb2a26cc 100644 --- a/kmtests/include/kmt_public.h +++ b/kmtests/include/kmt_public.h @@ -14,6 +14,9 @@ #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) diff --git a/kmtests/include/kmt_test.h b/kmtests/include/kmt_test.h index ff045ee91af..49460124e97 100644 --- a/kmtests/include/kmt_test.h +++ b/kmtests/include/kmt_test.h @@ -8,8 +8,6 @@ #ifndef _KMTEST_TEST_H_ #define _KMTEST_TEST_H_ -#include - typedef void KMT_TESTFUNC(void); typedef struct @@ -22,4 +20,60 @@ typedef const KMT_TEST CKMT_TEST, *PCKMT_TEST; 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_ */ diff --git a/kmtests/kmtest.rbuild b/kmtests/kmtest.rbuild index 08c2ec975f0..20bdc999a1c 100644 --- a/kmtests/kmtest.rbuild +++ b/kmtests/kmtest.rbuild @@ -1,6 +1,7 @@ include advapi32 + kmtest.c service.c diff --git a/kmtests/kmtest/kmtest.c b/kmtests/kmtest/kmtest.c index a517822540b..619acc869b1 100644 --- a/kmtests/kmtest/kmtest.c +++ b/kmtests/kmtest/kmtest.c @@ -16,6 +16,10 @@ #include "kmtest.h" #include #include +#define KMT_DEFINE_TEST_FUNCTIONS +#include + +#define LOGBUFFER_SIZE 65000 static void OutputError(FILE *fp, DWORD error); static DWORD RunTest(char *testName); @@ -40,9 +44,14 @@ 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); @@ -53,23 +62,19 @@ static DWORD RunTest(char *testName) 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; @@ -79,6 +84,9 @@ cleanup: if (hDevice != INVALID_HANDLE_VALUE) CloseHandle(hDevice); + if (ResultBuffer) + KmtFreeResultBuffer(ResultBuffer); + return error; } @@ -89,7 +97,7 @@ static DWORD ListTests(PSTR *testList) DWORD bytesRead; PSTR buffer = NULL; DWORD bufferSize; - + if (!testList) { error = ERROR_INVALID_PARAMETER; @@ -104,7 +112,7 @@ static DWORD ListTests(PSTR *testList) error = GetLastError(); goto cleanup; } - + bufferSize = 1024; buffer = HeapAlloc(GetProcessHeap(), 0, bufferSize); if (!buffer) @@ -125,10 +133,10 @@ cleanup: HeapFree(GetProcessHeap(), 0, buffer); buffer = NULL; } - + if (hDevice != INVALID_HANDLE_VALUE) CloseHandle(hDevice); - + if (testList) *testList = buffer; @@ -162,7 +170,7 @@ int __cdecl main(int argc, char **argv) printf(" %s\n", testName); testName += len + 1; } - + /* TODO: user-mode test parts */ if (error) @@ -171,7 +179,7 @@ int __cdecl main(int argc, char **argv) else { char *testName = argv[1]; - + if (argc > 2) fputs("Excess arguments ignored\n", stderr); diff --git a/kmtests/kmtest_drv.rbuild b/kmtests/kmtest_drv.rbuild index 3735673a1da..5d43511da18 100644 --- a/kmtests/kmtest_drv.rbuild +++ b/kmtests/kmtest_drv.rbuild @@ -4,6 +4,7 @@ ntdll hal pseh + kmtest_drv.c log.c diff --git a/kmtests/kmtest_drv/kmtest_drv.c b/kmtests/kmtest_drv/kmtest_drv.c index d238d4f0672..39c4194c153 100644 --- a/kmtests/kmtest_drv/kmtest_drv.c +++ b/kmtests/kmtest_drv/kmtest_drv.c @@ -8,6 +8,7 @@ #include #include #include +#include //#define NDEBUG #include @@ -19,9 +20,16 @@ /* 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; @@ -43,6 +51,8 @@ NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING Re { NTSTATUS Status = STATUS_SUCCESS; UNICODE_STRING DeviceName; + PDEVICE_EXTENSION DeviceExtension; + PAGED_CODE(); UNREFERENCED_PARAMETER(RegistryPath); @@ -55,7 +65,8 @@ NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING Re 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); @@ -64,13 +75,14 @@ NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING Re 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)) @@ -100,15 +112,21 @@ static VOID NTAPI DriverUnload(IN PDRIVER_OBJECT DriverObject) 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 @@ -117,19 +135,66 @@ static VOID NTAPI DriverUnload(IN PDRIVER_OBJECT DriverObject) * * @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; @@ -223,55 +288,54 @@ static NTSTATUS NTAPI DriverIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Ir 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; diff --git a/kmtests/kmtest_drv/log.c b/kmtests/kmtest_drv/log.c index edca4459882..9dda0939364 100644 --- a/kmtests/kmtest_drv/log.c +++ b/kmtests/kmtest_drv/log.c @@ -9,14 +9,8 @@ #include #include - -#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 /** * @name LogInit @@ -30,11 +24,6 @@ NTSTATUS LogInit(VOID) NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); - LogBuffer = ExAllocatePoolWithTag(NonPagedPool, LOGBUFFER_MAX, LOG_TAG); - - if (!LogBuffer) - Status = STATUS_INSUFFICIENT_RESOURCES; - return Status; } @@ -48,8 +37,6 @@ NTSTATUS LogInit(VOID) VOID LogFree(VOID) { PAGED_CODE(); - - ExFreePoolWithTag(LogBuffer, LOG_TAG); } /** @@ -64,10 +51,10 @@ VOID LogFree(VOID) */ 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); } /** @@ -105,47 +92,11 @@ VOID LogPrintF(IN PCSTR Format, ...) */ 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); } diff --git a/kmtests/kmtest_drv/testlist.c b/kmtests/kmtest_drv/testlist.c index d94e46f03c9..d53a6868a27 100644 --- a/kmtests/kmtest_drv/testlist.c +++ b/kmtests/kmtest_drv/testlist.c @@ -5,7 +5,7 @@ * PROGRAMMER: Thomas Faber */ -#include +#include #include KMT_TESTFUNC Test_Example; -- 2.17.1