Author: ion
Date: Sat Jul 1 07:36:15 2006
New Revision: 22734
URL:
http://svn.reactos.org/svn/reactos?rev=22734&view=rev
Log:
- Add some missing IO_ERROR definitions to the DDK and add some tags
- Fix IoSetThreadHardErrorMode... it was reading the TEB instead of the PETHREAD.
- Optimize Error Logging: Use a static work item instead of allocating one each time, and
don't use a spinlock for the buffer count, when we can use interlocked functions
instead.
- Log Entries can have Device AND/OR Driver Objects, not just a single one. They must also
be referenced/dereferenced on allocation/free.
- Rewrite IopLogWorker to properly deal with Device/Driver objects and querying their
names, as well as with additional strings that the caller might be sending.
Modified:
trunk/reactos/include/ddk/winddk.h
trunk/reactos/ntoskrnl/include/internal/io.h
trunk/reactos/ntoskrnl/include/internal/tag.h
trunk/reactos/ntoskrnl/io/error.c
Modified: trunk/reactos/include/ddk/winddk.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/ddk/winddk.h?rev=2…
==============================================================================
--- trunk/reactos/include/ddk/winddk.h (original)
+++ trunk/reactos/include/ddk/winddk.h Sat Jul 1 07:36:15 2006
@@ -1849,6 +1849,14 @@
#define IO_ERROR_LOG_MESSAGE_HEADER_LENGTH (sizeof(IO_ERROR_LOG_MESSAGE) - \
sizeof(IO_ERROR_LOG_PACKET) + \
(sizeof(WCHAR) * 40))
+#define ERROR_LOG_MESSAGE_LIMIT_SIZE \
+ (ERROR_LOG_LIMIT_SIZE + IO_ERROR_LOG_MESSAGE_HEADER_LENGTH)
+#define IO_ERROR_LOG_MESSAGE_LENGTH \
+ ((PORT_MAXIMUM_MESSAGE_LENGTH > ERROR_LOG_MESSAGE_LIMIT_SIZE) ? \
+ ERROR_LOG_MESSAGE_LIMIT_SIZE : \
+ PORT_MAXIMUM_MESSAGE_LENGTH)
+#define ERROR_LOG_MAXIMUM_SIZE (IO_ERROR_LOG_MESSAGE_LENGTH - \
+ IO_ERROR_LOG_MESSAGE_HEADER_LENGTH)
typedef struct _CONTROLLER_OBJECT {
CSHORT Type;
Modified: trunk/reactos/ntoskrnl/include/internal/io.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/io.h (original)
+++ trunk/reactos/ntoskrnl/include/internal/io.h Sat Jul 1 07:36:15 2006
@@ -217,6 +217,29 @@
PKINTERRUPT Interrupt[MAXIMUM_PROCESSORS];
KSPIN_LOCK SpinLock;
} IO_INTERRUPT, *PIO_INTERRUPT;
+
+//
+// I/O Error Log Packet Header
+//
+typedef struct _ERROR_LOG_ENTRY
+{
+ CSHORT Type;
+ CSHORT Size;
+ LIST_ENTRY ListEntry;
+ PDEVICE_OBJECT DeviceObject;
+ PDRIVER_OBJECT DriverObject;
+ LARGE_INTEGER TimeStamp;
+} ERROR_LOG_ENTRY, *PERROR_LOG_ENTRY;
+
+//
+// Event Log LPC Message
+//
+typedef struct _ELF_API_MSG
+{
+ PORT_MESSAGE h;
+ ULONG Unknown[2];
+ IO_ERROR_LOG_MESSAGE IoErrorMessage;
+} ELF_API_MSG, *PELF_API_MSG;
//
// To simplify matters, the kernel is made to support both the checked and free
@@ -604,10 +627,16 @@
//
// Error Logging Routines
//
-
-NTSTATUS
+VOID
+NTAPI
IopInitErrorLog(
VOID
+);
+
+VOID
+NTAPI
+IopLogWorker(
+ IN PVOID Parameter
);
//
Modified: trunk/reactos/ntoskrnl/include/internal/tag.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/tag.h (original)
+++ trunk/reactos/ntoskrnl/include/internal/tag.h Sat Jul 1 07:36:15 2006
@@ -49,6 +49,9 @@
#define IO_SMALLIRP_CPU TAG('I', 'r', 'p', 'S')
#define IOC_TAG1 TAG('I', 'p', 'c', ' ')
#define IOC_CPU TAG('I', 'p', 'c', 'P')
+#define TAG_APC TAG('K', 'A', 'P', 'C')
+#define TAG_IO TAG('I', 'o', ' ', ' ')
+#define TAG_ERROR_LOG TAG('I', 'o', 'E', 'r')
/* formerly located in io/work.c */
#define TAG_IOWI TAG('I', 'O', 'W', 'I')
Modified: trunk/reactos/ntoskrnl/io/error.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/error.c?rev=22…
==============================================================================
--- trunk/reactos/ntoskrnl/io/error.c (original)
+++ trunk/reactos/ntoskrnl/io/error.c Sat Jul 1 07:36:15 2006
@@ -1,13 +1,11 @@
-/* $Id$
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/io/errlog.c
- * PURPOSE: Error logging
- *
- * PROGRAMMERS: David Welch (welch(a)cwcom.net)
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: ntoskrnl/io/error.c
+ * PURPOSE: I/O Error Functions and Error Log Support
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
+ * Eric Kohl
*/
-
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
@@ -16,456 +14,457 @@
/* TYPES *********************************************************************/
-typedef struct _ERROR_LOG_ENTRY
-{
- LIST_ENTRY Entry;
- LARGE_INTEGER TimeStamp;
- PVOID IoObject;
- ULONG PacketSize;
-} ERROR_LOG_ENTRY, *PERROR_LOG_ENTRY;
-
-typedef struct _LOG_WORKER_DPC
-{
- KDPC Dpc;
- KTIMER Timer;
-} LOG_WORKER_DPC, *PLOG_WORKER_DPC;
-
-
-static VOID STDCALL
-IopLogWorker (PVOID Parameter);
-
+typedef struct _IOP_ERROR_LOG_WORKER_DPC
+{
+ KDPC Dpc;
+ KTIMER Timer;
+} IOP_ERROR_LOG_WORKER_DPC, *PIOP_ERROR_LOG_WORKER_DPC;
/* GLOBALS *******************************************************************/
-static KSPIN_LOCK IopAllocationLock;
-static ULONG IopTotalLogSize;
-
-static KSPIN_LOCK IopLogListLock;
-static LIST_ENTRY IopLogListHead;
-
-static BOOLEAN IopLogWorkerRunning = FALSE;
-static BOOLEAN IopLogPortConnected = FALSE;
-static HANDLE IopLogPort;
-
-
-/* FUNCTIONS *****************************************************************/
-
-NTSTATUS
-IopInitErrorLog (VOID)
-{
- IopTotalLogSize = 0;
- KeInitializeSpinLock (&IopAllocationLock);
-
- KeInitializeSpinLock (&IopLogListLock);
- InitializeListHead (&IopLogListHead);
-
- return STATUS_SUCCESS;
-}
-
-
-static VOID STDCALL
-IopLogDpcRoutine (PKDPC Dpc,
- PVOID DeferredContext,
- PVOID SystemArgument1,
- PVOID SystemArgument2)
-{
- PWORK_QUEUE_ITEM LogWorkItem;
-
- DPRINT ("\nIopLogDpcRoutine() called\n");
-
- /* Release the WorkerDpc struct */
- ExFreePool (DeferredContext);
-
- /* Allocate, initialize and restart a work item */
- LogWorkItem = ExAllocatePool (NonPagedPool,
- sizeof(WORK_QUEUE_ITEM));
- if (LogWorkItem == NULL)
- {
- IopLogWorkerRunning = FALSE;
- return;
- }
-
- ExInitializeWorkItem (LogWorkItem,
- IopLogWorker,
- LogWorkItem);
-
- ExQueueWorkItem (LogWorkItem,
- DelayedWorkQueue);
-}
-
-
-static VOID
-IopRestartLogWorker (VOID)
-{
- PLOG_WORKER_DPC WorkerDpc;
- LARGE_INTEGER Timeout;
-
- DPRINT ("IopRestartWorker() called\n");
-
- WorkerDpc = ExAllocatePool (NonPagedPool,
- sizeof(LOG_WORKER_DPC));
- if (WorkerDpc == NULL)
- {
- IopLogWorkerRunning = FALSE;
- return;
- }
-
- /* Initialize DPC and Timer */
- KeInitializeDpc (&WorkerDpc->Dpc,
- IopLogDpcRoutine,
- WorkerDpc);
- KeInitializeTimer (&WorkerDpc->Timer);
-
- /* Restart after 30 seconds */
- Timeout.QuadPart = (LONGLONG)-300000000;
- KeSetTimer (&WorkerDpc->Timer,
- Timeout,
- &WorkerDpc->Dpc);
-}
-
-
-static BOOLEAN
-IopConnectLogPort (VOID)
-{
- UNICODE_STRING PortName;
- NTSTATUS Status;
-
- DPRINT ("IopConnectLogPort() called\n");
-
- RtlInitUnicodeString (&PortName,
- L"\\ErrorLogPort");
-
- Status = ZwConnectPort (&IopLogPort,
- &PortName,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT ("ZwConnectPort() failed (Status %lx)\n", Status);
- return FALSE;
- }
-
- DPRINT ("IopConnectLogPort() done\n");
-
- return TRUE;
-}
-
-
-static VOID STDCALL
-IopLogWorker (PVOID Parameter)
-{
- PERROR_LOG_ENTRY LogEntry;
- PPORT_MESSAGE Request;
- PIO_ERROR_LOG_MESSAGE Message;
- PIO_ERROR_LOG_PACKET Packet;
- KIRQL Irql;
- NTSTATUS Status;
-
- UCHAR Buffer[256];
- POBJECT_NAME_INFORMATION ObjectNameInfo;
- ULONG ReturnedLength;
- PWCHAR DriverName;
- ULONG DriverNameLength;
-
- DPRINT ("IopLogWorker() called\n");
-
- /* Release the work item */
- ExFreePool (Parameter);
-
- /* Connect to the error log port */
- if (IopLogPortConnected == FALSE)
- {
- if (IopConnectLogPort () == FALSE)
- {
- IopRestartLogWorker ();
- return;
- }
-
- IopLogPortConnected = TRUE;
- }
-
- while (TRUE)
- {
- /* Remove last entry from the list */
- KeAcquireSpinLock (&IopLogListLock,
- &Irql);
-
- if (!IsListEmpty (&IopLogListHead))
- {
- LogEntry = CONTAINING_RECORD (IopLogListHead.Blink,
- ERROR_LOG_ENTRY,
- Entry);
- RemoveEntryList (&LogEntry->Entry);
- }
- else
- {
- LogEntry = NULL;
- }
-
- KeReleaseSpinLock (&IopLogListLock,
- Irql);
-
- if (LogEntry == NULL)
- {
- DPRINT ("No message in log list\n");
- break;
- }
-
- /* Get pointer to the log packet */
- Packet = (PIO_ERROR_LOG_PACKET)((ULONG_PTR)LogEntry + sizeof(ERROR_LOG_ENTRY));
-
-
- /* Get driver or device name */
- ObjectNameInfo = (POBJECT_NAME_INFORMATION)Buffer;
- Status = ObQueryNameString (LogEntry->IoObject,
- ObjectNameInfo,
- 256,
- &ReturnedLength);
- if (NT_SUCCESS(Status))
- {
- DPRINT ("ReturnedLength: %lu\n", ReturnedLength);
- DPRINT ("Length: %hu\n", ObjectNameInfo->Name.Length);
- DPRINT ("MaximumLength: %hu\n", ObjectNameInfo->Name.MaximumLength);
- DPRINT ("Object: %wZ\n", &ObjectNameInfo->Name);
-
- DriverName = wcsrchr(ObjectNameInfo->Name.Buffer, L'\\');
- if (DriverName != NULL)
- DriverName++;
- else
- DriverName = ObjectNameInfo->Name.Buffer;
-
- DriverNameLength = wcslen (DriverName) * sizeof(WCHAR);
- DPRINT ("Driver name '%S'\n", DriverName);
- }
- else
- {
- DriverName = NULL;
- DriverNameLength = 0;
- }
-
- /* Allocate request buffer */
- Request = ExAllocatePool (NonPagedPool,
- sizeof(PORT_MESSAGE) + PORT_MAXIMUM_MESSAGE_LENGTH);
- if (Request == NULL)
- {
- DPRINT ("Failed to allocate request buffer!\n");
-
- /* Requeue log message and restart the worker */
- ExInterlockedInsertTailList (&IopLogListHead,
- &LogEntry->Entry,
- &IopLogListLock);
- IopRestartLogWorker ();
-
- return;
- }
-
- /* Initialize the log message */
- Message = (PIO_ERROR_LOG_MESSAGE)(Request + 1);
- Message->Type = IO_TYPE_ERROR_MESSAGE;
- Message->Size =
- sizeof(IO_ERROR_LOG_MESSAGE) - sizeof(IO_ERROR_LOG_PACKET) +
- LogEntry->PacketSize + DriverNameLength;
- Message->DriverNameLength = (USHORT)DriverNameLength;
- Message->TimeStamp.QuadPart = LogEntry->TimeStamp.QuadPart;
- Message->DriverNameOffset = (DriverName != NULL) ? LogEntry->PacketSize : 0;
-
- /* Copy error log packet */
- RtlCopyMemory (&Message->EntryData,
- Packet,
- LogEntry->PacketSize);
-
- /* Copy driver or device name */
- RtlCopyMemory ((PVOID)((ULONG_PTR)Message + Message->DriverNameOffset),
- DriverName,
- DriverNameLength);
-
- DPRINT ("SequenceNumber %lx\n", Packet->SequenceNumber);
-
- Request->u1.s1.DataLength = Message->Size;
- Request->u1.s1.TotalLength =
- Request->u1.s1.DataLength + sizeof(PPORT_MESSAGE);
-
- /* Send the error message to the log port */
- Status = ZwRequestPort (IopLogPort,
- Request);
-
- /* Release request buffer */
- ExFreePool (Request);
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT ("ZwRequestPort() failed (Status %lx)\n", Status);
-
- /* Requeue log message and restart the worker */
- ExInterlockedInsertTailList (&IopLogListHead,
- &LogEntry->Entry,
- &IopLogListLock);
- IopRestartLogWorker ();
-
- return;
- }
-
- /* Release error log entry */
- KeAcquireSpinLock (&IopAllocationLock,
- &Irql);
-
- IopTotalLogSize -= (LogEntry->PacketSize - sizeof(ERROR_LOG_ENTRY));
- ExFreePool (LogEntry);
-
- KeReleaseSpinLock (&IopAllocationLock,
- Irql);
- }
-
- IopLogWorkerRunning = FALSE;
-
- DPRINT ("IopLogWorker() done\n");
-}
-
-
-/*
- * @implemented
- */
-PVOID STDCALL
-IoAllocateErrorLogEntry (IN PVOID IoObject,
- IN UCHAR EntrySize)
-{
- PERROR_LOG_ENTRY LogEntry;
- ULONG LogEntrySize;
- KIRQL Irql;
-
- DPRINT("IoAllocateErrorLogEntry() called\n");
-
- if (IoObject == NULL)
- return NULL;
-
- KeAcquireSpinLock (&IopAllocationLock,
- &Irql);
-
- if (IopTotalLogSize > PAGE_SIZE)
- {
- KeReleaseSpinLock (&IopAllocationLock,
- Irql);
- return NULL;
- }
-
- LogEntrySize = sizeof(ERROR_LOG_ENTRY) + EntrySize;
- LogEntry = ExAllocatePool (NonPagedPool,
- LogEntrySize);
- if (LogEntry == NULL)
- {
- KeReleaseSpinLock (&IopAllocationLock,
- Irql);
- return NULL;
- }
-
- IopTotalLogSize += EntrySize;
-
- LogEntry->IoObject = IoObject;
- LogEntry->PacketSize = LogEntrySize;
-
- KeReleaseSpinLock (&IopAllocationLock,
- Irql);
-
- return (PVOID)((ULONG_PTR)LogEntry + sizeof(ERROR_LOG_ENTRY));
-}
-
-
-/*
- * @implemented
- */
-VOID STDCALL
-IoFreeErrorLogEntry(IN PVOID ElEntry)
-{
- PERROR_LOG_ENTRY LogEntry;
- KIRQL Irql;
-
- DPRINT("IoFreeErrorLogEntry() called\n");
-
- if (ElEntry == NULL)
- return;
-
- LogEntry = (PERROR_LOG_ENTRY)((ULONG_PTR)ElEntry - sizeof(ERROR_LOG_ENTRY));
-
- KeAcquireSpinLock(&IopAllocationLock,
- &Irql);
-
- IopTotalLogSize -= (LogEntry->PacketSize - sizeof(ERROR_LOG_ENTRY));
- ExFreePool(LogEntry);
-
- KeReleaseSpinLock(&IopAllocationLock,
- Irql);
-}
-
-
-/*
- * @implemented
- */
-VOID STDCALL
-IoWriteErrorLogEntry (IN PVOID ElEntry)
-{
- PWORK_QUEUE_ITEM LogWorkItem;
- PERROR_LOG_ENTRY LogEntry;
- KIRQL Irql;
-
- DPRINT("IoWriteErrorLogEntry() called\n");
-
- LogEntry = (PERROR_LOG_ENTRY)((ULONG_PTR)ElEntry - sizeof(ERROR_LOG_ENTRY));
-
- /* Get time stamp */
- KeQuerySystemTime (&LogEntry->TimeStamp);
-
- KeAcquireSpinLock (&IopLogListLock,
- &Irql);
-
- InsertHeadList (&IopLogListHead,
- &LogEntry->Entry);
-
- if (IopLogWorkerRunning == FALSE)
- {
- LogWorkItem = ExAllocatePool (NonPagedPool,
- sizeof(WORK_QUEUE_ITEM));
- if (LogWorkItem != NULL)
- {
- ExInitializeWorkItem (LogWorkItem,
- IopLogWorker,
- LogWorkItem);
-
- ExQueueWorkItem (LogWorkItem,
- DelayedWorkQueue);
-
- IopLogWorkerRunning = TRUE;
- }
- }
-
- KeReleaseSpinLock (&IopLogListLock,
- Irql);
-
- DPRINT("IoWriteErrorLogEntry() done\n");
-}
-
-VOID
-STDCALL
-IopFreeApc(PKAPC Apc,
- PKNORMAL_ROUTINE *NormalRoutine,
- PVOID *NormalContext,
- PVOID *SystemArgument1,
- PVOID *SystemArgument2)
+LONG IopTotalLogSize;
+LIST_ENTRY IopLogListHead;
+KSPIN_LOCK IopLogListLock;
+
+BOOLEAN IopLogWorkerRunning;
+BOOLEAN IopLogPortConnected;
+HANDLE IopLogPort;
+WORK_QUEUE_ITEM IopErrorLogWorkItem;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+VOID
+NTAPI
+IopInitErrorLog(VOID)
+{
+ /* Initialize the locks and list head */
+ KeInitializeSpinLock(&IopLogListLock);
+ InitializeListHead(&IopLogListHead);
+}
+
+VOID
+NTAPI
+IopLogDpcRoutine(IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2)
+{
+ /* If we have a DPC, free it */
+ if (Dpc) ExFreePool(Dpc);
+
+ /* Initialize and queue the work item */
+ ExInitializeWorkItem(&IopErrorLogWorkItem, IopLogWorker, NULL);
+ ExQueueWorkItem(&IopErrorLogWorkItem, DelayedWorkQueue);
+}
+
+PLIST_ENTRY
+NTAPI
+IopGetErrorLogEntry(VOID)
+{
+ KIRQL OldIrql;
+ PLIST_ENTRY ListEntry;
+
+ /* Acquire the lock and check if the list is empty */
+ KeAcquireSpinLock(&IopLogListLock, &OldIrql);
+ if (IsListEmpty(&IopLogListHead))
+ {
+ /* List is empty, disable the worker and return NULL */
+ IopLogWorkerRunning = FALSE;
+ ListEntry = NULL;
+ }
+ else
+ {
+ /* Otherwise, remove an entry */
+ ListEntry = RemoveHeadList(&IopLogListHead);
+ }
+
+ /* Release the lock and return the entry */
+ KeReleaseSpinLock(&IopLogListLock, OldIrql);
+ return ListEntry;
+}
+
+VOID
+NTAPI
+IopRestartLogWorker(VOID)
+{
+ PIOP_ERROR_LOG_WORKER_DPC WorkerDpc;
+ LARGE_INTEGER Timeout;
+
+ /* Allocate a DPC Context */
+ WorkerDpc = ExAllocatePool(NonPagedPool, sizeof(IOP_ERROR_LOG_WORKER_DPC));
+ if (!WorkerDpc)
+ {
+ /* Fail */
+ IopLogWorkerRunning = FALSE;
+ return;
+ }
+
+ /* Initialize DPC and Timer */
+ KeInitializeDpc(&WorkerDpc->Dpc, IopLogDpcRoutine, WorkerDpc);
+ KeInitializeTimer(&WorkerDpc->Timer);
+
+ /* Restart after 30 seconds */
+ Timeout.QuadPart = (LONGLONG)-300000000;
+ KeSetTimer(&WorkerDpc->Timer, Timeout, &WorkerDpc->Dpc);
+}
+
+BOOLEAN
+NTAPI
+IopConnectLogPort(VOID)
+{
+ UNICODE_STRING PortName = RTL_CONSTANT_STRING(L"\\ErrorLogPort");
+ NTSTATUS Status;
+
+ /* Make sure we're not already connected */
+ if (IopLogPortConnected) return TRUE;
+
+ /* Connect the port */
+ Status = ZwConnectPort(&IopLogPort,
+ &PortName,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ /* Remmeber we're connected */
+ IopLogPortConnected = TRUE;
+ return TRUE;
+ }
+
+ /* We failed, try again */
+ IopRestartLogWorker();
+ return FALSE;
+}
+
+VOID
+NTAPI
+IopLogWorker(IN PVOID Parameter)
+{
+ PELF_API_MSG Message;
+ PIO_ERROR_LOG_MESSAGE ErrorMessage;
+ PLIST_ENTRY ListEntry;
+ PERROR_LOG_ENTRY LogEntry;
+ PIO_ERROR_LOG_PACKET Packet;
+ PCHAR StringBuffer;
+ ULONG RemainingLength;
+ PDRIVER_OBJECT DriverObject;
+ ULONG DriverNameLength = 0, DeviceNameLength;
+ UNICODE_STRING DriverNameString;
+ NTSTATUS Status;
+ UCHAR Buffer[256];
+ POBJECT_NAME_INFORMATION ObjectNameInfo = (POBJECT_NAME_INFORMATION)&Buffer;
+ POBJECT_NAME_INFORMATION PoolObjectNameInfo = NULL;
+ ULONG ReturnedLength, MessageLength;
+ PWCHAR p;
+ ULONG ExtraStringLength;
+ PAGED_CODE();
+
+ /* Connect to the port */
+ if (!IopConnectLogPort()) return;
+
+ /* Allocate the message */
+ Message = ExAllocatePool(PagedPool, IO_ERROR_LOG_MESSAGE_LENGTH);
+ if (!Message)
+ {
+ /* Couldn't allocate, try again */
+ IopRestartLogWorker();
+ return;
+ }
+
+ /* Copy the message */
+ RtlZeroMemory(Message, sizeof(ELF_API_MSG));
+
+ /* Get the actual I/O Structure */
+ ErrorMessage = &Message->IoErrorMessage;
+
+ /* Start loop */
+ while (TRUE)
+ {
+ /* Get an entry */
+ ListEntry = IopGetErrorLogEntry();
+ if (!ListEntry) break;
+ LogEntry = CONTAINING_RECORD(ListEntry, ERROR_LOG_ENTRY, ListEntry);
+
+ /* Get pointer to the log packet */
+ Packet = (PIO_ERROR_LOG_PACKET)((ULONG_PTR)LogEntry +
+ sizeof(ERROR_LOG_ENTRY));
+
+ /* Calculate the total length of the message only */
+ MessageLength = sizeof(IO_ERROR_LOG_MESSAGE) -
+ sizeof(ERROR_LOG_ENTRY) -
+ sizeof(IO_ERROR_LOG_PACKET) +
+ LogEntry->Size;
+
+ /* Copy the packet */
+ RtlMoveMemory(&ErrorMessage->EntryData,
+ Packet,
+ LogEntry->Size - sizeof(ERROR_LOG_ENTRY));
+
+ /* Set the timestamp and time */
+ ErrorMessage->TimeStamp = LogEntry->TimeStamp;
+ ErrorMessage->Type = IO_TYPE_ERROR_MESSAGE;
+
+ /* Check if this message has any strings */
+ if (Packet->NumberOfStrings)
+ {
+ /* String buffer is after the current strings */
+ StringBuffer = (PCHAR)&ErrorMessage->EntryData +
+ Packet->StringOffset;
+ }
+ else
+ {
+ /* Otherwise, string buffer is at the end */
+ StringBuffer = (PCHAR)ErrorMessage + MessageLength;
+ }
+
+ /* Align the buffer */
+ StringBuffer = (PVOID)ALIGN_UP(StringBuffer, WCHAR);
+
+ /* Set the offset for the driver's name to the current buffer */
+ ErrorMessage->DriverNameOffset = (ULONG)(StringBuffer -
+ (ULONG_PTR)ErrorMessage);
+
+ /* Check how much space we have left for the device string */
+ RemainingLength = (ULONG)((ULONG_PTR)Message +
+ IO_ERROR_LOG_MESSAGE_LENGTH -
+ (ULONG_PTR)StringBuffer);
+
+ /* Now check if there is a driver object */
+ DriverObject = LogEntry->DriverObject;
+ if (DriverObject)
+ {
+ /* Check if the driver has a name */
+ if (DriverObject->DriverName.Buffer)
+ {
+ /* Use its name */
+ DriverNameString.Buffer = DriverObject->DriverName.Buffer;
+ DriverNameLength = DriverObject->DriverName.Length;
+ }
+
+ /* Check if there isn't a valid name*/
+ if (!DriverNameLength)
+ {
+ /* Query the name directly */
+ Status = ObQueryNameString(DriverObject,
+ ObjectNameInfo,
+ sizeof(Buffer),
+ &ReturnedLength);
+ if (!(NT_SUCCESS(Status)) || !(ObjectNameInfo->Name.Length))
+ {
+ /* We don't have a name */
+ DriverNameLength = 0;
+ }
+ }
+ }
+ else
+ {
+ /* Use default name */
+ DriverNameString.Buffer = L"Application Popup";
+ DriverNameLength = wcslen(DriverNameString.Buffer) * sizeof(WCHAR);
+ }
+
+ /* Check if we have a driver name by here */
+ if (DriverNameLength)
+ {
+ /* Skip to the end of the driver's name */
+ p = &DriverNameString.Buffer[DriverNameLength / sizeof(WCHAR)];
+
+ /* Now we'll walk backwards and assume the minimum size */
+ DriverNameLength = sizeof(WCHAR);
+ p--;
+ while ((*p != L'\\') && (p != DriverNameString.Buffer))
+ {
+ /* No backslash found, keep going */
+ p--;
+ DriverNameLength += sizeof(WCHAR);
+ }
+
+ /* Now we probably hit the backslash itself, skip past it */
+ if (*p == L'\\')
+ {
+ p++;
+ DriverNameLength -= sizeof(WCHAR);
+ }
+
+ /*
+ * Now make sure that the driver name fits in our buffer, minus 3
+ * NULL chars, and copy the name in our string buffer
+ */
+ DriverNameLength = min(DriverNameLength,
+ RemainingLength - 3 * sizeof(UNICODE_NULL));
+ RtlMoveMemory(StringBuffer, p, DriverNameLength);
+ }
+
+ /* Null-terminate the driver name */
+ *((PWSTR)(StringBuffer + DriverNameLength)) = L'\0';
+ DriverNameLength += sizeof(WCHAR);
+
+ /* Go to the next string buffer position */
+ StringBuffer += DriverNameLength;
+ RemainingLength -= DriverNameLength;
+
+ /* Update the string offset and check if we have a device object */
+ ErrorMessage->EntryData.StringOffset = (USHORT)
+ ((ULONG_PTR)StringBuffer -
+ (ULONG_PTR)ErrorMessage);
+ if (LogEntry->DeviceObject)
+ {
+ /* We do, query its name */
+ Status = ObQueryNameString(LogEntry->DeviceObject,
+ ObjectNameInfo,
+ sizeof(OBJECT_NAME_INFORMATION) +
+ 100 -
+ DriverNameLength,
+ &ReturnedLength);
+ if ((!NT_SUCCESS(Status)) || !(ObjectNameInfo->Name.Length))
+ {
+ /* Setup an empty name */
+ ObjectNameInfo->Name.Length = 0;
+ ObjectNameInfo->Name.Buffer = L"";
+
+ /* Check if we failed because our buffer wasn't large enough */
+ if (Status == STATUS_INFO_LENGTH_MISMATCH)
+ {
+ /* Then we'll allocate one... we really want this name! */
+ PoolObjectNameInfo = ExAllocatePoolWithTag(PagedPool,
+ ReturnedLength,
+ TAG_IO);
+ if (PoolObjectNameInfo)
+ {
+ /* Query it again */
+ ObjectNameInfo = PoolObjectNameInfo;
+ Status = ObQueryNameString(LogEntry->DeviceObject,
+ ObjectNameInfo,
+ ReturnedLength,
+ &ReturnedLength);
+ if (NT_SUCCESS(Status))
+ {
+ /* Success, update the information */
+ ObjectNameInfo->Name.Length = 100 -
+ DriverNameLength;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* No device object, setup an empty name */
+ ObjectNameInfo->Name.Length = 0;
+ ObjectNameInfo->Name.Buffer = L"";
+ }
+
+ /*
+ * Now make sure that the device name fits in our buffer, minus 2
+ * NULL chars, and copy the name in our string buffer
+ */
+ DeviceNameLength = min(ObjectNameInfo->Name.Length,
+ RemainingLength - 2 * sizeof(UNICODE_NULL));
+ RtlMoveMemory(StringBuffer,
+ ObjectNameInfo->Name.Buffer,
+ DeviceNameLength);
+
+ /* Null-terminate the device name */
+ *((PWSTR)(StringBuffer + DeviceNameLength)) = L'\0';
+ DeviceNameLength += sizeof(WCHAR);
+
+ /* Free the buffer if we had one */
+ if (PoolObjectNameInfo) ExFreePool(PoolObjectNameInfo);
+
+ /* Go to the next string buffer position */
+ ErrorMessage->EntryData.NumberOfStrings++;
+ StringBuffer += DeviceNameLength;
+ RemainingLength -= DeviceNameLength;
+
+ /* Check if we have any extra strings */
+ if (Packet->NumberOfStrings)
+ {
+ /* Find out the size of the extra strings */
+ ExtraStringLength = LogEntry->Size -
+ sizeof(ERROR_LOG_ENTRY) -
+ Packet->StringOffset;
+
+ /* Make sure that the extra strings fit in our buffer */
+ if (ExtraStringLength > (RemainingLength - sizeof(UNICODE_NULL)))
+ {
+ /* They wouldn't, so set normalize the length */
+ MessageLength -= ExtraStringLength - RemainingLength;
+ ExtraStringLength = RemainingLength - sizeof(UNICODE_NULL);
+ }
+
+ /* Now copy the extra strings */
+ RtlMoveMemory(StringBuffer,
+ (PCHAR)Packet + Packet->StringOffset,
+ ExtraStringLength);
+
+ /* Null-terminate them */
+ *((PWSTR)(StringBuffer + ExtraStringLength)) = L'\0';
+ }
+
+ /* Set the driver name length */
+ ErrorMessage->DriverNameLength = (USHORT)DriverNameLength;
+
+ /* Update the message length to include the device and driver names */
+ MessageLength += DeviceNameLength + DriverNameLength;
+ ErrorMessage->Size = (USHORT)MessageLength;
+
+ /* Now update it again, internally, for the size of the actual LPC */
+ MessageLength += (FIELD_OFFSET(ELF_API_MSG, IoErrorMessage) -
+ FIELD_OFFSET(ELF_API_MSG, Unknown[0]));
+
+ /* Set the total and data lengths */
+ Message->h.u1.s1.TotalLength = (USHORT)(sizeof(PORT_MESSAGE) +
+ MessageLength);
+ Message->h.u1.s1.DataLength = (USHORT)(MessageLength);
+
+ /* Send the message */
+ Status = NtRequestPort(IopLogPort, (PPORT_MESSAGE)Message);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Requeue log message and restart the worker */
+ ExInterlockedInsertTailList(&IopLogListHead,
+ &LogEntry->ListEntry,
+ &IopLogListLock);
+ IopLogWorkerRunning = FALSE;
+ IopRestartLogWorker();
+ break;
+ }
+
+ /* Derefernece the device object */
+ if (LogEntry->DeviceObject) ObDereferenceObject(LogEntry->DeviceObject);
+ if (DriverObject) ObDereferenceObject(LogEntry->DriverObject);
+
+ /* Update size */
+ InterlockedExchangeAdd(&IopTotalLogSize,
+ -(LogEntry->Size - sizeof(ERROR_LOG_ENTRY)));
+ }
+
+ /* Free the LPC Message */
+ ExFreePool(Message);
+}
+
+VOID
+NTAPI
+IopFreeApc(IN PKAPC Apc,
+ IN PKNORMAL_ROUTINE *NormalRoutine,
+ IN PVOID *NormalContext,
+ IN PVOID *SystemArgument1,
+ IN PVOID *SystemArgument2)
{
/* Free the APC */
ExFreePool(Apc);
}
VOID
-STDCALL
-IopRaiseHardError(PKAPC Apc,
- PKNORMAL_ROUTINE *NormalRoutine,
- PVOID *NormalContext,
- PVOID *SystemArgument1,
- PVOID *SystemArgument2)
+NTAPI
+IopRaiseHardError(IN PKAPC Apc,
+ IN PKNORMAL_ROUTINE *NormalRoutine,
+ IN PVOID *NormalContext,
+ IN PVOID *SystemArgument1,
+ IN PVOID *SystemArgument2)
{
PIRP Irp = (PIRP)NormalContext;
//PVPB Vpb = (PVPB)SystemArgument1;
@@ -477,14 +476,141 @@
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
}
+/* PUBLIC FUNCTIONS **********************************************************/
+
/*
* @implemented
*/
-VOID
-STDCALL
-IoRaiseHardError(PIRP Irp,
- PVPB Vpb,
- PDEVICE_OBJECT RealDeviceObject)
+PVOID
+NTAPI
+IoAllocateErrorLogEntry(IN PVOID IoObject,
+ IN UCHAR EntrySize)
+{
+ PERROR_LOG_ENTRY LogEntry;
+ ULONG LogEntrySize;
+ PDRIVER_OBJECT DriverObject;
+ PDEVICE_OBJECT DeviceObject;
+
+ /* Make sure we have an object */
+ if (!IoObject) return NULL;
+
+ /* Check if we're past our buffer */
+ if (IopTotalLogSize > PAGE_SIZE) return NULL;
+
+ /* Calculate the total size and allocate it */
+ LogEntrySize = sizeof(ERROR_LOG_ENTRY) + EntrySize;
+ LogEntry = ExAllocatePoolWithTag(NonPagedPool,
+ LogEntrySize,
+ TAG_ERROR_LOG);
+ if (!LogEntry) return NULL;
+
+ /* Check if this is a device object or driver object */
+ if (((PDEVICE_OBJECT)IoObject)->Type == IO_TYPE_DEVICE)
+ {
+ /* It's a device, get the driver */
+ DeviceObject = (PDEVICE_OBJECT)IoObject;
+ DriverObject = DeviceObject->DriverObject;
+ }
+ else if (((PDEVICE_OBJECT)IoObject)->Type == IO_TYPE_DRIVER)
+ {
+ /* It's a driver, so we don' thave a device */
+ DeviceObject = NULL;
+ DriverObject = IoObject;
+ }
+ else
+ {
+ /* Fail */
+ return NULL;
+ }
+
+ /* Reference the Objects */
+ if (DeviceObject) ObReferenceObject(DeviceObject);
+ if (DriverObject) ObReferenceObject(DriverObject);
+
+ /* Update log size */
+ InterlockedExchangeAdd(&IopTotalLogSize, EntrySize);
+
+ /* Clear the entry and set it up */
+ RtlZeroMemory(LogEntry, EntrySize);
+ LogEntry->Type = IO_TYPE_ERROR_LOG;
+ LogEntry->Size = EntrySize;
+ LogEntry->DeviceObject = DeviceObject;
+ LogEntry->DriverObject = DriverObject;
+
+ /* Return the entry data */
+ return (PVOID)((ULONG_PTR)LogEntry + sizeof(ERROR_LOG_ENTRY));
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+IoFreeErrorLogEntry(IN PVOID ElEntry)
+{
+ PERROR_LOG_ENTRY LogEntry;
+
+ /* Make sure there's an entry */
+ if (!ElEntry) return;
+
+ /* Get the actual header */
+ LogEntry = (PERROR_LOG_ENTRY)((ULONG_PTR)ElEntry - sizeof(ERROR_LOG_ENTRY));
+
+ /* Dereference both objects */
+ if (LogEntry->DeviceObject) ObDereferenceObject(LogEntry->DeviceObject);
+ if (LogEntry->DriverObject) ObDereferenceObject(LogEntry->DriverObject);
+
+ /* Decrease total allocation size and free the entry */
+ InterlockedExchangeAdd(&IopTotalLogSize,
+ -(LogEntry->Size - sizeof(ERROR_LOG_ENTRY)));
+ ExFreePool(LogEntry);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+IoWriteErrorLogEntry(IN PVOID ElEntry)
+{
+ PERROR_LOG_ENTRY LogEntry;
+ KIRQL Irql;
+
+ /* Get the main header */
+ KEBUGCHECK(0);
+ LogEntry = (PERROR_LOG_ENTRY)((ULONG_PTR)ElEntry -
+ sizeof(ERROR_LOG_ENTRY));
+
+ /* Get time stamp */
+ KeQuerySystemTime(&LogEntry->TimeStamp);
+
+ /* Acquire the lock and insert this write in the list */
+ KeAcquireSpinLock(&IopLogListLock, &Irql);
+ InsertHeadList(&IopLogListHead, &LogEntry->ListEntry);
+
+ /* Check if the worker is runnign */
+ if (!IopLogWorkerRunning)
+ {
+ /* It's not, initialize it and queue it */
+ ExInitializeWorkItem(&IopErrorLogWorkItem,
+ IopLogWorker,
+ &IopErrorLogWorkItem);
+ ExQueueWorkItem(&IopErrorLogWorkItem, DelayedWorkQueue);
+ IopLogWorkerRunning = TRUE;
+ }
+
+ /* Release the lock and return */
+ KeReleaseSpinLock(&IopLogListLock, Irql);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+IoRaiseHardError(IN PIRP Irp,
+ IN PVPB Vpb,
+ IN PDEVICE_OBJECT RealDeviceObject)
{
PETHREAD Thread = (PETHREAD)&Irp->Tail.Overlay.Thread;
PKAPC ErrorApc;
@@ -501,7 +627,7 @@
/* Setup an APC */
ErrorApc = ExAllocatePoolWithTag(NonPagedPool,
sizeof(KAPC),
- TAG('K', 'A', 'P',
'C'));
+ TAG_APC);
KeInitializeApc(ErrorApc,
&Thread->Tcb,
Irp->ApcEnvironment,
@@ -519,39 +645,31 @@
* @unimplemented
*/
BOOLEAN
-STDCALL
-IoRaiseInformationalHardError(NTSTATUS ErrorStatus,
- PUNICODE_STRING String,
- PKTHREAD Thread)
+NTAPI
+IoRaiseInformationalHardError(IN NTSTATUS ErrorStatus,
+ IN PUNICODE_STRING String,
+ IN PKTHREAD Thread)
{
UNIMPLEMENTED;
return(FALSE);
}
-/**********************************************************************
- * NAME EXPORTED
- * IoSetThreadHardErrorMode@4
- *
- * ARGUMENTS
- * HardErrorEnabled
- * TRUE : enable hard errors processing;
- * FALSE: do NOT process hard errors.
- *
- * RETURN VALUE
- * Previous value for the current thread's hard errors
- * processing policy.
- *
+/*
* @implemented
*/
BOOLEAN
-STDCALL
+NTAPI
IoSetThreadHardErrorMode(IN BOOLEAN HardErrorEnabled)
{
- BOOLEAN PreviousHEM = (BOOLEAN)(NtCurrentTeb()->HardErrorDisabled);
-
- NtCurrentTeb()->HardErrorDisabled = ((TRUE == HardErrorEnabled) ? FALSE : TRUE);
-
- return((TRUE == PreviousHEM) ? FALSE : TRUE);
+ PETHREAD Thread = PsGetCurrentThread();
+ BOOLEAN Old;
+
+ /* Get the current value */
+ Old = !Thread->HardErrorsAreDisabled;
+
+ /* Set the new one and return the old */
+ Thread->HardErrorsAreDisabled = !HardErrorEnabled;
+ return Old;
}
/* EOF */