• BAR寄存器 读写


    BAR寄存器:

    • Base Address Register0~5:即BAR寄存器,保存PCI设备使用的地址空间的基地址,保存设备在PCI总线域中的地址,每个设备最多可以有6个基址空间;
    • PCI设备复位之后,存放PCI设备需要使用的基地址空间大小,该空间是I /O空间还是存储器空间等信息;
    • 软件对PCI总线进行配置时,首先获得BAR寄存器中的初始化信息,之后根据处理器系统的配置,将合理的基地址写入相应的BAR寄存器中;系统软件还可以使用该寄存器,获得PCI设备使用的BAR空间的长度,通过向BAR寄存器写入0xFFFF-FFFF,之后再读取该寄存器实现;
    • 处理器访问PCI设备的BAR空间时,需要使用BAR寄存器提供的基地址;但处理器使用存储器域的地址,而BAR寄存器存放PCI总线域的地址,因此处理器系统并不能直接使用“BAR寄存器+偏移”的方式访问PCI设备的寄存器空间,而需要将PCI总线域的地址转换为存储器域的地址;
    • 即使x86处理器系统使能了IOMMU,这两个地址也并不一定相等,因此处理器系统直接使用这个PCI总线域的物理地址,并不能确保访问PCI设备BAR空间的正确性;除此之外在Linux系统中,ioremap函数的输入参数为存储器域的物理地址,而不能使用PCI总线域的物理地址;
    • 而在pci_dev -> resource[bar].start参数中保存的地址已经经过PCI总线域到存储器域的地址转换,因此在编写Linux系统的设备驱动程序时,需要使用pci_dev -> resource[bar].start参数中的物理地址,然后再经过ioremap函数将物理地址转换为“存储器域”的虚拟地址,再访问;

    PCI标准定义了三种物理地址空间,分别是IO address, Memory address space以及Configuration address space。其中Configuration address space专门用于配置PCI设备,PCI标准规定了标准的configuration space header,每个PCI设备都必须实现,软件通过configuration address space,来访问device的configuration space header,从而可以对device进行配置。

    PCI标准要求device将内部寄存器,片上内存等资源map到IO space或者Memory space,从而软件可以通过发起IO/Memory space的读写来访问device的内部资源。PCI标准在configuration space header里预留了6个32-bit的Base address (BAR),系统软件可以通过往BAR里设置IO/Memory space的基地址,来实现对device内部资源的影射。在设置好这些BAR后,一旦软件发起对这些地址的读写,都会被device截获。

    PCI规定32位BAR的低4位为read-only,标识了这个device资源在IO space,32-bit的Memory space还是64-bit的Memory space,以及访问时是否prefetchable。BAR的最后一位标识了是IO space还是Memory space。


        BAR[bit:0] = 1 --- IO space
                      = 0 --- Memory space
    如何读取PCI <wbr>device <wbr>Bar的type,base <wbr>address,以及size
    如何读取PCI <wbr>device <wbr>Bar的type,base <wbr>address,以及size

    在OS启动前,BIOS会预先program好device的各个BAR的基地址,所以一般OS不需要重新去program BAR,但是当device资源出现冲突时,系统也可以通过写BAR的值,来重新修改device的资源影射。

    PCI标准规定,先往32位BAR里写0xffffffff,再读取该BAR,就可以得到该BAR的size。如果读到的size为0,说明该BAR没有被device使用。

    Power-up software can determine how much address space the device requires by writing a
    value of all 1's to the register and then reading the value back. The device will return 0's in
    all don't-care address bits, effectively specifying the address space required. Unimplemented
    Base Address registers are hardwired to zero.

    如果该BAR是64-bit Memory space,则下一个BAR被认为是64位的高32位,64位size的高32位,也可以通过同样的方法得到。

    64-bit (memory) Base Address registers can be handled the same, except that the second
    32-bit register is considered an extension of the first; i.e., bits 32-63. Software writes
    0FFFFFFFFh to both registers, reads them back, and combines the result into a 64-bit value.
    Size calculation is done on the 64-bit value.

    读取base,size以及type的伪代码:
    
        u32 base, size;
       pci_resource_type type;   (io_space, mem32_space, mem64_space)
       boolean  prefetchable;
        
        //得到base address
       pci_config_read(device, BARi, &base);   
    
       //得到size
       pci_config_write(device, BAR, 0xffffffff);   
       pci_config_read(device, BAR, &size);
    
        //重新写回base address,有需要也可以是其他的地址
       pci_config_write(device, BAR, base);    
    
       //确定type
        if (base & 0x1)
          type = io_space;
        else if((base & 0x6) == 0x4)
          type = mem64_space;
        else
          type = mem32_space;
    
        prefetchable = (base & 0x8) ? true : false;
    
        //如果是64-bit Memory space,得到base address和size的高32位,方法相同
        if (type == mem64_space) {
          u64 base64 = base;
          u64 size64 = size;
    
          //BAR+4指向下一个BAR的位置,此时被认为是64位的高32位
          pci_config_read(device, BAR+4, &base);   
    
          base64 |= ((u64)base << 32);
          
          pci_config_write(device, BAR+4,   0xffffffff);
          pci_config_read(device, BAR+4, &size);
    
          size64 |= ((u64)size << 32);
        }
  • 相关阅读:
    面向消息的持久通信与面向流的通信
    通信协议
    分布式系统简介
    Hadoop on Yarn 各组件详细原理
    Parquet文件结构笔记
    Redis部分数据结构方法小结
    Storm Ack框架笔记
    MapReduce格式与类型
    Hadoop 2.6 MapReduce运行原理详解
    Hadoop SequenceFile数据结构介绍及读写
  • 原文地址:https://www.cnblogs.com/dream397/p/13632542.html
Copyright © 2020-2023  润新知