v1:
https://lore.kernel.org/qemu-devel/[email protected]
v1->v2:
- Add Fixes tag.
- Rename amdvi_as_devid() to amdvi_get_as_devid().
- Cleanup and add macro to avoid hardcoding.
- Make AMD IOMMU extended feature register read-only.
- Drop the patch for enabling I/O page fault delivery when xtsup=on.
Recently, I tried using QEMU IOMMU emulation to study PCI device IOMMU page
faults.
It works well with intel-iommu.
[ 28.819456] DMAR: DRHD: handling fault status reg 2
[ 28.820403] DMAR: [DMA Write NO_PASID] Request device [01:00.0] fault addr
0xc0000000 [fault reason 0x05] PTE Write access is not set
[ 28.822325] DMAR: Dump dmar0 table entries for IOVA 0xc0000000
[ 28.823289] DMAR: root entry: 0x00000001014ef001
[ 28.823291] DMAR: context entry: hi 0x0000000000000602, low
0x00000001014ee001
[ 28.825266] DMAR: pte level: 4, pte value: 0x000000010208f403
[ 28.826211] DMAR: pte level: 3, pte value: 0x00000001020c8403
[ 28.827158] DMAR: pte level: 2, pte value: 0x0000000000000000
[ 28.828109] DMAR: page table not present at level 1
However, there are some issues with amd-iommu. This patchset aims to address
these issues through bugfixes and cleanup.
- Fix duplicate MSI capabilities for the IOMMU PCI device.
- Fix an invalid PCI address reported in I/O page fault events.
- Fix excessive GA log messages causing endless guest dmesg output.
The QEMU test patch I used to inject IOMMU IO page faults has been appended to
the end of this email. To execute "info version" HMP command will be able to
trigger an IO page fault.
The following is the QEMU command line. I have tested these changes with both
7.1 and v6.4 guest kernels. I have also tested with both xtsup=off and
xtsup=on.
qemu-system-x86_64 \
-machine q35,accel=kvm,kernel-irqchip=split \
-smp 4 -m 8G \
-cpu host \
-hda ol94.qcow2 \
-device
pcie-root-port,io-reserve=0,pref64-reserve=32M,bus=pcie.0,chassis=40,id=pcie-root-port.1,addr=05.00,multifunction=on
\
-device
virtio-net-pci,netdev=tapnet,bus=pcie-root-port.1,mq=true,vectors=9,mac=52:54:11:22:14:47,disable-legacy=on,iommu_platform=true,packed=true
\
-netdev tap,id=tapnet,script=qemu-ifup,downscript=no,queues=4,vhost=off \
-monitor stdio -vnc :18 \
-device amd-iommu,dma-remap=true,xtsup=off \
-kernel mainline-linux/arch/x86_64/boot/bzImage \
-append "root=/dev/sda1 init=/sbin/init text loglevel=7 console=ttyS0
clocksource=tsc iommu=force iommu.passthrough=0 amd_iommu=force_isolation
iommu.strict=1"
Dongli Zhang(5):
amd_iommu: Do not create duplicate MSI capability
amd_iommu: Use full BDF when reporting page faults
amd_iommu: Define MMIO register masks
amd_iommu: Make extended feature register read-only
amd_iommu: Do not latch unsupported GA log status bits
hw/i386/amd_iommu.c | 34 +++++++++++++++++++++-------------
hw/i386/amd_iommu.h | 25 +++++++++++++++++++++----
2 files changed, 42 insertions(+), 17 deletions(-)
Here is the QEMU test patch to inject IO page fault.
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 63e2faee99..9de0f302d7 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1877,6 +1877,8 @@ err_undo_map:
goto done;
}
+bool testsys_debug = false;
+
static void *virtqueue_packed_pop(VirtQueue *vq, size_t sz)
{
unsigned int i, max;
@@ -1951,6 +1953,13 @@ static void *virtqueue_packed_pop(VirtQueue *vq, size_t
sz)
do {
bool map_ok;
+ if (testsys_debug && (desc.addr & 0xff000000) == 0xff000000) {
+ testsys_debug = false;
+ printf("fault: virtqueue_packed_pop() desc.addr=0x%lx\n",
desc.addr);
+ desc.addr = 0xc0000000;
+ desc.len = 1;
+ }
+
if (desc.flags & VRING_DESC_F_WRITE) {
map_ok = virtqueue_map_desc(vdev, &in_num, addr + out_num,
iov + out_num,
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 443b8c785d..c42004d39b 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -114,6 +114,8 @@ void hmp_info_name(Monitor *mon, const QDict *qdict)
qapi_free_NameInfo(info);
}
+extern bool testsys_debug;
+
void hmp_info_version(Monitor *mon, const QDict *qdict)
{
VersionInfo *info;
@@ -125,6 +127,9 @@ void hmp_info_version(Monitor *mon, const QDict *qdict)
info->package);
qapi_free_VersionInfo(info);
+
+ printf("fault: enable one-time debug\n");
+ testsys_debug = true;
}
void hmp_quit(Monitor *mon, const QDict *qdict)
Thank you very much!
Dongli Zhang