windows 驱动开发-DMA技术(三)

在早期,是按照基于包或者基于流的方式来描述DMA的,不过这个描述可能不准确,故在Vista之后修改为使用数据包/使用公共缓冲区的系统DMA。

简单的解释一下基于包和基于流的说法的原因,数据包是指一个个基于一定大小的数据块,例如设定4096大小的内存页面,如果我们使用基于包的方式传输5000个字节,那么就是两个数据包,第一个数据包为4096字节,第二个数据包是904字节,实际传输两个数据包;如果使用基于流的,那么流传输每次回来1个数据包,缓冲区会根据自身的大小从里面拷贝数据,那么系统缓冲区先从第一个数据包中拷贝4096个字节,再从第二个数据包中拷贝906个字节。

在上面的描述中,我们会发现基于流的数据包对于数据利用率和容忍度更高一些。

使用公用缓冲区系统 DMA

使用系统 DMA 控制器的自动初始化模式的驱动程序必须为可以执行 DMA 传输的缓冲区分配内存。驱动程序调用 AllocateCommonBuffer 来获取此缓冲区,通常来自处理IRP_MN_START_DEVICE请求的 DispatchPnP 例程。 下图显示了驱动程序如何分配缓冲区并将其虚拟地址范围映射到系统物理内存。

如上图所示,驱动程序执行以下步骤为系统 DMA 分配缓冲区:

1. 驱动程序调用 AllocateCommonBuffer,将指针传递到 IoGetDmaAdapter 返回的适配器对象,以及为其缓冲区请求的长度(以字节为单位)。 若要以经济方式使用内存,缓冲区的输入 Length 值应小于或等于 PAGE_SIZE或应是PAGE_SIZE的整数倍数;

2. 如果 AllocateCommonBuffer 返回 NULL 指针,驱动程序应释放已声明的任何系统资源,并返回STATUS_INSUFFICIENT_RESOURCES以响应 IRP_MN_START_DEVICE 请求;否则, AllocateCommonBuffer 在系统虚拟地址空间中分配请求的内存量,并返回指向该缓冲区的两种不同类型的指针:

  • 上图中缓冲区的 LogicalAddress (BufferLogicalAddress) ,驱动程序必须为此提供存储,但随后应忽略存储
  • 上图中缓冲区虚拟地址 (BufferVirtualAddress) ,驱动程序还必须存储该地址,以便它可以生成描述其缓冲区的 MDL 以执行 DMA 操作

驱动程序应将这些指针存储在设备扩展或其他驱动程序分配的驻留内存中;

3. 驱动程序调用 IoAllocateMdl 为缓冲区分配 MDL。 驱动程序传递 AllocateCommonBuffer 返回的缓冲区的 VirtualAddress 及其缓冲区的 Length 以分配 MDL;

4. 驱动程序使用 IoAllocateMdl 返回的指针调用 MmBuildMdlForNonPagedPool,以将其驻留缓冲区的虚拟地址范围映射到系统物理内存;

分配公共缓冲区并映射其虚拟地址范围后,从属设备的驱动程序可以开始处理请求 DMA 传输的 IRP。 为此,驱动程序调用以下常规支持例程序列:

  • 由驱动程序编写者自行决定, RtlMoveMemory 将数据从锁定的用户缓冲区复制到驱动程序分配的公共缓冲区,以便传输到设备;
  • 当驱动程序准备好针对 DMA 对设备进行编程并需要系统 DMA 控制器时,AllocateAdapterChannel;
  • MapTransfer,使用描述驱动程序分配的公共缓冲区的 MDL,为传输操作设置系统 DMA 控制器,请注意,驱动程序仅调用 MapTransfer 一次,以将系统 DMA 控制器设置为使用其公共缓冲区。 在传输期间,驱动程序可以调用 ReadDmaCounter 来确定剩余要传输的字节数,并在必要时调用 RtlMoveMemory 以向用户缓冲区或从用户缓冲区复制更多数据;
  • 当驱动程序完成从属设备的 DMA 传输时调用FlushAdapterBuffers;
  • 只要传输了所有请求的数据,或者驱动程序必须因设备 I/O 错误而使 IRP 失败,则 FreeAdapterChannel;

IoGetDmaAdapter 返回的适配器对象指针是除 RtlMoveMemory 以外的每个支持例程的必需参数。

各个驱动程序在不同点调用此支持例程序列,具体取决于实现每个驱动程序以为其设备提供服务的方式。 例如,一个驱动程序的 StartIo 例程可能会调用 AllocateAdapterChannel,另一个驱动程序可能会从从驱动程序创建的互锁队列中删除 IRP 的例程发出此调用,另一个驱动程序可能在其从属 DMA 设备指示它已准备好传输数据时发出此调用。

分配适配器通道

驱动程序在其 DispatchRead 或 DispatchWrite 例程 (或任何其他处理 DMA 传输的调度例程之后调用 AllocateAdapterChannel之前) 需要检查 IRP 参数的有效性,可能已将一个或多个 IRP 排队到另一个驱动程序例程进行进一步处理,如果适用可能加载其公共缓冲区以及要传输的数据。

调用 AllocateAdapterChannel 的 驱动程序例程必须在 IRQL=DISPATCH_LEVEL 执行。 AllocateAdapterChannel 例程将驱动程序的 AdapterControl 例程排入队列,该例程在系统 DMA 控制器分配给此驱动程序后运行,并为驱动程序的 DMA 操作分配了一组映射寄存器。

输入时, 向 AdapterControl 例程提供指向设备对象的指针和在 调用 AllocateAdapterChannel 中传递的上下文,以及分配的映射寄存器的句柄。 如果驱动程序具有 StartIo 例程,还会为 AdapterControl 例程提供指向 DeviceObject->CurrentIrp 的指针。 如果驱动程序管理自己的 IRP 队列而不是 StartIo 例程,则驱动程序应包含指向当前 IRP 的指针,作为它在调用 AllocateAdapterChannel 时传递的上下文数据的一部分。

AdapterControl 例程通常执行以下操作:

  • 保存或初始化驱动程序维护的有关 DMA 操作的任何上下文。 上下文可能包括驱动程序必须传递给 MapTransfer 和 FlushAdapterBuffers 的输入 MapRegisterBase 句柄,以及从 IRP 中的 I/O 堆栈位置请求的传输的长度;
  • 设置从属设备以启动传输操作;
  • 返回值 KeepObject;

对于使用系统 DMA 控制器的自动初始化模式的驱动程序, AdapterControl 例程必须返回值 KeepObject, 这允许驱动程序保留系统 DMA 控制器的“所有权”和分配的映射寄存器 ,直到传输所有数据。

由于 AdapterControl 例程不能等待从属设备执行 DMA 操作, 因此 AdapterControl 例程必须至少执行以下操作:

  • 将上下文信息(尤其是 MapRegisterBase 句柄)保存在驱动程序的设备扩展、控制器扩展或其他驱动程序可访问的常驻存储区域中,驱动程序分配的非分页池。
  • 返回 KeepObject。

另一个驱动程序例程 (很可能是 DpcForIsr 例程) 必须在 DMA 传输操作完成时调用 FlushAdapterBuffers 和 FreeAdapterChannel 。

设置系统DMA

当 AllocateAdapterChannel 将控制权转移到驱动程序的 AdapterControl 例程时,驱动程序将“拥有”系统 DMA 控制器和一组映射寄存器。 然后,驱动程序必须调用 MapTransfer ,以将系统 DMA 控制器设置为使用驱动程序分配的公共缓冲区,然后驱动程序为传输操作设置其设备。

驱动程序向 MapTransfer 提供以下参数:

  • IoGetDmaAdapter 返回的适配器对象指针;
  • 指向描述驱动程序分配的公共缓冲区的 MDL 的指针;
  • 通过 AllocateAdapterChannel 传递给驱动程序的 AdapterControl 例程的 MapRegisterBase 句柄;
  • 指向变量的指针 (Length) 指示驱动程序分配的公共缓冲区的大小,以字节为单位;
  • 一个布尔值,指示传输操作的方向,请求从系统内存传输到设备;

MapTransfer 返回一个逻辑地址,使用系统 DMA 的驱动程序必须忽略该地址。 当 MapTransfer 返回控件时,驱动程序应为 DMA 操作设置其设备。 驱动程序只调用 MapTransfer 一次,但会继续在其公共缓冲区和锁定的用户缓冲区之间复制数据,直到完成请求的传输。

驱动程序可以调用 ReadDmaCounter 来确定当前在公共缓冲区中要传输的字节数,然后驱动程序可以继续使用用户数据填充其公共缓冲区,或将数据从其公共缓冲区复制到用户缓冲区,具体取决于 DMA 操作的方向。

传输完成或驱动程序必须返回 IRP 的错误状态时,驱动程序将调用 FlushAdapterBuffers ,以确保将系统 DMA 控制器中缓存的任何数据读入系统内存或写出到设备。 然后,驱动程序应立即调用 FreeAdapterChannel ,以释放系统 DMA 控制器供任何驱动程序 (包括自身) 使用。

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

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

相关文章

IDA pro动态调试so层初级教程

一、开启服务 adb push D:\MyApp\IDA_Pro_7.7\dbgsrv\android_server64 /data/local/tmpadb shell cd /data/local/tmp chmod 777 android_server64 ./android_server64二、IDA附加进程 十万个注意:IDA打开的so文件路径不能有中文 手机打开要调试的app 附加成功

讯飞星火大模型赋能教育,引领教育实现数字化转型 | 最新快讯

(原标题:讯飞星火大模型赋能教育,引领教育实现数字化转型) 随着人工智能的发展,大模型正成为人们获取知识、学习知识的“超级助手”,是解放生产力、释放想象力的“好帮手”。随着大模型在多个领域大放异彩…

guidance - Microsoft 推出的编程范式

文章目录 一、关于 guidance安装 二、加载模型llama.cppTransformersVertex AIOpenAI 三、基本生成四、限制的生成选择(基本)正则表达正则表达式来限制生成正则表达式作为停止标准 上下文无关语法 五、状态控制生成1、不可变对象中的状态2、有状态的 gui…

Nodejs 第六十九章(杀毒)

杀毒 杀毒(Antivirus)是指一类计算机安全软件,旨在检测、阻止和清除计算机系统中的恶意软件,如病毒、蠕虫、木马、间谍软件和广告软件等。这些恶意软件可能会对计算机系统和用户数据造成损害,包括数据丢失、系统崩溃、…

基于ROS从零开始构建自主移动机器人:仿真和硬件

书籍:Build Autonomous Mobile Robot from Scratch using ROS:Simulation and Hardware 作者:Rajesh Subramanian 出版:Apress 书籍下载-《基于ROS从零开始构建自主移动机器人:仿真和硬件》您将开始理解自主机器人发…

(1)从头搞懂 Transformer模型(图解)

1、Transformer简介 GPT回答:(面试被问到可以这么介绍) Transformer是一种用于处理序列数据的深度学习模型架构,最初由Vaswani等人在2017年的论文《Attention is All You Need》中提出。它在处理序列到序列(seq2seq&…

2024年Q1葡萄酒行业线上电商(京东天猫淘宝)销售排行榜

五一聚餐不可缺少饮品——葡萄酒。鲸参谋监测的线上电商平台(某东)Q1季度葡萄酒行业销售数据已揭晓! 从鲸参谋的数据中,我们可以明显看到今年Q1季度在线上电商平台(某东)葡萄酒行业的销售情况呈现出积极的…

Java面试八股之int和Integer有什么区别

int和Integer有什么区别 基本类型与包装类: int:int是Java中的一个基本数据类型(primitive type),用于表示整数。它直接存储数值,没有独立的对象实例,不涉及内存管理。 Integer:I…

WebGL渲染引擎优化方向 -- 加载性能优化

作者:caven chen 前言 WebGL 是一种强大的图形渲染技术,可以在浏览器中快速渲染复杂的 3D 场景。但是,由于 WebGL 的高性能和高质量要求,如果不注意性能优化,它可能会消耗大量的 CPU 和 GPU 资源,导致应用…

使用 VLC Media Player 播放 RTSP 流媒体

VLC 是一款自由、开源的跨平台多媒体播放器及框架,可播放大多数多媒体文件,以及 DVD、音频 CD、VCD 及各类流媒体协议,也可以播放 RTSP 流媒体。 一、简介: VLC Media Player 是一款功能强大且开源的跨平台多媒体播放器。 支持…

LeetCode 102.对称二叉树

题目描述 给你一个二叉树的根节点 root , 检查它是否轴对称。 示例 1: 输入:root [1,2,2,3,4,4,3] 输出:true示例 2: 输入:root [1,2,2,null,3,null,3] 输出:false提示: 树中节点数…

【免费Java系列】大家好 ,给大家出一些今天学习内容的案例点赞收藏关注,持续更新作品 !

多态 Java中的多态是指同一个方法在不同的对象上有不同的行为: 案例一 以下有四个类 : 动物类与狗、猫类 Test测试类 // 动物类 class Animal {public void sound() {System.out.println("动物发出声音");} }// 狗类 class Dog extends Animal {Overridepublic void…

Go实现树莓派按键识别

环境 在Windows要注意交叉编译设置, 这个库目前没有使用C, 所以不需要配置GCC、G, 配置如下 GOOSlinux GOARCHarm 代码 package mainimport ("fmt""github.com/stianeikeland/go-rpio/v4""os""time" )var (…

C语言-整体内容简单的认识

目录 一、数据类型的介绍二、数据的变量和常量三、变量的作用域和生命周期四、字符串五、转义字符六、操作符六、常见的关键字6.1 关键字static 七、内存分配八、结构体九、指针 一、数据类型的介绍 sizeof是一个操作符,是计算机类型/变量所占内存空间的大小   sc…

实验三 .Java 语言继承和多态应用练习 (课内实验)

一、实验目的 本次实验的主要目的是通过查看程序的运行结果及实际编写程序,练习使用 Java 语言的继承特性。 二、实验要求 1. 认真阅读实验内容,完成实验内容所设的题目 2. 能够应用多种编辑环境编写 JAVA 语言源程序 3. 认真体会多态与继承的作用…

【项目构建】04:动态库与静态库制作

OVERVIEW 1.编译动态链接库(1)编译动态库(2)链接动态库(3)运行时使用动态库 2.编译静态链接库(1)编译静态库(2)链接静态库(3)运行时使…

【数据结构-之八大排序(下),冒泡排序,快速排序,挖坑法,归并排序】

🌈个人主页:努力学编程’ ⛅个人推荐:基于java提供的ArrayList实现的扑克牌游戏 |C贪吃蛇详解 ⚡学好数据结构,刷题刻不容缓:点击一起刷题 🌙心灵鸡汤:总有人要赢,为什么不能是我呢 …

信息管理与信息系统就业方向及前景分析

信息管理与信息系统(IMIS)专业的就业方向十分广泛,包含计算机方向、企业信息化管理、数据处理和数据分析等,随着大数据、云计算、人工智能、物联网等技术的兴起,对能够处理复杂信息系统的专业人才需求激增,信息管理与信息系统就业…

动态数据结构中的表扩张性:摊还分析、伪代码与C语言实现

动态数据结构中的表扩张性:摊还分析、伪代码与C语言实现 引言表扩张性的概念摊还分析在表扩张性中的应用伪代码示例:TABLE-INSERT操作C语言实现结论 引言 在处理数据结构时,尤其是表(或数组),我们经常面临…

第一课 自动驾驶概述

1. contents 2. 什么是无人驾驶/自动驾驶 3 智慧出行大智慧 4. 无人驾驶的发展历程