【问题标题】:If I have only the physical address of device buffer (PCIe), how can I map this buffer to user-space?如果我只有设备缓冲区 (PCIe) 的物理地址,如何将此缓冲区映射到用户空间?
【发布时间】:2013-11-29 20:34:59
【问题描述】:

如果我只有通过 PCI-Express BAR(基地址寄存器)将设备缓冲区映射到的内存缓冲区的物理地址,我如何将此缓冲区 映射到用户空间

例如,Linux 内核中的代码通常应该是什么样子?

unsigned long long phys_addr = ...; // get device phys addr
unsigned long long size_buff = ...l // get device size buff

// ... mmap(), remap_pfn_range(), Or what should I do now?

开启:Linux x86_64

发件人:https://stackoverflow.com/a/17278263/1558037

ioremap() 将物理地址映射到内核虚拟地址。 remap_pfn_range() 将物理地址直接映射到用户空间。

发件人:https://stackoverflow.com/a/9075865/1558037

int remap_pfn_range(struct vm_area_struct *vma, unsigned long virt_addr, 
    unsigned long pfn, unsigned long size, pgprot_t prot);

remap_pfn_range - 将内核内存重新映射到用户空间

我可以这样用吗?

unsigned long long phys_addr = ...; // get device phys addr
unsigned long long size_buff = ...l // get device size buff

remap_pfn_range(vma, vma->vm_start, (phys_addr >> PAGE_SHIFT), 
    size_buff, vma->vm_page_prot);

问题:但是,我在哪里可以获得wma,以及在致电remap_pfn_range() 之前我必须使用wma 做什么?

【问题讨论】:

  • @Alec Teal 是的。在 Linux x86_64 上

标签: c linux linux-kernel posix pci-e


【解决方案1】:

映射 PCI 资源取决于架构。

用户空间已经可以使用 BAR 和 sysfs 文件 /sys/bus/pci/devices/*/resource*,它支持 mmap

这是由drivers/pci/pci-sysfs.c中的函数pci_mmap_resource实现的,最终调用pci_mmap_page_range

【讨论】:

  • 谢谢!我是否只需要使用pci_mmap_resource() 将整个任何 BAR(BAR01/23/45)从 sysfs 文件/sys/bus/pci/devices/*/resource* 重新映射到用户空间?你能写一个使用pci_mmap_resource()的简单例子吗?
  • 您的用户空间程序只能打开 sysfs 文件。这些函数不会为驱动程序导出。
  • 好的。如果我的设备有 8GB BAR,那么在启动时 /sys/bus/pci/devices/*/resource* 将分配 8GB 范围的 PTE?
  • 我是否需要使用msync() 将数据从内存发送(刷新)到设备?
  • BAR 被映射为未缓存; *_wc 文件被映射为写组合。
【解决方案2】:

Linux 内核,至少 2.6.x 版本使用 ioremap() 函数。

void *vaddr = ioremap (phys_addr, size_addr);
if (vaddr) {
  /* do stuff with the memory using vaddr pointer */
  iounmap (vaddr);
}

您应该之前调用request_mem_region() 以检查该内存空间是否已被另一个驱动程序回收,并礼貌地请求该内存由您的代码(驱动程序)拥有。完整的示例应如下所示:

void *vaddr;
if (request_mem_region (phys_addr, size_addr, "my_driver")) {
  vaddr = ioremap (phys_addr, size_addr);
  if (vaddr) {
    /* do stuff with the memory */
    iounmap (vaddr);
  }
  release_mem_region (phys_addr, size_addr);
}

您可以通过检查/proc/iomem来检查您的所有权,这将反映您系统中每块内存的地址范围和所有者。

更新:我真的不知道这是否适用于 64 位内核。它适用于 32 位。如果 64 位内核没有这些内核函数,我猜它们会有类似的。

【讨论】:

  • 谢谢!但是我应该为 PCIe 设备缓冲区使用 ioremap_uc() 而不是 ioremap() 来禁用该区域的 CPU 缓存吗? ioremap[_uc|_wc]() 函数是否返回指向虚拟地址的指针在我需要的用户空间中,而不是在内核空间中?
  • 关于ioremap[_uc|_wc]() 我的意思是这些:stackoverflow.com/q/19811237/1558037
  • 这个例子和这些函数只在内核模式下工作。要从用户空间访问此内存,您可以通过 /proc/mem 或编写一个设备驱动程序来为您的设备实现 mmap() 系统调用。
  • 好的。但可能我可以直接使用remap_pfn_range(),就像这里所说的那样? stackoverflow.com/a/17278263/1558037
  • memremap() 对于较新的内核似乎更好的方法。
猜你喜欢
  • 1970-01-01
  • 2018-05-23
  • 1970-01-01
  • 1970-01-01
  • 2013-06-09
  • 2021-07-17
  • 1970-01-01
  • 1970-01-01
  • 2021-06-13
相关资源
最近更新 更多