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.
991 lines
23 KiB
991 lines
23 KiB
/*++
|
|
|
|
Module Name:
|
|
|
|
mca.c
|
|
|
|
Abstract:
|
|
|
|
Sample device driver to register itself with the HAL and log Machine Check
|
|
Errors on a Intel Architecture Platform
|
|
|
|
Author:
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <ntddk.h>
|
|
#include "imca.h"
|
|
|
|
//
|
|
// Device names for the MCA driver
|
|
//
|
|
|
|
#define MCA_DEVICE_NAME "\\Device\\imca" // ANSI Name
|
|
#define MCA_DEVICE_NAME_U L"\\Device\\imca" // Unicode Name
|
|
#define MCA_DEVICE_NAME_DOS "\\DosDevices\\imca" // Device Name for Win32 App
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
NTSTATUS
|
|
MCAOpen(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
MCAClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
MCAStartIo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
#if defined(_AMD64_)
|
|
|
|
ERROR_SEVERITY
|
|
MCADriverExceptionCallback(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
|
IN PMCA_EXCEPTION InException
|
|
);
|
|
|
|
#else
|
|
|
|
ERROR_SEVERITY
|
|
MCADriverExceptionCallback(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PMCA_EXCEPTION InException
|
|
);
|
|
|
|
#endif
|
|
|
|
VOID
|
|
MCADriverDpcCallback(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemContext1,
|
|
IN PVOID SystemContext2
|
|
);
|
|
|
|
NTSTATUS
|
|
MCACleanup(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
McaCancelIrp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
MCADeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
MCAUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
NTSTATUS
|
|
MCACreateSymbolicLinkObject(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
MCAProcessWorkItem(
|
|
PVOID Context
|
|
);
|
|
|
|
//
|
|
// This temporary buffer holds the data between the Machine Check error
|
|
// notification from HAL and the asynchronous IOCTL completion to the
|
|
// application
|
|
//
|
|
|
|
typedef struct _MCA_DEVICE_EXTENSION {
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PIRP SavedIrp;
|
|
BOOLEAN WorkItemQueued;
|
|
WORK_QUEUE_ITEM WorkItem;
|
|
// Place to log the exceptions. Whenever the exception callback
|
|
// routine is called by the HAL MCA component, record the exception here.
|
|
// This can potentially be a link list.
|
|
MCA_EXCEPTION McaException;
|
|
|
|
} MCA_DEVICE_EXTENSION, *PMCA_DEVICE_EXTENSION;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, DriverEntry)
|
|
#pragma alloc_text(INIT, MCACreateSymbolicLinkObject)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This routine does the driver specific initialization at entry time
|
|
|
|
Arguments:
|
|
DriverObject: Pointer to the driver object
|
|
RegistryPath: Path to driver's registry key
|
|
|
|
Return Value:
|
|
Success or failure
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PMCA_DEVICE_EXTENSION Extension;
|
|
PDEVICE_OBJECT McaDeviceObject;
|
|
MCA_DRIVER_INFO McaDriverInfo;
|
|
|
|
//
|
|
// Create device object for MCA device.
|
|
//
|
|
|
|
RtlInitUnicodeString(&UnicodeString, MCA_DEVICE_NAME_U);
|
|
|
|
//
|
|
// Device is created as exclusive since only a single thread can send
|
|
// I/O requests to this device
|
|
//
|
|
|
|
Status = IoCreateDevice(
|
|
DriverObject,
|
|
sizeof(MCA_DEVICE_EXTENSION),
|
|
&UnicodeString,
|
|
FILE_DEVICE_UNKNOWN,
|
|
0,
|
|
TRUE,
|
|
&McaDeviceObject
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
DbgPrint("Mca DriverEntry: IoCreateDevice failed\n");
|
|
return Status;
|
|
}
|
|
|
|
McaDeviceObject->Flags |= DO_BUFFERED_IO;
|
|
|
|
Extension = McaDeviceObject->DeviceExtension;
|
|
RtlZeroMemory(Extension, sizeof(MCA_DEVICE_EXTENSION));
|
|
Extension->DeviceObject = McaDeviceObject;
|
|
|
|
//
|
|
// Make the device visible to Win32 subsystem
|
|
//
|
|
|
|
Status = MCACreateSymbolicLinkObject ();
|
|
if (!NT_SUCCESS( Status )) {
|
|
DbgPrint("Mca DriverEntry: McaCreateSymbolicLinkObject failed\n");
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Set up the device driver entry points.
|
|
//
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = MCAOpen;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MCAClose;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MCADeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MCACleanup;
|
|
DriverObject->DriverUnload = MCAUnload;
|
|
DriverObject->DriverStartIo = MCAStartIo;
|
|
|
|
//
|
|
// Register the driver with the HAL
|
|
//
|
|
|
|
McaDriverInfo.ExceptionCallback = MCADriverExceptionCallback;
|
|
McaDriverInfo.DpcCallback = MCADriverDpcCallback;
|
|
McaDriverInfo.DeviceContext = McaDeviceObject;
|
|
|
|
Status = HalSetSystemInformation(
|
|
HalMcaRegisterDriver,
|
|
sizeof(MCA_DRIVER_INFO),
|
|
(PVOID)&McaDriverInfo
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
DbgPrint("Mca DriverEntry: HalMcaRegisterDriver failed\n");
|
|
//
|
|
// Clean up whatever we have done so far
|
|
//
|
|
MCAUnload(DriverObject);
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
//
|
|
// This is the place where you would check non-volatile area (if any) for
|
|
// any Machine Check errros logged and process them.
|
|
// ...
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
MCACreateSymbolicLinkObject(
|
|
VOID
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Makes MCA device visible to Win32 subsystem
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
Success or failure
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
STRING DosString;
|
|
STRING NtString;
|
|
UNICODE_STRING DosUnicodeString;
|
|
UNICODE_STRING NtUnicodeString;
|
|
|
|
//
|
|
// Create a symbolic link for sharing.
|
|
//
|
|
|
|
RtlInitAnsiString( &DosString, MCA_DEVICE_NAME_DOS );
|
|
|
|
Status = RtlAnsiStringToUnicodeString(
|
|
&DosUnicodeString,
|
|
&DosString,
|
|
TRUE
|
|
);
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
return Status;
|
|
}
|
|
|
|
RtlInitAnsiString( &NtString, MCA_DEVICE_NAME );
|
|
|
|
Status = RtlAnsiStringToUnicodeString(
|
|
&NtUnicodeString,
|
|
&NtString,
|
|
TRUE
|
|
);
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
return Status;
|
|
}
|
|
|
|
Status = IoCreateSymbolicLink(
|
|
&DosUnicodeString,
|
|
&NtUnicodeString
|
|
);
|
|
RtlFreeUnicodeString( &DosUnicodeString );
|
|
RtlFreeUnicodeString( &NtUnicodeString );
|
|
|
|
return (Status);
|
|
}
|
|
|
|
//
|
|
// Dispatch routine for close requests
|
|
//
|
|
|
|
NTSTATUS
|
|
MCAClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
Close dispatch routine
|
|
|
|
Arguments:
|
|
DeviceObject: Pointer to the device object
|
|
Irp: Incoming Irp
|
|
|
|
Return Value:
|
|
Success or failure
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Complete the request and return status.
|
|
//
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return (Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
MCAOpen(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This routine is the dispatch routine for create/open requests.
|
|
|
|
Arguments:
|
|
DeviceObject: Pointer to the device object
|
|
Irp: Incoming Irp
|
|
|
|
Return Value:
|
|
Success or failure
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Complete the request and return status.
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = FILE_OPENED;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
ERROR_SEVERITY
|
|
MCADriverExceptionCallback(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
#if defined(_AMD64_)
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
|
#endif
|
|
IN PMCA_EXCEPTION InException
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This is the callback routine for MCA exception. It was registered
|
|
by this driver at INIT time with the HAL as a callback when a
|
|
non-restartable error occurs. This routine simply copies the
|
|
information to a platform specific area
|
|
|
|
NOTE: If the information needs to be saved in NVRAM, this is the place
|
|
to do it.
|
|
|
|
Once you return from this callback, the system is going to bugcheck.
|
|
|
|
Arguments:
|
|
DeviceObject: Pointer to the device object
|
|
InException: Exception information record
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PMCA_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
|
|
PCHAR Destination, Source;
|
|
UCHAR Bytes;
|
|
|
|
//
|
|
// An exception has occured on a processor.
|
|
// Perform any vendor specific action here like saving stuff in NVRAM
|
|
// NOTE : No system services of any kind can be used here.
|
|
//
|
|
|
|
//
|
|
// Save the exception from HAL. May want to use link list for these
|
|
// exceptions.
|
|
//
|
|
|
|
Destination = (PCHAR)&(Extension->McaException); // Put your platform
|
|
// specific destination
|
|
Source = (PCHAR)InException;
|
|
|
|
//
|
|
// Copy from source to destination here
|
|
//
|
|
|
|
#if defined(_IA64_)
|
|
|
|
//
|
|
// Return information to the generic HAL MCA handler.
|
|
//
|
|
// Update it accordingly here, the default value being the ERROR_SEVERITY value
|
|
// in the MCA exception.
|
|
//
|
|
|
|
return( InException->ErrorSeverity );
|
|
|
|
#endif // defined(_IA64_)
|
|
|
|
#if defined(_AMD64_)
|
|
|
|
//
|
|
// Return the error severity information to the HAL MCA handler.
|
|
//
|
|
// Chose from:
|
|
//
|
|
// ErrorRecoverable
|
|
// ErrorFatal
|
|
// ErrorCorrected
|
|
//
|
|
|
|
return ErrorRecoverable;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
//
|
|
// DPC routine for IRP completion
|
|
//
|
|
|
|
VOID
|
|
MCADriverDpcCallback(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemContext1,
|
|
IN PVOID SystemContext2
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This is the DPC - callback routine for MCA exception. It was registered
|
|
by this driver at INIT time with the HAL as a DPC callback when a
|
|
restartable error occurs (which causes Machine Check exception)
|
|
|
|
Arguments:
|
|
Dpc: The DPC Object itself
|
|
DefferedContext: Pointer to the device object
|
|
SystemContext1: Not used
|
|
SystemContext2: Not used
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PMCA_DEVICE_EXTENSION Extension;
|
|
|
|
Extension = ((PDEVICE_OBJECT)DeferredContext)->DeviceExtension;
|
|
|
|
if (Extension->SavedIrp == NULL) {
|
|
//
|
|
// We got an MCA exception but no app was asking for anything.
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If we have reached this point, it means that the exception was
|
|
// restartable. Since we cannot read the log at Dispatch level,
|
|
// queue a work item to read the Machine Check log at Passive level
|
|
//
|
|
|
|
if (Extension->WorkItemQueued == FALSE) {
|
|
|
|
//
|
|
// Set a boolean to indicate that we have already queued a work item
|
|
//
|
|
Extension->WorkItemQueued = TRUE;
|
|
|
|
//
|
|
// Initialize the work item
|
|
//
|
|
ExInitializeWorkItem(&Extension->WorkItem,
|
|
(PWORKER_THREAD_ROUTINE)MCAProcessWorkItem,
|
|
(PVOID)DeferredContext
|
|
);
|
|
|
|
//
|
|
// Queue the work item for processing at PASSIVE level
|
|
//
|
|
ExQueueWorkItem(&Extension->WorkItem, CriticalWorkQueue);
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
MCAProcessWorkItem(
|
|
PVOID Context
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This routine gets invoked when a work item is queued from the DPC
|
|
callback routine for a restartable machine check error.
|
|
|
|
Its job is to read the machine check registers and copy the log
|
|
to complete the asynchronous IRP
|
|
|
|
Arguments:
|
|
Context : Pointer to the device object
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PMCA_DEVICE_EXTENSION Extension;
|
|
KIRQL CancelIrql;
|
|
ULONG ReturnedLength;
|
|
NTSTATUS Status;
|
|
|
|
Extension = ((PDEVICE_OBJECT)Context)->DeviceExtension;
|
|
|
|
//
|
|
// Mark this IRP as non-cancellable
|
|
//
|
|
IoAcquireCancelSpinLock(&CancelIrql);
|
|
if (Extension->SavedIrp->Cancel == TRUE) {
|
|
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
|
|
} else {
|
|
|
|
IoSetCancelRoutine(Extension->SavedIrp, NULL);
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
|
|
//
|
|
// Call HalQuerySystemInformation() to obtain MCA log.
|
|
//
|
|
|
|
Status = HalQuerySystemInformation(
|
|
HalMcaLogInformation,
|
|
sizeof(MCA_EXCEPTION),
|
|
Extension->SavedIrp->AssociatedIrp.SystemBuffer,
|
|
&ReturnedLength
|
|
);
|
|
|
|
ASSERT(Status != STATUS_NO_SUCH_DEVICE);
|
|
ASSERT(Status != STATUS_NOT_FOUND);
|
|
|
|
IoStartPacket(((PDEVICE_OBJECT)Context), Extension->SavedIrp, 0, NULL);
|
|
|
|
Extension->SavedIrp = NULL;
|
|
Extension->WorkItemQueued = FALSE;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
MCAStartIo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This routine completes the async call from the app
|
|
|
|
Arguments:
|
|
DeviceObject: Pointer to the device object
|
|
Irp: Incoming Irp
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// The system Buffer has already been setup
|
|
//
|
|
|
|
Irp->IoStatus.Information = sizeof(MCA_EXCEPTION);
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
|
|
IoStartNextPacket(DeviceObject, TRUE);
|
|
}
|
|
|
|
VOID
|
|
McaCancelIrp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function gets called when the IRP is cancelled. When this routine
|
|
is called, we hold the cancel spin lock and we are at DISPATCH level
|
|
|
|
Arguments:
|
|
DeviceObject and the Irp to be cancelled.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
((PMCA_DEVICE_EXTENSION)(DeviceObject->DeviceExtension))->SavedIrp = NULL;
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
MCADeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This routine is the dispatch routine for the IOCTL requests to driver.
|
|
It accepts an I/O Request Packet, performs the request, and then
|
|
returns with the appropriate status.
|
|
|
|
Arguments:
|
|
DeviceObject: Pointer to the device object
|
|
Irp: Incoming Irp
|
|
|
|
Return Value:
|
|
Success or failure
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PMCA_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
|
|
KIRQL CancelIrql;
|
|
ULONG ReturnedLength;
|
|
ULONG PhysicalAddress;
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// Get a pointer to the current stack location in the IRP. This is
|
|
// where the function codes and parameters are stored.
|
|
//
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
//
|
|
// The individual IOCTLs will return errors if HAL MCA is not installed
|
|
//
|
|
|
|
//
|
|
// Switch on the IOCTL code that is being requested by the user. If the
|
|
// operation is a valid one for this device do the needful.
|
|
//
|
|
|
|
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
case IOCTL_READ_BANKS:
|
|
|
|
//
|
|
// we need a user buffer for this call to complete
|
|
// Our user buffer is in SystemBuffer
|
|
//
|
|
if (Irp->AssociatedIrp.SystemBuffer == NULL) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength !=
|
|
sizeof(MCA_EXCEPTION)) {
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Call HalQuerySystemInformation() to obtain MCA log.
|
|
// This call can also fail if the processor does not support
|
|
// Intel Machine Check Architecture
|
|
//
|
|
|
|
Status = HalQuerySystemInformation(
|
|
HalMcaLogInformation,
|
|
sizeof(MCA_EXCEPTION),
|
|
Irp->AssociatedIrp.SystemBuffer,
|
|
&ReturnedLength
|
|
);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Irp->IoStatus.Information = ReturnedLength;
|
|
} else {
|
|
|
|
if (Status == STATUS_NO_SUCH_DEVICE) {
|
|
//
|
|
// MCA support not available\n");
|
|
//
|
|
NOTHING;
|
|
}
|
|
|
|
if (Status == STATUS_NOT_FOUND) {
|
|
//
|
|
// No machine check errors present\n");
|
|
//
|
|
NOTHING;
|
|
}
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case IOCTL_READ_BANKS_ASYNC:
|
|
|
|
if (Irp->AssociatedIrp.SystemBuffer == NULL) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength !=
|
|
sizeof(MCA_EXCEPTION)) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Implementation Note:
|
|
//
|
|
// Our Async model is such that the next DeviceIoControl
|
|
// does not start from the app until the previous one
|
|
// completes (asynchronously). Since there is no inherent
|
|
// parallelism that is needed here, we do not have to worry
|
|
// about protecting data integrity in the face of more than
|
|
// one app level ioctls active at the same time.
|
|
//
|
|
|
|
//
|
|
// asynchronous reads provide a mechanism for the
|
|
// app to asynchronously get input from the HAL on an
|
|
// exception. This request is marked as pending at this time
|
|
// but it will be completed when an MCA exception occurs.
|
|
//
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
//
|
|
// Complete the processing in StartIo Dispatch routine
|
|
// ASSERT: at any given time there is only 1 async call pending
|
|
// So just save the pointer
|
|
//
|
|
|
|
if (Extension->SavedIrp == NULL) {
|
|
Extension->SavedIrp = Irp;
|
|
} else {
|
|
//
|
|
// We can have ONLY one outstanding ASYNC request
|
|
//
|
|
Status = STATUS_DEVICE_BUSY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the IRP to cancellable state
|
|
//
|
|
IoAcquireCancelSpinLock(&CancelIrql);
|
|
IoSetCancelRoutine(Irp, McaCancelIrp);
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
|
|
return(STATUS_PENDING);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// This should not happen
|
|
//
|
|
|
|
DbgPrint("MCA driver: Bad ioctl\n");
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Copy the final status into the return status, complete the request and
|
|
// get out of here.
|
|
//
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
|
|
//
|
|
// Complete the Io Request
|
|
//
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
}
|
|
|
|
return (Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
MCACleanup(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This is the dispatch routine for cleanup requests.
|
|
All queued IRPs are completed with STATUS_CANCELLED.
|
|
|
|
Arguments:
|
|
DeviceObject: Pointer to the device object
|
|
Irp: Incoming Irp
|
|
|
|
Return Value:
|
|
Success or failure
|
|
|
|
--*/
|
|
|
|
{
|
|
PIRP CurrentIrp;
|
|
PMCA_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// Complete all queued requests with STATUS_CANCELLED.
|
|
//
|
|
|
|
if (Extension->SavedIrp != NULL) {
|
|
|
|
CurrentIrp = Extension->SavedIrp;
|
|
|
|
//
|
|
// Acquire the Cancel Spinlock
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&CurrentIrp->CancelIrql);
|
|
|
|
Extension->SavedIrp = NULL;
|
|
|
|
if (CurrentIrp->Cancel == TRUE) {
|
|
|
|
//
|
|
// Cancel routine got called for this one.
|
|
// No need to do anything else
|
|
//
|
|
|
|
IoReleaseCancelSpinLock(CurrentIrp->CancelIrql);
|
|
|
|
} else {
|
|
|
|
if (CurrentIrp->CancelRoutine == NULL) {
|
|
//
|
|
// Release the Cancel Spinlock
|
|
//
|
|
|
|
IoReleaseCancelSpinLock(CurrentIrp->CancelIrql);
|
|
|
|
|
|
} else {
|
|
(CurrentIrp->CancelRoutine)(DeviceObject, CurrentIrp );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Complete the Cleanup Dispatch with STATUS_SUCCESS
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
MCAUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
Dispatch routine for unloads
|
|
|
|
Arguments:
|
|
DeviceObject: Pointer to the device object
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
STRING DosString;
|
|
UNICODE_STRING DosUnicodeString;
|
|
|
|
//
|
|
// Delete the user visible device name.
|
|
//
|
|
|
|
RtlInitAnsiString( &DosString, MCA_DEVICE_NAME_DOS );
|
|
|
|
Status = RtlAnsiStringToUnicodeString(
|
|
&DosUnicodeString,
|
|
&DosString,
|
|
TRUE
|
|
);
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
DbgPrint("MCAUnload: Error in RtlAnsiStringToUnicodeString\n");
|
|
return;
|
|
}
|
|
|
|
Status = IoDeleteSymbolicLink(
|
|
&DosUnicodeString
|
|
);
|
|
|
|
RtlFreeUnicodeString( &DosUnicodeString );
|
|
|
|
//
|
|
// Delete the device object
|
|
//
|
|
|
|
IoDeleteDevice(DriverObject->DeviceObject);
|
|
|
|
return;
|
|
}
|
|
|