VTD_ECAP_PT (bit 6, Pass Through Support) was incorrectly OR'd into
s->cap (Capability Register) instead of s->ecap (Extended Capability
Register) in vtd_cap_init().

Per VT-d spec Section 11.4.3, PT is bit 6 of the Extended Capability
Register, indicating hardware support for pass-through translation in
context-entries and scalable-mode PASID-table entries.

This caused vtd_pe_type_check() to always reject PGTT=4 (pass-through)
in scalable mode, since it correctly checks s->ecap & VTD_ECAP_PT,
which was never set.

Move VTD_ECAP_PT from s->cap to s->ecap initialization to fix
scalable-mode pass-through translation.

Reproduce:
$ ./check-vtd-ecap-pt.sh ./build/qemu-system-x86_64

Before fix: CAP bit 6: 1, ECAP bit 6: 0
After fix:  CAP bit 6: 0, ECAP bit 6: 1

```sh
#!/bin/bash
#
# check-vtd-ecap-pt.sh
# Check VTD_ECAP_PT (bit 6) in CAP/ECAP registers of emulated Intel IOMMU.
#
# Q35 IOMMU MMIO base = 0xfed90000 (VT-d spec Section 11.4)
#   CAP  register offset = 0x08 → address 0xfed90008
#   ECAP register offset = 0x10 → address 0xfed90010
#

QEMU="${1:-./build/qemu-system-x86_64}"

OUTPUT=$(echo '{"execute": "qmp_capabilities"}
{"execute": "human-monitor-command", "arguments": {"command-line": "xp/1gx 
0xfed90008"}}
{"execute": "human-monitor-command", "arguments": {"command-line": "xp/1gx 
0xfed90010"}}' \
| timeout 5 "$QEMU" -machine q35 \
    -device intel-iommu,x-scalable-mode=on \
    -display none -qmp stdio -nodefaults 2>&1)

CAP=$(echo "$OUTPUT"  | grep -oP 'fed90008: \K0x\w+')
ECAP=$(echo "$OUTPUT" | grep -oP 'fed90010: \K0x\w+')

echo " CAP ($CAP)  bit 6: $(( (CAP >> 6) & 1 ))"
echo "ECAP ($ECAP)  bit 6: $(( (ECAP >> 6) & 1 ))"
```

Signed-off-by: Fengyuan Yu <[email protected]>
---
 hw/i386/intel_iommu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index f395fa248c..7b2cead8f8 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -4998,7 +4998,7 @@ static void vtd_cap_init(IntelIOMMUState *s)
 {
     X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
 
-    s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | VTD_ECAP_PT |
+    s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND |
              VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SSLPS | VTD_CAP_DRAIN |
              VTD_CAP_ESRTPS | VTD_CAP_MGAW(s->aw_bits);
     if (x86_iommu->dma_translation) {
@@ -5009,7 +5009,7 @@ static void vtd_cap_init(IntelIOMMUState *s)
                     s->cap |= VTD_CAP_SAGAW_48bit;
             }
     }
-    s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO;
+    s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO | VTD_ECAP_PT;
 
     if (x86_iommu_ir_supported(x86_iommu)) {
         s->ecap |= VTD_ECAP_IR | VTD_ECAP_MHMV;
-- 
2.39.5


Reply via email to