Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1201 lines
34 KiB

/*++
Copyright (c) 1991 - 2001 Microsoft Corporation
Module Name:
## # ## ### ###### #### ## ## ##### ##### #### #### ##### #####
## ### ## ### ## ## # ## ## ## ## ## ## ## # ## # ## ## ## ##
## ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
## # # ## ## ## ## ## ####### ## ## ## ## ## ### ## ## ## ## ##
### ### ####### ## ## ## ## ## ## ## ## ## ## ## ##### #####
### ### ## ## ## ## # ## ## ## ## ## ## ## ## ## ## # ## ##
## ## ## ## ## #### ## ## ##### ##### ##### ## #### ## ##
Abstract:
This module contains functions specfic to the
watchdog device. The logic in this module is not
hardware specific, but is logic that is common
to all hardware implementations.
Author:
Wesley Witt (wesw) 1-Oct-2001
Environment:
Kernel mode only.
Notes:
--*/
#include "internal.h"
NTSTATUS
SaWatchdogDeviceInitialization(
IN PSAPORT_DRIVER_EXTENSION DriverExtension
)
/*++
Routine Description:
This is the NVRAM specific code for driver initialization.
This function is called by SaPortInitialize, which is called by
the NVRAM driver's DriverEntry function.
Arguments:
DriverExtension - Driver extension structure
Return Value:
NT status code.
--*/
{
UNREFERENCED_PARAMETER(DriverExtension);
return STATUS_SUCCESS;
}
NTSTATUS
SaWatchdogIoValidation(
IN PWATCHDOG_DEVICE_EXTENSION DeviceExtension,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This is the NVRAM specific code for processing
all I/O validation for reads and writes.
Arguments:
DeviceExtension - NVRAM device extension
Irp - Pointer to an IRP structure that describes the requested I/O operation.
IrpSp - Irp stack pointer
Return Value:
NT status code.
--*/
{
UNREFERENCED_PARAMETER(DeviceExtension);
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(IrpSp);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
SaWatchdogShutdownNotification(
IN PWATCHDOG_DEVICE_EXTENSION DeviceExtension,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This is the NVRAM specific code for processing
the system shutdown notification.
Arguments:
DeviceExtension - NVRAM device extension
Irp - Pointer to an IRP structure that describes the requested I/O operation.
IrpSp - Irp stack pointer
Return Value:
NT status code.
--*/
{
UNREFERENCED_PARAMETER(DeviceExtension);
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(IrpSp);
return STATUS_SUCCESS;
}
VOID
WatchdogProcessPingThread(
IN PVOID StartContext
)
/*++
Routine Description:
This function runs as a system thread and serves to
ping the watchdog hardware while the system boots.
Arguments:
StartContext - Context pointer; device extension
Return Value:
None.
--*/
{
PWATCHDOG_DEVICE_EXTENSION DeviceExtension = (PWATCHDOG_DEVICE_EXTENSION) StartContext;
NTSTATUS Status;
LARGE_INTEGER DueTime;
UNICODE_STRING UnicodeString;
PFILE_OBJECT DisplayFileObject = NULL;
PDEVICE_OBJECT DisplayDeviceObject = NULL;
BOOLEAN BusyMessageDisplayed = FALSE;
ULONG TimerValue = WATCHDOG_TIMER_VALUE;
//
// Set the timer resolution
//
Status = CallMiniPortDriverDeviceControl(
DeviceExtension,
DeviceExtension->DeviceObject,
IOCTL_SAWD_SET_TIMER,
&TimerValue,
sizeof(ULONG),
NULL,
0
);
if (!NT_SUCCESS(Status)) {
REPORT_ERROR( DeviceExtension->DeviceType, "Failed to ping the watchdog\n", Status );
}
//
// Ping loop
//
while (1) {
//
// Get a pointer to the display device
//
if (DisplayDeviceObject == NULL) {
RtlInitUnicodeString( &UnicodeString, SA_DEVICE_DISPLAY_NAME_STRING );
Status = IoGetDeviceObjectPointer(
&UnicodeString,
FILE_ALL_ACCESS,
&DisplayFileObject,
&DisplayDeviceObject
);
if (!NT_SUCCESS(Status)) {
REPORT_ERROR( DeviceExtension->DeviceType, "IoGetDeviceObjectPointer failed", Status );
}
}
//
// Display the busy message if necessary
//
if (DisplayDeviceObject && BusyMessageDisplayed == FALSE) {
Status = CallMiniPortDriverDeviceControl(
DeviceExtension,
DisplayDeviceObject,
IOCTL_SADISPLAY_BUSY_MESSAGE,
NULL,
0,
NULL,
0
);
if (!NT_SUCCESS(Status)) {
REPORT_ERROR( DeviceExtension->DeviceType, "Failed to display the busy message", Status );
} else {
BusyMessageDisplayed = TRUE;
ObDereferenceObject( DisplayFileObject );
}
}
//
// Call the watchdog driver so that the hardware is pinged
// and prevent the system from rebooting
//
Status = CallMiniPortDriverDeviceControl(
DeviceExtension,
DeviceExtension->DeviceObject,
IOCTL_SAWD_PING,
NULL,
0,
NULL,
0
);
if (!NT_SUCCESS(Status)) {
REPORT_ERROR( DeviceExtension->DeviceType, "Failed to ping the watchdog\n", Status );
}
//
// Wait...
//
DueTime.QuadPart = -SecToNano(WATCHDOG_PING_SECONDS);
Status = KeWaitForSingleObject( &DeviceExtension->PingEvent, Executive, KernelMode, FALSE, &DueTime );
if (Status != STATUS_TIMEOUT) {
//
// The ping event was triggered
//
//
// Call the watchdog driver so that the hardware is pinged
// and prevent the system from rebooting
//
Status = CallMiniPortDriverDeviceControl(
DeviceExtension,
DeviceExtension->DeviceObject,
IOCTL_SAWD_PING,
NULL,
0,
NULL,
0
);
if (!NT_SUCCESS(Status)) {
REPORT_ERROR( DeviceExtension->DeviceType, "Failed to ping the watchdog\n", Status );
}
return;
} else {
//
// We timed out
//
ExAcquireFastMutex( &DeviceExtension->DeviceLock );
if (DeviceExtension->ActiveProcessCount == 0) {
KeQuerySystemTime( &DueTime );
DueTime.QuadPart = NanoToSec( DueTime.QuadPart - DeviceExtension->LastProcessTime.QuadPart );
if (DueTime.QuadPart > WATCHDOG_INIT_SECONDS) {
ExReleaseFastMutex( &DeviceExtension->DeviceLock );
return;
}
}
ExReleaseFastMutex( &DeviceExtension->DeviceLock );
}
}
}
VOID
WatchdogProcessWatchThread(
IN PVOID StartContext
)
/*++
Routine Description:
This function runs as a system thread and the sole
purpose is to wait for a list of processes to terminate.
Arguments:
StartContext - Context pointer; device extension
Return Value:
None.
--*/
{
PWATCHDOG_PROCESS_WATCH ProcessWatch = (PWATCHDOG_PROCESS_WATCH) StartContext;
PWATCHDOG_DEVICE_EXTENSION DeviceExtension = ProcessWatch->DeviceExtension;
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
CLIENT_ID ClientId;
HANDLE ProcessHandle = NULL;
LARGE_INTEGER CurrentTime;
__try {
InitializeObjectAttributes( &Obja, NULL, 0, NULL, NULL );
ClientId.UniqueThread = NULL;
ClientId.UniqueProcess = ProcessWatch->ProcessId;
Status = ZwOpenProcess(
&ProcessHandle,
PROCESS_ALL_ACCESS,
&Obja,
&ClientId
);
if (!NT_SUCCESS(Status)) {
ERROR_RETURN( DeviceExtension->DeviceType, "ZwOpenProcess failed", Status );
}
//
// Wait for the process to complete
//
Status = ZwWaitForSingleObject(
ProcessHandle,
FALSE,
NULL
);
if (!NT_SUCCESS(Status)) {
REPORT_ERROR( DeviceExtension->DeviceType, "KeWaitForSingleObject failed", Status );
}
//
// The process terminated
//
ExAcquireFastMutex( &DeviceExtension->DeviceLock );
DeviceExtension->ActiveProcessCount -= 1;
if (DeviceExtension->ActiveProcessCount == 0) {
KeQuerySystemTime( &CurrentTime );
CurrentTime.QuadPart = CurrentTime.QuadPart - DeviceExtension->LastProcessTime.QuadPart;
if (NanoToSec(CurrentTime.QuadPart) > WATCHDOG_INIT_SECONDS) {
KeSetEvent( &DeviceExtension->PingEvent, 0, FALSE );
}
}
ExReleaseFastMutex( &DeviceExtension->DeviceLock );
} __finally {
if (ProcessHandle != NULL) {
ZwClose( ProcessHandle );
}
ExFreePool( ProcessWatch );
}
}
VOID
WatchdogInitializeThread(
IN PVOID StartContext
)
/*++
Routine Description:
This function runs as a system thread and serves to
look for a list of processes running on the system.
Arguments:
StartContext - Context pointer; device extension
Return Value:
None.
--*/
{
PWATCHDOG_DEVICE_EXTENSION DeviceExtension = (PWATCHDOG_DEVICE_EXTENSION) StartContext;
NTSTATUS Status;
ULONG BufferSize;
PUCHAR Buffer = NULL;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
ULONG TotalOffset;
ULONG TaskBufferSize = 0;
PKEY_VALUE_FULL_INFORMATION KeyInformation = NULL;
PUCHAR p;
ULONG TaskCount = 0;
OBJECT_ATTRIBUTES Obja;
HANDLE ThreadHandle;
LARGE_INTEGER DueTime;
UNICODE_STRING ProcessName;
PWATCHDOG_PROCESS_WATCH ProcessWatch;
PHANDLE Tasks = NULL;
__try {
//
// Read the task names from the registry
//
Status = ReadRegistryValue(
DeviceExtension->DriverExtension,
&DeviceExtension->DriverExtension->RegistryPath,
L"ExceptionTasks",
&KeyInformation
);
if (!NT_SUCCESS(Status)) {
ERROR_RETURN( DeviceExtension->DeviceType, "ReadRegistryValue failed", Status );
}
if (KeyInformation->Type != REG_MULTI_SZ) {
Status = STATUS_OBJECT_TYPE_MISMATCH;
ERROR_RETURN( DeviceExtension->DeviceType, "ExceptionTasks value is corrupt", Status );
}
//
// Count the number of tasks
//
p = (PUCHAR)((PUCHAR)KeyInformation + KeyInformation->DataOffset);
while (*p) {
p += (STRING_SZ(p) + sizeof(WCHAR));
TaskCount += 1;
}
if (TaskCount == 0) {
Status = STATUS_NO_MORE_ENTRIES;
ERROR_RETURN( DeviceExtension->DeviceType, "No tasks specified in the ExceptionTasks registry value", Status );
}
//
// Allocate an array to hold the process handles
//
Tasks = (PHANDLE) ExAllocatePool( NonPagedPool, (TaskCount + 1) * sizeof(HANDLE) );
if (Tasks == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
ERROR_RETURN( DeviceExtension->DeviceType, "Failed to allocate pool for task array buffer", Status );
}
while (1) {
//
// Query the system for the number of tasks that are running
//
Status = ZwQuerySystemInformation(
SystemProcessInformation,
NULL,
0,
&BufferSize
);
if (Status != STATUS_INFO_LENGTH_MISMATCH) {
ERROR_RETURN( DeviceExtension->DeviceType, "ZwQuerySystemInformation failed", Status );
}
//
// Allocate the pool to hold that process information
//
Buffer = (PUCHAR) ExAllocatePool( NonPagedPool, BufferSize + 2048 );
if (Buffer == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
ERROR_RETURN( DeviceExtension->DeviceType, "Failed to allocate pool for system information buffer", Status );
}
//
// Get the task list from the system
//
Status = ZwQuerySystemInformation(
SystemProcessInformation,
Buffer,
BufferSize,
NULL
);
if (!NT_SUCCESS(Status)) {
ERROR_RETURN( DeviceExtension->DeviceType, "ZwQuerySystemInformation failed", Status );
}
//
// Loop over each running process and check it
// against the exception process list. If the process
// is specified as an exception process then open a handle
// to the process.
//
TaskCount = 0;
p = (PUCHAR)((PUCHAR)KeyInformation + KeyInformation->DataOffset);
//
// Walk the list of processes in the registry value
//
while (*p) {
//
// Loop initialization
//
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) Buffer;
TotalOffset = 0;
RtlInitUnicodeString( &ProcessName, (PWSTR)p );
//
// Walk the processes in the system process list
// and try to match each with the selected process
// from the registry.
//
while (1) {
//
// Only valid process names
//
if (ProcessInfo->ImageName.Buffer) {
//
// Compare the process names
//
if (RtlCompareUnicodeString( &ProcessInfo->ImageName, &ProcessName, TRUE ) == 0) {
//
// Check to see if we've already seen the process in
// a previous loop thru thr process list
//
if (Tasks[TaskCount] != ProcessInfo->UniqueProcessId) {
//
// The process matches and is new so set things up so
// that we start watching the process to end
//
Tasks[TaskCount] = ProcessInfo->UniqueProcessId;
ProcessWatch = (PWATCHDOG_PROCESS_WATCH) ExAllocatePool( NonPagedPool, sizeof(WATCHDOG_PROCESS_WATCH) );
if (ProcessWatch == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
ERROR_RETURN( DeviceExtension->DeviceType, "Failed to allocate pool for process watch structure", Status );
}
//
// Start the ping thread iff this is the first being watched
//
ExAcquireFastMutex( &DeviceExtension->DeviceLock );
if (DeviceExtension->ActiveProcessCount == 0) {
InitializeObjectAttributes( &Obja, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
Status = PsCreateSystemThread( &ThreadHandle, 0, &Obja, 0, NULL, WatchdogProcessPingThread, DeviceExtension );
if (!NT_SUCCESS(Status)) {
ExReleaseFastMutex( &DeviceExtension->DeviceLock );
ERROR_RETURN( DeviceExtension->DeviceType, "PsCreateSystemThread failed", Status );
}
ZwClose( ThreadHandle );
}
KeQuerySystemTime( &DeviceExtension->LastProcessTime );
DeviceExtension->ActiveProcessCount += 1;
ExReleaseFastMutex( &DeviceExtension->DeviceLock );
//
// Start a thread to watch this process
//
ProcessWatch->DeviceExtension = DeviceExtension;
ProcessWatch->ProcessId = ProcessInfo->UniqueProcessId;
InitializeObjectAttributes( &Obja, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
Status = PsCreateSystemThread( &ThreadHandle, 0, &Obja, 0, NULL, WatchdogProcessWatchThread, ProcessWatch );
if (!NT_SUCCESS(Status)) {
ERROR_RETURN( DeviceExtension->DeviceType, "PsCreateSystemThread failed", Status );
}
ZwClose( ThreadHandle );
}
}
}
//
// Loop to the next process in the system process list
//
if (ProcessInfo->NextEntryOffset == 0) {
break;
}
TotalOffset += ProcessInfo->NextEntryOffset;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &Buffer[TotalOffset];
}
//
// Loop to the next process in the registry list
//
p += (STRING_SZ(p) + sizeof(WCHAR));
TaskCount += 1;
}
//
// Clean up all resources allocated in this loop
//
ExFreePool( Buffer );
Buffer = NULL;
//
// Delay execution before looping again
//
DueTime.QuadPart = -SecToNano(WATCHDOG_INIT_SECONDS);
Status = KeWaitForSingleObject( &DeviceExtension->StopEvent, Executive, KernelMode, FALSE, &DueTime );
if (Status != STATUS_TIMEOUT) {
__leave;
}
}
} __finally {
if (KeyInformation) {
ExFreePool( KeyInformation );
}
if (Buffer) {
ExFreePool( Buffer );
}
if (Tasks) {
ExFreePool( Tasks );
}
}
}
ULONG
IsTextModeSetupRunning(
IN PWATCHDOG_DEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This function checks to see if we are running in
text mode setup.
Arguments:
DeviceExtension - NVRAM device extension
Return Value:
NT status code.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING UnicodeString;
HANDLE SetupKey = NULL;
ULONG TextModeSetupInProgress = 0;
//
// Check to see if we're running in GUI mode setup
//
__try {
RtlInitUnicodeString( &UnicodeString, L"\\Registry\\Machine\\System\\ControlSet001\\Services\\setupdd" );
InitializeObjectAttributes(
&Obja,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = ZwOpenKey(
&SetupKey,
KEY_READ,
&Obja
);
if (NT_SUCCESS(Status)) {
TextModeSetupInProgress = 1;
} else {
ERROR_RETURN( DeviceExtension->DeviceType, "ZwOpenKey failed", Status );
}
} __finally {
if (SetupKey) {
ZwClose( SetupKey );
}
}
return TextModeSetupInProgress;
}
ULONG
IsGuiModeSetupRunning(
IN PWATCHDOG_DEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This function checks to see if we are running in
GUI mode setup.
Arguments:
DeviceExtension - NVRAM device extension
Return Value:
NT status code.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING UnicodeString;
HANDLE SetupKey = NULL;
UCHAR KeyInformationBuffer[sizeof(KEY_VALUE_FULL_INFORMATION)+64];
PKEY_VALUE_FULL_INFORMATION KeyInformation = (PKEY_VALUE_FULL_INFORMATION) KeyInformationBuffer;
ULONG KeyValueLength;
ULONG SystemSetupInProgress = 0;
//
// Check to see if we're running in GUI mode setup
//
__try {
RtlInitUnicodeString( &UnicodeString, L"\\Registry\\Machine\\System\\Setup" );
InitializeObjectAttributes(
&Obja,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = ZwOpenKey(
&SetupKey,
KEY_READ,
&Obja
);
if (!NT_SUCCESS(Status)) {
ERROR_RETURN( DeviceExtension->DeviceType, "ZwOpenKey failed", Status );
}
RtlInitUnicodeString( &UnicodeString, L"SystemSetupInProgress" );
Status = ZwQueryValueKey(
SetupKey,
&UnicodeString,
KeyValueFullInformation,
KeyInformation,
sizeof(KeyInformationBuffer),
&KeyValueLength
);
if (!NT_SUCCESS(Status)) {
ERROR_RETURN( DeviceExtension->DeviceType, "ZwQueryValueKey failed", Status );
}
if (KeyInformation->Type != REG_DWORD) {
Status = STATUS_OBJECT_TYPE_MISMATCH;
ERROR_RETURN( DeviceExtension->DeviceType, "SystemSetupInProgress value is corrupt", Status );
}
SystemSetupInProgress = *(PULONG)((PUCHAR)KeyInformation + KeyInformation->DataOffset);
} __finally {
if (SetupKey) {
ZwClose( SetupKey );
}
}
return SystemSetupInProgress;
}
NTSTATUS
SaWatchdogStartDevice(
IN PWATCHDOG_DEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This is the NVRAM specific code for processing
the PNP start device request.
Arguments:
DeviceExtension - NVRAM device extension
Return Value:
NT status code.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE ThreadHandle;
ULONG SetupInProgress = 0;
//
// Setup the device extension fields
//
ExInitializeFastMutex( &DeviceExtension->DeviceLock );
KeInitializeEvent( &DeviceExtension->PingEvent, SynchronizationEvent, FALSE );
KeInitializeEvent( &DeviceExtension->StopEvent, SynchronizationEvent, FALSE );
//
// Check to see if we're running in setup
//
if (IsTextModeSetupRunning( DeviceExtension ) || IsGuiModeSetupRunning( DeviceExtension )) {
SetupInProgress = 1;
}
if (SetupInProgress != 0) {
//
// Start the ping thread so that setup is not terminated
//
DeviceExtension->ActiveProcessCount += 1;
InitializeObjectAttributes( &Obja, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
Status = PsCreateSystemThread( &ThreadHandle, 0, &Obja, 0, NULL, WatchdogProcessPingThread, DeviceExtension );
if (!NT_SUCCESS(Status)) {
REPORT_ERROR( DeviceExtension->DeviceType, "PsCreateSystemThread failed", Status );
} else {
ZwClose( ThreadHandle );
}
return STATUS_SUCCESS;
}
//
// Start the delay boot initialization thread
//
InitializeObjectAttributes( &Obja, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
Status = PsCreateSystemThread( &ThreadHandle, 0, &Obja, 0, NULL, WatchdogInitializeThread, DeviceExtension );
if (!NT_SUCCESS(Status)) {
REPORT_ERROR( DeviceExtension->DeviceType, "PsCreateSystemThread failed", Status );
} else {
ZwClose( ThreadHandle );
}
return STATUS_SUCCESS;
}
DECLARE_IOCTL_HANDLER( HandleWdDisable )
/*++
Routine Description:
This routine allows the watchdog timer to be started or stopped.
Arguments:
DeviceObject - The device object for the target device.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
DeviceExtension - Pointer to the main port driver device extension.
InputBuffer - Pointer to the user's input buffer
InputBufferLength - Length in bytes of the input buffer
OutputBuffer - Pointer to the user's output buffer
OutputBufferLength - Length in bytes of the output buffer
Return Value:
NT status code.
--*/
{
if (InputBufferLength != sizeof(ULONG)) {
REPORT_ERROR( DeviceExtension->DeviceType, "Input buffer != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
}
return DO_DEFAULT();
}
DECLARE_IOCTL_HANDLER( HandleWdQueryExpireBehavior )
/*++
Routine Description:
This routine queries the watchdog expiry behavior
Arguments:
DeviceObject - The device object for the target device.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
DeviceExtension - Pointer to the main port driver device extension.
InputBuffer - Pointer to the user's input buffer
InputBufferLength - Length in bytes of the input buffer
OutputBuffer - Pointer to the user's output buffer
OutputBufferLength - Length in bytes of the output buffer
Return Value:
NT status code.
--*/
{
if (OutputBufferLength != sizeof(ULONG)) {
REPORT_ERROR( DeviceExtension->DeviceType, "output buffer != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
}
return DO_DEFAULT();
}
DECLARE_IOCTL_HANDLER( HandleWdSetExpireBehavior )
/*++
Routine Description:
This routine set/changes the watchdog expiry behavior
Arguments:
DeviceObject - The device object for the target device.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
DeviceExtension - Pointer to the main port driver device extension.
InputBuffer - Pointer to the user's input buffer
InputBufferLength - Length in bytes of the input buffer
OutputBuffer - Pointer to the user's output buffer
OutputBufferLength - Length in bytes of the output buffer
Return Value:
NT status code.
--*/
{
if (InputBufferLength != sizeof(ULONG)) {
REPORT_ERROR( DeviceExtension->DeviceType, "Input buffer != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
}
return DO_DEFAULT();
}
DECLARE_IOCTL_HANDLER( HandleWdPing )
/*++
Routine Description:
This routine pings the watchdog timer to prevent
the timer from expiring and restarting the system.
Arguments:
DeviceObject - The device object for the target device.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
DeviceExtension - Pointer to the main port driver device extension.
InputBuffer - Pointer to the user's input buffer
InputBufferLength - Length in bytes of the input buffer
OutputBuffer - Pointer to the user's output buffer
OutputBufferLength - Length in bytes of the output buffer
Return Value:
NT status code.
--*/
{
if (!IS_IRP_INTERNAL( Irp )) {
KeSetEvent( &((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->StopEvent, 0, FALSE );
KeSetEvent( &((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->PingEvent, 0, FALSE );
}
return DO_DEFAULT();
}
DECLARE_IOCTL_HANDLER( HandleWdDelayBoot )
/*++
Routine Description:
This routine pings the watchdog timer to prevent
the timer from expiring and restarting the system.
Arguments:
DeviceObject - The device object for the target device.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
DeviceExtension - Pointer to the main port driver device extension.
InputBuffer - Pointer to the user's input buffer
InputBufferLength - Length in bytes of the input buffer
OutputBuffer - Pointer to the user's output buffer
OutputBufferLength - Length in bytes of the output buffer
Return Value:
NT status code.
--*/
{
NTSTATUS Status;
LARGE_INTEGER CurrentTime;
OBJECT_ATTRIBUTES Obja;
HANDLE ThreadHandle;
if (InputBufferLength != sizeof(ULONG)) {
REPORT_ERROR( ((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->DeviceType, "Input buffer length != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
}
ExAcquireFastMutex( &((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->DeviceLock );
switch (*((PULONG)InputBuffer)) {
case 0:
//
// Disable the delay boot, meaning that the system should continue booting
//
((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->ActiveProcessCount -= 1;
if (((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->ActiveProcessCount == 0) {
KeQuerySystemTime( &CurrentTime );
CurrentTime.QuadPart = CurrentTime.QuadPart - ((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->LastProcessTime.QuadPart;
if (NanoToSec(CurrentTime.QuadPart) > WATCHDOG_INIT_SECONDS) {
KeSetEvent( &((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->PingEvent, 0, FALSE );
}
}
break;
case 1:
//
// Enable the delay boot, meaning that the system will delay until this driver is finished
//
if (((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->ActiveProcessCount == 0) {
InitializeObjectAttributes( &Obja, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
Status = PsCreateSystemThread( &ThreadHandle, 0, &Obja, 0, NULL, WatchdogProcessPingThread, DeviceExtension );
if (!NT_SUCCESS(Status)) {
REPORT_ERROR( ((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->DeviceType, "PsCreateSystemThread failed", Status );
} else {
ZwClose( ThreadHandle );
}
}
((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->ActiveProcessCount += 1;
break;
default:
break;
}
ExReleaseFastMutex( &((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->DeviceLock );
return DO_DEFAULT();
}
DECLARE_IOCTL_HANDLER( HandleWdQueryTimer )
/*++
Routine Description:
This routine queries the watchdog timer value. The timer counts
down from a BIOS set value to zero. When the timer reaches zero the
BIOS assumes that the system is non-responsive and the system
is either restarted or shutdown.
Arguments:
DeviceObject - The device object for the target device.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
DeviceExtension - Pointer to the main port driver device extension.
InputBuffer - Pointer to the user's input buffer
InputBufferLength - Length in bytes of the input buffer
OutputBuffer - Pointer to the user's output buffer
OutputBufferLength - Length in bytes of the output buffer
Return Value:
NT status code.
--*/
{
if (OutputBufferLength != sizeof(ULONG)) {
REPORT_ERROR( DeviceExtension->DeviceType, "Output buffer != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
}
return DO_DEFAULT();
}
DECLARE_IOCTL_HANDLER( HandleWdSetTimer )
/*++
Routine Description:
This routine sets/changes the watchdog timer value. The timer counts
down from a BIOS set value to zero. When the timer reaches zero the
BIOS assumes that the system is non-responsive and the system
is either restarted or shutdown.
Arguments:
DeviceObject - The device object for the target device.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
DeviceExtension - Pointer to the main port driver device extension.
InputBuffer - Pointer to the user's input buffer
InputBufferLength - Length in bytes of the input buffer
OutputBuffer - Pointer to the user's output buffer
OutputBufferLength - Length in bytes of the output buffer
Return Value:
NT status code.
--*/
{
if (InputBufferLength != sizeof(ULONG)) {
REPORT_ERROR( DeviceExtension->DeviceType, "Input buffer != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
}
return DO_DEFAULT();
}