| 1 | /* |
| 2 | * QTest for Intel IOMMU (VT-d) with iommu-testdev |
| 3 | * |
| 4 | * This QTest file is used to test the Intel IOMMU with iommu-testdev so that |
| 5 | * we can test VT-d without any guest kernel or firmware. |
| 6 | * |
| 7 | * Copyright (c) 2026 Fengyuan Yu <15fengyuan@gmail.com> |
| 8 | * |
| 9 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 10 | */ |
| 11 | |
| 12 | #include "qemu/osdep.h" |
| 13 | #include "libqtest.h" |
| 14 | #include "libqos/pci.h" |
| 15 | #include "libqos/pci-pc.h" |
| 16 | #include "hw/i386/intel_iommu_internal.h" |
| 17 | #include "hw/misc/iommu-testdev.h" |
| 18 | #include "libqos/qos-intel-iommu.h" |
| 19 | |
| 20 | #define DMA_LEN 4 |
| 21 | |
| 22 | static uint64_t intel_iommu_expected_gpa(uint64_t iova) |
| 23 | { |
| 24 | return (QVTD_PT_VAL & VTD_PAGE_MASK_4K) + (iova & 0xfff); |
| 25 | } |
| 26 | |
| 27 | static void run_intel_iommu_translation(const QVTDTestConfig *cfg) |
| 28 | { |
| 29 | QTestState *qts; |
| 30 | QPCIBus *pcibus; |
| 31 | QPCIDevice *dev; |
| 32 | QPCIBar bar; |
| 33 | |
| 34 | if (!qtest_has_machine("q35")) { |
| 35 | g_test_skip("q35 machine not available"); |
| 36 | return; |
| 37 | } |
| 38 | |
| 39 | /* Initialize QEMU environment for Intel IOMMU testing */ |
| 40 | qts = qtest_initf("-machine q35 -smp 1 -m 512 -net none " |
| 41 | "%s -device iommu-testdev", |
| 42 | qvtd_iommu_args(cfg->trans_mode)); |
| 43 | |
| 44 | /* Check CAP/ECAP capabilities for required translation mode */ |
| 45 | if (!qvtd_check_caps(qts, cfg->trans_mode)) { |
| 46 | qtest_quit(qts); |
| 47 | return; |
| 48 | } |
| 49 | |
| 50 | /* Setup and configure IOMMU-testdev PCI device */ |
| 51 | dev = qvtd_setup_qtest_pci_device(qts, &pcibus, &bar); |
| 52 | g_assert(dev); |
| 53 | |
| 54 | g_test_message("### Intel IOMMU translation mode=%d ###", cfg->trans_mode); |
| 55 | qvtd_run_translation_case(qts, dev, bar, Q35_HOST_BRIDGE_IOMMU_ADDR, cfg); |
| 56 | g_free(dev); |
| 57 | qpci_free_pc(pcibus); |
| 58 | qtest_quit(qts); |
| 59 | } |
| 60 | |
| 61 | static void test_intel_iommu_legacy_pt(void) |
| 62 | { |
| 63 | QVTDTestConfig cfg = { |
| 64 | .trans_mode = QVTD_TM_LEGACY_PT, |
| 65 | .dma_gpa = QVTD_IOVA, /* pass-through: GPA == IOVA */ |
| 66 | .dma_len = DMA_LEN, |
| 67 | .expected_result = 0, |
| 68 | }; |
| 69 | |
| 70 | run_intel_iommu_translation(&cfg); |
| 71 | } |
| 72 | |
| 73 | static void test_intel_iommu_legacy_trans(void) |
| 74 | { |
| 75 | QVTDTestConfig cfg = { |
| 76 | .trans_mode = QVTD_TM_LEGACY_TRANS, |
| 77 | .dma_gpa = intel_iommu_expected_gpa(QVTD_IOVA), |
| 78 | .dma_len = DMA_LEN, |
| 79 | .expected_result = 0, |
| 80 | }; |
| 81 | |
| 82 | run_intel_iommu_translation(&cfg); |
| 83 | } |
| 84 | |
| 85 | static void test_intel_iommu_scalable_pt(void) |
| 86 | { |
| 87 | QVTDTestConfig cfg = { |
| 88 | .trans_mode = QVTD_TM_SCALABLE_PT, |
| 89 | .dma_gpa = QVTD_IOVA, /* pass-through: GPA == IOVA */ |
| 90 | .dma_len = DMA_LEN, |
| 91 | .expected_result = 0, |
| 92 | }; |
| 93 | |
| 94 | run_intel_iommu_translation(&cfg); |
| 95 | } |
| 96 | |
| 97 | static void test_intel_iommu_scalable_slt(void) |
| 98 | { |
| 99 | QVTDTestConfig cfg = { |
| 100 | .trans_mode = QVTD_TM_SCALABLE_SLT, |
| 101 | .dma_gpa = intel_iommu_expected_gpa(QVTD_IOVA), |
| 102 | .dma_len = DMA_LEN, |
| 103 | .expected_result = 0, |
| 104 | }; |
| 105 | |
| 106 | run_intel_iommu_translation(&cfg); |
| 107 | } |
| 108 | |
| 109 | static void test_intel_iommu_scalable_flt(void) |
| 110 | { |
| 111 | QVTDTestConfig cfg = { |
| 112 | .trans_mode = QVTD_TM_SCALABLE_FLT, |
| 113 | .dma_gpa = intel_iommu_expected_gpa(QVTD_IOVA), |
| 114 | .dma_len = DMA_LEN, |
| 115 | .expected_result = 0, |
| 116 | }; |
| 117 | |
| 118 | run_intel_iommu_translation(&cfg); |
| 119 | } |
| 120 | |
| 121 | int main(int argc, char **argv) |
| 122 | { |
| 123 | g_test_init(&argc, &argv, NULL); |
| 124 | |
| 125 | /* Legacy mode tests */ |
| 126 | qtest_add_func("/iommu-testdev/intel/legacy-pt", |
| 127 | test_intel_iommu_legacy_pt); |
| 128 | qtest_add_func("/iommu-testdev/intel/legacy-trans", |
| 129 | test_intel_iommu_legacy_trans); |
| 130 | |
| 131 | /* Scalable mode tests */ |
| 132 | qtest_add_func("/iommu-testdev/intel/scalable-pt", |
| 133 | test_intel_iommu_scalable_pt); |
| 134 | qtest_add_func("/iommu-testdev/intel/scalable-slt", |
| 135 | test_intel_iommu_scalable_slt); |
| 136 | qtest_add_func("/iommu-testdev/intel/scalable-flt", |
| 137 | test_intel_iommu_scalable_flt); |
| 138 | |
| 139 | return g_test_run(); |
| 140 | } |