WDF虚拟磁盘驱动程序

#ifndef _RAMDISK_H_
#define _RAMDISK_H_

#pragma warning(disable:4201)  // nameless struct/union warning

#include <ntddk.h>
#include <ntdddisk.h>

#pragma warning(default:4201)

#include <wdf.h>
#define NTSTRSAFE_LIB
#include <ntstrsafe.h>
#include "forward_progress.h"

#define NT_DEVICE_NAME                  L"//Device//Ramdisk"
#define DOS_DEVICE_NAME                 L"//DosDevices//"

#define RAMDISK_TAG                     'DmaR'  // "RamD"
#define DOS_DEVNAME_LENGTH              (sizeof(DOS_DEVICE_NAME)+sizeof(WCHAR)*10)
#define DRIVE_LETTER_LENGTH             (sizeof(WCHAR)*10)

#define DRIVE_LETTER_BUFFER_SIZE        10
#define DOS_DEVNAME_BUFFER_SIZE         (sizeof(DOS_DEVICE_NAME) / 2) + 10

#define RAMDISK_MEDIA_TYPE              0xF8
#define DIR_ENTRIES_PER_SECTOR          16

#define DEFAULT_DISK_SIZE               (1024*1024)     // 1 MB
#define DEFAULT_ROOT_DIR_ENTRIES        512
#define DEFAULT_SECTORS_PER_CLUSTER     2
#define DEFAULT_DRIVE_LETTER            L"Z:"

typedef struct _DISK_INFO {
    ULONG   DiskSize;           // Ramdisk size in bytes
    ULONG   RootDirEntries;     // No. of root directory entries
    ULONG   SectorsPerCluster;  // Sectors per cluster
    UNICODE_STRING DriveLetter; // Drive letter to be used
} DISK_INFO, *PDISK_INFO;

typedef struct _DEVICE_EXTENSION {
    PUCHAR              DiskImage;                  // Pointer to beginning of disk image
    DISK_GEOMETRY       DiskGeometry;               // Drive parameters built by Ramdisk
    DISK_INFO           DiskRegInfo;                // Disk parameters from the registry
    UNICODE_STRING      SymbolicLink;               // Dos symbolic name; Drive letter
    WCHAR               DriveLetterBuffer[DRIVE_LETTER_BUFFER_SIZE];
    WCHAR               DosDeviceNameBuffer[DOS_DEVNAME_BUFFER_SIZE];
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, DeviceGetExtension)

typedef struct _QUEUE_EXTENSION {
    PDEVICE_EXTENSION DeviceExtension;
} QUEUE_EXTENSION, *PQUEUE_EXTENSION;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_EXTENSION, QueueGetExtension)

#pragma pack(1)

typedef struct  _BOOT_SECTOR
{
    UCHAR       bsJump[3];          // x86 jmp instruction, checked by FS
    CCHAR       bsOemName[8];       // OEM name of formatter
    USHORT      bsBytesPerSec;      // Bytes per Sector
    UCHAR       bsSecPerClus;       // Sectors per Cluster
    USHORT      bsResSectors;       // Reserved Sectors
    UCHAR       bsFATs;             // Number of FATs - we always use 1
    USHORT      bsRootDirEnts;      // Number of Root Dir Entries
    USHORT      bsSectors;          // Number of Sectors
    UCHAR       bsMedia;            // Media type - we use RAMDISK_MEDIA_TYPE
    USHORT      bsFATsecs;          // Number of FAT sectors
    USHORT      bsSecPerTrack;      // Sectors per Track - we use 32
    USHORT      bsHeads;            // Number of Heads - we use 2
    ULONG       bsHiddenSecs;       // Hidden Sectors - we set to 0
    ULONG       bsHugeSectors;      // Number of Sectors if > 32 MB size
    UCHAR       bsDriveNumber;      // Drive Number - not used
    UCHAR       bsReserved1;        // Reserved
    UCHAR       bsBootSignature;    // New Format Boot Signature - 0x29
    ULONG       bsVolumeID;         // VolumeID - set to 0x12345678
    CCHAR       bsLabel[11];        // Label - set to RamDisk
    CCHAR       bsFileSystemType[8];// File System Type - FAT12 or FAT16
    CCHAR       bsReserved2[448];   // Reserved
    UCHAR       bsSig2[2];          // Originial Boot Signature - 0x55, 0xAA
}   BOOT_SECTOR, *PBOOT_SECTOR;

typedef struct  _DIR_ENTRY
{
    UCHAR       deName[8];          // File Name
    UCHAR       deExtension[3];     // File Extension
    UCHAR       deAttributes;       // File Attributes
    UCHAR       deReserved;         // Reserved
    USHORT      deTime;             // File Time
    USHORT      deDate;             // File Date
    USHORT      deStartCluster;     // First Cluster of file
    ULONG       deFileSize;         // File Length
}   DIR_ENTRY, *PDIR_ENTRY;

#pragma pack()

//
// Directory Entry Attributes
//

#define DIR_ATTR_READONLY   0x01
#define DIR_ATTR_HIDDEN     0x02
#define DIR_ATTR_SYSTEM     0x04
#define DIR_ATTR_VOLUME     0x08
#define DIR_ATTR_DIRECTORY  0x10
#define DIR_ATTR_ARCHIVE    0x20

DRIVER_INITIALIZE DriverEntry;

EVT_WDF_DRIVER_DEVICE_ADD RamDiskEvtDeviceAdd;

EVT_WDF_DEVICE_CONTEXT_CLEANUP RamDiskEvtDeviceContextCleanup;

EVT_WDF_IO_QUEUE_IO_READ RamDiskEvtIoRead;
EVT_WDF_IO_QUEUE_IO_WRITE RamDiskEvtIoWrite;
EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL RamDiskEvtIoDeviceControl;

VOID
RamDiskQueryDiskRegParameters(
    __in PWSTR RegistryPath,
    __in PDISK_INFO DiskRegInfo
    );

NTSTATUS
RamDiskFormatDisk(
    IN PDEVICE_EXTENSION DeviceExtension
    );

BOOLEAN
RamDiskCheckParameters(
    IN PDEVICE_EXTENSION devExt,
    IN LARGE_INTEGER ByteOffset,
    IN size_t Length
    );

EVT_WDF_OBJECT_CONTEXT_CLEANUP EvtForwardProgressRequestCleanup;
EVT_WDF_OBJECT_CONTEXT_DESTROY EvtForwardProgressRequestDestroy;
EVT_WDF_IO_WDM_IRP_FOR_FORWARD_PROGRESS EvtIoWdmIrpForForwardProgress;
EVT_WDF_IO_ALLOCATE_RESOURCES_FOR_RESERVED_REQUEST EvtIoAllocateResourcesForReservedRequest;
EVT_WDF_IO_ALLOCATE_REQUEST_RESOURCES EvtIoAllocateResources;

 

/*++

Copyright (c) Microsoft Corporation, All Rights Reserved

Module Name:

    Ramdisk.c

Abstract:

    This is the Ramdisk sample driver.  This version of the driver has been
    modified to support the driver frameworks. This driver basically creates
    a nonpaged pool and exposes that as a storage media. User can
    find the device in the disk manager and format the media to use
    as FAT or NTFS volume.

Environment:

    Kernel mode only.

--*/

#include "ramdisk.h"
#include "ntintsafe.h"

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, RamDiskEvtDeviceAdd)
#pragma alloc_text(PAGE, RamDiskEvtDeviceContextCleanup)
#pragma alloc_text(PAGE, RamDiskQueryDiskRegParameters)
#pragma alloc_text(PAGE, RamDiskFormatDisk)
#endif

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )

/*++

Routine Description:

    Installable driver initialization entry point.
    This entry point is called directly by the I/O system.

Arguments:

    DriverObject - pointer to the driver object

    RegistryPath - pointer to a unicode string representing the path
                   to driver-specific key in the registry

Return Value:

    STATUS_SUCCESS if successful.

--*/

{
    WDF_DRIVER_CONFIG config;

    KdPrint(("Windows Ramdisk Driver - Driver Framework Edition./n"));
    KdPrint(("Built %s %s/n", __DATE__, __TIME__));

    WDF_DRIVER_CONFIG_INIT( &config, RamDiskEvtDeviceAdd );

    return WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE);
}

VOID
RamDiskEvtIoRead(
    IN WDFQUEUE Queue,
    IN WDFREQUEST Request,
    IN size_t Length
    )
/*++

Routine Description:

    This event is called when the framework receives IRP_MJ_READ request.

Arguments:

    Queue -  Handle to the framework queue object that is associated with the
             I/O request.

    Request - Handle to a framework request object.

    Length - Length of the data buffer associated with the request.
             The default property of the queue is to not dispatch
             zero length read & write requests to the driver and
             complete is with status success. So we will never get
             a zero length request.

Return Value:

    VOID

--*/
{
    PDEVICE_EXTENSION      devExt = QueueGetExtension(Queue)->DeviceExtension;
    NTSTATUS               Status = STATUS_INVALID_PARAMETER;
    WDF_REQUEST_PARAMETERS Parameters;
    LARGE_INTEGER          ByteOffset;
    WDFMEMORY              hMemory;

    __analysis_assume(Length > 0);

    WDF_REQUEST_PARAMETERS_INIT(&Parameters);
    WdfRequestGetParameters(Request, &Parameters);

    ByteOffset.QuadPart = Parameters.Parameters.Read.DeviceOffset;

    if (RamDiskCheckParameters(devExt, ByteOffset, Length)) {

        Status = WdfRequestRetrieveOutputMemory(Request, &hMemory);
        if(NT_SUCCESS(Status)){

            Status = WdfMemoryCopyFromBuffer(hMemory,   // Destination
                                             0,         // Offset into the destination
                                             devExt->DiskImage + ByteOffset.LowPart, // source
                                             Length);
        }
    }

    WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length);
}

VOID
RamDiskEvtIoWrite(
    IN WDFQUEUE Queue,
    IN WDFREQUEST Request,
    IN size_t Length
    )

/*++

Routine Description:

    This event is invoked when the framework receives IRP_MJ_WRITE request.

Arguments:

    Queue -  Handle to the framework queue object that is associated with the
             I/O request.

    Request - Handle to a framework request object.

    Length - Length of the data buffer associated with the request.
             The default property of the queue is to not dispatch
             zero length read & write requests to the driver and
             complete is with status success. So we will never get
             a zero length request.

Return Value:

    VOID

--*/
{
    PDEVICE_EXTENSION      devExt = QueueGetExtension(Queue)->DeviceExtension;
    NTSTATUS               Status = STATUS_INVALID_PARAMETER;
    WDF_REQUEST_PARAMETERS Parameters;
    LARGE_INTEGER          ByteOffset;
    WDFMEMORY              hMemory;

    __analysis_assume(Length > 0);

    WDF_REQUEST_PARAMETERS_INIT(&Parameters);
    WdfRequestGetParameters(Request, &Parameters);

    ByteOffset.QuadPart = Parameters.Parameters.Write.DeviceOffset;

    if (RamDiskCheckParameters(devExt, ByteOffset, Length)) {

        Status = WdfRequestRetrieveInputMemory(Request, &hMemory);
        if(NT_SUCCESS(Status)){

            Status = WdfMemoryCopyToBuffer(hMemory, // Source
                                    0,              // offset in Source memory where the copy has to start
                                    devExt->DiskImage + ByteOffset.LowPart, // destination
                                    Length);
        }

    }

    WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length);
}

VOID
RamDiskEvtIoDeviceControl(
    IN WDFQUEUE Queue,
    IN WDFREQUEST Request,
    IN size_t OutputBufferLength,
    IN size_t InputBufferLength,
    IN ULONG IoControlCode
    )
/*++

Routine Description:

    This event is called when the framework receives IRP_MJ_DEVICE_CONTROL
    requests from the system.

Arguments:

    Queue - Handle to the framework queue object that is associated
            with the I/O request.
    Request - Handle to a framework request object.

    OutputBufferLength - length of the request's output buffer,
                        if an output buffer is available.
    InputBufferLength - length of the request's input buffer,
                        if an input buffer is available.

    IoControlCode - the driver-defined or system-defined I/O control code
                    (IOCTL) that is associated with the request.

Return Value:

    VOID

--*/
{
    NTSTATUS          Status = STATUS_INVALID_DEVICE_REQUEST;
    ULONG_PTR         information = 0;
    size_t            bufSize;
    PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    switch (IoControlCode) {
    case IOCTL_DISK_GET_PARTITION_INFO: {

            PPARTITION_INFORMATION outputBuffer;
            PBOOT_SECTOR bootSector = (PBOOT_SECTOR) devExt->DiskImage;

            information = sizeof(PARTITION_INFORMATION);

            Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(PARTITION_INFORMATION), &outputBuffer, &bufSize);
            if(NT_SUCCESS(Status) ) {

                outputBuffer->PartitionType =
                    (bootSector->bsFileSystemType[4] == '6') ? PARTITION_FAT_16 : PARTITION_FAT_12;

                outputBuffer->BootIndicator       = FALSE;
                outputBuffer->RecognizedPartition = TRUE;
                outputBuffer->RewritePartition    = FALSE;
                outputBuffer->StartingOffset.QuadPart = 0;
                outputBuffer->PartitionLength.QuadPart = devExt->DiskRegInfo.DiskSize;
                outputBuffer->HiddenSectors       = (ULONG) (1L);
                outputBuffer->PartitionNumber     = (ULONG) (-1L);

                Status = STATUS_SUCCESS;
            }
        }
        break;

    case IOCTL_DISK_GET_DRIVE_GEOMETRY:  {

            PDISK_GEOMETRY outputBuffer;

            //
            // Return the drive geometry for the ram disk. Note that
            // we return values which were made up to suit the disk size.
            //
            information = sizeof(DISK_GEOMETRY);

            Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(DISK_GEOMETRY), &outputBuffer, &bufSize);
            if(NT_SUCCESS(Status) ) {

                RtlCopyMemory(outputBuffer, &(devExt->DiskGeometry), sizeof(DISK_GEOMETRY));
                Status = STATUS_SUCCESS;
            }
        }
        break;

    case IOCTL_DISK_CHECK_VERIFY:
    case IOCTL_DISK_IS_WRITABLE:

        //
        // Return status success
        //

        Status = STATUS_SUCCESS;
        break;
    }

    WdfRequestCompleteWithInformation(Request, Status, information);
}

VOID
RamDiskEvtDeviceContextCleanup(
    IN WDFOBJECT Device
    )
/*++

Routine Description:

   EvtDeviceContextCleanup event callback cleans up anything done in
   EvtDeviceAdd, except those things that are automatically cleaned
   up by the Framework.

   In the case of this sample, everything is automatically handled.  In a
   driver derived from this sample, it's quite likely that this function could
   be deleted.

Arguments:

    Device - Handle to a framework device object.

Return Value:

    VOID

--*/
{
    PDEVICE_EXTENSION pDeviceExtension = DeviceGetExtension(Device);

    PAGED_CODE();

    if(pDeviceExtension->DiskImage) {
        ExFreePool(pDeviceExtension->DiskImage);
    }
}

NTSTATUS
RamDiskEvtDeviceAdd(
    IN WDFDRIVER Driver,
    IN PWDFDEVICE_INIT DeviceInit
    )
/*++
Routine Description:

    EvtDeviceAdd is called by the framework in response to AddDevice
    call from the PnP manager. We create and initialize a device object to
    represent a new instance of the device.

Arguments:

    Driver - Handle to a framework driver object created in DriverEntry

    DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.

Return Value:

    NTSTATUS

--*/
{
    WDF_OBJECT_ATTRIBUTES   deviceAttributes;
    NTSTATUS                status;
    WDFDEVICE               device;
    WDF_OBJECT_ATTRIBUTES   queueAttributes;
    WDF_IO_QUEUE_CONFIG     ioQueueConfig;
    PDEVICE_EXTENSION       pDeviceExtension;
    PQUEUE_EXTENSION        pQueueContext = NULL;
    WDFQUEUE                queue;
    DECLARE_CONST_UNICODE_STRING(ntDeviceName, NT_DEVICE_NAME);

    PAGED_CODE();

    UNREFERENCED_PARAMETER(Driver);

    //
    // Storage drivers have to name their FDOs. Since we are not unique'fying
    // the device name, we wouldn't be able to install more than one instance
    // of this ramdisk driver.
    //
    status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK);
    WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
    WdfDeviceInitSetExclusive(DeviceInit, FALSE);

    //
    // Since this is a pure software only driver, there is no need to register
    // any PNP/Power event callbacks. Framework will respond to these
    // events appropriately.
    //
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION);
    deviceAttributes.EvtCleanupCallback = RamDiskEvtDeviceContextCleanup;

    status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    //
    // Now that the WDF device object has been created, set up any context
    // that it requires.
    //

    pDeviceExtension = DeviceGetExtension(device);

    //
    // Configure a default queue so that requests that are not
    // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto
    // other queues get dispatched here.
    //
    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE (
        &ioQueueConfig,
        WdfIoQueueDispatchSequential
        );

    ioQueueConfig.EvtIoDeviceControl = RamDiskEvtIoDeviceControl;
    ioQueueConfig.EvtIoRead          = RamDiskEvtIoRead;
    ioQueueConfig.EvtIoWrite         = RamDiskEvtIoWrite;

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_EXTENSION);

    status = WdfIoQueueCreate( device,
                               &ioQueueConfig,
                               &queueAttributes,
                               &queue );
    if (!NT_SUCCESS(status)) {
        return status;
    }

     // Context is the Queue handle
    pQueueContext = QueueGetExtension(queue);

    //
    // Set the context for our default queue as our device extension.
    //
    pQueueContext->DeviceExtension = pDeviceExtension;

    //
    // Enable forward progress on the queue we just created.
    // NOTE: If you are planning to use this code without forward progress,
    // comment out the call to SetForwardProgressOnQueue below.
    //
    status = SetForwardProgressOnQueue(queue);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    //
    // Now do any RAM-Disk specific initialization
    //
    pDeviceExtension->DiskRegInfo.DriveLetter.Buffer =
        (PWSTR) &pDeviceExtension->DriveLetterBuffer;
    pDeviceExtension->DiskRegInfo.DriveLetter.MaximumLength =
        sizeof(pDeviceExtension->DriveLetterBuffer);

    //
    // Get the disk parameters from the registry
    //
    RamDiskQueryDiskRegParameters(
        WdfDriverGetRegistryPath(WdfDeviceGetDriver(device)),
        &pDeviceExtension->DiskRegInfo
        );

    //
    // Allocate memory for the disk image.
    //
    pDeviceExtension->DiskImage = ExAllocatePoolWithTag(
        NonPagedPool,
        pDeviceExtension->DiskRegInfo.DiskSize,
        RAMDISK_TAG
        );

    if (pDeviceExtension->DiskImage) {

        UNICODE_STRING deviceName;
        UNICODE_STRING win32Name;

        RamDiskFormatDisk(pDeviceExtension);

        status = STATUS_SUCCESS;

        //
        // Now try to create a symbolic link for the drive letter.
        //
        RtlInitUnicodeString(&win32Name, DOS_DEVICE_NAME);
        RtlInitUnicodeString(&deviceName, NT_DEVICE_NAME);

        pDeviceExtension->SymbolicLink.Buffer = (PWSTR)
            &pDeviceExtension->DosDeviceNameBuffer;
        pDeviceExtension->SymbolicLink.MaximumLength =
            sizeof(pDeviceExtension->DosDeviceNameBuffer);
        pDeviceExtension->SymbolicLink.Length = win32Name.Length;

        RtlCopyUnicodeString(&pDeviceExtension->SymbolicLink, &win32Name);
        RtlAppendUnicodeStringToString(&pDeviceExtension->SymbolicLink,
                                       &pDeviceExtension->DiskRegInfo.DriveLetter);

        status = WdfDeviceCreateSymbolicLink(device,
                                             &pDeviceExtension->SymbolicLink);
    }

    return status;
}

VOID
RamDiskQueryDiskRegParameters(
    __in PWSTR RegistryPath,
    __in PDISK_INFO DiskRegInfo
    )

/*++

Routine Description:

    This routine is called from the DriverEntry to get the debug
    parameters from the registry. If the registry query fails, then
    default values are used.

Arguments:

    RegistryPath    - Points the service path to get the registry parameters

Return Value:

    None

--*/

{

    RTL_QUERY_REGISTRY_TABLE rtlQueryRegTbl[5 + 1];  // Need 1 for NULL
    NTSTATUS                 Status;
    DISK_INFO                defDiskRegInfo;

    PAGED_CODE();

    ASSERT(RegistryPath != NULL);

    // Set the default values

    defDiskRegInfo.DiskSize          = DEFAULT_DISK_SIZE;
    defDiskRegInfo.RootDirEntries    = DEFAULT_ROOT_DIR_ENTRIES;
    defDiskRegInfo.SectorsPerCluster = DEFAULT_SECTORS_PER_CLUSTER;

    RtlInitUnicodeString(&defDiskRegInfo.DriveLetter, DEFAULT_DRIVE_LETTER);

    RtlZeroMemory(rtlQueryRegTbl, sizeof(rtlQueryRegTbl));

    //
    // Setup the query table
    //

    rtlQueryRegTbl[0].Flags         = RTL_QUERY_REGISTRY_SUBKEY;
    rtlQueryRegTbl[0].Name          = L"Parameters";
    rtlQueryRegTbl[0].EntryContext  = NULL;
    rtlQueryRegTbl[0].DefaultType   = (ULONG_PTR)NULL;
    rtlQueryRegTbl[0].DefaultData   = NULL;
    rtlQueryRegTbl[0].DefaultLength = (ULONG_PTR)NULL;

    //
    // Disk paramters
    //

    rtlQueryRegTbl[1].Flags         = RTL_QUERY_REGISTRY_DIRECT;
    rtlQueryRegTbl[1].Name          = L"DiskSize";
    rtlQueryRegTbl[1].EntryContext  = &DiskRegInfo->DiskSize;
    rtlQueryRegTbl[1].DefaultType   = REG_DWORD;
    rtlQueryRegTbl[1].DefaultData   = &defDiskRegInfo.DiskSize;
    rtlQueryRegTbl[1].DefaultLength = sizeof(ULONG);

    rtlQueryRegTbl[2].Flags         = RTL_QUERY_REGISTRY_DIRECT;
    rtlQueryRegTbl[2].Name          = L"RootDirEntries";
    rtlQueryRegTbl[2].EntryContext  = &DiskRegInfo->RootDirEntries;
    rtlQueryRegTbl[2].DefaultType   = REG_DWORD;
    rtlQueryRegTbl[2].DefaultData   = &defDiskRegInfo.RootDirEntries;
    rtlQueryRegTbl[2].DefaultLength = sizeof(ULONG);

    rtlQueryRegTbl[3].Flags         = RTL_QUERY_REGISTRY_DIRECT;
    rtlQueryRegTbl[3].Name          = L"SectorsPerCluster";
    rtlQueryRegTbl[3].EntryContext  = &DiskRegInfo->SectorsPerCluster;
    rtlQueryRegTbl[3].DefaultType   = REG_DWORD;
    rtlQueryRegTbl[3].DefaultData   = &defDiskRegInfo.SectorsPerCluster;
    rtlQueryRegTbl[3].DefaultLength = sizeof(ULONG);

    rtlQueryRegTbl[4].Flags         = RTL_QUERY_REGISTRY_DIRECT;
    rtlQueryRegTbl[4].Name          = L"DriveLetter";
    rtlQueryRegTbl[4].EntryContext  = &DiskRegInfo->DriveLetter;
    rtlQueryRegTbl[4].DefaultType   = REG_SZ;
    rtlQueryRegTbl[4].DefaultData   = defDiskRegInfo.DriveLetter.Buffer;
    rtlQueryRegTbl[4].DefaultLength = 0;

    Status = RtlQueryRegistryValues(
                 RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
                 RegistryPath,
                 rtlQueryRegTbl,
                 NULL,
                 NULL
             );

    if (NT_SUCCESS(Status) == FALSE) {

        DiskRegInfo->DiskSize          = defDiskRegInfo.DiskSize;
        DiskRegInfo->RootDirEntries    = defDiskRegInfo.RootDirEntries;
        DiskRegInfo->SectorsPerCluster = defDiskRegInfo.SectorsPerCluster;
        RtlCopyUnicodeString(&DiskRegInfo->DriveLetter, &defDiskRegInfo.DriveLetter);
    }

    KdPrint(("DiskSize          = 0x%lx/n", DiskRegInfo->DiskSize));
    KdPrint(("RootDirEntries    = 0x%lx/n", DiskRegInfo->RootDirEntries));
    KdPrint(("SectorsPerCluster = 0x%lx/n", DiskRegInfo->SectorsPerCluster));
    KdPrint(("DriveLetter       = %wZ/n",   &(DiskRegInfo->DriveLetter)));

    return;
}

NTSTATUS
RamDiskFormatDisk(
    IN PDEVICE_EXTENSION devExt
    )

/*++

Routine Description:

    This routine formats the new disk.

Arguments:

    DeviceObject - Supplies a pointer to the device object that represents
                   the device whose capacity is to be read.

Return Value:

    status is returned.

--*/
{

    PBOOT_SECTOR bootSector = (PBOOT_SECTOR) devExt->DiskImage;
    PUCHAR       firstFatSector;
    ULONG        rootDirEntries;
    ULONG        sectorsPerCluster;
    USHORT       fatType;        // Type FAT 12 or 16
    USHORT       fatEntries;     // Number of cluster entries in FAT
    USHORT       fatSectorCnt;   // Number of sectors for FAT
    PDIR_ENTRY   rootDir;        // Pointer to first entry in root dir

    PAGED_CODE();
    ASSERT(sizeof(BOOT_SECTOR) == 512);
    ASSERT(devExt->DiskImage != NULL);

    RtlZeroMemory(devExt->DiskImage, devExt->DiskRegInfo.DiskSize);

    devExt->DiskGeometry.BytesPerSector = 512;
    devExt->DiskGeometry.SectorsPerTrack = 32;     // Using Ramdisk value
    devExt->DiskGeometry.TracksPerCylinder = 2;    // Using Ramdisk value

    //
    // Calculate number of cylinders.
    //

    devExt->DiskGeometry.Cylinders.QuadPart = devExt->DiskRegInfo.DiskSize / 512 / 32 / 2;

    //
    // Our media type is RAMDISK_MEDIA_TYPE
    //

    devExt->DiskGeometry.MediaType = RAMDISK_MEDIA_TYPE;

    KdPrint((
        "Cylinders: %ld/n TracksPerCylinder: %ld/n SectorsPerTrack: %ld/n BytesPerSector: %ld/n",
        devExt->DiskGeometry.Cylinders.QuadPart, devExt->DiskGeometry.TracksPerCylinder,
        devExt->DiskGeometry.SectorsPerTrack, devExt->DiskGeometry.BytesPerSector
        ));

    rootDirEntries = devExt->DiskRegInfo.RootDirEntries;
    sectorsPerCluster = devExt->DiskRegInfo.SectorsPerCluster;

    //
    // Round Root Directory entries up if necessary
    //

    if (rootDirEntries & (DIR_ENTRIES_PER_SECTOR - 1)) {

        rootDirEntries =
            (rootDirEntries + (DIR_ENTRIES_PER_SECTOR - 1)) &
                ~ (DIR_ENTRIES_PER_SECTOR - 1);
    }

    KdPrint((
        "Root dir entries: %ld/n Sectors/cluster: %ld/n",
        rootDirEntries, sectorsPerCluster
        ));

    //
    // We need to have the 0xeb and 0x90 since this is one of the
    // checks the file system recognizer uses
    //

    bootSector->bsJump[0] = 0xeb;
    bootSector->bsJump[1] = 0x3c;
    bootSector->bsJump[2] = 0x90;

    //
    // Set OemName to "RajuRam "
    // NOTE: Fill all 8 characters, eg. sizeof(bootSector->bsOemName);
    //
    bootSector->bsOemName[0] = 'R';
    bootSector->bsOemName[1] = 'a';
    bootSector->bsOemName[2] = 'j';
    bootSector->bsOemName[3] = 'u';
    bootSector->bsOemName[4] = 'R';
    bootSector->bsOemName[5] = 'a';
    bootSector->bsOemName[6] = 'm';
    bootSector->bsOemName[7] = ' ';

    bootSector->bsBytesPerSec = (SHORT)devExt->DiskGeometry.BytesPerSector;
    bootSector->bsResSectors  = 1;
    bootSector->bsFATs        = 1;
    bootSector->bsRootDirEnts = (USHORT)rootDirEntries;

    bootSector->bsSectors     = (USHORT)(devExt->DiskRegInfo.DiskSize /
                                         devExt->DiskGeometry.BytesPerSector);
    bootSector->bsMedia       = (UCHAR)devExt->DiskGeometry.MediaType;
    bootSector->bsSecPerClus  = (UCHAR)sectorsPerCluster;

    //
    // Calculate number of sectors required for FAT
    //

    fatEntries =
        (bootSector->bsSectors - bootSector->bsResSectors -
            bootSector->bsRootDirEnts / DIR_ENTRIES_PER_SECTOR) /
                bootSector->bsSecPerClus + 2;

    //
    // Choose between 12 and 16 bit FAT based on number of clusters we
    // need to map
    //

    if (fatEntries > 4087) {
        fatType =  16;
        fatSectorCnt = (fatEntries * 2 + 511) / 512;
        fatEntries   = fatEntries + fatSectorCnt;
        fatSectorCnt = (fatEntries * 2 + 511) / 512;
    }
    else {
        fatType =  12;
        fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512;
        fatEntries   = fatEntries + fatSectorCnt;
        fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512;
    }

    bootSector->bsFATsecs       = fatSectorCnt;
    bootSector->bsSecPerTrack   = (USHORT)devExt->DiskGeometry.SectorsPerTrack;
    bootSector->bsHeads         = (USHORT)devExt->DiskGeometry.TracksPerCylinder;
    bootSector->bsBootSignature = 0x29;
    bootSector->bsVolumeID      = 0x12345678;

    //
    // Set Label to "RamDisk    "
    // NOTE: Fill all 11 characters, eg. sizeof(bootSector->bsLabel);
    //
    bootSector->bsLabel[0]  = 'R';
    bootSector->bsLabel[1]  = 'a';
    bootSector->bsLabel[2]  = 'm';
    bootSector->bsLabel[3]  = 'D';
    bootSector->bsLabel[4]  = 'i';
    bootSector->bsLabel[5]  = 's';
    bootSector->bsLabel[6]  = 'k';
    bootSector->bsLabel[7]  = ' ';
    bootSector->bsLabel[8]  = ' ';
    bootSector->bsLabel[9]  = ' ';
    bootSector->bsLabel[10] = ' ';

    //
    // Set FileSystemType to "FAT1?   "
    // NOTE: Fill all 8 characters, eg. sizeof(bootSector->bsFileSystemType);
    //
    bootSector->bsFileSystemType[0] = 'F';
    bootSector->bsFileSystemType[1] = 'A';
    bootSector->bsFileSystemType[2] = 'T';
    bootSector->bsFileSystemType[3] = '1';
    bootSector->bsFileSystemType[4] = '?';
    bootSector->bsFileSystemType[5] = ' ';
    bootSector->bsFileSystemType[6] = ' ';
    bootSector->bsFileSystemType[7] = ' ';

    bootSector->bsFileSystemType[4] = ( fatType == 16 ) ? '6' : '2';

    bootSector->bsSig2[0] = 0x55;
    bootSector->bsSig2[1] = 0xAA;

    //
    // The FAT is located immediately following the boot sector.
    //

    firstFatSector    = (PUCHAR)(bootSector + 1);
    firstFatSector[0] = (UCHAR)devExt->DiskGeometry.MediaType;
    firstFatSector[1] = 0xFF;
    firstFatSector[2] = 0xFF;

    if (fatType == 16) {
        firstFatSector[3] = 0xFF;
    }

    //
    // The Root Directory follows the FAT
    //
    rootDir = (PDIR_ENTRY)(bootSector + 1 + fatSectorCnt);

    //
    // Set device name to "MS-RAMDR"
    // NOTE: Fill all 8 characters, eg. sizeof(rootDir->deName);
    //
    rootDir->deName[0] = 'M';
    rootDir->deName[1] = 'S';
    rootDir->deName[2] = '-';
    rootDir->deName[3] = 'R';
    rootDir->deName[4] = 'A';
    rootDir->deName[5] = 'M';
    rootDir->deName[6] = 'D';
    rootDir->deName[7] = 'R';

    //
    // Set device extension name to "IVE"
    // NOTE: Fill all 3 characters, eg. sizeof(rootDir->deExtension);
    //
    rootDir->deExtension[0] = 'I';
    rootDir->deExtension[1] = 'V';
    rootDir->deExtension[2] = 'E';

    rootDir->deAttributes = DIR_ATTR_VOLUME;

    return STATUS_SUCCESS;
}

BOOLEAN
RamDiskCheckParameters(
    IN PDEVICE_EXTENSION devExt,
    IN LARGE_INTEGER ByteOffset,
    IN size_t Length
    )

{
    //
    // Check for invalid parameters.  It is an error for the starting offset
    // + length to go past the end of the buffer, or for the length to
    // not be a proper multiple of the sector size.
    //
    // Others are possible, but we don't check them since we trust the
    // file system.
    //

    if( devExt->DiskRegInfo.DiskSize < Length ||
        ByteOffset.QuadPart < 0 || // QuadPart is signed so check for negative values
        ((ULONGLONG)ByteOffset.QuadPart > (devExt->DiskRegInfo.DiskSize - Length)) ||
            (Length & (devExt->DiskGeometry.BytesPerSector - 1))) {

        //
        // Do not give an I/O boost for parameter errors.
        //

        KdPrint((
            "Error invalid parameter/n"
            "ByteOffset: %I64x/n"
            "Length: %d/n",
            ByteOffset.QuadPart,
            Length
         ));

        return FALSE;
    }

    return TRUE;
}

 

 

 

时间: 2024-10-03 17:20:42

WDF虚拟磁盘驱动程序的相关文章

Windows Azure主机更新:原因、时间和方式

Windows http://www.aliyun.com/zixun/aggregation/13357.html">Azure 的计算平台(其中包括 Web Role.Worker Role 和虚拟机)基于计算机虚拟化.对基础操作系统的深入访问使 Windows Azure 的平台即服务 (PaaS) 与许多现有软件组件.运行时和语言唯一兼容,当然,如果没有这种深入访问(包括用户自己提供操作系统映像的能力),Windows Azure 的虚拟机则不能归类为基础设施即服务 (IaaS).

wdf框架pci驱动-windows下wdf框架下pci驱动如何实现一驱多卡?

问题描述 windows下wdf框架下pci驱动如何实现一驱多卡? 请问我有多个PCI相同的设备插在了同一台主机上,可是只有一个设备功能正常. 请教我怎样修改驱动程序让它驱动多个相同设备呢?希望各位大虾提供些思路或代码,小弟是pci的初学者 解决方案 windows驱动之WDF---CharSample

windows驱动程序wdf--KMDF大致框架

继WDM后微软出了WDF,封装了WDM中的一些基本代码逻辑.本人菜鸟,也不知道本质上有何区别,只觉得是多了Wdf开头的函数,基本的编程框架上有点出入. KMDF是WDF的内核级部分,为了理清KMDF的结构,又觉得内核编程很复杂,HelloWorld类型的程序实在说明不了什么  修改一下<windows设备驱动WDF开发>的CharSample,查了WDK帮助文档加上注释以帮助自己理解KMDF的大致运作过程. CharSample原本是应用层输入数字字符,驱动读取输入缓冲区返还相应的中文,自己修

windows驱动程序wdf--KMDF获取应用程序数据缓冲区地址

有3种常用方式:METHOD_BUFFERED  METHOD_IN_DIRECT  METHOD_OUT_DIRECT   还有METHOD_NEITHER,<windows设备驱动WDF开发>描述为:源自win 9x的VxD的模式,不建议读者掌握.这个就不管了.   METHOD_BUFFERED:无论读和写都对应同一缓冲区   METHOD_IN_DIRECT\ METHOD_OUT_DIRECT:输入缓冲区可作为附加输出缓冲区,输出缓冲区可作为附加输入缓冲区,两者区别只在DMA读写要分

使用 C++ 编写内核模式驱动程序的优点与缺点

使用 C++ 编写内核模式驱动程序的优点与缺点      C++ 及其对象特性似乎与 Microsoft Windows Driver Model (WDM) 和 Windows Driver Foundation (WDF) 驱动程序的语义非常吻合.但是,对于内核模式驱动程序,C++ 语言的一些特性可能导致难以发现和解决的问题.为了帮助您进行合理选择,本文将与您分享来自 Microsoft 关于使用 C++ 为 Windows 家族操作系统编写内核模式驱动程序的调查的见解和建议. 此信息适用于

华硕网卡驱动程序导致IE9经常显示已停止工作

  首先请按一下[Windows + R]键,然后输入 msconfig 后在按一下 确定按钮. 请按一下[服务]标签页,然后找到[AtherosSvs]服务,并且取消勾选. 接下来,请再找到[ZAtherosBt&2Wlan Coex Agent],并且取消勾选,完成之后按一下[确定]. 最后请按一下[重新启动]. 重新启动您的电脑之后,您会发现再使用 Internet Explorer 浏览网页会有明显的改善,不过若要彻底解决此问题,建议您可以去华硕官网上找到相应的电脑型号,并更新网卡驱动程

Win8改进一键挂载VHD虚拟磁盘教程

Windows8发布到现在也有一段时间了,不知道又有多少朋友升级到Win8了呢?相信应该有不少吧,Windows8相比于以前的Windows而言的确是有着很多不同凡响的改进的,也确实让我们的用户体验更加的优秀了,在Windows 8发布之前的时候我们就向大家介绍过Windows 8一些非常人性化的改进,比如说支持直接挂载ISO文件,省去了我们安装虚拟光驱软件的麻烦,其实除了可以直接挂在ISO文件之外,在Windows 8中还支持直接双击挂载VHD文件,相比于Windows7而言,这又是一项改进了

使用Windows虚拟设备驱动程序(VxD)之2

八.VxD初始化 VMM初始化一个VxD时做下列工作: 1.装载实模式初始化段并调用实模式初始化过程.该过程可以完成阻止装载VxD,阻止启动Windows,指定设备实例数据和在内存中选择页面给 设备专用的工作. 2.装载VxD其它段到32位平坦内存模式的保护模式内存,并丢弃实模式初始化段. 3.发送Sys_Critical_Init消息到设备控制过程.禁止硬件中断,所以VxD应该尽可能地用较少的时间完成自身初始化. 4.发送Device_Init消息到设备控制过程.允许硬件中断,所以必须准备让V

Win8创建VHD虚拟磁盘图文教程

  Win8的VHD虚拟磁盘功能不知道大家体验过没,vhd是从Win7开始就有的一个功能,可以在C盘划分一定的空间出来,然后利用这个空间虚拟一个硬盘,一般用于安装多个操作系统.Win8也增加了对虚拟磁盘的支持,可以直接打开vhd.iso等文件,更加方便用户们使用.下面就带来Win8创建VHD虚拟磁盘图文教程. 操作方法 在传统桌面下,将鼠标指针移动到左下角,点击鼠标右键(或者使用Win+X快捷键),在打开的菜单中选择"磁盘管理"; 在磁盘管理窗口中,依次点击"操作"