zoukankan      html  css  js  c++  java
  • 第二十七篇:Windows驱动中的PCI, DMA, ISR, DPC, ScatterGater, MapRegsiter, CommonBuffer, ConfigSpace

    近期有些人问我PCI设备驱动的问题, 和他们交流过后, 我建议他们先看一看<<The Windows NT Device Driver Book>>这本书, 个人感觉, 这本书写得很连贯流畅.


    PCI设备驱动基本包含了PCI的资源获取, 配置空间的读写, 中断的处理, 中断后半部在DPC中的处理.

    同一时候, 也必须了解DMA, ScatterGater, MapRegister, Common Buffer等基础.


    1.1 PCI设备资源获取

    PCI设备的资源是系统依据设备的属性(配置空间中寄存器的值)来动态分配的.

    驱动中仅仅需在PNP START中获取这些系统分配的资源:

    比如: 笔者开发的PCI电视卡驱动中, 就使用到了当中了两类资源, CmResourceTypePort与CmResourceTypeInterrupt.

    Port地址作为设备寄存器首地址, 之后, 能够使用WRITE_PORT_ULONG与READ_PORT_ULONG加上对应的OFFSET来对设备寄存器进行訪问.

    Interrupt资源中解释出来的内容, 则主要作为IoConnectInterrupt系统函数的參数, 将设备的硬件中断与ISR相关联, KINTERRUPT的实例则是设备中断的软件形式的载体.


    1.2 DMA

    DMA设备, 在系统中分为MASTER与SLAVE, 另外一个非常重要的能力就是是否支持Scatter/Gather.

    这些能力终于表如今DEVICE_DESCRIPTION所定义的数据结构的成员中, 比如:DmaWidth, ScatterGather, Master, Dma32BitAddresses, Dma64BitAddresses.

    系统终于将各种不同类型的设备DMA抽象为DMA_ADAPTER的实例, 它是设备DMA软件形式的载体.

    驱动代码通过IoGetDmaAdapter系统调用, 将物理设备对象PDO与DMA描写叙述结构作为參数, 终于得到这个DMA_ADAPTER对象, 作为兴许一系列DMA相关操作的实体对象.


    1.3 Map Register

    用户空间, 内核空间的虚拟内存与物理内存的关联是通过页表来映射的, 驱动程序猿经常会使用MDL, 它也是某一特定区域虚拟内存与物理内存的映射关系.

    而DMA设备则须要从总线地址(MSDN中又叫逻辑地址)与内存物理的映射关系角度去看待系统内存.

    这个映射的关系就是由Map Register承担的.

    只是, 这批Map Register则依据系统而定, 有些是硬件实现, 有些是软件中划分出来的特定的一块内存.

    IoGetDmaAdapter的调用, 也是向系统申请Map Register的过程.


    1.4 Common Buffer

    这也是大家问得最多的问题

    简单地讲, Common buffer是以DMA_ADAPTER为代表所申请的, 申请成功后, 既能通过虚拟地址訪问, 也能够通过DMA控制器所属逻辑地址空间的地址来訪问的连续物理内存.

    它的优点就是物理上连续, 存在的问题是系统中连续物理内存是随着系统的执行时间的流逝, 越来越稀缺.

    AllocateCommonBuffer系统调用是作为DMA_ADAPTER的DmaOperations形式存在的, 所以, 详细的一块Common Buffer能够说, 是与详细的一个DMA控制器所关联的.

    AllocateCommonBuffer成功调用后, 会返回虚拟地址与DMA控制器所属逻辑空间的逻辑地址.

    笔者开发的PCI电视卡, 就是通过AllocateCommonBuffer分配一块较小的连续物理内存, 用来存放Scatter/Gather列表 (某块内存的逻辑地址SCATTER_GATHER_LIST.Elements[i].Address.LowPart 与该内存的长度SCATTER_GATHER_LIST.Elements[i].Length, 对应操作通过common buffer的虚拟地址 ).

    这个Scatter/Gather List列表终于由具有S/G能力的DMA控制器来读取(对应操作通过common buffer的逻辑地址), 依据当中的表项, 进行DMA读/写操作.


    1.5 S/G

    S/G的能力是DMA控制器的特性, 假设具有S/G的能力, 则能够批量地DMA操作, 否则, 必须一次一次地使用MapTransfer来完毕DMA操作.

    系统空间的中虚拟内存与物理内存之间的联系通过IoAllocateMdl与MmBuildMdlForNonPagedPool建立特定的MDL来表示.

    其后,通过DMA_ADAPTER的DmaOperations中的GetScatterGatherList获取MDL所描写叙述的虚拟地址内存的S/G列表, 最后, 在GetScatterGatherList的

    ExecutionRoutine 函数中, 将该列表填入Common buffer的TABLE(起始逻辑地址 与 长度)中, 以供DMA Controller所用.


    1.6 ISR与DPC
    刚才已经提到, ISR是通过IoConnectInterrupt注冊的.
    ISR在设备中断到来时实调用, 但详细的事项则交由(KeInsertQueueDpc)DPC来处理.
    而DPC则是通过KeInitializeDpc系统调用, 将DPC对象KDPC与详细的KDEFERRED_ROUTINE DPC处理函数相关联的.

    1.7 PCI设备配置空间的訪问

    其实, 普通情况下, Windows PCI设备并不须要訪问PCI设备配置空间.
    但作为一个完整的PCI设备驱动, 这里提及一下.

    因为PCI设备的配置空间与IO/MEM空间是分开的, 前面已经提及IO/MEM的訪问方式, 配置空间的訪问例如以下:
    定义变量:BUS_INTERFACE_STANDARD m_BusInterfaceStandard;
    建立: IRP, 主与次分别为IRP_MJ_PNP, IRP_MN_QUERY_INTERFACE, 得到BUS_INTERFACE_STANDARD数据结构.
    之后, 通过BUS_INTERFACE_STANDARD中的SetBusDataGetBusData来进行PCI配置空间的寄存器读写.

    PCI设备驱动全然能够用在PCIe设备上, 毕竟上层来讲, 他们没有太多的差别.

    与USB驱动不同, PCI设备须要考虑驱动设计中的方方面面, 希望这篇文章对大家有所借鉴作用.







  • 相关阅读:
    LA 2038 Strategic game(最小点覆盖,树形dp,二分匹配)
    UVA 10564 Paths through the Hourglass(背包)
    Codeforces Round #323 (Div. 2) D 582B Once Again...(快速幂)
    UVALive 3530 Martian Mining(贪心,dp)
    UVALive 4727 Jump(约瑟夫环,递推)
    UVALive 4731 Cellular Network(贪心,dp)
    UVA Mega Man's Mission(状压dp)
    Aizu 2456 Usoperanto (贪心)
    UVA 11404 Plalidromic Subsquence (回文子序列,LCS)
    Aizu 2304 Reverse Roads(无向流)
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/7105762.html
Copyright © 2011-2022 走看看