磁盘驱动与虚拟磁盘Miniport驱动一

                                                                                                                         By Fanxiushu ,引用和转载请注明原作者。


这里讨论的是磁盘驱动,而非文件驱动,两者是不同的。

文件驱动是更上层的驱动,他管理着文件的所有属性和内容,面对的是单个的文件对象。
磁盘驱动是在文件驱动之下的,所有对文件的读写,已经被上层的文件驱动转换成单纯的扇区和位置偏移的读写请求。
所有的文件操作,都会通过文件驱动,最终进入到目标磁盘。
这个时候,磁盘驱动就发挥了它应该有的作用,他协调控制磁盘硬件和上层驱动的读写请求。
虚拟磁盘驱动,其实就是模拟出一块虚拟磁盘出来,
对这块虚拟磁盘上的所有文件读写请求, 转化成虚拟磁盘驱动对’虚拟扇区'的读写请求。
网上介绍挺多的就是 filedisk驱动,这是一个简单的驱动框架,还有WDK7下的实例代码,位置在(src\storage\ramdisk)
其实也是跟filedisk一样的框架,只是它是用WDF实现的。

为什么说他简单呢,因为他的实现框架确实不复杂, DriverEntry调用IoCreateDevice创建一个 FILE_DEVICE_DISK类型的设备,
同时实现 IRP_MJ_CREATE/CLEANUP/CLOSE, IRP_MJ_READ/WRITE, IRP_MJ_DEVICE_CONTROL 等派遣函数。
重点在 DEVICE_CONTROL和 READ/WRITE的实现。
IRP_MJ_DEVICE_CONTROL处理跟磁盘信息相关的命令,主要如下:
IOCTL_DISK_CHECK_VERIFY,IOCTL_CDROM_CHECK_VERIFY
IOCTL_STORAGE_CHECK_VERIFY,IOCTL_STORAGE_CHECK_VERIFY2
以上分区校验命令,
IOCTL_DISK_GET_DRIVE_GEOMETRY,获得磁盘的物理信息,比如扇区,柱面,磁道等。
IOCTL_DISK_GET_LENGTH_INFO, 获得磁盘大小。
IOCTL_DISK_GET_PARTITION_INFO,IOCTL_DISK_GET_PARTITION_INFO_EX,获得磁盘分区信息。
IOCTL_DISK_IS_WRITABLE,磁盘是否可写。
IOCTL_DISK_MEDIA_REMOVAL,IOCTL_STORAGE_MEDIA_REMOVAL,是否移动磁盘。
IOCTL_DISK_SET_PARTITION_INFO,设置分区信息。
还有更多的命令,可查阅相关文档。

控制命令比较多点,但是 IRP_MJ_READ和IRP_MJ_WRITE就比较好理解了,就是对磁盘数据的读写请求。
注意一点是,因为已经是磁盘驱动了,所以 READ/WRITE是直接针对的这个虚拟磁盘的扇区块和偏移地址读写。
如果把最终的读写磁盘地址使用一块大的内存块代替,那就成为了一个内存类型的虚拟磁盘驱动,
如果把最终的读写磁盘地址使用一个真正的文件代替,那就成为了一个文件类型的虚拟磁盘驱动。
如果把最终的读写磁盘地址连接到网络上去,那就成为了一个网络类型的虚拟磁盘驱动。
这就是虚拟磁盘驱动的主要实际用处。

在应用层,我们调用DefineDosDevice把在驱动创建的设备和自定义的盘符关联起来,科学名称叫mount(挂载),
之后就可以对这个磁盘操作像正常的其他磁盘一样的操作了。

以上只不过是实现磁盘驱动的一个比较简单的途径, 微软在实现真正的磁盘驱动上,拥有他们自己的一套层次结构。
首先实现磁盘类驱动,为一类磁盘提供公共属性,接着是端口类驱动和微端口(Miniport)驱动。
端口类驱动只是微软提供的一些公共函数(主要有ScsiPort和StorPort),微端口驱动才跟真正的硬件打交道。
系统目录下有个disk.sys驱动,这个就是磁盘类驱动,他接收上层的命令,解释并沟通和协调下层的微端口驱动,
disk.sys包装和处理所有的在上文介绍filedisk时提到的控制命令,这样处理了之后,
我们在微端口驱动这一层,就只看到了对磁盘扇区和偏移地址的读写命令(当然包括一些跟硬件有关的控制命令)。
上文提到filedisk或者ramdisk,其实是简单的自己实现了一个磁盘类驱动,把磁盘类驱动和微端口驱动合并到一块了。
可以这么猜测,filedisk是微软最早的模型,但是随着各种磁盘硬件的发展,
这一模型做开发越来越麻烦,从而才有了划分得更加详细的层次结构。
微端口驱动的上层,微软又提供了StorPort和ScsiPort端口驱动模型。其中StorPort是最新的最推荐使用的。
但是StorPort最低要求的系统是 win2003, 使用winxp的用户,还得必须使用ScsiPort。
还有一个办法,别使用微软的StorPort和ScsiPort,自己开发微端口驱动跟磁盘类驱动进行连接,但是工作量挺大,这里就不讨论了。

先介绍使用ScsiPort开发WinXP系统下的虚拟磁盘驱动的办法,这是一个艰难的选择。
微软早先提供的ScsiPort并不支持虚拟磁盘的概念,也没有对应的虚拟总线,所以不支持即插即用。
如果非要支持即插即用,还得自己开发虚拟总线驱动,也挺麻烦,所以这里也不讨论。
把ScsiPort做成非即插即用的虚拟磁盘驱动,还是可行的。 填写 HW_INITIALIZATION_DATA 初始化结构时候,
AdapterInterfaceType 对应写成 Isa, 表示模拟成ISA设备。
在DriverEntry入口函数里,
    HW_INITIALIZATION_DATA HwInitData;
    RtlZeroMemory( &HwInitData, sizeof(HW_INITIALIZATION_DATA) );
    HwInitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
    HwInitData.HwFindAdapter    = VirtHwFindAdapter; //查找设备
    HwInitData.HwInitialize     = VirtHwInitialize;  //设备初始化
    HwInitData.HwStartIo        = VirtHwStartIo; //处理SRB
    HwInitData.HwResetBus       = VirtHwResetBus;//
    HwInitData.HwAdapterControl = VirtHwAdapterControl;//
    ///参数初始化
    HwInitData.AdapterInterfaceType = Isa; //模拟成ISA
    HwInitData.MapBuffers = 1 ; //
    HwInitData.MultipleRequestPerLu = TRUE; //
    HwInitData.AutoRequestSense = TRUE;
    //extension
    HwInitData.DeviceExtensionSize = sizeof(adapter_t );
    HwInitData.SpecificLuExtensionSize = sizeof( vlun_t);
    HwInitData.SrbExtensionSize = sizeof(vsrb_t );
    ///
    status = ScsiPortInitialize( DriverObject, reg_str, &HwInitData , NULL );
重点实现上边的回调函数,VirtHwStatIo实现真正的数据读写和各种控制命令。
这些函数的处理跟StorPort基本相同,所以下边讲解StorPort的时候会提到。

安装的时候有点麻烦,不使用INF来安装,把sys驱动文件copy到系统的drivers目录,
然后创建自动运行的NT驱动服务,接着重启系统,系统会自动安装,
但是这样要连续重启2-3次,比较的麻烦,这是作为Non-PNP的方式安装的。
安装成功之后,在设备管理器里,就能看到我们开发的 SCSI/RAID 控制设备了。
(应该是微软的pnpscsi.inf提供的 “SCSI/RAID Host Controller" 的名字,但是驱动是我们的)

至于 StorPort模型,那就先进多了,他也支持虚拟磁盘驱动的概念,支持即插即用,安装也不用那么麻烦,
(WIN2003需要安装一个补丁才能支持虚拟磁盘驱动)
它使用 VIRTUAL_HW_INITIALIZATION_DATA 结构进行初始化,AdapterInterfaceType对应写成Internel。
 在DriverEntry入口函数里,
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    VIRTUAL_HW_INITIALIZATION_DATA HwInitData;
    RtlZeroMemory( &HwInitData, sizeof(VIRTUAL_HW_INITIALIZATION_DATA) );
    HwInitData.HwInitializationDataSize = sizeof(VIRTUAL_HW_INITIALIZATION_DATA);

    HwInitData.HwFindAdapter    = VirtHwFindAdapter; //查找设备
    HwInitData.HwInitialize     = VirtHwInitialize;  //设备初始化
    HwInitData.HwStartIo        = VirtHwStartIo; //处理SRB
    HwInitData.HwResetBus       = VirtHwResetBus;
    HwInitData.HwAdapterControl = VirtHwAdapterControl;
    HwInitData.HwFreeAdapterResources = VirtHwFreeAdapterResources;
    HwInitData.HwProcessServiceRequest = VirtHwProcessServiceRequest;
    ///
    HwInitData.AdapterInterfaceType = Internal; //内部
    HwInitData.MultipleRequestPerLu = TRUE; //
    HwInitData.AutoRequestSense = TRUE;
    //extension
    HwInitData.DeviceExtensionSize = sizeof(adapter_t );
    HwInitData.SpecificLuExtensionSize = sizeof( vlun_t);
    HwInitData.SrbExtensionSize = sizeof(vsrb_t );
    ////
    status = StorPortInitialize( DriverObject, reg_str, (PHW_INITIALIZATION_DATA)&HwInitData , NULL ); 
重点还是在那个几个回调函数的实现上,他们掌管了磁盘驱动核心部分。

安装就简单了, 使用inf安装,可以动态安装和卸载驱动,这就是即插即用的好处。

待续。。。

(注:对应的源代码资源从  http://download.csdn.net/detail/fanxiushu/5994583 下载)

你可能感兴趣的:(C++,windows,驱动开发)