windows驱动开发-DMA技术(一)
DMA(Direct Memory Access)是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量中断负载,否则CPU 需要从设备缓存中把每一页的数据复制到缓存中,然后把它们再次写入到新的地方,在这个过程中中,CPU 需要一直控制这个过程。 DMA 则是由DMA控制器直接将数据从一个地址空间复制到另外一个地址空间。
由于现在电脑基本上统一了内部总线,所以所有的DMA都是PCI总线来进行的,故了解了PCI总线是如何处理DMA的,那也就了解了DMA是如何进行的。
如果调试过PCI总线,那么会发现,DMA是以一个内存页面为单位进行的,每次DMA传输的总是内存页面的整数倍,PCI会先将windows的内存地址写入到DMA控制器,然后向寄存器写入数据来启动DMA传输,但是,这一切操作已经被windows封装起来了,在windows中,我们会直接分配适配器对象,使用适配器来操作DMA。
适配器对象
任何使用直接 I/O 和 DMA 的驱动程序都必须创建适配器对象。 适配器对象表示 DMA 控制器通道或端口,或总线-主设备。
两种最低级别驱动程序必须使用适配器对象:
- 使用系统 DMA 控制器的设备驱动程序。 此类设备称为 从属设备 ,称为“使用系统 (或 从属) DMA”。
- 用作总线-主适配器的设备驱动程序。 此类设备与系统仲裁以使用 I/O 总线,因此使用总线主 DMA。
驱动程序通常位于设备扩展中,为指向适配器对象的指针提供存储。
为了执行 DMA 传输,使用这些 DMA 方法的设备驱动程序通常具有AdapterControl 例程,并调用系统提供的用于操作适配器对象的支持例程。 不需要 AdapterControl 例程的 (驱动程序包括 那些使用Scatter/Gather DMA 的驱动程序,以及那些使用 common-buffer、bus-master DMA.)就是使用总线主DMA的驱动。
作为设备启动操作的一部分,处理 DMA 操作的驱动程序调用 I/O 管理器,后者又调用特定于平台的 HAL 来创建一组适配器对象。 在任何 Windows 平台上,适配器对象集通常包括以下对象的适配器对象:
- 从属设备连接到的每个系统 DMA 控制器通道或端口。
- 计算机中的每个总线主 DMA 设备。
获取/释放适配器
在设备启动时,使用系统或总线主 DMA 的驱动程序会调用 IoGetDmaAdapter 来获取指向适配器对象的指针,并确定每个传输操作可用的映射寄存器的最大数目。 当驱动程序调用 IoGetDmaAdapter 时,I/O 管理器反过来会调用 HAL 以获取特定于平台的必要信息。
驱动程序必须在调用 IoGetDmaAdapter 时,在系统定义的DEVICE_DESCRIPTION结构中提供某些信息。 驱动程序必须使用 RtlZeroMemory 初始化 DEVICE_DESCRIPTION 结构,并在其中设置值。
所需数据包括有关驱动程序设备功能的信息,例如设备是否为总线主机、设备是否具有散点/收集功能,以及设备一次可以传输多少字节的数据, (MaximumLength) 。
所需的设备说明数据还包括特定于平台的信息,例如总线主设备驱动程序控制的特定于平台和系统分配的总线编号。 驱动程序可以通过调用 IoGetDeviceProperty 来获取此信息。
DEVICE_DESCRIPTION结构包括一些可能与某些 DMA 设备或驱动程序无关的字段。 例如,WDM 驱动程序中不使用 BusNumber 字段。 每个驱动程序应为相关结构成员提供值,并应将所有其他成员的值设置为零。
当请求必须分解为两个或更多个 DMA 操作时,除非设备能够等待系统 DMA 控制器重新编程,否则从属设备的驱动程序不应在 ScatterGather 字段中传递 TRUE。
IoGetDmaAdapter 返回指向适配器对象的指针和特定于平台或特定于设备的值,该值指示适配器对象可用于每个 DMA 传输操作的映射寄存器数。
返回的适配器对象包含三个可供驱动程序访问的字段:
- 版本号 (版本)
- 大小 (大小)
- 指向 DmaOperations(DMA_OPERATIONS) 结构的指针
DMA_OPERATIONS 结构包含指向驱动程序在其设备上执行 DMA 操作时必须使用的函数的指针表, 函数只能通过此数据结构中的指针访问,驱动程序无法直接按名称调用它们。 (请注意,这些例程替换以前版本的 Windows NT 中支持的 HalXxx 例程。为了确保旧驱动程序的兼容性,Wdm.h 和 Ntddk.h 头文件提供具有过时名称的宏,但新驱动程序应始终通过 data structure.)
映射寄存器的数量可能因设备以及平台而异。 通常,HAL 根据以下条件分配多个映射寄存器:
如果可能,HAL 将返回一个值,该值比传输 MaximumLength 字节所需的映射寄存器数多一个,如驱动程序对 IoGetDmaAdapter 的调用中所述。
否则,HAL 将返回一个较小的值,该值对于特定平台来说尽可能大。
换句话说,HAL 通常为每个驱动程序提供足够的映射寄存器,以最大化其设备的 DMA 吞吐量,但 HAL 在某些 Windows 平台上可以返回较小的值。 无法保证驱动程序将获取它请求的映射寄存器数,因此驱动程序应始终检查返回的值。
任何 DMA 设备驱动程序都必须为 IoGetDmaAdapter 返回的适配器对象指针和 NumberOfMapRegisters 值提供存储。 此指针是指向系统提供的用于 DMA 的支持例程的必需参数。 由于其中许多支持例程必须在 IRQL = DISPATCH_LEVEL调用,因此驱动程序分配的存储必须是驻留的。 大多数 DMA 驱动程序在 设备扩展中提供必要的存储。 但是,如果驱动程序也使用控制器对象或驱动程序分配的非分页池,则存储可以位于 控制器 扩展中。
驱动程序完成所有 DMA 操作后,会调用 PutDmaAdapter 以释放适配器对象。
AdaptControl例程要求
AdapterControl 例程必须至少执行以下操作:
1. 保存输入 MapRegisterBase 值以及驱动程序为当前 IRP 执行一个或多个 DMA 传输操作所需的任何其他上下文信息。 每个 DMA 传输操作完成后,驱动程序必须将 MapRegisterBase 值传递给 FlushAdapterBuffers 。
2. 返回相应的 IO_ALLOCATION_ACTION 值:
- 如果设备是从属设备,则为 KeepObject,因此驱动程序使用系统 DMA。
- 如果设备是总线主机,则 DeallocateObjectKeepRegisters,因此驱动程序使用基于数据包的总线主 DMA。
根据驱动程序的设计,其 AdapterControl 例程也可以在返回控制权之前执行以下操作:
- 1. 确定传输在其设备上的起始位置;
- 2. 根据由于传输的开始位置而对其设备的任何限制,计算可能的传输大小;一般情况下,调用 AllocateAdapterChannel 的例程负责确定是否必须将转移请求拆分为部分传输,因为针对每个 DMA 传输操作可用的 NumberOfMapRegisters 存在任何特定于平台的限制;
- 3. 设置有关设备 (或控制器) 扩展中的每个传输请求的任何驱动程序维护的状态;例如,AdapterControl 例程可能会使用 CustomTimerDpc 例程的入口点调用 KeSetTimer,该例程超时驱动程序的 DMA 传输操作;
- 4. 使用在 Irp-> MdlAddress传递的 MDL 指针调用 MmGetMdlVirtualAddress,以获取传输开始的索引,适合传递给 MapTransfer;
- 5. 调用 MapTransfer 以设置系统 DMA 控制器或获取总线-主设备的物理到逻辑地址映射。
- 6. 使用通过调用 KeSynchronizeExecution 调用的 SynchCritSection 例程对驱动程序的设备进行编程,以便执行传输操作。
如果传输请求要求驱动程序执行一系列部分传输操作以满足当前 IRP,则驱动程序的 DpcForIsr 或 CustomDpc 例程通常负责对设备进行重新编程,以便执行后续传输操作。 每个传入传输 IRP 仅调用 一次 AdapterControl 例程。
完成当前传输 IRP 的驱动程序例程(通常是 DpcForIsr 或 CustomDpc 例程)也负责通过分别调用 FreeAdapterChannel 或 FreeMapRegisters 来释放系统 DMA 控制器或总线-主适配器。 此驱动程序例程应在完成其最后一次部分传输操作时尽快发出相应的调用,以便从属 DMA 设备的驱动程序可以分配系统 DMA 控制器,或者总线-主驱动程序可以立即开始处理下一个传输 IRP。
IRP_MN_START_DEVICE 请求的驱动程序调度例程必须为 AdapterControl 例程执行以下操作:
- 通过填写 DEVICE_DESCRIPTION结构并 调用 IoGetDmaAdapter,为设备的 DMA 功能设置适配器对象。
- 保存 IoGetDmaAdapter 返回的适配器对象指针和 NumberOfMapRegisters。
- IoGetDmaAdapter 返回的平台特定最大 NumberOfMapRegisters 或驱动程序设备的传输功能(以限制性更强者为准)确定驱动程序是否必须拆分给定的传输请求并在其设备上执行多个 DMA 操作来满足该 IRP。
返回的适配器对象指针、驱动程序的 AdapterControl 例程的入口点、表示当前 IRP 的目标设备的 DeviceObject 指针、指向已为 AdapterControl 例程设置的区域的上下文指针,以及 NumberOfMapRegisters 值(可能小于较小传输请求的最大可能数目)必须在调用中传递给 AllocateAdapterChannel。 通常,驱动程序的 StartIo (或可能是 ControllerControl) 例程在调用 AllocateAdapterChannel 之前在 Context 处设置区域。
在系统中,可能以两种不同的方式使用DMA,基于数据包的系统DMA、基于公用缓冲区的系统DMA。
相关文章:
windows驱动开发-DMA技术(一)
DMA(Direct Memory Access)是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量中断负载,否则CPU 需要从设备缓存中把每一页的数据复制到缓存中,然后把它们再次写入到新的地方,在这个过…...
实用的Chrome命令
以下是一些实用的Chrome命令及其用途: --allow-outdated-plugins:允许浏览器使用过期的插件,这在开发过程中可能会用到,以便测试兼容性。chrome://downloads:打开Chrome的下载页面,查看和管理你的下载文件…...
数据库(MySQL)基础:约束
一、概述 1.概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据。 2.目的:保证数据库中数据的正确、有效性和完整性。 3.分类 约束描述关键字非空约束限制该字段的数据不能为nullnot null唯一约束保证该字段的所有数据都是唯一…...
ControlNet作者放大招!IC-Light:控制生成图片光照效果!
ControlNet作者张吕敏近日又开源了一项新的工作:IC-Light (Impose Constant Light),在不改变图片内容的条件下,可以控制生成图片的光照效果。 作者发布了两种类型的模型:文本条件重打光模型和背景条件重打光…...
【Java】Java中类的初始化顺序(静态方法,静态块,非静态块,最后有流程图)
📝个人主页:哈__ 期待您的关注 目录 一、无继承关系类的初始化 1、静态变量k被初始化 2、静态变量t1初始化 3、静态变量 t2初始化 4、静态变量i初始化 5、静态变量n初始化 6、静态块初始化 7、非静态块初始化 8、非静态属性初始化 9、执行构造…...
在RK3588开发板使用FFMpeg 结合云服务器加SRS实现摄像头数据推流到云端拱其他设备查看
今天测试了一把在开发板把摄像头数据推流到云端服务器,然后给其他电脑通过val软件拉取显示摄像头画面,浅浅记录一下大概步骤 1.开发板端先下载ffmpeg apt install ffmpeg2.云服务器先安装SRS的库 云服务器我使用ubuntu系统,SRS是个什么东西&…...
elasticsearch搭建教程
主要参看这里就行,需要特别注意其中报错的解决方案:搭建elasticsearch 单机节点里,按照上述教程搭建只能开放本地访问,如果需要其他机器访问,需要在elasticsearch.yml里新增几个配置: node.name: node-1 network.host…...
c++ 归并排序
归并排序是一种遵循分而治之方法的排序算法。它的工作原理是递归地将输入数组划分为较小的子数组并对这些子数组进行排序,然后将它们合并在一起以获得排序后的数组。 简单来说,归并排序的过程就是将数组分成两半,对每一半进行排序,…...
基于vs和C#的WPF应用之动画3
注:1、在内部和外部使用缓动函数 <Grid.Resources> <PowerEase x:Key"powerease" Power"3" EasingMode"EaseInOut"/> </Grid.Resources> <DoubleAnimation EasingFunction"{StaticResource powerease}&quo…...
Python import 必看技巧:打造干净利落的代码结构
大家好,学习Python你肯定绕不过一个概念import,它是连接不同模块的桥梁,是实现代码复用和模块化的关键。本文将带你深入探索Python中import的原理,并分享一些实用的导入技巧。 1. import 原理 导入机制概述 在Python中,模块(module)是一种封装Python代码的方式,它允许…...
计算机视觉(CV)(Computer Vision)
计算机视觉技术(Computer Vision),解决的是什么? 图片和视频是非结构化数据,机器如果要理解某一图片或视频表达的内容,是无法直接分析的,这种情况,就需要有计算机视觉技术ÿ…...
python:画折线图
import pandas as pd import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties# 设置新宋体字体的路径 font_path D:/reportlab/simsun/simsun.ttf# 加载新宋体字体 prop FontProperties(fnamefont_path)""" # 读取 xlsx 文件 d…...
Spring Data JPA 与 MyBatisPlus的比较
前言 JPA(Java Persistence API)和MyBatis Plus是两种不同的持久化框架,它们具有不同的特点和适用场景。 JPA是Java官方的持久化规范,它提供了一种基于对象的编程模型,可以通过注解或XML配置来实现对象与数据库的映射…...
【C++】STL-list的使用
目录 1、list的使用 1.1 list的构造 1.2 list的遍历 1.3 list capacity 1.4 list element access 1.5 容量相关 list是一个带头双向循环链表 1、list的使用 1.1 list的构造 1.2 list的遍历 list只有两种遍历方式,因为没有operator[] 因为list的双向链表&am…...
进度条(小程序)
缓冲区的概念 缓冲区是内存中的一个临时存储区域,用来存放输入或输出数据。在标准 I/O 库中,缓冲区的使用可以提高数据处理的效率。例如,当向终端输出文本时,字符通常存储在缓冲区中,直到缓冲区满或者遇到特定条件时才…...
PyCharm安装教程(超详细图文教程)
一、下载和安装 1.进入PyCharm官方下载,官网下载地址: https://www.jetbrains.com/pycharm/download/ 专业版安装插件放网盘了,网盘下载即可:itcxy.xyz/229.html2.安装 1.下载后找到PyCharm安装包,然后双击双击.ex…...
金蝶BI应收分析报表:关于应收,这样分析
这是一张出自奥威-金蝶BI方案的BI应收分析报表,是一张综合运用了筛选、内存计算等智能分析功能以及数据可视化图表打造而成的BI数据可视化分析报表,可以让企业运用决策层快速知道应收账款有多少?账龄如何?周转情况如何?…...
salmon使用体验
文章目录 salmon转录本定量brief模式一:fastq作为输入文件需要特别注意得地方 模式二: bam文件作为输入 salmon转录本定量 brief 第一点是,通常说的转录组分析其中有一项是转录本定量,这是一个很trick的说话,说成定量…...
Ubuntu 20.04 安装 Ansible
使用官方的 Ubuntu PPA 更新包列表: apt update安装软件属性常用命令 apt install software-properties-common添加 Ansible PPA 到系统: add-apt-repository --yes --update ppa:ansible/ansible再次更新包列表以包括新添加的 PPA: apt …...
TypeScript学习笔记:强类型JavaScript的优雅之旅
在前端开发领域,JavaScript以其灵活性和广泛的支持度成为无可争议的王者。然而,随着项目规模的增长,JavaScript的动态类型特性开始暴露出一些问题,比如代码的可维护性、类型错误难以提前发现等。为了解决这些问题,Micr…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
