SCSI miniport 驾驶一个简单的框架

        前段时间,只需用一台新电脑,由于资金有限没有匹配了心仪已久的SSD。我没感觉到飞翔的感觉,总不甘心,仔细想想。我死了相当大的存储,我们可以假设部分内存作为硬盘驱动器把它弄出来。不会比固态硬盘的速度快,我们開始吧。

        首先。我们要做的就是写一个硬盘控制器的驱动,我们知道。存储类型的驱动一般都遵守 class/port/miniport driver 这种结构。微软已经完毕了磁盘类的驱动,以及 SCSI 总线的 Port 驱动,我们仅仅须要完毕 SCSI 总线上硬盘控制器的 Miniport 驱动就能够了。

拿出 DDK 的源代码分析一遍,微软果然不负众望地提供了一个驱动的源代码,我用的是DDK 7600.16385.1,里面有一个 ramdisk 的源代码,但读起来就发现。它是用 wdf 框架来实现的。我对 wdf 框架不熟悉。决定自己用 wdm 框架来又一次实现一遍。

        接着便是各种资料的查询。最后最终摸清了SCSI miniport 驱动的大体框架。为了给一个极致简单的框架。我省去了很多冗余的代码,代码例如以下:

#define DBG 1

#include <ntddk.h>
#include <srb.h>
#include <scsi.h>

#define MODULE_NAME_PREFIX       "RamDisk: "
#define KdPrintThisFunction()    KdPrint((MODULE_NAME_PREFIX"%s
", __FUNCTION__))

#define RAMDISK_SECTOR_SIZE      512
#define RAMDISK_CAPACITY         16 * 1024 *1024        

//typedef struct _DEVICE_EXTENSION {

//} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

// Miniport 的一些回调函数
BOOLEAN Initialize(__in PVOID DeviceExtension);
BOOLEAN ResetBus(__in PVOID DeviceExtension, __in ULONG PathId);
BOOLEAN StartIo(__in PVOID DeviceExtension, __in PSCSI_REQUEST_BLOCK Srb);
BOOLEAN Interrupt(__in PVOID DeviceExtension);
ULONG FindAdapter(
    __in PVOID DeviceExtension,
    __in PVOID HwContext,
    __in PVOID BusInformation,
    __in PCHAR ArgumentString,
    __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo,
    __out PBOOLEAN Again
    );
BOOLEAN AdapterState(__in PVOID DeviceExtension, __in PVOID Context, __in BOOLEAN SaveState);
SCSI_ADAPTER_CONTROL_STATUS AdapterControl(PVOID DeviceExtension,SCSI_ADAPTER_CONTROL_TYPE ctlType,PVOID pParameters);


VOID DriverUnload(__in struct _DRIVER_OBJECT *DriverObject);

PVOID RamDiskMemroy;

NTSTATUS 
DriverEntry( 
    __in struct _DRIVER_OBJECT  *DriverObject,
    __in PUNICODE_STRING  RegistryPath 
    )
{
    HW_INITIALIZATION_DATA HwInitData;

    KdPrintThisFunction();

    RtlZeroMemory(&HwInitData, sizeof(HW_INITIALIZATION_DATA));
    HwInitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);

    HwInitData.HwInitialize = Initialize;
    HwInitData.HwResetBus = ResetBus;
    HwInitData.HwStartIo = StartIo;
    HwInitData.HwInterrupt = NULL;                         // 不须要中断服务
    HwInitData.HwFindAdapter = FindAdapter;
    HwInitData.HwAdapterState = AdapterState;
    HwInitData.HwAdapterControl = AdapterControl;

    HwInitData.AdapterInterfaceType = Isa;
    HwInitData.DeviceExtensionSize = 0;
    HwInitData.SrbExtensionSize = 0;    
    HwInitData.NumberOfAccessRanges = 0;

    HwInitData.MapBuffers = TRUE;
    HwInitData.NeedPhysicalAddresses = FALSE;
    HwInitData.TaggedQueuing = FALSE;
    HwInitData.AutoRequestSense = TRUE;
    HwInitData.MultipleRequestPerLu = FALSE;
    HwInitData.ReceiveEvent = FALSE;
    
    // 初始化
    ScsiPortInitialize(DriverObject, RegistryPath, &HwInitData, NULL);

    DriverObject->DriverUnload = DriverUnload;
 
    RamDiskMemroy = ExAllocatePool(NonPagedPool, RAMDISK_CAPACITY);
    if (RamDiskMemroy == NULL) {
        KdPrint(("RamDisk: Allocate memory failed!
"));
        return STATUS_FAILED_DRIVER_ENTRY;
    }

    KdPrint(("MyRamDisk: RamDiskMemroy - 0x%p
", RamDiskMemroy));

    return STATUS_SUCCESS;
}

VOID
DriverUnload(
    __in struct _DRIVER_OBJECT *DriverObject
    )
{
    KdPrintThisFunction();
    ExFreePool(RamDiskMemroy);
}

BOOLEAN 
Initialize(
    __in PVOID DeviceExtension
    )
{
    KdPrintThisFunction();
    return TRUE;
}

BOOLEAN
ResetBus(
    __in PVOID DeviceExtension, 
    __in ULONG PathId
    )
{
    KdPrintThisFunction();
    return TRUE;
}

BOOLEAN
ReadCapacityData(
    PSCSI_REQUEST_BLOCK Srb
    )
{
    PREAD_CAPACITY_DATA CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
    ULONG Value = 0;

    KdPrintThisFunction();

    // this two value should in Big Endian
    Value = RAMDISK_CAPACITY / RAMDISK_SECTOR_SIZE - 1;
    REVERSE_LONG(&Value);
    CapacityData->LogicalBlockAddress = Value;
    Value = RAMDISK_SECTOR_SIZE;
    REVERSE_LONG(&Value);
    CapacityData->BytesPerBlock = Value;

    return TRUE;
}

BOOLEAN
Inquiry(
    PSCSI_REQUEST_BLOCK Srb
    )
{
    PINQUIRYDATA InquiryData = (PINQUIRYDATA)Srb->DataBuffer;
    PCDB Cdb = &Srb->Cdb;

    KdPrintThisFunction();

    InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
    InquiryData->DeviceTypeQualifier = DEVICE_CONNECTED;
    InquiryData->DeviceTypeModifier = 0;
    InquiryData->RemovableMedia = 0;
    InquiryData->ResponseDataFormat = 2;
    InquiryData->Versions = 0;
    InquiryData->AdditionalLength = sizeof(INQUIRYDATA) - 5;
    
    // 这些数据关系到系统中设备管理器的显示
    RtlMoveMemory(InquiryData->VendorId,"HENZOX",6);
    RtlMoveMemory(InquiryData->ProductId,"RamDisk - Henzox",16);
    RtlMoveMemory(InquiryData->ProductRevisionLevel,"1010",4);

    KdPrint(("Inquiry: succeeded(target-lun)=(%d,%d)
", Srb->TargetId, Srb->Lun));

    return TRUE;
}

BOOLEAN
ReadDisk(
    PSCSI_REQUEST_BLOCK Srb
    )
{
    ULONG Start = 0;                     // 開始扇区
    USHORT Count = 0;                    // 读取大小,以扇区为单位

    PCDB Cdb = &Srb->Cdb[0];
    Start = *(PULONG)&Cdb->CDB10.LogicalBlockByte0;
    REVERSE_LONG(&Start);
    Count = *(PUSHORT)&Cdb->CDB10.TransferBlocksMsb;
    REVERSE_SHORT(&Count);

    if ((Start + Count) * RAMDISK_SECTOR_SIZE > RAMDISK_CAPACITY) {
        KdPrint(("ReadDisk: overflow!
"));
        return FALSE;
    }
    // Count * RAMDISK_SECTOR_SIZE equals to Srb->DataTransferLength
    KdPrint(("ReadDisk: Start - %d, Size - %d
", Start * RAMDISK_SECTOR_SIZE, Srb->DataTransferLength));
    RtlMoveMemory(Srb->DataBuffer, (PUCHAR)RamDiskMemroy + Start * RAMDISK_SECTOR_SIZE, Srb->DataTransferLength);
    return TRUE;
}

BOOLEAN
WriteDisk(
    PSCSI_REQUEST_BLOCK Srb
    )
{
    ULONG Start = 0;                     // 開始地址
    USHORT Count = 0;                    // 读取大小,以扇区为单位

    PCDB Cdb = &Srb->Cdb[0];
    Start = *(PULONG)&Cdb->CDB10.LogicalBlockByte0;
    REVERSE_LONG(&Start);
    Count = *(PUSHORT)&Cdb->CDB10.TransferBlocksMsb;
    REVERSE_SHORT(&Count);

    if (Start + Count * RAMDISK_SECTOR_SIZE > RAMDISK_CAPACITY) {
        KdPrint(("WriteDisk: overflow!
"));
        return FALSE;
    }

    KdPrint(("WriteDisk: Start - %d, Size - %d
", Start * RAMDISK_SECTOR_SIZE, Srb->DataTransferLength));
    RtlMoveMemory((PUCHAR)RamDiskMemroy + Start * RAMDISK_SECTOR_SIZE, Srb->DataBuffer, Srb->DataTransferLength);
    return TRUE;

}

BOOLEAN
ExecuteScsi(
    PSCSI_REQUEST_BLOCK Srb
    )
{
    BOOLEAN ReturnValue = FALSE;
    PCDB Cdb = (PCDB)&Srb->Cdb[0];
    
    KdPrintThisFunction();

    switch (Cdb->CDB10.OperationCode) {
    case 0x28:
        // Read disk
        ReturnValue = ReadDisk(Srb);
        break;
    case 0x2A:
        // Write disk
        ReturnValue = WriteDisk(Srb);
        break;
    case 0x25:
        // Read the capacity of the disk
        ReturnValue = ReadCapacityData(Srb);
        break;
    case 0x12:
        // Disk inquiry
        ReturnValue = Inquiry(Srb);
        break;
    default:
        KdPrint(("ExecuteScsi: Unknown operation code(0x%p)
", Cdb->CDB10.OperationCode));
        ReturnValue = TRUE;
    }

    return ReturnValue;
}

BOOLEAN
DoIoControl(
    PSCSI_REQUEST_BLOCK Srb
    )
{
    KdPrintThisFunction();

    return TRUE;
}

BOOLEAN 
StartIo(
    __in PVOID DeviceExtension, 
    __in PSCSI_REQUEST_BLOCK Srb
    )
{
    BOOLEAN ReturnValue = TRUE;

    KdPrintThisFunction();

    Srb->SrbStatus = SRB_STATUS_SUCCESS;
    Srb->ScsiStatus = SCSISTAT_GOOD;

    switch(Srb->Function) {
    case SRB_FUNCTION_SHUTDOWN:
        KdPrint(("StartIo: SRB_FUNCTION_SHUTDOWN
"));
        break;
    case SRB_FUNCTION_FLUSH:
        KdPrint(("StartIo: SRB_FUNCTION_FLUSH
"));
        break;
    case SRB_FUNCTION_EXECUTE_SCSI:
        // 运行 SCSI 命令
        ReturnValue = ExecuteScsi(Srb);
        break;
    case SRB_FUNCTION_IO_CONTROL:
        Srb->SrbStatus = SRB_STATUS_PENDING;
        ReturnValue = DoIoControl(Srb);
        break;

    default:
        Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
    }

    ScsiPortNotification(RequestComplete, DeviceExtension, Srb);
    ScsiPortNotification(NextRequest, DeviceExtension);
    return ReturnValue;
}

BOOLEAN
Interrupt(
    __in PVOID DeviceExtension
    )
{
    KdPrintThisFunction();
    return TRUE;
}

ULONG FindAdapter(
    __in PVOID DeviceExtension,
    __in PVOID HwContext,
    __in PVOID BusInformation,
    __in PCHAR ArgumentString,
    __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo,
    __out PBOOLEAN Again
    )
{
    KdPrintThisFunction();

    ConfigInfo->AdapterInterfaceType = Isa;
    ConfigInfo->AlignmentMask = 0x00000003;
    ConfigInfo->AutoRequestSense = TRUE;
    ConfigInfo->BufferAccessScsiPortControlled = FALSE;
    ConfigInfo->BusInterruptLevel = 0;
    ConfigInfo->BusInterruptVector = 0;
    ConfigInfo->Dma32BitAddresses = TRUE;
    ConfigInfo->Master = TRUE;
    ConfigInfo->CachesData = TRUE;
    ConfigInfo->NumberOfBuses = 1;
    ConfigInfo->MaximumNumberOfTargets = 1;
    ConfigInfo->MaximumTransferLength = 0x10000;
    ConfigInfo->MultipleRequestPerLu = FALSE;
    ConfigInfo->NumberOfPhysicalBreaks = 0x00F8;
    ConfigInfo->ScatterGather = TRUE;
    ConfigInfo->TaggedQueuing = FALSE;

    *Again = FALSE;
    return SP_RETURN_FOUND;
}

SCSI_ADAPTER_CONTROL_STATUS 
AdapterControl(
    PVOID DeviceExtension,
    SCSI_ADAPTER_CONTROL_TYPE CtlType,
    PVOID Parameters
    )
{
    PSCSI_SUPPORTED_CONTROL_TYPE_LIST ScsiList=NULL;
    SCSI_ADAPTER_CONTROL_STATUS status = ScsiAdapterControlSuccess;

    KdPrintThisFunction();

    switch (CtlType<span style="font-family: Arial, Helvetica, sans-serif;">) </span>{
    case ScsiQuerySupportedControlTypes:
        KdPrint(("AdapterControl: ScsiQuerySupportedControlTypes
"));
        ScsiList = (PSCSI_SUPPORTED_CONTROL_TYPE_LIST)Parameters;
        <span style="font-family: Arial, Helvetica, sans-serif;">ScsiList</span>->SupportedTypeList[ScsiStopAdapter] = TRUE;
        ScsiList->SupportedTypeList[ScsiRestartAdapter] = TRUE;
        ScsiList->SupportedTypeList[ScsiQuerySupportedControlTypes] = TRUE;
        break;

    case ScsiStopAdapter:
        KdPrint(("AdapterControl: ScsiStopAdapter
"));
        break;

    case ScsiRestartAdapter:
        KdPrint(("AdapterControl: ScsiRestartAdapter
"));
        break;

    default:
        status = ScsiAdapterControlUnsuccessful;
        break;
    }

    return status;
}

BOOLEAN
AdapterState(
    __in PVOID DeviceExtension,
    __in PVOID Context,
    __in BOOLEAN SaveState
    )
{
    KdPrintThisFunction();
    return TRUE;
}

        简要地说明一下。Scsiminiport 驱动事实上非常easy,就是调用ScsiPortInitialize 初始化之后,完毕各种 Srb 命令就能够了,源代码中本来想用中文凝视和英文凝视混杂。这是我的一个不好习惯,但凝视明了。极易读懂。

        编译出来之后。能够直接安装。然后在磁盘管理里会新出现一个磁盘。初始化这个磁盘就能够了,我只设了 16M 以用来实现,能够通过改动源代码达到你想要的大小。把它用来当浏览器的暂时文件夹存储盘是相当不错的。每次重新启动,该盘会销毁,在微软的 wdf 源代码中有怎样使该盘自己主动初始化的源代码。你也能够加入一些其他功能,比方关机时把该盘中的功能 dump 到一个文件中,设备重新启动后再载入。就可以达到固化的效果。事实上网上有许多的成熟的产品能够使用,自己写一个也不过为了练习而已,驱动没有经过大量測试,这可能会导致蓝屏,而且它也可以在虚拟机上更改。



版权声明:本文博客原创文章,博客,未经同意,不得转载。

原文地址:https://www.cnblogs.com/lcchuguo/p/4654010.html