我的 PCI 设备驱动程序如何将 PCI 内存重新映射到用户空间?
How can my PCI device driver remap PCI memory to userspace?
我正在尝试为 QEMU 上的虚拟 PCI 设备实现 PCI 设备驱动程序。设备将 BAR 区域定义为 RAM,驱动程序可以对该区域执行 ioremap() 并毫无问题地访问它。下一步是将该区域(或其中的一部分)分配给用户应用程序。
为此,我还实现了一个 .mmap 函数作为我的驱动程序文件操作的一部分。这个mmap只是简单地使用了remap_pfn_range,但是它也传递了之前ioremap()返回的内存指针的pfn。
然而,在 运行 用户 space 应用程序上,mmap 是成功的,但是当应用程序尝试访问内存时,它被杀死并且我得到以下 dmesg 错误。
”
a.out:地址 7f66248b8000
处的损坏页面 table
..某些页面 table 信息..
坏页table: 000f [#2] SMP NOPTI
..和核心转储..
“
有谁知道我做错了什么?我错过了一步吗?或者它可能是 QEMU 特有的错误?
我的 QEMU 配置是 运行 x86_softmmu 内核是 4.14
我已经解决了这个问题并设法通过驱动程序将 PCI 内存映射到用户 space。正如 @IanAbbott 所暗示的那样,我已经更改了我在自定义 ->mmap()
.
中使用的 remap_pfn_range()
函数的 pfn
输入
原文是:
io_remap_pfn_range(vma, vma->vm_start, pfn, vma->vm_end - vma->vm_start, vma->vm_page_prot));
其中 pfn
是缓冲区指针 return 来自 ioremap()
的结果。我将 pfn
更改为:
pfn = pci_resource_start(pdev, BAR) >> PAGE_SHIFT;
那基本就是指向BAR实际指向的起始地址了。我的工作 remap_pfn_range()
功能现在是:
io_remap_pfn_range(vma, vma->vm_start, pci_resource_start(pdev, BAR) >> PAGE_SHIFT, vma->vm_end - vma->vm_start,vma->vm_page_prot);
我通过对我的驱动程序中的缓冲区指针进行一些虚拟写入,然后在我的用户 space 应用程序中读取并进行一些写入来确认它可以工作。
我正在尝试为 QEMU 上的虚拟 PCI 设备实现 PCI 设备驱动程序。设备将 BAR 区域定义为 RAM,驱动程序可以对该区域执行 ioremap() 并毫无问题地访问它。下一步是将该区域(或其中的一部分)分配给用户应用程序。 为此,我还实现了一个 .mmap 函数作为我的驱动程序文件操作的一部分。这个mmap只是简单地使用了remap_pfn_range,但是它也传递了之前ioremap()返回的内存指针的pfn。
然而,在 运行 用户 space 应用程序上,mmap 是成功的,但是当应用程序尝试访问内存时,它被杀死并且我得到以下 dmesg 错误。
” a.out:地址 7f66248b8000
处的损坏页面 table..某些页面 table 信息..
坏页table: 000f [#2] SMP NOPTI
..和核心转储.. “ 有谁知道我做错了什么?我错过了一步吗?或者它可能是 QEMU 特有的错误? 我的 QEMU 配置是 运行 x86_softmmu 内核是 4.14
我已经解决了这个问题并设法通过驱动程序将 PCI 内存映射到用户 space。正如 @IanAbbott 所暗示的那样,我已经更改了我在自定义 ->mmap()
.
remap_pfn_range()
函数的 pfn
输入
原文是:
io_remap_pfn_range(vma, vma->vm_start, pfn, vma->vm_end - vma->vm_start, vma->vm_page_prot));
其中 pfn
是缓冲区指针 return 来自 ioremap()
的结果。我将 pfn
更改为:
pfn = pci_resource_start(pdev, BAR) >> PAGE_SHIFT;
那基本就是指向BAR实际指向的起始地址了。我的工作 remap_pfn_range()
功能现在是:
io_remap_pfn_range(vma, vma->vm_start, pci_resource_start(pdev, BAR) >> PAGE_SHIFT, vma->vm_end - vma->vm_start,vma->vm_page_prot);
我通过对我的驱动程序中的缓冲区指针进行一些虚拟写入,然后在我的用户 space 应用程序中读取并进行一些写入来确认它可以工作。