Windows 虚拟磁盘驱动开发(采用原始办法实现类似Storport框架的相同功能)

news2025/1/17 9:28:08

其实以前讲述windows平台下的磁盘驱动的开发挺多,而且时间也是非常早。

以下连接:

https://blog.csdn.net/fanxiushu/article/details/9903123?spm=1001.2014.3001.5501

https://blog.csdn.net/fanxiushu/article/details/11713357?spm=1001.2014.3001.5501

讲述的主要就是以 Storport 和 Scsiport 框架为主的windows平台的虚拟磁盘驱动开发,

并且在CSDN上提供了一个基于这两个框架的例子代码:

https://download.csdn.net/download/fanxiushu/5994583?spm=1001.2014.3001.5501

看看写博客的时间,距今快10年了,一个非常难言而又漫长的岁月(相对日新月异的信息技术而言)

然而仔细分析却会发现,其核心和本质的东西,并没改变多少,基本保持着多年前的哪些框架和原理。

除非在信息技术和操作系统领域发生了颠覆性的革命(比如以生物计算代替硅基电路),

否则经过人们多年努力建立起来的基础核心,都不会有太大变化。

比如现在的电脑,各种终端,服务器等都遵循着 冯·诺依曼型计算机的基本规则。

回到我们的windows虚拟磁盘驱动。

为何想到要用原始办法来开发类似Storport框架的虚拟磁盘驱动?

估计是闲的蛋疼吧。

又或者为了彰显曾经无法理解和实现的,现在具备了一定基础,再来实现,却发现变得异常的简单。

记得以前开发winxp下的Scsiport框架的虚拟磁盘驱动,非常的麻烦,

不但要解决虚拟模拟部分,安装驱动电脑还得重启好几次才能安装成功。

以前讲述过虚拟磁盘驱动,

有基于filedisk模型的,这个纯粹就是在文件系统下面挂一个接口,

直接接收来自文件系统转化而成的数据块读写指令, 不能被磁盘管理器识别,也不能被windows当成真正的“设备”,

但好处也显而易见,模型简单易懂,很快就能实现,

而且节省了windows下驱动命令的弯弯绕绕的浪费(这个纯粹基于心理上,现在的电脑性能根本不在乎这些)

有基于Storport和scsiport框架的,

而Storport 属于windows中目前几乎所有磁盘驱动(包括虚拟磁盘,更包括真实的磁盘)通用的框架。

因此如果需要开发不管是虚拟的,还是基于硬件的,掌握Storport框架,基本就可以了。

而我们今天要讲述的,则是从更底层的,更本质角度去实现虚拟磁盘驱动。

简单的说,使用原始代码,自己码代码来实现类似Storport框架一样的磁盘驱动,

因为Storport框架的代码我没看过,也不清楚Storport框架底层代码是如何实现的。

但是根据windows的wdm驱动的运行规律,PDO和FDO等基本常识,

Storport实现的大致流程,跟我准备讲述的应该比较接近,或者总体思路比较接近。

开始之前,我们需要一些准备知识。

首先熟悉PDO和FDO等基本概念。

需要熟悉windows平台下通用的总线驱动开发流程,

熟悉SCSI磁盘相关命令。

这些准备知识,这里不再具体阐述。

而运气好稍好,以上我都具备,因此从底层码代码来实现虚拟磁盘驱动,就显得比较容易了。

首先,我们抛开了storport 框架,自己码代码来实现虚拟磁盘驱动,是需要建立在虚拟总线驱动之上的。

当初为了实现USB虚拟总线驱动,曾经非常认认真真的研究了微软的toaster例子,而且是研究wdm的,不是kmdf框架。

为何需要这么做,那是因为window7,8 这些的系统不像windows10,有专门提供UDE和UCX框架来实现usb控制器的虚拟。

winxp,win7,win8就只能从更底层的总线驱动来实现USB主机控制器的模拟。

而且USB相关的指令是异常的繁多。

当初为了开发usb总线驱动,还重新构建了基于wdm模型的总线驱动框架代码,其实主要是处理 IRP_MJ_PNP, IRP_MJ_POWER命令,

别看只有两个命令,其实处理的内容非常多,还得考虑如何管理PDO等内容。

自己实现的这个框架代码,目前用在了 USB虚拟主机控制器的开发上(以前的文章阐述过usb虚拟总线的开发,有兴趣可去查阅),

也用在了 Indirect Display Driver (win10的虚拟显示器驱动)的总线枚举上,

同时也用在了目前讨论的虚拟磁盘开发上,然后发现:虚拟总线驱动这玩意用处还挺多。

打开设备管理器,查看 “存储控制器” 和 “ 磁盘驱动器” 里边的内容,

会发现里边对应一个磁盘控制器驱动(存储控制器)和一个或者多个对应的磁盘(磁盘驱动器),

不同电脑,对应的磁盘控制器不一定在 “存储控制器” 里边,有可能是对应着“IDE ATA/ATAPI 控制器” 等,

反正不管怎么说,一块磁盘,都会对应着磁盘控制器驱动。

如果我们把这个控制器驱动称作 FDO ,把对应的每个磁盘称作 PDO,现在我们来具体分析FDO和PDO的对应关系。

为了更好理解,用下面的实物图来说明,

这个是我笔记本电脑上的磁盘情况,使用Devicetree工具软件分析磁盘驱动里边的设备情况:

在上图中,左边是“设备管理器”,中间是Devicetree显示的内容,右边是Apple磁盘显示的属性。

Apple 是笔记本电脑上的唯一块真实硬盘

设备管理器里 “Apple Solid State Drive Device“ 是Apple磁盘控制器驱动。

它的驱动名是 AppleSSD.sys,这可以从右边的属性里看到。驱动是基于Storport框架的(现在绝大部分磁盘驱动基本都是基于此框架),

在中间Devicetree软件里可以看到 \Driver\AppleSSD 驱动里创建了两个Device设备,我们重点关注 \Device\00000037 。

可以看到它上面挂载了\Device\Harddisk0\DR0, 接着有挂载了 \Driver\partmgr,

很显然 \Device\00000037 是块磁盘设备, 是最底层的 PDO 设备。

同时从右边属性里可以看到,它是 “Apple APPLE SSD AP0512 SCSI Disk Device” ,

也就是设备管理器“磁盘驱动器”里边的 对应的磁盘。

这个关系也就挺明显了:

Apple Solid State Drive Device 磁盘控制器驱动(也就是FDO)里创建了某块磁盘的 PDO,并且管理着这个磁盘PDO的行为模式。

另外设备管理器还出现了

“Fanxiushu Primitive Virtual SCSI Adapter” 和 “Fanxiushu xFsRedir Virtual SCSI Adapter”

两个 虚拟磁盘控制器,

其中xFsRedir对应为xFsRedir软件开发的扩展虚拟磁盘驱动,是基于Storport框架的。

而Primitive 则是本文讨论的,直接基于底层的虚拟总线驱动实现的虚拟磁盘控制器。

他们都能同时管理多块磁盘设备。

理清了上面的关系,我们会发现,基于原始虚拟总线驱动开发虚拟磁盘的总体框架,变得异常的简单

(当然得先熟悉通用的虚拟总线驱动和FDO,PDO这些基本的东西),

我们甚至可以首先开发一个通用的虚拟总线驱动程序,驱动里边创建一个或多个PDO设备,

PDO怎么创建则取决于你以后打算如何规划这个磁盘设备,现在就假设简单的创建一个PDO设备。

现在的问题是,如何把这个通用的虚拟总线驱动变成一个虚拟磁盘驱动,

让windows系统认为我们开发的是一块磁盘驱动程序。

首先,在制作 inf安装配置文件的时候,把[Version]里的 CLASS设置成 SCSIAdapter类,

ClassGUID 设置成 {4D36E97B-E325-11CE-BFC1-08002BE10318}。

在这个SCSIAdapter类里面,windows会把驱动当成是磁盘控制器,自然就会发送一些磁盘相关的命令到我们的驱动。

于是接下来的重头戏,就是得正确响应这些跟磁盘相关的命令。

(当然我们在调用IoCreateDEvice创建设备的时候,设置 FILE_DEVICE_DISK,表示我们创建的设备类型是 磁盘类型。)

而接受磁盘相关命令的主要是PDO设备。

以下是一些伪代码来描述这样一个总体框架。

NTSTATUS DriverEntry(.....)

{

........

DriverObject->DriverExtension->AddDevice = AddDevice;

DriverObject->DriverUnload = DriverUnload;

DriverObject->MajorFunction[IRP_MJ_PNP] = pnp_dispatch;

DriverObject->MajorFunction[IRP_MJ_POWER] = power_dispatch;

DriverObject->MajorFunction[IRP_MJ_CREATE] =

DriverObject->MajorFunction[IRP_MJ_CLEANUP] =

DriverObject->MajorFunction[IRP_MJ_CLOSE] =

DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] =

DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =

DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = vscsi_dispatch;

..........

}

static NTSTATUS vscsi_dispatch(PDEVICE_OBJECT deviceObject, PIRP Irp)

{

NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;

PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);

base_exts_t* base = (base_exts_t*)deviceObject->DeviceExtension;

if (base->devType == 1) { // FDO

fdo_exts_t* fdo = (fdo_exts_t*)base;

/

switch (irpStack->MajorFunction)

{

case IRP_MJ_CREATE:

case IRP_MJ_CLEANUP:

case IRP_MJ_CLOSE:

case IRP_MJ_DEVICE_CONTROL:

return ioctl_dispatch_function(deviceObject, Irp);

case IRP_MJ_SYSTEM_CONTROL:

return wmi_system_control(deviceObject, Irp); ///

default:

status = STATUS_INVALID_DEVICE_REQUEST;

DPT("V: --FDO: Not Process MJ=[0x%X]\n", irpStack->MajorFunction);

break;

}

//

}

else { // PDO

/

switch (irpStack->MajorFunction)

{

case IRP_MJ_CREATE:

case IRP_MJ_CLEANUP:

case IRP_MJ_CLOSE:

DPT("V: ++PDO: Do Raw Create Close. MJ=0x%X\n", irpStack->MajorFunction ); 2016-06-11

status = STATUS_SUCCESS;

break;

case IRP_MJ_DEVICE_CONTROL:

return pdo_devicecontrol_dispatch(deviceObject, Irp, irpStack, (pdo_exts_t*)base);

case IRP_MJ_INTERNAL_DEVICE_CONTROL:

return pdo_srb_trans_dispatch(deviceObject, Irp, irpStack, (pdo_exts_t*)base);

default:

status = STATUS_INVALID_DEVICE_REQUEST;

DPT("V: ++PDO: Not Process MJ=[0x%X]\n", irpStack->MajorFunction);

break;

}

/

}

/

return complete_irp(Irp, status, 0);

}

以上 vscsi_dispatch 派遣函数中,

其中 ioctl_dispatch_function 函数处理的FDO相关IOCTL,这个IOCTL可以传递我们自己定义的一些数据,

比如我们打算把虚拟磁盘的读写数据传输到应用层来处理,以及其他一些自定义命令。

总之这个函数里不传输windows系统命令。

而 pdo_devicecontrol_dispatch 和 pdo_srb_trans_dispatch 函数则是必须响应windows系统下发的IOCTL命令。

其中 pdo_devicecontrol_dispatch 响应windows系统定义的命令,目前通过测试 其中

IOCTL_STORAGE_QUERY_PROPERTY 命令是必须正确响应并处理的,否则系统不会认为这是磁盘驱动。

当然还包括其他一些命令,具体可以在不同系统下测试,然后再做处理。

pdo_srb_trans_dispatch 函数处理的就是核心的磁盘通信了,基本都是SCSI命令。

这个的处理基本和 Storport框架里边关于 SRB (SCSI_REQUEST_BLOCK 结构)的处理基本一致。

srb通过IRP获取,如下:

PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);

PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;

PCDB cdb = (PCDB)srb->Cdb;

因此如果你熟悉 Storport框架,以及scsi命令的话,这个也不是难事。

因为在以前阐述虚拟磁盘驱动的时候,阐述过相关内容,

这里也就不再赘述了。

最近计划着重温多年前的关于无盘启动的技术,其实当年(大概是10年前,因为根据cdsn博客上写的文章的时间推断)

实现了winxp的无盘启动,到后来win7没成功,什么原因后来一直处于搁置,这次有机会看看能不能解决。

当然现在关于无盘启动的现成软件也挺多,

而且现在也并不如当初那么火热,毕竟技术在发展,现在使用云桌面构建通用的远程平台应该更合适。

无论如何,如果有空就折腾来玩玩。而且打算这次把虚拟磁盘换成目前新开发的这种原始总线驱动方式来进行无盘启动。

关于xFsRedir软件,也计划把Storport框架的扩展虚拟磁盘驱动换成这种原始总线驱动方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/161873.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

游戏开发 状态同步

【状态同步】1、将所有的操作发送给Server(T1),由Server计算(T2),并返回结果(T3)。权威服务器架构能够防止很多的作弊,但是直接用这种方法会让游戏的响应变得迟缓。如果 …

three games 之 桌球

接下来介绍一些 Vue4 中的一些进阶使用,希望对大家有所帮助,谢谢。 如果文中有不对、疑惑的地方,欢迎在评论区留言指正🌻 一、项目结构 Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则: …

移动硬盘怎么分区?

硬盘分区指的是硬盘上被划分出来的区块,可用于分类存储各种数据。而我们日常购买的移动硬盘通常来说分为两种,一种是买回来已分好区的,还有一种是未经过分区的。如果移动硬盘没有经过分区,那么在将它连接到电脑的USB接口时&#x…

android四大组件之四-BroadCast实现原理分析

前言: 一开始的目标是解决各种各样的ANR问题的,但是我们知道,ANR总体上分有四种类型,这四种ANR类型有三种是和四大组件相对应的,所以,如果想了解ANR发生的根因,对安卓四大组件的实现原理必须要…

伙伴云与飞书、金山办公一同入选亿欧2022中国数字化企业服务商TOP50

近日,由中关村国家自主创新示范区展示中心、中关村会展与服务产业联盟与亿欧联合举办的SHOWTECH2022-WIM 创新者年会”在京顺利召开,会上,亿欧网重磅发布《2022世界创新奖榜单》。伙伴云凭借10年来为企业数字化转型赋能的成功经验和卓越贡献&…

数据结构学习-队列

坚持看完,结尾有思维导图总结 这里写目录标题队列的定义于性质如何实现队列的功能初始化队列入队列出队列队列的销毁队列取队头数据队列取队尾数据判断队列是否为空判断队列长度总结队列的定义于性质 队列是一种数据结构,他储存数据的方式就和排队一样 …

二十六、Kubernetes中Horizontal Pod Autoscaler(HPA)控制器详解

1、概述 在kubernetes中,有很多类型的pod控制器,每种都有自己的适合的场景,常见的有下面这些: ReplicationController:比较原始的pod控制器,已经被废弃,由ReplicaSet替代 ReplicaSet&#xff…

年终盘点(三)丨2022计讯物联团队不负韶华,奋力前行

光阴荏苒,时光悄然,成长的齿轮不断转动。2022年,计讯人在挑战中创造不凡,2023年,计讯人在希望中迎接新未来。 回首过去,计讯物联团队不断壮大,在奋勇前行中以坚持书写拼搏,在知难而…

记好这24个ES6方法,用于解决实际开发的JS问题

本文主要介绍24中es6方法&#xff0c;这些方法都挺实用的&#xff0c;本本请记好&#xff0c;时不时翻出来看看。 1.如何隐藏所有指定的元素 1 const hide (el) > Array.from(el).forEach(e > (e.style.display none)); 2 3 // 事例:隐藏页面上所有<img>元素? …

echarts——实现 面积图+柱状图+折线图等——基础积累

因为到年底了&#xff0c;很多项目组都开始做年终汇报&#xff0c;年终汇报的展示形式最常见的就是看板。 样式美观&#xff0c;可以放到电视机或者大屏上&#xff0c;通过图表的形式进行展示&#xff0c;简单明了&#xff0c;通俗易懂。 直接上最终效果图&#xff1a;是一个…

【C++】打开C++的大门

目录前言1.什么是C2.C的发展史3.C关键字&#xff08;C98&#xff09;4.命名空间4.1命名冲突4.2命名空间定义4.3命名空间使用5.输入输出6.缺省参数6.1缺省参数的概念6.2缺省参数分类7.函数重载7.1函数重载概念7.2C函数重载的原理——名字修改8.引用8.1引用的概念8.2引用特性8.3常…

ArcGIS基础实验操作100例--实验94计算栅格图层总和值

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 空间分析篇--实验94 计算栅格图层总和值 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;…

【观察】软硬件底层创新“开花结果”,亚马逊云科技的沉淀与释放

2006年&#xff0c;亚马逊云科技推出了Amazon Web Services&#xff0c;正式“开创”出了云计算市场。同年8月&#xff0c;Amazon Elastic Compute Cloud (EC2) 开放了 beta 测试&#xff0c;启动了云上计算的创新和革命。从此&#xff0c;亚马逊云科技在云计算软硬件底层技术创…

软件测试复习03:动态测试——黑盒测试

作者&#xff1a;非妃是公主 专栏&#xff1a;《软件测试》 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录等价划分法边值分析法错误推测法因果图法示例习题等价划分法 等价类&#xff1a;一个几何&#xf…

阿里云 gradle maven配置中心地址

仓库名称阿里云仓库地址阿里云仓库地址(老版)源地址centralhttps://maven.aliyun.com/repository/centralhttps://maven.aliyun.com/nexus/content/repositories/centralhttps://repo1.maven.org/maven2/jcenterhttps://maven.aliyun.com/repository/publichttps://maven.aliyu…

dp(五) 最长公共子串

最长公共子串_牛客题霸_牛客网 描述 给定两个字符串str1和str2,输出两个字符串的最长公共子串 题目保证str1和str2的最长公共子串存在且唯一。 数据范围&#xff1a; 1≤∣str1∣,∣str2∣≤50001≤∣str1∣,∣str2∣≤5000 要求&#xff1a; 空间复杂度 O(n2)O(n2)&#x…

【阶段三】Python机器学习22篇:机器学习项目实战:GBDT分类模型

本篇的思维导图: 项目实战(GBDT分类模型) 项目背景 应用GBDT算法实现多分类模型,目标是实现GBDT多分类项目的全流程。 数据获取 本次建模数据来源于网络,数据项统计如下: 编号  变量名称 <

聚焦:XuperOS成长计划FAQ

1月12日&#xff0c;百度超级链发布XuperOS成长计划&#xff08;&#x1f449;XuperOS 新年致辞&#xff1a;创世、监督、共建、国际&#xff09;。以下是我们整理的关于成长计划的常见问题&#xff0c;为关心XuperOS的广大朋友答疑解惑。问&#xff1a;XuperChain除了发行这四…

662. 二叉树最大宽度

662. 二叉树最大宽度 难度中等530 给你一棵二叉树的根节点 root &#xff0c;返回树的 最大宽度 。 树的 最大宽度 是所有层中最大的 宽度 。 每一层的 宽度 被定义为该层最左和最右的非空节点&#xff08;即&#xff0c;两个端点&#xff09;之间的长度。将这个二叉树视作…

IT信息化推进那么难,为什么,怎么办 ?

IT信息化推进除了管理层的支持外&#xff0c;更重要的是要赢得业务的支持。但往往业务方有时会排斥IT信息化&#xff0c;这里面有很多的原因&#xff0c;比如&#xff1a;不懂业务的想法难沟通&#xff1b;系统不好用、体验不好、问题太多&#xff0c;不想用。换一波IT团队&…