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\n", __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!\n"));
        return STATUS_FAILED_DRIVER_ENTRY;
    }

    KdPrint(("MyRamDisk: RamDiskMemroy - 0x%p\n", 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)\n", 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!\n"));
        return FALSE;
    }
    // Count * RAMDISK_SECTOR_SIZE equals to Srb->DataTransferLength
    KdPrint(("ReadDisk: Start - %d, Size - %d\n", 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!\n"));
        return FALSE;
    }

    KdPrint(("WriteDisk: Start - %d, Size - %d\n", 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)\n", 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\n"));
        break;
    case SRB_FUNCTION_FLUSH:
        KdPrint(("StartIo: SRB_FUNCTION_FLUSH\n"));
        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\n"));
        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\n"));
        break;

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

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

时间: 2024-11-08 14:16:46

SCSI miniport 驾驶一个简单的框架的相关文章

Ogre: 建立一个简单的框架——关于场景节点

[转载请保证内容的完整性和正确性] 建立一个简单的框架——关于场景节点 如果我们要做一个类似于<跑跑卡丁车>的游戏,人物模型是需要随着卡丁车模型一起进行各种变换的(平移.旋转等),我们需要分别计算两个关联的模型的位置吗?这样能解决问题,但是太麻烦了,利用Ogre的场景节点可以很方便地解决这种问题. 添加一个新的模型 之前添加的模型都是由3DMAX等软件导出的模型,接下来我们利用Ogre生成一个Cube模型. 1 //DemoManager.cpp 2 Ogre::ManualObject* c

Ogre: 建立一个简单的框架——响应键盘事件

[转载请保证内容的完整性和正确性] 建立一个简单的框架——响应键盘事件 上一节我们在场景中添加了一个机器人,这一节我们将建立一个FrameListener类(顾名思义,这是一个侦听类),来控制模型进行移动. 创建FrameListener类 FrameListener类主要负责事件的侦听,如帧结束.键盘输入等事件.它继承自ExampleFrameListener类,如果需要的话还可以继承KeyListener(键盘事件).MouseListener(鼠标事件)和JoyStickListener(

搭建一个简单struts2框架的登陆

第一步:下载struts2对应的jar包,可以到struts官网下载:http://struts.apache.org/download.cgi#struts252 出于学习的目的,可以把整个完整的压缩文件都下载下来. 里面包括:1 apps:示例应用,对学习很有帮助 : 2 docs:相关学习文档.API文档等: 3 lib:核心类库,依赖包: 4:src:源代码 第二步:在eclipse新建一个Dynamic Web Project类型工程,一直点next,记得勾选generate web.

WPF中使用MVVM创建一个简单的框架

MVVM模式 一.MVVM模式概述 MVVM Pattern : Model\View\ViewModel View:视图.UI界面 ViewModel:ViewModel是对Model的封装,通过一系列属性暴露Model的状态,提供给View进行显示 Model:数据模型 使用MVVM模式可以将代码逻辑和UI进行分离,因此开发团队可以关注创建健壮的ViewModel类,而设计团队可以关注设计界面友好的View.要融合两个团队输出只需要在View的xaml上进行正确的绑定即可. 二.演示程序 下

[python] 理解metaclass并实现一个简单ORM框架

metaclass 除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass. metaclass,直译为元类,简单的解释就是: 当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例. 但是如果我们想创建出类呢?那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类. 连接起来就是:先定义metaclass,就可以创建类,最后创建实例. 所以,metaclass允许你创建类或者修改类.换句话说,你可以把类看成是met

一个简单RPC框架是如何炼成的(V)——引入传输层

开局篇我们说了,RPC框架的四个核心内容 RPC数据的传输. RPC消息 协议 RPC服务注册 RPC消息处理    接下来处理数据传输.实际应用场景一般都是基于socket.socket代码比较多,使用起来也比较麻烦.而且具体的传输通道使用socket或者其他的方式,如更上层的http,或者android里的binder,都是可替换的,只是具体的一种实现而已.所以,这里我就偷个懒,只是引入一个很简单的Connection类,用来描述一下如何将数据传输 这一层给独立出来. 首先简单列出Conne

一个简单RPC框架是如何炼成的(VI)——引入服务注册机制

开局篇我们说了,RPC框架的四个核心内容 RPC数据的传输. RPC消息 协议 RPC服务注册 RPC消息处理 接下来处理RPC服务的注册机制.所谓注册机制,就是Server需要声明支持哪些rpc方法,然后当客户端发送调用某个声明的rpc方法之后,服务端能自动找到执行该请求的具体方法.以实际的例子为例,这是现在server端处理RPC请求的代码 def procRequest(self): # 循环读取并处理收到的客户端请求 while True: req = self.conn.recv()

一个简单RPC框架是如何炼成的(II)——制定RPC消息

开局篇我们说了,RPC框架的四个核心内容 RPC数据的传输. RPC消息 协议 RPC服务注册 RPC消息处理 下面,我们先看一个普通的过程调用 class Client(object): def __init__(self): self.remote = None ## # 内部是委托给远程remote对象来获取结果. def sayHello(self): if self.remote: return self.remote.sayHello() else : return None cla

一个简单RPC框架是怎样炼成的(II)——制定RPC消息

开局篇我们说了,RPC框架的四个核心内容 RPC数据的传输. RPC消息 协议 RPC服务注冊 RPC消息处理 以下,我们先看一个普通的过程调用 class Client(object): def __init__(self): self.remote = None ## # 内部是托付给远程remote对象来获取结果. def sayHello(self): if self.remote: return self.remote.sayHello() else : return None cla