linux - 通过用户空间 I/O (UIO) Linux 驱动程序与 QEMU edu 设备连接

标签 linux linux-device-driver kernel-module qemu pci

我正在查看 QEMU 的 edu device ( source ) 它在 QEMU 中提供了一个基本的“教育”PCI 设备,它可以作为 PCI 设备从 QEMU guest (如 Linux)中访问。

我一直在努力让它与 UIO 一起工作驱动程序(用户空间 I/O)通过 UIO PCI 通用驱动程序,作为练习以更好地理解 QEMU 和 Linux 中的 PCI 设备。

我的总体目标是为 FPGA 实现 Linux 驱动程序。 FPGA 作为 PCI-E 设备连接到 ARM Cortex-A53 CPU,提供几个不同的内存块,这些内存块将被视为设备配置的寄存器。我最初使用 x86_64 QEMU 是为了熟悉 PCI 驱动程序和 UIO。注:vfio有人向我建议,但我相信这依赖于 IOMMU 支持,我不确定我的目标平台是否存在。

我在内存区域映射方面遇到了一些问题。 UIO PCI 驱动程序(我认为)旨在为每个可寻址区域在 /sys/class/uio/uio0/map 中创建条目,但是据我所知,没有区域被自动检测到或者在UIO驱动绑定(bind)edu设备时设置。

我正在使用 yocto 生成的“相当标准”的 Linux 4.9 x86_64 发行版启动我新编译的 QEMU (./configure --target-list=x86_64-softmmu):

$ ./x86_64-softmmu/qemu-system-x86_64 --device edu -m 512 -nographic -serial mon:stdio -append 'console=ttyS0 root=/dev/hda' -kernel bzImage -hda image-qemu.ext3

然后在 guest 中,检测到 edu PCI 设备:

# lspci
00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)
00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]
00:01.1 IDE interface: Intel Corporation 82371SB PIIX3 IDE [Natoma/Triton II]
00:01.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 03)
00:02.0 VGA compatible controller: Device 1234:1111 (rev 02)
00:03.0 Ethernet controller: Intel Corporation 82540EM Gigabit Ethernet Controller (rev 03)
00:04.0 Unclassified device [00ff]: Device 1234:11e8 (rev 10)

加载 uio_pci_generic 模块并将其绑定(bind)到 edu 设备:

# modprobe uio_pci_generic
# echo "1234 11e8" > /sys/bus/pci/drivers/uio_pci_generic/new_id

# ls -l /sys/bus/pci/devices/0000\:00\:04.0/driver
lrwxrwxrwx 1 root root 0 Mar 15 01:50 /sys/bus/pci/devices/0000:00:04.0/driver -> ../../../bus/pci/drivers/uio_pci_generic

仔细查看设备,注意内存地址 fea00000:

# lspci -v -s 00:04.0
00:04.0 Unclassified device [00ff]: Device 1234:11e8 (rev 10)
Subsystem: Red Hat, Inc Device 1100
Flags: fast devsel, IRQ 10
Memory at fea00000 (32-bit, non-prefetchable) [size=1M]
Capabilities: [40] MSI: Enable- Count=1/1 Maskable- 64bit+
Kernel driver in use: uio_pci_generic

我 build 了 lsuio来自来源:

# ./lsuio -m -v
uio0: name=uio_pci_generic, version=0.01.0, events=0
Device attributes:
vendor=0x1234
uevent=DRIVER=uio_pci_generic
subsystem_vendor=0x1af4
subsystem_device=0x1100
resource=0x00000000fea00000 0x00000000feafffff 0x0000000000040200
msi_bus=1
modalias=pci:v00001234d000011E8sv00001AF4sd00001100bc00scFFi00
local_cpus=1
local_cpulist=0
irq=10
enable=1
driver_override=(null)
dma_mask_bits=32
device=0x11e8
d3cold_allowed=0
consistent_dma_mask_bits=32
config=4è
class=0x00ff00
broken_parity_status=0

# ls /sys/class/uio/uio0/ -l
total 0
-r--r--r-- 1 root root 4096 Mar 15 01:53 dev
lrwxrwxrwx 1 root root    0 Mar 15 01:53 device -> ../../../0000:00:04.0
-r--r--r-- 1 root root 4096 Mar 15 01:53 event
-r--r--r-- 1 root root 4096 Mar 15 01:53 name
drwxr-xr-x 2 root root    0 Mar 15 01:53 power
lrwxrwxrwx 1 root root    0 Mar 15 01:53 subsystem -> ../../../../../class/uio
-rw-r--r-- 1 root root 4096 Mar 15 01:22 uevent
-r--r--r-- 1 root root 4096 Mar 15 01:53 version

据此,我认为应该有一个从 0xfea00000 开始的可映射区域,但没有出现“ map ”目录,我一直无法弄清楚原因。尝试访问 /dev/uio0(读取或 mmap)会导致错误 22:“参数无效”。打开文件并扫描到末尾显示 block 设备的大小为零。

首先,我需要手动创建这些区域映射,还是应该由 UIO 驱动程序自动设置这些映射?教育设备是否需要做一些额外的事情来实现这一点?

其次,是否有其他已知可与 UIO 一起工作的 QEMU PCI 设备?理想情况下,有一个可用的 Linux 驱动程序,这样我就可以尝试了解 QEMU 设备端和相应的 Linux 驱动程序端。

关于最后一点,有人知道 edu 设备的 Linux 驱动程序吗?

最佳答案

原来 documentation有点模棱两可,至少足以混淆我自己和另一个人:

long and windy thread说明 ui_pci_generic 驱动程序实际上并不将 PCI BAR 区域映射到 maps 目录。相反,目的是使用标准 PCI sysfs 接口(interface):

因此,我已经能够通过 /sys/class/uio/uio0/device/resource0 的 mmap 访问 PCI 设备的内存。

然而,尝试在 /dev/uio0 上进行阻塞读取仍然会导致“无效参数”错误,因此我还不确定如何使用此 sysfs 接口(interface)等待或处理中断.

关于linux - 通过用户空间 I/O (UIO) Linux 驱动程序与 QEMU edu 设备连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49309162/

相关文章:

linux - Git 推送问题

Java - UnixFileSystem - 列表如何对 child 进行排序?

c - 从内核模块获取对输入设备的引用

c - 向指定端口写入/读取命令

linux - 是否有一个内核模块可以准确地返回简单的 'ifconfig' 的作用?

kernel-module - 如何在 Google Compute Engine (GCE) 内核上获取 AUFS 内核模块?

linux - 直接从 Makefile 构建 RPM

linux - Ubuntu 中打开终端(shell)时执行哪些启动脚本

c - Linux可加载模块精确定时

c - 内核散点列表在虚拟地址中是否连续?