49、Windows驱动程序模型设计笔记(七),IRP

简介: 一、IRP MdlAddress(PMDL)域指向一个内存描述符表(MDL),该表描述了一个与该请求关联的用户模式缓冲区。如果顶级设备对象的Flags域为DO_DIRECT_IO,则I/O管理器为IRP_MJ_READ或IRP_MJ_WRITE请求创建这个MDL。

一、IRP<?xml:namespace prefix = o />

MdlAddress(PMDL)域指向一个内存描述符表(MDL),该表描述了一个与该请求关联的用户模式缓冲区。如果顶级设备对象的Flags域为DO_DIRECT_IO,则I/O管理器为IRP_MJ_READ或IRP_MJ_WRITE请求创建这个MDL。如果一个IRP_MJ_DEVICE_CONTROL请求的控制代码指定METHOD_IN_DIRECT或METHOD_OUT_DIRECT操作方式,则I/O管理器为该请求使用的输出缓冲区创建一个MDL。MDL本身用于描述用户模式虚拟缓冲区,但它同时也含有该缓冲区锁定内存页的物理地址。

wps_clip_image-11937

    AssociatedIrp(union)域是一个三指针联合。其中,与WDM驱动程序相关的指针是AssociatedIrp.SystemBuffer。 SystemBuffer指针指向一个数据缓冲区,该缓冲区位于内核模式的非分页内存中。对于IRP_MJ_READ和IRP_MJ_WRITE操作,如果顶级设备指定DO_BUFFERED_IO标志,则I/O管理器就创建这个数据缓冲区。对于IRP_MJ_DEVICE_CONTROL操作,如果I/O控制功能代码指出需要缓冲区,则I/O管理器就创建这个数据缓冲区。I/O管理器把用户模式程序发送给驱动程序的数据复制到这个缓冲区,这也是创建IRP过程的一部分。这些数据可以是与WriteFile调用有关的数据,或者是DeviceIoControl调用中所谓的输入数据。对于读请求,设备驱动程序把读出的数据填到这个缓冲区,然后I/O管理器再把缓冲区的内容复制到用户模式缓冲区。对于指定了METHOD_BUFFERED的I/O控制操作,驱动程序把所谓的输出数据放到这个缓冲区,然后I/O管理器再把数据复制到用户模式的输出缓冲区。

    IoStatus(IO_STATUS_BLOCK)是一个仅包含两个域的结构,驱动程序在最终完成请求时设置这个结构。IoStatus.Status域将收到一个NTSTATUS代码,而IoStatus.Information的类型为ULONG_PTR,它将收到一个信息值,该信息值的确切含义要取决于具体的IRP类型和请求完成的状态。Information域的一个公认用法是用于保存数据传输操作,如IRP_MJ_READ,的流量总计。某些PnP请求把这个域作为指向另外一个结构的指针,这个结构通常包含查询请求的结果。

    UserBuffer(PVOID) 对于METHOD_NEITHER方式的IRP_MJ_DEVICE_CONTROL请求,该域包含输出缓冲区的用户模式虚拟地址。该域还用于保存读写请求缓冲区的用户模式虚拟地址,但指定了DO_BUFFERED_IO或DO_DIRECT_IO标志的驱动程序,其读写例程通常不需要访问这个域。当处理一个METHOD_NEITHER控制操作时,驱动程序能用这个地址创建自己的MDL。

    Tail.Overlay是Tail联合中的一种结构,它含有几个对WDM驱动程序有潜在用途的成员。图示是Tail联合的组成图。在这个图中,以水平方向从左到右是这个联合的三个可选成员,在垂直方向是每个结构的成员描述。Tail.Overlay.DeviceQueueEntry(KDEVICE_QUEUE_ENTRY)和Tail.Overlay.DriverContext(PVOID[4])是Tail.Overlayare内一个未命名联合的两个可选成员(只能出现一个)。I/O管理器把DeviceQueueEntry作为设备标准请求队列中的连接域。当IRP还没有进入某个队列时,如果你拥有这个IRP你可以使用这个域,你可以任意使用DriverContext中的四个指针。Tail.Overlay.ListEntry(LIST_ENTRY)仅能作为你自己实现的私有队列的连接域。

wps_clip_image-19510

二、IO堆栈

    任何内核模式程序在创建一个IRP时,同时还创建了一个与之关联的IO_STACK_LOCATION结构数组:数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序,另外还有一个堆栈单元供IRP的创建者使用。堆栈单元中包含该IRP的类型代码和参数信息以及完成函数的地址。

wps_clip_image-27319

图示. 驱动程序和I/O堆栈之间的平行关系

wps_clip_image-12586

. I/O堆栈单元数据结构

    MajorFunction(UCHAR)是该IRP的主功能码。这个代码应该为类似IRP_MJ_READ一样的值,并与驱动程序对象中MajorFunction表的某个派遣函数指针相对应。

    MinorFunction(UCHAR)是该IRP的副功能码。

    Parameters(union)是几个子结构的联合,每个请求类型都有自己专用的参数,而每个子结构就是一种参数。这些子结构包括Create(IRP_MJ_CREATE请求)、Read(IRP_MJ_READ请求)、StartDevice(IRP_MJ_PNP的IRP_MN_START_DEVICE子类型),等等。

    DeviceObject(PDEVICE_OBJECT)是与该堆栈单元对应的设备对象的地址。该域由IoCallDriver函数负责填写。

    FileObject(PFILE_OBJECT)是内核文件对象的地址,IRP的目标就是这个文件对象。驱动程序通常在处理清除请求(IRP_MJ_CLEANUP)时使用FileObject指针,以区分队列中与该文件对象无关的IRP。

    CompletionRoutine(PIO_COMPLETION_ROUTINE)是一个I/O完成例程的地址,该地址是由与这个堆栈单元对应的驱动程序的更上一层驱动程序设置的。你绝对不要直接设置这个域,应该调用IoSetCompletionRoutine函数,该函数知道如何参考下一层驱动程序的堆栈单元。设备堆栈的最低一级驱动程序并不需要完成例程,因为它们必须直接完成请求。然而,请求的发起者有时确实需要一个完成例程,但通常没有自己的堆栈单元。这就是为什么每一级驱动程序都使用下一级驱动程序的堆栈单元保存自己完成例程指针的原因。

    Context(PVOID)是一个任意的与上下文相关的值,将作为参数传递给完成例程。你绝对不要直接设置该域;它由IoSetCompletionRoutine函数自动设置,其值来自该函数的某个参数。

wps_clip_image-8415

. IRP处理的“标准模型”

1、创建

可以使用下面任何一种函数创建IRP:

•IoBuildAsynchronousFsdRequest 创建异步IRP(不需要等待其完成)。该函数和下一个函数仅适用于创建某些类型的IRP。

•IoBuildSynchronousFsdRequest 创建同步IRP(需要等待其完成)。

•IoBuildDeviceIoControlRequest 创建一个同步IRP_MJ_DEVICE_CONTROL或IRP_MJ_INTERNAL_DEVICE_CONTROL请求。

•IoAllocateIrp 创建上面三个函数不支持的其它种类的IRP。

2、发往派遣例程

创建完IRP后,你可以调用IoGetNextIrpStackLocation函数获得该IRP第一个堆栈单元的指针。然后初始化这个堆栈单元。在初始化过程的最后,你需要填充MajorFunction代码。堆栈单元初始化完成后,就可以调用IoCallDriver函数把IRP发送到设备驱动程序:

PDEVICE_OBJECT DeviceObject; //something gives you this

PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp);

stack->MajorFunction = IRP_MJ_Xxx;

<other initialization of "stack">

NTSTATUS status = IoCallDriver(DeviceObject, Irp);

IoCallDriver函数的第一个参数是你在某处获得的设备对象的地址

    IRP中的第一个堆栈单元指针被初始化成指向该堆栈单元之前的堆栈单元,因为I/O堆栈实际上是IO_STACK_LOCATION结构数组,你可以认为这个指针被初始化为指向一个不存在的“-1”元素,因此当我们要初始化第一个堆栈单元时我们实际需要的是“下一个”堆栈单元。IoCallDriver将沿着这个堆栈指针找到第0个表项,并提取我们放在那里的主功能代码,在上例中为IRP_MJ_Xxx。然后IoCallDriver函数将利用DriverObject指针找到设备对象中的MajorFunction表。IoCallDriver将使用主功能代码索引这个表,最后调用找到的地址(派遣函数)。

NTSTATUS IoCallDriver(PDEVICE_OBJECT device, PIRP Irp)

{

IoSetNextIrpStackLocation(Irp);

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

stack->DeviceObject = device;

ULONG fcn = stack->MajorFunction;

PDRIVER_OBJECT driver = device->DriverObject;

return (*driver->MajorFunction[fcn])(device, Irp);

}

目录
相关文章
|
2月前
|
并行计算 数据格式 异构计算
完整教程:从0到1在Windows下训练YOLOv8模型
本文详细介绍在Windows系统下使用YOLOv8训练目标检测模型的完整步骤,涵盖环境配置、数据集准备、模型训练与测试、常见问题解决及GPU加速技巧。提供详细命令与代码示例,并推荐现成数据集与工具,助您高效完成模型训练。
884 13
完整教程:从0到1在Windows下训练YOLOv8模型
|
6月前
|
Web App开发 人工智能 JSON
Windows版来啦!Qwen3+MCPs,用AI自动发布小红书图文/视频笔记!
上一篇用 Qwen3+MCPs实现AI自动发小红书的最佳实践 有超多小伙伴关注,同时也排队在蹲Windows版本的教程。
831 1
|
8月前
|
算法 关系型数据库 测试技术
WHQL微软驱动签名方案,让驱动程序在Windows系统流畅运行
WHQL认证(Windows徽标认证)是微软设立的严格测试标准,旨在确保驱动程序的兼容性、稳定性和互通性。本文介绍了三种WHQL微软驱动签名方案:单系统签名、多系统签名和硬件兼容性测试方案,分别满足不同开发商的需求。通过WHQL认证,不仅能消除Windows安装警告,提升用户体验,还能获得“Designed for Windows”徽标授权,入列全球Windows Catalog及HCL产品表,提升品牌权威性和采购优先权。此外,访问微软OCA可获取错误反馈,助力产品质量改进。选择合适的签名方案,让驱动在Windows系统中流畅运行!
|
监控 Ubuntu Linux
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
这篇文章介绍了如何在Ubuntu和Windows系统中通过设置相同的时区并使用ntp服务来解决时间同步问题。
264 4
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
|
Linux Apache C++
FFmpeg开发笔记(三十五)Windows环境给FFmpeg集成libsrt
该文介绍了如何在Windows环境下为FFmpeg集成SRT协议支持库libsrt。首先,需要安装Perl和Nasm,然后编译OpenSSL。接着,下载libsrt源码并使用CMake配置,生成VS工程并编译生成srt.dll和srt.lib。最后,将编译出的库文件和头文件按照特定目录结构放置,并更新环境变量,重新配置启用libsrt的FFmpeg并进行编译安装。该过程有助于优化直播推流的性能,减少卡顿问题。
384 2
FFmpeg开发笔记(三十五)Windows环境给FFmpeg集成libsrt
|
存储 安全 数据安全/隐私保护
Windows 32 汇编笔记(一):基础知识
Windows 32 汇编笔记(一):基础知识
|
算法 Linux Windows
FFmpeg开发笔记(十七)Windows环境给FFmpeg集成字幕库libass
在Windows环境下为FFmpeg集成字幕渲染库libass涉及多个步骤,包括安装freetype、libxml2、gperf、fontconfig、fribidi、harfbuzz和libass。每个库的安装都需要下载源码、配置、编译和安装,并更新PKG_CONFIG_PATH环境变量。最后,重新配置并编译FFmpeg以启用libass及相关依赖。完成上述步骤后,通过`ffmpeg -version`确认libass已成功集成。
487 1
FFmpeg开发笔记(十七)Windows环境给FFmpeg集成字幕库libass
|
存储 编译器 Linux
Windows 32 汇编笔记(二):使用 MASM
Windows 32 汇编笔记(二):使用 MASM
|
编解码 Windows
FFmpeg开发笔记(二十九)Windows环境给FFmpeg集成libxvid
XviD是开源MPEG-4视频编码器,与DivX相似但后者非开源。早期MP4常使用XviD或DivX编码,现已被H.264取代。在Windows上集成FFmpeg的XviD编解码库libxvid,需访问<https://labs.xvid.com/source/>下载源码,解压后在MSYS环境中配置、编译和安装。之后重新配置FFmpeg,启用libxvid并编译安装。详细步骤包括configure命令、make和make install。成功后,通过`ffmpeg -version`检查是否启用libxvid。更多音视频开发技术可参考《FFmpeg开发实战:从零基础到短视频上线》。
296 0
FFmpeg开发笔记(二十九)Windows环境给FFmpeg集成libxvid
|
编解码 5G Linux
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
AVS3是中国首个8K及5G视频编码标准,相比AVS2和HEVC性能提升约30%。解码器libuavs3d支持8K/60P视频实时解码,兼容多种平台。《FFmpeg开发实战》书中介绍了在Windows环境下如何集成libuavs3d到FFmpeg。集成步骤包括下载源码、使用Visual Studio 2022编译、调整配置、安装库文件和头文件,以及重新配置和编译FFmpeg以启用libuavs3d。
434 0
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器

热门文章

最新文章

下一篇
开通oss服务