WDF驱动开发-内存缓冲区
驱动程序通常使用内存缓冲区向/从框架和其他驱动程序传递数据,或在本地存储信息。 WDF常见的内存缓冲区包括框架内存对象(WDFMEMORY)、 lookaside、 MDL 和 本地缓冲区。
使用框架内存对象
框架使用 内存对象 来描述驱动程序从中接收并传递给框架的内存缓冲区。 每个框架内存对象表示一个缓冲区。
若要创建内存对象,驱动程序会调用以下对象方法之一:
- WdfMemoryCreate,用于创建内存对象并分配指定大小的内存缓冲区;
- WdfMemoryCreatePreallocated,它为预分配的缓冲区创建内存对象;
- WdfMemoryCreateFromLookaside,用于从 旁视列表创建内存缓冲区;
若要获取表示接收的 I/O 请求缓冲区的内存对象,驱动程序会调用 WdfRequestRetrieveInputMemory 和 WdfRequestRetrieveOutputMemory。 有关检索 I/O 请求缓冲区的详细信息,请参阅 在 Framework-Based 驱动程序中访问数据缓冲区。
若要获取内存对象缓冲区的地址和大小,驱动程序会调用 WdfMemoryGetBuffer。
若要将数据移入或移出内存对象的缓冲区,驱动程序会调用 WdfMemoryCopyFromBuffer 或 WdfMemoryCopyToBuffer。 这些对象方法检查源大小和目标大小,并防止缓冲区溢出错误。
如果驱动程序通过调用 WdfMemoryCreatePreallocated 创建内存对象,则它随后可以通过调用 WdfMemoryAssignBuffer 将不同的缓冲区分配给内存对象。
当驱动程序将 I/O 请求发送到 I/O 目标时,它通常会将输入或输出缓冲区传递给 框架 I/O 目标对象方法。 驱动程序通过传递描述缓冲区的 WDF_MEMORY_DESCRIPTOR 结构或通过传递内存对象句柄来指定缓冲区。 同步发送 I/O 请求的 I/O 目标对象方法需要 WDF_MEMORY_DESCRIPTOR 结构,异步发送 I/O 请求的方法需要内存对象句柄。
使用 Lookaside 列表
如果驱动程序需要许多大小大致相同的缓冲区,则应从 lookaside中分配它们。 驱动程序通过调用 WdfLookasideListCreate 创建lookaside。 随后,驱动程序可以通过调用 WdfMemoryCreateFromLookaside 从 lookaside 列表中获取缓冲区。
每次驱动程序调用 WdfMemoryCreateFromLookaside 时,框架都会创建一个内存对象,从 lookaside 列表中获取缓冲区,并将缓冲区分配给对象。 当驱动程序使用完这些内存对象之一后,它将调用 WdfObjectDelete,这将删除内存对象并将缓冲区空间返回到lookaside。
操作系统管理分配给lookaside的内存资源。 如果驱动程序在无可用(例如驱动程序第一次调用 WdfMemoryCreateFromLookaside)时从lookaside中请求缓冲区,系统会分配缓冲区并将其分配给列表。 当驱动程序 调用 WdfObjectDelete 并将缓冲区空间返回到lookaside时,系统会在列表中保留现在未分配的缓冲区,直到驱动程序再次需要它。 系统根据需要增加lookaside的大小;例如,更频繁地请求缓冲区的驱动程序会收到较大的lookaside。 另一方面,如果驱动程序未全部使用缓冲区,系统可能会减少lookaside中的缓冲区数。
使用 MDL
某些驱动程序使用内存描述符列表 (MDL) 来描述缓冲区。 例如, (DMA) 设备的直接内存访问驱动程序必须将 MDL 传递给 WdfDmaTransactionInitialize 方法(如果它调用该方法)。
使用 MDL 的驱动程序可以通过调用 WdfRequestRetrieveInputWdmMdl 和 WdfRequestRetrieveOutputWdmMdl 来获取表示已接收 I/O 请求缓冲区的 MDL。
大多数基于框架的驱动程序不使用 MDL。
分配本地缓冲区
需要不传递给框架的本地内部缓冲区空间的驱动程序不必创建内存对象来表示缓冲区。 驱动程序可以调用 ExAllocatePoolWithTag 来分配内部缓冲区。 驱动程序使用完缓冲区后,必须调用 ExFreePoolWithTag。
但是,驱动程序还可以将内存对象用于本地缓冲区。 使用内存缓冲区而不是调用 ExAllocatePoolWithTag的一个优点是,在删除每个对象的父对象时,框架会自动删除内存对象及其缓冲区。
注意:我们讨论的 ExAllocatePool DDI 已在 Windows 10 版本 2004 中弃用,并已替换为 ExAllocatePool2 和 ExAllocatePool3。
对齐缓冲区
驱动程序可以使用 WDF_ALIGN_SIZE_UP 或 WDF_ALIGN_SIZE_DOWN 函数来计算与指定的对齐偏移量对齐的缓冲区大小。 如果驱动程序必须分配多个连续缓冲区,并且每个缓冲区必须从地址对齐边界开始,则此计算非常有用。
内存缓冲区生命周期
内存缓冲区的生命周期跨越从创建缓冲区到删除缓冲区的时间。 下面从缓冲区几种使用方案来看它们在删除缓冲区时的影响。
在 KMDF内核模式驱动程序框架中,请求对象表示 I/O 请求。 每个请求对象都与一个或多个内存对象相关联,每个内存对象表示用于请求中的输入或输出的缓冲区。
当框架创建表示传入 I/O 请求的请求和内存对象时,它会将请求对象设置为关联内存对象的父对象。 因此,内存对象的保留期不能超过请求对象的生存期。 当基于框架的驱动程序完成 I/O 请求时,框架将删除请求对象和内存对象,使这两个对象的句柄变得无效。
但是,基础缓冲区是不同的。 根据创建缓冲区的组件及其创建缓冲区的方式,缓冲区可能具有引用计数,并且可能由内存对象拥有,也可能不具有引用计数。 如果内存对象拥有缓冲区,则缓冲区具有引用计数,并且其生存期限制为内存对象的生存期。 如果其他组件创建了缓冲区,则缓冲区的生存期与内存对象无关。
基于框架的驱动程序还可以创建自己的请求对象以发送到 I/O 目标。 驱动程序创建的请求可以重复使用驱动程序在 I/O 请求中收到的现有内存对象。 经常向 I/O 目标发送请求的驱动程序可以重复使用它创建 的请求对象 。
了解请求对象、内存对象和基础缓冲区的生存期对于确保驱动程序不会尝试引用无效句柄或缓冲区指针非常重要。
请考虑以下使用场景:
方案 1:驱动程序从 KMDF 接收 I/O 请求,对其进行处理并完成
在最简单的方案中,KMDF 将请求调度到驱动程序,该驱动程序执行 I/O 并完成请求。 在这种情况下,基础缓冲区可能是由用户模式应用程序、其他驱动程序或操作系统本身创建的。
当驱动程序 完成请求时,框架将删除内存对象。 缓冲区指针随后无效。
方案 2:驱动程序从 KMDF 接收 I/O 请求并将其转发到 I/O 目标
在此方案中,驱动程序 将请求转发 到 I/O 目标。 以下示例代码演示驱动程序如何从传入请求对象检索内存对象的句柄、设置要发送到 I/O 目标的请求的格式,以及发送请求:
VOID
EvtIoRead(IN WDFQUEUE Queue,IN WDFREQUEST Request,IN size_t Length)
{NTSTATUS status;WDFMEMORY memory;WDFIOTARGET ioTarget;BOOLEAN ret;ioTarget = WdfDeviceGetIoTarget(WdfIoQueueGetDevice(Queue));status = WdfRequestRetrieveOutputMemory(Request, &memory);if (!NT_SUCCESS(status)) {goto End;}status = WdfIoTargetFormatRequestForRead(ioTarget,Request,memory,NULL,NULL);if (!NT_SUCCESS(status)) {goto End;}WdfRequestSetCompletionRoutine(Request,RequestCompletionRoutine,WDF_NO_CONTEXT);ret = WdfRequestSend (Request, ioTarget, WDF_NO_SEND_OPTIONS);if (!ret) {status = WdfRequestGetStatus (Request);goto End;}return;End:WdfRequestComplete(Request, status);return;}
当 I/O 目标完成请求时,框架将调用驱动程序为请求设置的完成回调。 以下代码显示了一个简单的完成回调:
VOID
RequestCompletionRoutine(IN WDFREQUEST Request,IN WDFIOTARGET Target,PWDF_REQUEST_COMPLETION_PARAMS CompletionParams,IN WDFCONTEXT Context)
{UNREFERENCED_PARAMETER(Target);UNREFERENCED_PARAMETER(Context);WdfRequestComplete(Request, CompletionParams->IoStatus.Status);return;}
当驱动程序从其完成回调调用 WdfRequestComplete 时,框架将删除内存对象。 驱动程序检索的内存对象句柄现在无效。
方案 3:驱动程序发出使用现有内存对象的 I/O 请求。
某些驱动程序发出自己的 I/O 请求并将其发送到 I/O 目标,这些目标由 I/O 目标对象表示。 驱动程序可以创建自己的请求对象,也可以 重复使用框架创建的请求对象。 使用任一技术,驱动程序都可以重复使用来自上一个请求的内存对象。 驱动程序不得更改基础缓冲区,但在设置新 I/O 请求的格式时,它可以传递缓冲区偏移量。
当框架格式化要发送到 I/O 目标的请求时,它将代表 I/O 目标对象对回收的内存对象进行引用。 I/O 目标对象将保留此引用,直到执行以下操作之一:
- 请求已完成;
- 驱动程序通过调用 WdfIoTargetFormatRequestXxx 或 WdfIoTargetSendXxxSynchronously 方法之一再次重新设置请求对象的格式;
- 驱动程序调用 WdfRequestReuse;
新的 I/O 请求完成后,框架将调用驱动程序为此请求设置的 I/O 完成回调。 此时,I/O 目标对象仍保留对内存对象的引用。 因此,在 I/O 完成回调中,驱动程序必须先对驱动程序创建的请求对象调用 WdfRequestReuse ,然后才能完成从中检索内存对象的原始请求。 如果驱动程序不调用 WdfRequestReuse,则由于额外的引用,检查会出现 bug。
方案 4:驱动程序发出使用新内存对象的 I/O 请求
框架为驱动程序提供了三种方法来创建新的内存对象,具体取决于基础缓冲区的源。 有关详细信息,请参阅 使用内存缓冲区。
如果缓冲区由框架分配或从驱动程序创建的 lookaside 列表中分配,则内存对象拥有该缓冲区,因此只要内存对象存在,缓冲区指针就保持有效。 发出异步 I/O 请求的驱动程序应始终使用内存对象拥有的缓冲区,以便框架可以确保缓冲区一直存在,直到 I/O 请求完成发证驱动程序。
如果驱动程序通过调用 WdfMemoryCreatePreallocated 将以前分配的缓冲区分配给新的内存对象,则内存对象不拥有该缓冲区。 在这种情况下,内存对象的生存期与基础缓冲区的生存期无关。 驱动程序必须管理缓冲区的生存期,并且不得尝试使用无效的缓冲区指针。
方案 5:驱动程序重复使用它创建的请求对象
驱动程序可以重用其创建的请求对象,但在每次重用之前,它必须通过调用 WdfRequestReuse 来重新初始化每个此类对象。
相关文章:
WDF驱动开发-内存缓冲区
驱动程序通常使用内存缓冲区向/从框架和其他驱动程序传递数据,或在本地存储信息。 WDF常见的内存缓冲区包括框架内存对象(WDFMEMORY)、 lookaside、 MDL 和 本地缓冲区。 使用框架内存对象 框架使用 内存对象 来描述驱动程序从中接收并传递给框架的内存缓冲区。 每…...
c语言连接两个字符串
在C语言中,连接两个字符串可以使用 strcat 函数。这个函数将一个字符串复制到另一个字符串的末尾。使用 strcat 函数之前,需要确保目标字符串有足够的空间来容纳源字符串,否则可能会导致缓冲区溢出。 下面是一个使用 strcat 函数连接两个字符…...
基于springboot的大学计算机基础网络教学系统
文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于springboot的大学计算机基础网络教学…...
UOS常用命令
shutdown 关机 reboot 重启 reboot -f 强制重启 history 查看使用的历史命令 history -c 清空命令行常见目录结构 /bin 存储常用用户指令 /boot 存放用于系统引导时使用的各种文件 /dev 存放设备文件 /etc 存放系统,服务的配置…...
vue3 如何给表单添加表单效验+正则表达式
校验要求 我们的表单中有密码、电话号码 ,两项。 我们设置用密码为3到20位的非空字符 电话号码就用目前用的电话号码正则表达式,要求手机号码以 1 开头,第二位为 3 到 9 之间的数字,后面跟着任意 9 个数字,总共是 11…...
JavaScript算法实现dfs查找省市区路径
需求 存在如下数组,实现一个算法通过输入区名,返回省->市->区格式的路径,例如输入西湖区,返回浙江省->杭州市->西湖区。 // 定义省市区的嵌套数组 const data [{name: "浙江省",children: [{name: "…...
map文件分析
以下是一个具体的map文件示例,并附上详细的描述,帮助你更好地理解如何读取和分析map文件: 示例map文件 Memory ConfigurationName Origin Length Attributes FLASH 0x08000000 0x0…...
MySQL-创建表~数据类型
070-创建表 create table t_user(no int,name varchar(20),gender char(1) default 男);071-插入数据 语法格式: insert into 表名(字段名1, 字段名2, 字段名3,......) values (值1,值2,值3,......);insert into t_user(no, name, gender) values(1, Cupid, 男);字…...
【鸿蒙 HarmonyOS】Swiper组件
一、背景 项目中通常会遇到图片轮播,内容轮播的场景;如:在一些应用首页显示推荐的内容时,需要用到轮播显示的能力。 二、源码地址 ✍Gitee开源项目地址👉:https://gitee.com/cheinlu/harmony-os-next-swi…...
玩具机器人脚本适合场景
玩具机器人脚本作为一个模拟的玩具机器人脚本,适合以下场合: 1.教育和学习:对于初学者和编程爱好者来说,这个脚本是一个很好的学习工具,可以帮助他们理解如何编写和执行简单的控制逻辑。 2.在计算机科学、机器人技术或…...
人工智能模型组合学习的理论和实验实践
组合学习,即掌握将基本概念结合起来构建更复杂概念的能力,对人类认知至关重要,特别是在人类语言理解和视觉感知方面。这一概念与在未观察到的情况下推广的能力紧密相关。尽管它在智能中扮演着核心角色,但缺乏系统化的理论及实验研…...
MySQL备份与恢复:确保数据的安全与可靠性
引言: 数据的安全性和可靠性的重要性 在现代企业和组织中,数据已经成为了最重要的资产之一。数据的安全性和可靠性对于企业的运营至关重要。首先,数据的安全性保证了敏感信息不会落入错误的手中,防止了潜在的经济损失和法律风险。其次,数据的可靠性则确保了企业能够准确…...
Noisee AI – AI音乐影片MV在线生成工具,专门为Suno的好搭子来了~
导读 现在很多各大平台,抖音、快手、微视,还不能直接发布音频文件,如果有一个好听的音乐想做成MV,怎么办呢? 这时候就是Noisee AI的主场,上传一段音乐加上简单的描述就可以在3-5分钟内生成一个可以发布到…...
实战计算机网络02——物理层
实战计算机网络02——物理层 1、物理层实现的功能2、数据与信号2.1 数据通信模型2.2 通信领域常用术语2.3 模拟信号和数字信号 3、信道和调制3.1 信道3.2 单工通信、半双工通信、全双工通信3.3 调制3.4 奈式准则3.5 香农定律 4、传输媒体4.1 导向传输媒体4.2 非导向传输媒体 5、…...
Doris:冷热分层
目录 一、冷热分层介绍 二、存储策略(Storage policy) 2.1 创建存储资源 2.2 创建存储策略 2.3 使用存储策略 三、使用限制 一、冷热分层介绍 冷热分层支持所有 Doris 功能,只是把部分数据放到对象存储上,以节省成本&am…...
28.启动与暂停程序
上一个内容:27.设计注入功能界面 以它 27.设计注入功能界面 的代码为基础进行修改 点击添加游戏按钮之后就把游戏启动了 CWndINJ.cpp文件中修改: void CWndINJ::OnBnClickedButton1() {// TODO: 在此添加控件通知处理程序代码/*ExeLst.InsertItem(0, L…...
404 页面代码
<template> <div class"container"><h1>404</h1> <div ><p class"text-center">当前页面无法访问,可能没有权限或已删除</p><p class"text-center"> 去别处看看吧</p> </div> <…...
java设计模式和面向对象编程思想
Java设计模式和面向对象编程思想是软件开发中的核心概念,对于构建可维护、可扩展的软件系统至关重要。下面是对这两个主题的知识点总结: 面向对象编程(OOP)思想 封装:将数据(属性)和操作这些数据…...
超万卡训练集群网络互联技术解读
超万卡训练集群互联关键技术 大模型迈向万亿参数的多模态升级,万卡集群计算能力亟需飞跃。关键在于增强单芯片性能、提升超节点算力、融合DPU多计算能力,并追求算力能效比极致。这一系列提升将强有力支撑更大规模模型训练和推理,快速响应业务…...
AtomicInteger类介绍
文章目录 一、AtomicInteger的定义二、AtomicInteger的使用场景和作用1.使用场景2.作用 三、AtomicInteger的常用方法四、AtomicInteger的底层原理五、AtomicInteger和Integer的区别1.数据类型与线程安全性2.默认值与初始化3.常用方法与操作:4.内存模型与可见性5.使…...
Es 索引查询排序分析
文章目录 概要一、Es数据存储1.1、_source1.2、stored fields 二、Doc values2.1、FieldCache2.2、DocValues 三、Fielddata四、Index sorting五、小结六、参考 概要 倒排索引 优势在于快速的查找到包含特定关键词的所有文档,但是排序,过滤、聚合等操作…...
【C语言】解决C语言报错:Format String Vulnerability
文章目录 简介什么是Format String VulnerabilityFormat String Vulnerability的常见原因如何检测和调试Format String Vulnerability解决Format String Vulnerability的最佳实践详细实例解析示例1:直接使用不受信任的输入作为格式化字符串示例2:未验证格…...
Python深度学习:Bi-LSTM和LSTM在网络上有什么区别,对比来看
文章目录 LSTM代码解释类定义和构造函数前向传播方法 (`forward`)总结Bi-LSTMLSTM 代码 class BaseLSTMModel(nn.Module):def __init__(self, input_dim, hidden_dim, layer_dim, class_num):super().__init__...
Keepalived LVS群集
一、Keepalived案例分析 企业应用中,单台服务器承担应用存在单点故障的危险 单点故障一旦发生,企业服务将发生中断,造成极大的危害 二、Keepalived工具介绍 专为LVS和HA设计的一款健康检查工具 支持故障自动切换(Failover&#…...
harbor问题总结
1. http协议的仓库docker login不上,更改/etc/docker/daemon.json,加一个镜像仓库地址 http: server gave HTTP response to HTTPS client 分析一下这个问题如何解决中文告诉我详细的解决方案-CSDN博客 2. Error response from daemon: login attempt t…...
windows系统,家庭自用NAS。本地局域网 Docker安装nextcloud
windows系统,家庭自用NAS。本地局域网 Docker安装nextcloud 1、docker安装 太简单了,直接去搜一搜。 docker-compose 相关命令 docker-compose down docker compose up -d2、还是使用老的 在你需要挂载的目录下,新建一个文件,…...
迅狐跨境商城系统|全平台兼容|前端采用uni-app跨端框架,后端采用ThinkPHP5框架
高效实现全平台兼容的迅狐跨境商城系统 迅狐跨境商城系统是一款专为跨境电商企业设计的全平台兼容系统。其前端采用uni-app跨端框架,后端采用ThinkPHP5框架,旨在实现高效的开发和运营管理。 1. 全平台兼容的前端设计 迅狐跨境商城系统的前端采用uni-a…...
Elixir学习笔记——进程(Processes)
在 Elixir 中,所有代码都在进程内运行。进程彼此隔离,彼此并发运行并通过消息传递进行通信。进程不仅是 Elixir 中并发的基础,而且还提供了构建分布式和容错程序的方法。 Elixir 的进程不应与操作系统进程混淆。Elixir 中的进程在内存和 CPU…...
困惑度作为nlp指标的理解示例
为了更清晰地说明困惑度的计算过程以及如何通过困惑度判断模型的优劣,我们可以通过一个简单的例子来演示。假设我们有一个非常简单的文本语料库和两个基础的语言模型进行比较。 示例文本 假设我们的文本数据包括以下两个句子: “cat sits on the mat”…...
01 Pytorch 基础
paddle不需要放数据到gpu! 区别:1.batch_norlization 不同 2. 1.数据处理 1.取一个数据,以及计算大小 (剩下的工作,取batch,pytorch会自动做好了) 2.模型相关 如何得到结果 3.模型训练/模型…...
做二手房的端口网站/下载百度网盘app
前言 在项目中频繁遇到数组、集合和泛型,在使用vue时,用到最多的是数组;在后台时使用最多的是泛型,有时还用到IList,下面来学习一下它们之间的关系。 正文 数组 概念 一组类型相同的有序数据,它是…...
营口软件开发/咖啡seo是什么意思
引言Java没有提供任何机制来安全地终止线程,但提供了中断机制,即thread.interrupt()方法。线程中断是一种协作式的机制,并不是说调用了中断方法之后目标线程一定会立即中断,而是发送了一个中断请求给目标线程,目标线程…...
江西赣州网站建设/搜索网站哪个好
参考:http://www.mamicode.com/info-detail-1705113.html 先声明,热更新词库,需要用到,web项目和Tomcat。不会的,请移步 Eclipse下Maven新建项目、自动打依赖jar包(包含普通项目和Web项目) Tomc…...
wordpress++分页/宁波超值关键词优化
一个无锁消息队列引发的血案(四)——月:RingQueue(上) 自旋锁 - shines77 - 博客园 #ifndef _RINGQUEUE_ #define _RINGQUEUE_#include <stdbool.h> #include <stdio.h> #include <string.h>// 队列包含的信息 typedef str…...
建设网站公司名称大全/电商网络推广怎么做
许多朋友在生活中遇到过手机没有信号的情况。尽管无法和通讯录中的号码进行通话,但是像 110,120 这种紧急号码却还能打通。原因其实很简单。我们知道,手机在正常开机后,会先检测是否有 SIM 卡,再搜索附近的运营商基站和…...
陕西省城乡建设厅网站/百度手机版
PDFAction 当激活PDF批注或单击大纲项目时执行的操作 class PDFAction : NSObject 使用教程 PDFAction对象表示与PDF元件,诸如注释或链路相关联的动作,观看者应用程序可以执行。有关动作和动作类型的更多信息,请参见Adobe PDF规范。 PDFActio…...