This is a driver for a PCIe test device with DMA capabilities in QEMU.
Warning: this is currently an out-of-tree kernel module, so use this in a safe environment (QEMU).
- Clone and build the QEMU source containing hw/misc/pcie-testdev.c (https://github.com/liujennifer/qemu.git)
- Create a disk image/install a guest OS in the VM. More information here.
$ qemu/build/x86_64-softmmu/qemu-system-x86_64 -enable-kvm -hda <disk image> -m 2048
-device ioh3420,id=root_port,bus=pcie.0,addr=7.0 \
-device pcie-testdev,bus=root_port,id=testdev
-device ioh3420 is a PCIe root port complex, to which PCIe endpoints like pcie-testdev can be connected to. You can see this relationship by running 'lspci -t' in the guest.
The id property allows you to reference the specific device (like "root_port" is used here, and also if you want to reference it in the QEMU Monitor).
$ qemu/build/x86_64-softmmu/qemu-system-x86_64 -enable-kvm -hda <disk image> -m 2048
-M q35,accel=kvm,kernel-irqchip=split \
-device intel-iommu,intremap=on,caching-mode=on,device-iotlb=on \
-device ioh3420,id=root_port,bus=pcie.0,addr=7.0 \
-device pcie-testdev,bus=root_port,id=testdev
-M q35 is necessary here to support the IOMMU (More info about using Intel VT-d/intel-iommu)
- You may need to enable the IOMMU in the guest. Navigate to /etc/default/grub and edit it to be:
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on"
- Then run (may need to "sudo apt-get install update-grub" first)
$ sudo update-grub
-
After booting up QEMU, clone this repo inside your guest. Enter the folder and run make.
-
Insert the module now with:
$ sudo insmod testdev_driver.ko
- View the kernel logs by running:
$ sudo dmesg
-
If you booted QEMU without an IOMMU, you should see two successes (STATUS = 0). With an IOMMU, you should see the first transfer succeed, and the second one fail (non-zero status). This is because the first transfer is using the DMAR-safe DMA-API mappings, and the second one uses the deprecated virt-to-bus ones.
-
Remove your module with:
$ sudo rmmod testdev_driver
- In aggressive mode, pcie-testdev will immediately and repeatedly make DMA transfers, which may be a useful test for vulnerabilities
- You can enable this and set the source address, destination address, transfer size, and delay (in ms) between transfers. For example (you can pick appropriate addresses from the output of running "sudo cat /proc/iomem" in the guest):
-device pcie-testdev,bus=root_port1,id=testdev,aggressive,srcaddr=0x0009f000,dstaddr=0x0009fb00,size=1,aggression_delay_ms=2000