• 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 到一个文件中,设备重新启动后再载入。就可以达到固化的效果。事实上网上有许多的成熟的产品能够使用,自己写一个也不过为了练习而已,驱动没有经过大量測试,这可能会导致蓝屏,而且它也可以在虚拟机上更改。



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

  • 相关阅读:
    基于Appium的自动化case开发及case分层结构设计
    功能自动化接入持续集成方案
    Windows上部署Appium自动化测试框架
    Mac上部署Appium测试框架
    Appium原理简述
    开篇
    数据结构和算法动态可视化
    Request实现简易注册登录
    过滤器解决中文乱码
    简易登录拦截(没有登录前直接访问主页则跳转到登录页)
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4654010.html
Copyright © 2020-2023  润新知