1257 lines
30 KiB
C
1257 lines
30 KiB
C
/*++
|
|
|
|
Copyright (c) 1993-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ramdisk.c
|
|
|
|
Abstract:
|
|
|
|
This is the RAM disk driver for Windows.
|
|
|
|
Author:
|
|
|
|
Chuck Lenzmeier (ChuckL) 2001
|
|
based on prototype XIP driver by DavePr
|
|
based on NT4 DDK ramdisk by RobertN
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include <initguid.h>
|
|
#include <ntddstor.h>
|
|
#include <ntddramd.h>
|
|
|
|
//
|
|
// ISSUE: 2000/10/11-DavePr -- haven't decided how to define DO_XIP appropriately.
|
|
//
|
|
#ifndef DO_XIP
|
|
#define DO_XIP 0x00020000
|
|
#endif
|
|
|
|
//
|
|
// Data declarations.
|
|
//
|
|
|
|
PDEVICE_OBJECT RamdiskBusFdo = NULL;
|
|
|
|
BOOLEAN ReportDetectedDevice;
|
|
|
|
ULONG MinimumViewCount;
|
|
ULONG DefaultViewCount;
|
|
ULONG MaximumViewCount;
|
|
ULONG MinimumViewLength;
|
|
ULONG DefaultViewLength;
|
|
ULONG MaximumViewLength;
|
|
|
|
ULONG MaximumPerDiskViewLength;
|
|
|
|
UNICODE_STRING DriverRegistryPath;
|
|
BOOLEAN MarkRamdisksAsRemovable;
|
|
|
|
#if SUPPORT_DISK_NUMBERS
|
|
|
|
ULONG DiskNumbersBitmapSize;
|
|
|
|
#endif // SUPPORT_DISK_NUMBERS
|
|
|
|
#if DBG
|
|
|
|
ULONG BreakOnEntry = DEFAULT_BREAK_ON_ENTRY;
|
|
ULONG DebugComponents = DEFAULT_DEBUG_COMPONENTS;
|
|
ULONG DebugLevel = DEFAULT_DEBUG_LEVEL;
|
|
|
|
BOOLEAN DontLoad = FALSE;
|
|
|
|
#endif
|
|
|
|
//
|
|
// Local functions.
|
|
//
|
|
|
|
NTSTATUS
|
|
DriverEntry (
|
|
IN OUT PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
NTSTATUS
|
|
RamdiskCreateClose (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
RamdiskFlushBuffers (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
RamdiskFlushBuffersReal (
|
|
IN PDISK_EXTENSION DiskExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
RamdiskSystemControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
RamdiskUnload (
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
VOID
|
|
QueryParameters (
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
#if DBG
|
|
|
|
NTSTATUS
|
|
RamdiskInvalidDeviceRequest (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
QueryDebugParameters (
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Declare pageable routines.
|
|
//
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
|
|
#pragma alloc_text( INIT, DriverEntry )
|
|
#pragma alloc_text( INIT, QueryParameters )
|
|
|
|
#pragma alloc_text( PAGE, RamdiskCreateClose )
|
|
#pragma alloc_text( PAGE, RamdiskFlushBuffers )
|
|
#pragma alloc_text( PAGE, RamdiskFlushBuffersReal )
|
|
#pragma alloc_text( PAGE, RamdiskSystemControl )
|
|
#pragma alloc_text( PAGE, RamdiskUnload )
|
|
#pragma alloc_text( PAGE, RamdiskWorkerThread )
|
|
|
|
#if DBG
|
|
#pragma alloc_text( INIT, QueryDebugParameters )
|
|
#endif // DBG
|
|
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
NTSTATUS
|
|
DriverEntry (
|
|
IN OUT PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the operating system to initialize the driver.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to a driver object for the driver
|
|
|
|
RegistryPath - a pointer to our Services key in the registry
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE handle;
|
|
ULONG i;
|
|
PDEVICE_OBJECT pdo = NULL;
|
|
PLOADER_PARAMETER_BLOCK loaderBlock;
|
|
|
|
//
|
|
// Initialize pool debugging, if enabled.
|
|
//
|
|
|
|
#if defined(POOL_DBG)
|
|
RamdiskInitializePoolDebug();
|
|
#endif
|
|
|
|
//
|
|
// Get debugging parameters from the registry.
|
|
//
|
|
|
|
#if DBG
|
|
QueryDebugParameters( RegistryPath );
|
|
#endif
|
|
|
|
DBGPRINT( DBG_INIT, DBG_VERBOSE,
|
|
("DriverEntry: DriverObject = %x, RegistryPath = %ws\n",
|
|
DriverObject, RegistryPath->Buffer) );
|
|
|
|
//
|
|
// If requested, break into the debugger.
|
|
//
|
|
|
|
#if DBG
|
|
if ( BreakOnEntry ) {
|
|
KdBreakPoint();
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If requested, fail the driver load.
|
|
//
|
|
|
|
#if DBG
|
|
if ( DontLoad ) {
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Get non-debug parameters from the registry.
|
|
//
|
|
|
|
QueryParameters( RegistryPath );
|
|
|
|
//
|
|
// Save the path to the driver's registry key.
|
|
//
|
|
|
|
DriverRegistryPath.Length = RegistryPath->Length;
|
|
DriverRegistryPath.MaximumLength = (USHORT)(RegistryPath->Length + sizeof(WCHAR));
|
|
DriverRegistryPath.Buffer = ALLOCATE_POOL( PagedPool, DriverRegistryPath.MaximumLength, TRUE );
|
|
|
|
if ( DriverRegistryPath.Buffer == NULL ) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyUnicodeString( &DriverRegistryPath, RegistryPath );
|
|
ASSERT( DriverRegistryPath.Length == RegistryPath->Length );
|
|
|
|
//
|
|
// Initialize the driver object with this driver's entry points.
|
|
//
|
|
|
|
#if DBG
|
|
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
|
|
DriverObject->MajorFunction[i] = RamdiskInvalidDeviceRequest;
|
|
}
|
|
#endif
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = RamdiskCreateClose;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = RamdiskCreateClose;
|
|
DriverObject->MajorFunction[IRP_MJ_READ] = RamdiskReadWrite;
|
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = RamdiskReadWrite;
|
|
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = RamdiskFlushBuffers;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RamdiskDeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = RamdiskPnp;
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = RamdiskPower;
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = RamdiskSystemControl;
|
|
DriverObject->MajorFunction[IRP_MJ_SCSI] = RamdiskScsi;
|
|
|
|
DriverObject->DriverUnload = RamdiskUnload;
|
|
DriverObject->DriverExtension->AddDevice = RamdiskAddDevice;
|
|
|
|
//
|
|
// If the registry tells us to do so, or if textmode setup is running and
|
|
// virtual floppy RAM disks are specified in the registry, call
|
|
// IoReportDetectedDevice to hook us up to PnP, then call RamdiskAddDevice
|
|
// directly. This is necessary during textmode in order to get any virtual
|
|
// floppy RAM disks created -- our AddDevice routine is not normally called
|
|
// during textmode. Calling IoReportDetectedDevice is also necessary during
|
|
// a boot from a RAM disk in order to get the device plumbed early enough.
|
|
//
|
|
// We don't want to call IoReportDetectedDevice during textmode setup if
|
|
// no virtual floppies exist, because calling IoReportDetectedDevice
|
|
// causes a devnode for the controller device to be written to the
|
|
// registry, and textmode setup only deletes the devnode if virtual
|
|
// floppies exist. If we leave the devnode in the registry, then GUI setup
|
|
// installs ramdisk.sys on the machine, even though we don't really want
|
|
// it to.
|
|
//
|
|
|
|
loaderBlock = *(PLOADER_PARAMETER_BLOCK *)KeLoaderBlock;
|
|
|
|
if ( ReportDetectedDevice ||
|
|
( (loaderBlock != NULL) &&
|
|
(loaderBlock->SetupLoaderBlock != NULL) &&
|
|
CreateRegistryDisks( TRUE ) ) ) {
|
|
|
|
//
|
|
// Inform PnP that we have detected the bus enumerator device and will be
|
|
// doing the AddDevice ourselves.
|
|
//
|
|
|
|
status = IoReportDetectedDevice(
|
|
DriverObject,
|
|
InterfaceTypeUndefined,
|
|
-1,
|
|
-1,
|
|
NULL, //allocatedResources,
|
|
NULL, //ioResourceReq,
|
|
FALSE,
|
|
&pdo
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DBGPRINT( DBG_ALL, DBG_ERROR,
|
|
("RamdiskDriverEntry: IoReportDetectedDevice failed: %x\n", status) );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Attach a device object to the pdo
|
|
//
|
|
|
|
status = RamdiskAddDevice(DriverObject, pdo);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
DBGPRINT( DBG_ALL, DBG_ERROR,
|
|
("RamdiskDriverEntry: RamdiskAddDevice failed: %x\n", status) );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Indicate that the device is done initializing.
|
|
//
|
|
|
|
pdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
}
|
|
|
|
//
|
|
// Indicate that the driver has loaded successfully.
|
|
//
|
|
|
|
DBGPRINT( DBG_INIT, DBG_VERBOSE, ("%s", "DriverEntry: succeeded\n") );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // DriverEntry
|
|
|
|
NTSTATUS
|
|
RamdiskCreateClose (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the I/O system when a device owned by the driver
|
|
is opened or closed.
|
|
|
|
No action is performed other than completing the request successfully.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the object that represents the device on which
|
|
I/O is to be performed
|
|
|
|
Irp - a pointer to the I/O Request Packet for this request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
COMPLETE_REQUEST( STATUS_SUCCESS, FILE_OPENED, Irp );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // RamdiskCreateClose
|
|
|
|
NTSTATUS
|
|
RamdiskFlushBuffers (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the I/O system when a FLUSH_BUFFERS IRP is
|
|
issued.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the object that represents the device on which
|
|
I/O is to be performed
|
|
|
|
Irp - a pointer to the I/O Request Packet for this request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - the status of the operation
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PDISK_EXTENSION diskExtension = DeviceObject->DeviceExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// If the target RAM disk is not file-backed, there's nothing to do. If it
|
|
// is file-backed, we need to do the work in a thread.
|
|
//
|
|
|
|
if ( (diskExtension->DeviceType != RamdiskDeviceTypeDiskPdo) ||
|
|
!RAMDISK_IS_FILE_BACKED(diskExtension->DiskType) ) {
|
|
|
|
COMPLETE_REQUEST( STATUS_SUCCESS, 0, Irp );
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
status = SendIrpToThread( DeviceObject, Irp );
|
|
|
|
if ( status != STATUS_PENDING ) {
|
|
|
|
COMPLETE_REQUEST( status, 0, Irp );
|
|
}
|
|
|
|
return status;
|
|
|
|
} // RamdiskFlushBuffers
|
|
|
|
NTSTATUS
|
|
RamdiskFlushBuffersReal (
|
|
IN PDISK_EXTENSION DiskExtension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called in a thread in the system process to handle a
|
|
FLUSH_BUFFERS IRP.
|
|
|
|
Arguments:
|
|
|
|
DiskExtension - a pointer to the device object extension for the target
|
|
device
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - the status of the operation
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Flush the virtual memory associated with the RAM disk.
|
|
//
|
|
|
|
return RamdiskFlushViews( DiskExtension );
|
|
|
|
} // RamdiskFlushBuffersReal
|
|
|
|
NTSTATUS
|
|
RamdiskSystemControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the I/O system when a SYSTEM_CONTROL IRP is
|
|
issued.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the object that represents the device on which
|
|
I/O is to be performed
|
|
|
|
Irp - a pointer to the I/O Request Packet for this request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - the status of the operation
|
|
|
|
--*/
|
|
|
|
{
|
|
PCOMMON_EXTENSION commonExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// If the target device is a bus FDO, pass the IRP down to the next
|
|
// device in the stack. Otherwise, the target is a disk PDO, in which
|
|
// case we just complete the IRP with the current status.
|
|
//
|
|
|
|
commonExtension = DeviceObject->DeviceExtension;
|
|
|
|
if ( commonExtension->DeviceType == RamdiskDeviceTypeBusFdo ) {
|
|
|
|
IoSkipCurrentIrpStackLocation( Irp );
|
|
return IoCallDriver( commonExtension->LowerDeviceObject, Irp );
|
|
}
|
|
|
|
status = Irp->IoStatus.Status;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
|
|
return status;
|
|
|
|
} // RamdiskSystemControl
|
|
|
|
|
|
VOID
|
|
RamdiskUnload (
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the I/O system to unload the driver.
|
|
|
|
Any resources previously allocated must be freed.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to the object that represents our driver
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if ( DriverRegistryPath.Buffer != NULL ) {
|
|
|
|
FREE_POOL( DriverRegistryPath.Buffer, TRUE );
|
|
}
|
|
|
|
//
|
|
// ISSUE: What other cleanup is needed here?
|
|
//
|
|
|
|
return;
|
|
|
|
} // RamdiskUnload
|
|
|
|
VOID
|
|
RamdiskWorkerThread (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine executes thread-based operations for the RAM disk driver.
|
|
It runs in the context of the system process.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the object that represents the device on which
|
|
I/O is to be performed
|
|
|
|
Context - a pointer to the IRP for the I/O operation
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PLIST_ENTRY listEntry;
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PCOMMON_EXTENSION commonExtension;
|
|
PBUS_EXTENSION busExtension;
|
|
PDISK_EXTENSION diskExtension;
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
ULONG controlCode;
|
|
PUCHAR originalDataBuffer;
|
|
PUCHAR mappedDataBuffer;
|
|
PUCHAR inputDataBuffer;
|
|
PUCHAR systemAddress;
|
|
ULONG originalDataBufferOffset;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Get a pointer to the IRP.
|
|
//
|
|
|
|
irp = Context;
|
|
irpSp = IoGetCurrentIrpStackLocation( irp );
|
|
|
|
//
|
|
// Free the work item.
|
|
//
|
|
|
|
IoFreeWorkItem( irp->Tail.Overlay.DriverContext[0] );
|
|
|
|
//
|
|
// Get pointers to the device extension.
|
|
//
|
|
|
|
commonExtension = DeviceObject->DeviceExtension;
|
|
busExtension = DeviceObject->DeviceExtension;
|
|
diskExtension = DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// Acquire the remove lock for the device. If this fails, bail out.
|
|
//
|
|
|
|
status = IoAcquireRemoveLock( &commonExtension->RemoveLock, irp );
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
COMPLETE_REQUEST( status, 0, irp );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Dispatch based on the IRP function.
|
|
//
|
|
|
|
switch ( irpSp->MajorFunction ) {
|
|
|
|
case IRP_MJ_READ:
|
|
case IRP_MJ_WRITE:
|
|
|
|
status = RamdiskReadWriteReal( irp, diskExtension );
|
|
|
|
break;
|
|
|
|
case IRP_MJ_FLUSH_BUFFERS:
|
|
|
|
status = RamdiskFlushBuffersReal( diskExtension );
|
|
irp->IoStatus.Information = 0;
|
|
|
|
break;
|
|
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
|
|
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
case IOCTL_DISK_GET_DRIVE_LAYOUT:
|
|
|
|
status = RamdiskGetDriveLayout( irp, diskExtension );
|
|
|
|
break;
|
|
|
|
case IOCTL_DISK_GET_PARTITION_INFO:
|
|
|
|
status = RamdiskGetPartitionInfo( irp, diskExtension );
|
|
|
|
break;
|
|
|
|
case IOCTL_DISK_SET_PARTITION_INFO:
|
|
|
|
status = RamdiskSetPartitionInfo( irp, diskExtension );
|
|
|
|
break;
|
|
|
|
case FSCTL_CREATE_RAM_DISK:
|
|
|
|
status = RamdiskCreateRamDisk( DeviceObject, irp, FALSE );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBGPRINT( DBG_IOCTL, DBG_ERROR,
|
|
("RamdiskThread: bogus IOCTL IRP with code %x received\n",
|
|
irpSp->Parameters.DeviceIoControl.IoControlCode) );
|
|
ASSERT( FALSE );
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IRP_MJ_SCSI:
|
|
|
|
srb = irpSp->Parameters.Scsi.Srb;
|
|
controlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
//
|
|
// Remember the original data buffer pointer. We might have to
|
|
// change the pointer.
|
|
//
|
|
|
|
originalDataBuffer = srb->DataBuffer;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
if ( irp->MdlAddress != NULL ) {
|
|
|
|
//
|
|
// There is an MDL in the IRP. Get a usable system address for
|
|
// the data buffer based on the MDL.
|
|
//
|
|
|
|
systemAddress = MmGetSystemAddressForMdlSafe(
|
|
irp->MdlAddress,
|
|
NormalPagePriority
|
|
);
|
|
|
|
if ( systemAddress != NULL ) {
|
|
|
|
//
|
|
// The SRB data buffer might be at an offset from the
|
|
// start of the MDL. Calculate that offset and add it
|
|
// to the system address just obtained. This is the
|
|
// data buffer address that we will use.
|
|
//
|
|
|
|
originalDataBufferOffset = (ULONG)(originalDataBuffer -
|
|
(PCHAR)MmGetMdlVirtualAddress( irp->MdlAddress ));
|
|
mappedDataBuffer = systemAddress + originalDataBufferOffset;
|
|
srb->DataBuffer = mappedDataBuffer;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Couldn't get a system address. Abort.
|
|
//
|
|
|
|
srb->SrbStatus = SRB_STATUS_ABORTED;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
if ( NT_SUCCESS(status) ) {
|
|
|
|
//
|
|
// Remember the data buffer address that we're sending down.
|
|
// If it doesn't change, we'll need to reset the address to
|
|
// that which was passed in to us.
|
|
//
|
|
|
|
inputDataBuffer = srb->DataBuffer;
|
|
|
|
//
|
|
// Dispatch based on the I/O type in the SRB.
|
|
//
|
|
|
|
if ( controlCode == IOCTL_SCSI_EXECUTE_NONE ) {
|
|
|
|
status = RamdiskScsiExecuteNone(
|
|
diskExtension->Pdo,
|
|
irp,
|
|
srb,
|
|
controlCode
|
|
);
|
|
} else {
|
|
|
|
status = RamdiskScsiExecuteIo(
|
|
diskExtension->Pdo,
|
|
irp,
|
|
srb,
|
|
controlCode
|
|
);
|
|
}
|
|
|
|
//
|
|
// If the data buffer address didn't change, put the original
|
|
// address back in the SRB.
|
|
//
|
|
|
|
if ( srb->DataBuffer == inputDataBuffer ) {
|
|
srb->DataBuffer = originalDataBuffer;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the I/O worked, write the transfer length into the IRP.
|
|
//
|
|
|
|
if ( NT_SUCCESS(status) ) {
|
|
irp->IoStatus.Information = srb->DataTransferLength;
|
|
} else {
|
|
irp->IoStatus.Information = 0;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBGPRINT( DBG_IOCTL, DBG_ERROR,
|
|
("RamdiskThread: bogus IRP with major function %x received\n",
|
|
irpSp->MajorFunction) );
|
|
ASSERT( FALSE );
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
//
|
|
// Release the remove lock and complete the request.
|
|
//
|
|
|
|
IoReleaseRemoveLock( &commonExtension->RemoveLock, irp );
|
|
|
|
ASSERT( status != STATUS_PENDING );
|
|
|
|
irp->IoStatus.Status = status;
|
|
IoCompleteRequest( irp, IO_DISK_INCREMENT );
|
|
|
|
return;
|
|
|
|
} // RamdiskWorkerThread
|
|
|
|
VOID
|
|
QueryParameters (
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called from DriverEntry() to get driver parameters from
|
|
the registry. If the registry query fails, then default values are used.
|
|
|
|
Arguments:
|
|
|
|
RegistryPath - a pointer to the service path for the registry parameters
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
RTL_QUERY_REGISTRY_TABLE queryTable[12];
|
|
PRTL_QUERY_REGISTRY_TABLE queryEntry;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT( DBG_INIT, DBG_VERBOSE, ("%s", "QueryParameters\n") );
|
|
|
|
ASSERT( RegistryPath->Buffer != NULL );
|
|
|
|
//
|
|
// Set the default values.
|
|
//
|
|
|
|
ReportDetectedDevice = FALSE;
|
|
MarkRamdisksAsRemovable = FALSE;
|
|
|
|
MinimumViewCount = MINIMUM_MINIMUM_VIEW_COUNT;
|
|
DefaultViewCount = DEFAULT_DEFAULT_VIEW_COUNT;
|
|
MaximumViewCount = DEFAULT_MAXIMUM_VIEW_COUNT;
|
|
MinimumViewLength = MINIMUM_MINIMUM_VIEW_LENGTH;
|
|
DefaultViewLength = DEFAULT_DEFAULT_VIEW_LENGTH;
|
|
MaximumViewLength = DEFAULT_MAXIMUM_VIEW_LENGTH;
|
|
|
|
MaximumPerDiskViewLength = DEFAULT_MAXIMUM_PER_DISK_VIEW_LENGTH;
|
|
|
|
#if SUPPORT_DISK_NUMBERS
|
|
DiskNumbersBitmapSize = DEFAULT_DISK_NUMBERS_BITMAP_SIZE;
|
|
#endif // SUPPORT_DISK_NUMBERS
|
|
|
|
//
|
|
// Set up the query table.
|
|
//
|
|
|
|
RtlZeroMemory( queryTable, sizeof(queryTable) );
|
|
|
|
//
|
|
// We're looking for subkey "Parameters" under the given registry key.
|
|
//
|
|
|
|
queryEntry = &queryTable[0];
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_SUBKEY;
|
|
queryEntry->Name = L"Parameters";
|
|
queryEntry->EntryContext = NULL;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
//
|
|
// These are the values we want to read.
|
|
//
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"ReportDetectedDevice";
|
|
queryEntry->EntryContext = &ReportDetectedDevice;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"MarkRamdisksAsRemovable";
|
|
queryEntry->EntryContext = &MarkRamdisksAsRemovable;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"MinimumViewCount";
|
|
queryEntry->EntryContext = &MinimumViewCount;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"DefaultViewCount";
|
|
queryEntry->EntryContext = &DefaultViewCount;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"MaximumViewCount";
|
|
queryEntry->EntryContext = &MaximumViewCount;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"MinimumViewLength";
|
|
queryEntry->EntryContext = &MinimumViewLength;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"DefaultViewLength";
|
|
queryEntry->EntryContext = &DefaultViewLength;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"MaximumViewLength";
|
|
queryEntry->EntryContext = &MaximumViewLength;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"MaximumPerDiskViewLength";
|
|
queryEntry->EntryContext = &MaximumPerDiskViewLength;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
#if SUPPORT_DISK_NUMBERS
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"DiskNumbersBitmapSize";
|
|
queryEntry->EntryContext = &DiskNumbersBitmapSize;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
#endif // SUPPORT_DISK_NUMBERS
|
|
|
|
//
|
|
// Do the query.
|
|
//
|
|
|
|
status = RtlQueryRegistryValues(
|
|
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
|
|
RegistryPath->Buffer,
|
|
queryTable,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Check the validity of the parameters.
|
|
//
|
|
|
|
if ( MinimumViewCount < MINIMUM_MINIMUM_VIEW_COUNT ) {
|
|
MinimumViewCount = MINIMUM_MINIMUM_VIEW_COUNT;
|
|
} else if ( MinimumViewCount > MAXIMUM_MINIMUM_VIEW_COUNT ) {
|
|
MinimumViewCount = MAXIMUM_MINIMUM_VIEW_COUNT;
|
|
}
|
|
|
|
if ( DefaultViewCount < MinimumViewCount ) {
|
|
DefaultViewCount = MinimumViewCount;
|
|
} else if ( DefaultViewCount > MAXIMUM_DEFAULT_VIEW_COUNT ) {
|
|
DefaultViewCount = MAXIMUM_DEFAULT_VIEW_COUNT;
|
|
}
|
|
|
|
if ( MaximumViewCount < DefaultViewCount ) {
|
|
MaximumViewCount = DefaultViewCount;
|
|
} else if ( MaximumViewCount > MAXIMUM_MAXIMUM_VIEW_COUNT ) {
|
|
MaximumViewCount = MAXIMUM_MAXIMUM_VIEW_COUNT;
|
|
}
|
|
|
|
if ( MinimumViewLength < MINIMUM_MINIMUM_VIEW_LENGTH ) {
|
|
MinimumViewLength = MINIMUM_MINIMUM_VIEW_LENGTH;
|
|
} else if ( MinimumViewLength > MAXIMUM_MINIMUM_VIEW_LENGTH ) {
|
|
MinimumViewLength = MAXIMUM_MINIMUM_VIEW_LENGTH;
|
|
}
|
|
|
|
if ( DefaultViewLength < MinimumViewLength ) {
|
|
DefaultViewLength = MinimumViewLength;
|
|
} else if ( DefaultViewLength > MAXIMUM_DEFAULT_VIEW_LENGTH ) {
|
|
DefaultViewLength = MAXIMUM_DEFAULT_VIEW_LENGTH;
|
|
}
|
|
|
|
if ( MaximumViewLength < DefaultViewLength ) {
|
|
MaximumViewLength = DefaultViewLength;
|
|
} else if ( MaximumViewLength > MAXIMUM_MAXIMUM_VIEW_LENGTH ) {
|
|
MaximumViewLength = MAXIMUM_MAXIMUM_VIEW_LENGTH;
|
|
}
|
|
|
|
if ( MaximumPerDiskViewLength < MINIMUM_MAXIMUM_PER_DISK_VIEW_LENGTH ) {
|
|
MaximumPerDiskViewLength = MINIMUM_MAXIMUM_PER_DISK_VIEW_LENGTH;
|
|
} else if ( MaximumViewLength > MAXIMUM_MAXIMUM_PER_DISK_VIEW_LENGTH ) {
|
|
MaximumPerDiskViewLength = MAXIMUM_MAXIMUM_PER_DISK_VIEW_LENGTH;
|
|
}
|
|
|
|
#if SUPPORT_DISK_NUMBERS
|
|
if ( DiskNumbersBitmapSize < MINIMUM_DISK_NUMBERS_BITMAP_SIZE ) {
|
|
DiskNumbersBitmapSize = MINIMUM_DISK_NUMBERS_BITMAP_SIZE;
|
|
} else if ( DiskNumbersBitmapSize > MAXIMUM_DISK_NUMBERS_BITMAP_SIZE ) {
|
|
DiskNumbersBitmapSize = MAXIMUM_DISK_NUMBERS_BITMAP_SIZE;
|
|
}
|
|
#endif // SUPPORT_DISK_NUMBERS
|
|
|
|
DBGPRINT( DBG_INIT, DBG_INFO, ("DefaultViewCount = 0x%x\n", DefaultViewCount) );
|
|
DBGPRINT( DBG_INIT, DBG_INFO, ("MaximumViewCount = 0x%x\n", MaximumViewCount) );
|
|
DBGPRINT( DBG_INIT, DBG_INFO, ("DefaultViewLength = 0x%x\n", DefaultViewLength) );
|
|
DBGPRINT( DBG_INIT, DBG_INFO, ("MaximumViewLength = 0x%x\n", MaximumViewLength) );
|
|
DBGPRINT( DBG_INIT, DBG_INFO, ("MaximumPerDiskViewLength = 0x%x\n", MaximumPerDiskViewLength) );
|
|
|
|
#if SUPPORT_DISK_NUMBERS
|
|
DBGPRINT( DBG_INIT, DBG_INFO, ("DiskNumbersBitmapSize = 0x%x\n", DiskNumbersBitmapSize) );
|
|
#endif // SUPPORT_DISK_NUMBERS
|
|
|
|
return;
|
|
|
|
} // QueryParameters
|
|
|
|
#if DBG
|
|
|
|
NTSTATUS
|
|
RamdiskInvalidDeviceRequest (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the I/O system when an IRP that we don't
|
|
process is issued.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the object that represents the device on which
|
|
I/O is to be performed
|
|
|
|
Irp - a pointer to the I/O Request Packet for this request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_INVALID_DEVICE_REQUEST
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// We really do recognize CLEANUP and SHUTDOWN IRPs. For any other IRP,
|
|
// print a message and break into the debugger.
|
|
//
|
|
|
|
switch ( IoGetCurrentIrpStackLocation(Irp)->MajorFunction ) {
|
|
|
|
case IRP_MJ_CLEANUP:
|
|
case IRP_MJ_SHUTDOWN:
|
|
break;
|
|
|
|
default:
|
|
|
|
DBGPRINT( DBG_IOCTL, DBG_ERROR,
|
|
("Ramdisk: Unrecognized IRP: major/minor = %x/%x\n",
|
|
IoGetCurrentIrpStackLocation(Irp)->MajorFunction,
|
|
IoGetCurrentIrpStackLocation(Irp)->MinorFunction) );
|
|
ASSERT( FALSE );
|
|
|
|
}
|
|
|
|
//
|
|
// If this is a power IRP, we need to start the next one.
|
|
//
|
|
|
|
if ( IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_POWER ) {
|
|
PoStartNextPowerIrp( Irp );
|
|
}
|
|
|
|
//
|
|
// Tell the I/O system that we don't recognize this IRP.
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
} // RamdiskInvalidDeviceRequest
|
|
|
|
VOID
|
|
QueryDebugParameters (
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called from DriverEntry() to get the debug parameters
|
|
from the registry. If the registry query fails, then default values are
|
|
used.
|
|
|
|
Arguments:
|
|
|
|
RegistryPath - a pointer to the service path for the registry parameters
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
RTL_QUERY_REGISTRY_TABLE queryTable[5];
|
|
PRTL_QUERY_REGISTRY_TABLE queryEntry;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT( DBG_INIT, DBG_VERBOSE, ("%s", "QueryDebugParameters\n") );
|
|
|
|
ASSERT( RegistryPath->Buffer != NULL );
|
|
|
|
//
|
|
// Set the default values.
|
|
//
|
|
|
|
BreakOnEntry = DEFAULT_BREAK_ON_ENTRY;
|
|
DebugComponents = DEFAULT_DEBUG_COMPONENTS;
|
|
DebugLevel = DEFAULT_DEBUG_LEVEL;
|
|
|
|
//
|
|
// Set up the query table.
|
|
//
|
|
|
|
RtlZeroMemory( queryTable, sizeof(queryTable) );
|
|
|
|
//
|
|
// We're looking for subkey "Debug" under the given registry key.
|
|
//
|
|
|
|
queryEntry = &queryTable[0];
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_SUBKEY;
|
|
queryEntry->Name = L"Debug";
|
|
queryEntry->EntryContext = NULL;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
//
|
|
// These are the values we want to read.
|
|
//
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"BreakOnEntry";
|
|
queryEntry->EntryContext = &BreakOnEntry;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"DebugComponents";
|
|
queryEntry->EntryContext = &DebugComponents;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
queryEntry++;
|
|
queryEntry->Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryEntry->Name = L"DebugLevel";
|
|
queryEntry->EntryContext = &DebugLevel;
|
|
queryEntry->DefaultType = REG_NONE;
|
|
queryEntry->DefaultData = NULL;
|
|
queryEntry->DefaultLength = 0;
|
|
|
|
//
|
|
// Do the query.
|
|
//
|
|
|
|
status = RtlQueryRegistryValues(
|
|
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
|
|
RegistryPath->Buffer,
|
|
queryTable,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
DBGPRINT( DBG_INIT, DBG_INFO, ("BreakOnEntry = 0x%x\n", BreakOnEntry) );
|
|
DBGPRINT( DBG_INIT, DBG_INFO, ("DebugComponents = 0x%x\n", DebugComponents) );
|
|
DBGPRINT( DBG_INIT, DBG_INFO, ("DebugLevel = 0x%x\n", DebugLevel) );
|
|
|
|
return;
|
|
|
|
} // QueryDebugParameters
|
|
|
|
#endif
|
|
|