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

前面描述了DMA技术中适配器相关的部分以及DMA的分类,接下来看一下系统具体在支持两种DMA时候的操作的细微差别。

此处解释一下Scatter/Gather,这个也翻译为散点/收集,是指指示设备能够读取或写入内存中的任何区域,而不仅仅是特定范围。在早期,DMA读写的区域必须是一个整页面,但是这种要求其实对于内核来说,不是每时每刻都可以满足的,故和MDL类似,系统也支持将不在同一个页面上N个数据块映射为一整个页面。

使用基于数据包的系统 DMA

使用基于数据包的 DMA 的从属设备的驱动程序在处理请求 DMA 传输的 IRP 时调用以下常规支持例程序列:

  • 尝试分配系统 DMA 控制器 ;
  • 当驱动程序准备好针对 DMA 对设备进行编程并需要系统 DMA 控制器调用AllocateAdapterChannel,AllocateAdapterChannel 依次调用驱动程序的 AdapterControl 例程。
  • MmGetMdlVirtualAddress 获取 MDL 中的索引,在对 MapTransfer 的初始调用中需要作为参数MapTransfer 为传输操作对系统 DMA 控制器进行编程
  • 驱动程序可能需要多次调用 MapTransfer 来传输所有请求的数据;
  • FlushAdapterBuffers ,就在每个 DMA 传输操作与从属设备之间
  • 如果驱动程序必须多次调用 MapTransfer 以传输所有请求的数据,则它必须调用 FlushAdapterBuffers 的次数与调用 MapTransfer 的次数一样多。
  • FreeAdapterChannel 只要传输了所有请求的数据,或者驱动程序因设备 I/O 错误导致 IRP 失败

IoGetDmaAdapter 返回的适配器对象指针是每个例程的必需参数,KeFlushIoBuffers 和 MmGetMdlVirtualAddress 除外,后者需要指向在 Irp->MdlAddress 传递的 MDL 的指针。

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

分配适配器通道

为了准备基于数据包的系统 DMA,驱动程序在收到IRP_MJ_READ或IRP_MJ_WRITE请求后调用 KeFlushIoBuffers 和 AllocateAdapterChannel。

在驱动程序调用这些例程之前,其 DispatchRead 或 DispatchWrite 例程 (或其他处理 DMA 传输) 的调度例程应已检查 IRP 参数的有效性。 调度例程还可能已将 IRP 排到另一个驱动程序例程进行进一步处理。

调用 AllocateAdapterChannel 的 驱动程序例程必须在 IRQL=DISPATCH_LEVEL执行。 除了指向 IoGetDmaAdapter 返回的适配器对象的指针之外,驱动程序还必须在调用 AllocateAdapterChannel 时提供以下内容:

  • 指向目标设备对象的指针
  • 其 AdapterControl 例程的入口点
  • 指向 AdapterControl 例程将使用的任何驱动程序确定的上下文信息的指针

AllocateAdapterChannel 将驱动程序的 AdapterControl 例程排队,该例程在系统 DMA 控制器分配给此驱动程序时运行,并且已为驱动程序的 DMA 操作分配了一组 映射寄存器。

输入时,AdapterControl 例程接收在对 AllocateAdapterChannel 的调用中传递的 DeviceObject 和 Context 指针,以及分配的映射寄存器 (MapRegisterBase) 句柄。

如果驱动程序具有 StartIo 例程,AdapterControl 例程还会收到指向 DeviceObject->CurrentIrp 的指针。 如果驱动程序管理自己的 IRP 队列,而不是使用StartIo 例程,则驱动程序应包含指向当前 IRP 的指针,作为它在调用 AllocateAdapterChannel 时传递的上下文的一部分。

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

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

每个 AdapterControl 例程都必须返回 IO_ALLOCATION_ACTION类型的系统定义值。 对于使用系统 DMA 的驱动程序, AdapterControl 例程必须返回值 KeepObject。 这允许驱动程序保留系统 DMA 控制器和分配的映射寄存器的所有权,直到传输了所有请求的数据。

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

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

另一个驱动程序例程 (可能是 DpcForIsr 例程) 必须在每个 DMA 传输操作完成时调用 FlushAdapterBuffers 。 如果需要多次设置 DMA 控制器以满足当前 IRP 的传输请求,此例程还必须再次调用 MapTransfer 和 FlushAdapterBuffers 。

当驱动程序满足当前 IRP 的请求时,它必须调用 FreeAdapterChannel。 此支持例程应在上次调用当前 IRP 的 FlushAdapterBuffers 之后立即调用,以便系统 DMA 控制器可供任何驱动程序 迅速满足其他传输请求。

具有Scatter/Gather功能的从属设备的驱动程序还应从其 AdapterControl 例程返回 KeepObject。 当驱动程序必须拆分给定 DMA 请求时,当系统 DMA 控制器在 DMA 操作之间重新编程时,设备必须能够等待。 在某些 Windows 平台上,此类设备每次 DMA 操作最多可以传输一页数据,因为 HAL 只能将单个映射寄存器分配给该设备的驱动程序。

设置系统DMA

当 AllocateAdapterChannel 将控制权转移到驱动程序的 AdapterControl 例程时,驱动程序将“拥有”系统 DMA 控制器和一组映射寄存器。 然后,驱动程序必须为传输操作设置 DMA 控制器,如下图所示:

如果驱动程序具有 StartIo 例程,则 AllocateAdapterChannel 会将 PIrp 参数中指向 DeviceObject-CurrentIrp> 的指针传递到 AdapterControl 例程。 但是,如果驱动程序管理自己的 IRP 队列,则驱动程序应包含指向当前 IRP 的指针,作为它传递给 AdapterControl 的上下文的一部分。

如上图所示,驱动程序的 AdapterControl 例程设置 DMA 传输,如下所示:

1. AdapterControl 例程获取开始传输的地址。 对于满足 IRP 所需的初始传输, AdapterControl 例程调用 MmGetMdlVirtualAddress,将指针传递到 Irp->MdlAddress 处的 MDL,该指针描述此 DMA 传输的缓冲区;MmGetMdlVirtualAddress 返回一个虚拟地址,驱动程序可以使用该地址作为应开始传输的系统物理地址的索引;如果 IRP 需要多个传输操作,驱动程序将计算更新的起始地址,如后面所述。

2. AdapterControl 例程保存 MmGetMdlVirtualAddress 返回或在步骤 1 中计算的地址。 此地址是 MapTransfer (CurrentVa) 的必需参数。

3. AdapterControl 例程调用 MapTransfer 来设置系统 DMA 控制器,并提供以下参数:

  • IoGetDmaAdapter 返回的适配器对象指针;
  • 指向当前 IRP 的 Irp-> MdlAddress处的 MDL (Mdl 的指针),通过 AllocateAdapterChannel 传递给驱动程序的 AdapterControl 例程的 MapRegisterBase 句柄;
  • 如果这是第一次调用 IRP 的 MapTransfer,则 mmGetMdlVirtualAddress 返回的 Current) Va 值 ;否则,驱动程序会提供更新的 CurrentVa 值,指示下一个传输操作应在缓冲区中的哪个位置启动;
  • 指向变量的指针 (Length) 指示此传输的字节数;
  • 如果驱动程序可以通过一次调用 MapTransfer 来传输请求的所有数据,并且对其 DMA 操作没有特定于设备的约束,则可以在驱动程序的 I/O 堆栈位置的 IRP 中将 Length 设置为 Length 值。 最多可以 (PAGE_SIZE * IoGetDmaAdapter) 返回的 NumberOfMapRegisters,以字节为单位。 否则,驱动程序必须拆分请求(如拆分传输请求中所述),并且必须在对当前 IRP 的 MapTransfer 的后续调用中更新 Length 值;
  • 一个布尔值 (WriteToDevice) ,指示传输操作的方向, TRUE 将数据从系统内存传输到设备;反之亦然;

4. MapTransfer 返回逻辑地址,使用系统 DMA 的驱动程序必须忽略此值;

5. AdapterControl 例程为 DMA 操作设置设备;

6. AdapterControl 例程返回 KeepObject;

当设备指示其当前 DMA 操作已完成时,驱动程序应调用 FlushAdapterBuffers,通常是从驱动程序的 DpcForIsr 例程调用。

完成 DMA 操作的 DpcForIsr 例程或其他驱动程序例程调用 FlushAdapterBuffers,以确保将系统 DMA 控制器中缓存的任何数据读入系统内存或写出到设备。 如果需要重新编程系统 DMA 控制器以便为当前 IRP 传输更多数据,则同一例程还必须再次调用 MapTransfer ;同样它必须在每次传输操作后再次调用 FlushAdapterBuffers 。

如果驱动程序必须多次为当前 IRP 调用 MapTransfer ,它将在每次调用中提供相同的适配器对象指针、 Mdl 指针、 MapRegisterBase 句柄和传输方向。 但是,驱动程序必须先更新 CurrentVa 和 Length 参数,然后才能对 MapTransfer 进行第二次和任何后续调用。 若要计算其中每个参数的更新值,请使用以下公式:

  • CurrentVa = 在对 MapTransfer的前面调用中请求的 CurrentVa + Length;
  • Length = 最小剩余要传输的长度, (PAGE_SIZE * IoGetDmaAdapter) ) 返回的 NumberOfMapRegisters;

每个驱动程序应维护的有关其 DMA 传输的上下文信息取决于其特定设备的需求。 典型上下文可能包括 MDL (CurrentVa) 中的当前虚拟地址、到目前为止传输的字节数、要传输的剩余字节数、可能指向当前 IRP 的指针,以及驱动程序编写者认为有用的任何其他信息。

当请求的传输完成时,或者如果驱动程序必须返回 IRP 的错误状态,则驱动程序应立即调用 FreeAdapterChannel ,以释放系统 DMA 控制器以供其他驱动程序和此驱动程序使用。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

构建智能化商旅服务:酒店中台云服务架构设计与实践

随着商旅行业的不断发展和智能化趋势的兴起,酒店中台云服务成为了提升服务质量和效率的关键。本文将探讨酒店商旅中台云服务的架构设计与实现,介绍其关键特点和最佳实践,助力商旅行业迈向智能化未来。 1. **需求分析与场景设计:*…

【阿里云服务器】ubuntu 22.04.1安装docker以及部署java环境

我的服务器配置是2GB CPU 2GB 内存 Ubuntu22.04 目录 一、阿里云 ubuntu 22.04.1安装docker 二、docker基础命令 三、Windows电脑访问云服务器 四、安装java环境 安装OpenJDK 8(可以根据需要安装其他版本的JDK) 安装java的依赖管理工具maven 一、…

基于yolov2深度学习网络模型的鱼眼镜头中人员检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 load yolov2.mat% 加载训练好的目标检测器 img_size [448,448]; imgPath test/; % 图像…

LeetCode 15 —— 三数之和

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 首先我们对数组进行从小到大排序,然后遍历数组 [ 0 , n u m s . s i z e ( ) − 3 ] [0,nums.size()-3] [0,nums.size()−3] 作为三元组中的 a a a,由于三元组的索引互不相同&#xff0c…

文件与IO基础常识知识

在这里,只介绍理论知识,不介绍代码。 目录 1.IO 1.1.字面概念 1.2.输入输出模型 2.文件 2.1.文件目录 2.2.文件路径 2.3.文件分类 1.IO 为了我们接下来学习的文件IO,所以我们先来认识什么是IO。 1.1.字面概念 (1&#x…

【知识加油站】——机电产品数字孪生机理模型构建

明确一种多领域、多层次、参数化、一致性的机电一体化装备数字孪生机理模型构建准则! 关键词英文简称: 数字孪生:DT物联网:IoT网络物理系统:CPS高级架构:HLA统一建模语言:UML数控机床&#xf…

Sarcasm detection论文解析 |A2Text-Net:一种用于讽刺检测的新型深度神经网络

论文地址 论文地址:A2Text-Net: A Novel Deep Neural Network for Sarcasm Detection | IEEE Conference Publication | IEEE Xplore github:lliyuan1117/A2Text-Net (github.com) 论文首页 A2Text-Net:一种用于讽刺检测的新型深度神经网络 &#x1f4c5…

Win11 怎么让软件运行后台全部显示在任务栏上 win11任务栏展开显示所有软件图标

Win11 怎么让软件运行后台全部显示在任务栏上 win11任务栏展开显示所有软件图标 方法二 搜索cmd 打开命令行面板 然后输入 explorer shell:::{05d7b0f4-2121-4eff-bf6b-ed3f69b894d9}就能显示出来了 ## 方法三 通知区域图标不存在 如图,显示为这样 这种时候桌面…

深入解析Java中的String对象及其性能优化

作者主页: 🔗进朱者赤的博客 精选专栏:🔗经典算法 作者简介:阿里非典型程序员一枚 ,记录在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法(公众号同名) ❤️觉得文章还…

uniapp乡村社区户籍问外来人员管理系统 微信小程序python+java+node.js+php

基于微信小程序的外来人员管理系统项目的概述设计分析,主要内容有的私教预约平台系统平台的具体分析,进行数据库的是设计,数据采用MySQL数据库,并且对于系统的设计采用比较人性化的操作设计,对于系统出现的错误信息可以…

用Jenkins Gerrit-Trigger插件实现提交gerrit后自动启动编译验证-解决编译依赖问题

用Jenkins Gerrit-Trigger插件实现提交gerrit后自动启动编译验证-CSDN博客讨论了如何利用插件在提交gerrit的时候自动出发一个jenkins job编译固件,但是没有解决编译依赖问题。本文提出一种解决方案 首先在git commit -m ""的时候在commit message中设置Depend-On:…

Typescript基础语法(四)

模块化 模块化是指将复杂的程序拆解为多个独⽴的⽂件单元,每个⽂件被称为⼀个模块。在 TypeScript 中,默认情况下,每个模块都拥有⾃⼰的作⽤域,这意味着在⼀个模块中声明的任何内容(如变量、函数、类等)在该…

我们的手机是如何连接上网的?骨干网又是什么?

什么是骨干网(Backbone Network) 几台计算机连接起来,互相可以看到其他人的文件,这叫局域网。整个城市的计算机都连接起来,就是城域网。把城市之间连接起来的网就叫骨干网。 这些骨干网是国家批准的可以直接和国外连…

CUDA CPP Unity Compute Shader

为学 开始一个新的学习计划,涵盖: 主题学习内容CUDAProfessional CUDA C Programming/NVIDIA CUDA初级教程视频(周斌)CCPrimer / The Cherno CPPUnity Compute ShaderUdemy Learn to Write Unity Compute ShadersLinear AlgebraMIT 18.06 Prof.Gilbert…

【Anaconda 3 】Jupyter Notebook 的安装配置及使用

Jupyter Notebook 的安装配置及使用 一、引言 Jupyter Notebook 是一种交互式笔记本,它允许用户将代码、注释、方程式、可视化内容等整合到一个文档中,并支持多种编程语言,如 Python、R、Julia 等。它在数据科学、机器学习和教育领域中得到…

Idea 自动生成测试

先添加测试依赖&#xff01;&#xff01; <!--Junit单元测试依赖--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>5.9.1</version><scope>test</scope><…

MATLAB 集成

MATLAB 集成&#xff08;Integration&#xff09; 集成处理两种本质上不同的问题。 在第一种类型中&#xff0c;给出了函数的导数&#xff0c;我们想找到函数。因此&#xff0c;我们从根本上扭转了分化的过程。这种反向过程称为反微分&#xff0c;或者找到原始函数&#xff0…

基于SSM的宠物领养平台(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的宠物领养平台&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

专项技能训练五《云计算网络技术与应用》实训7-1:安装mininet

文章目录 mininet安装1. 按6-1教程安装opendaylight控制器。2. 按6-2教程安装RYU控制器。3. 按5-1教程安装openvswitch虚拟交换机并开启服务。4. 将老师所给mininet安装包试用winSCP传送至电脑端。5. 安装net-tools。6. 安装mininet7. 安装完成后&#xff0c;使用命令建立拓扑&…

Stable Diffusion webUI 配置指南

Stable Diffusion webUI 配置指南 本博客主要介绍部署Stable Diffusion到本地&#xff0c;生成想要的风格图片。 文章目录 Stable Diffusion webUI 配置指南1、配置环境&#xff08;1&#xff09;pip环境[可选]&#xff08;2&#xff09;conda环境[可选] 2、配置Stable Diffu…
最新文章