| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/06/26 22:59 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": [
"KVM_AMD",
"AMD_IOMMU"
],
"FocusSymbols": [
"avic_pi_update_irte",
"avic_update_iommu_vcpu_affinity",
"amd_iommu_update_ga",
"amd_iommu_activate_guest_mode",
"avic_add_vcpu_to_gappi_wakeup_list",
"avic_remove_vcpu_from_gappi_wakeup_list",
"avic_gappi_wakeup_handler",
"__amd_iommu_update_ga"
],
"Reasoning": "This patch introduces GAPPI (Guest APIC Posted Interrupts) support for AMD IOMMU and KVM SVM AVIC. It modifies core interrupt remapping and vCPU affinity logic, which is reachable in virtualized environments (e.g., nested KVM on AMD). Fuzzing is necessary to ensure the new wakeup lists and interrupt handling logic do not introduce concurrency bugs or memory corruption.",
"WorthFuzzing": true
} |
| 1/1 | 2026/06/26 22:59 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit c0768996eaac9664c1914a485a5e22859a96eb5b\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Fri Jun 26 22:59:34 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h\nindex 37b94f484ef338..40a2206a33c08d 100644\n--- a/arch/x86/include/asm/irq_remapping.h\n+++ b/arch/x86/include/asm/irq_remapping.h\n@@ -35,8 +35,8 @@ struct amd_iommu_pi_data {\n \tu64 vapic_addr;\t\t/* Physical address of the vCPU's vAPIC. */\n \tu32 ga_tag;\n \tu32 vector;\t\t/* Guest vector of the interrupt */\n-\tint cpu;\n-\tbool ga_log_intr;\n+\tint apicid;\n+\tint flags;\n \tbool is_guest_mode;\n \tvoid *ir_data;\n };\ndiff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c\nindex cdd5a6dc646f11..d238f65a8172bc 100644\n--- a/arch/x86/kvm/svm/avic.c\n+++ b/arch/x86/kvm/svm/avic.c\n@@ -63,6 +63,9 @@\n \tga_tag;\t\t\t\t\t\t\t\t\\\n })\n \n+static DEFINE_PER_CPU(struct list_head, gappi_vcpu_wakeup_list);\n+static DEFINE_PER_CPU(raw_spinlock_t, gappi_vcpu_wakeup_list_lock);\n+\n static_assert(__AVIC_GATAG(AVIC_VM_ID_MASK, AVIC_VCPU_IDX_MASK) == -1u);\n \n #define AVIC_AUTO_MODE -1\n@@ -874,6 +877,9 @@ int avic_init_vcpu(struct vcpu_svm *svm)\n \tINIT_LIST_HEAD(\u0026svm-\u003eir_list);\n \traw_spin_lock_init(\u0026svm-\u003eir_list_lock);\n \n+\tINIT_LIST_HEAD(\u0026svm-\u003egappi_vcpu_wakeup_list);\n+\tsvm-\u003egappi_cpu = -1;\n+\n \tif (!enable_apicv || !irqchip_in_kernel(vcpu-\u003ekvm))\n \t\treturn 0;\n \n@@ -886,6 +892,44 @@ int avic_init_vcpu(struct vcpu_svm *svm)\n \treturn ret;\n }\n \n+static void avic_add_vcpu_to_gappi_wakeup_list(struct vcpu_svm *svm, int cpu)\n+{\n+\tstruct list_head *wakeup_list;\n+\traw_spinlock_t *spinlock;\n+\n+\tif (WARN_ON(cpu \u003c 0))\n+\t\treturn;\n+\n+\twakeup_list = \u0026per_cpu(gappi_vcpu_wakeup_list, cpu);\n+\tspinlock = \u0026per_cpu(gappi_vcpu_wakeup_list_lock, cpu);\n+\traw_spin_lock(spinlock);\n+\tif (list_empty(\u0026svm-\u003egappi_vcpu_wakeup_list))\n+\t\tlist_add_tail(\u0026svm-\u003egappi_vcpu_wakeup_list, wakeup_list);\n+\traw_spin_unlock(spinlock);\n+}\n+\n+static void avic_remove_vcpu_from_gappi_wakeup_list(struct vcpu_svm *svm, int cpu)\n+{\n+\traw_spinlock_t *spinlock;\n+\n+\tif (WARN_ON(cpu \u003c 0))\n+\t\treturn;\n+\n+\tspinlock = \u0026per_cpu(gappi_vcpu_wakeup_list_lock, cpu);\n+\traw_spin_lock(spinlock);\n+\tif (!list_empty(\u0026svm-\u003egappi_vcpu_wakeup_list))\n+\t\tlist_del_init(\u0026svm-\u003egappi_vcpu_wakeup_list);\n+\traw_spin_unlock(spinlock);\n+}\n+\n+void avic_destroy_vcpu(struct vcpu_svm *svm)\n+{\n+\tif (svm-\u003egappi_cpu != -1 \u0026\u0026 amd_iommu_gappi) {\n+\t\tavic_remove_vcpu_from_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\n+\t\tsvm-\u003egappi_cpu = -1;\n+\t}\n+}\n+\n void avic_apicv_post_state_restore(struct kvm_vcpu *vcpu)\n {\n \tavic_handle_dfr_update(vcpu);\n@@ -896,13 +940,18 @@ static void svm_ir_list_del(struct kvm_kernel_irqfd *irqfd)\n {\n \tstruct kvm_vcpu *vcpu = irqfd-\u003eirq_bypass_vcpu;\n \tunsigned long flags;\n+\tstruct vcpu_svm *svm;\n \n \tif (!vcpu)\n \t\treturn;\n \n-\traw_spin_lock_irqsave(\u0026to_svm(vcpu)-\u003eir_list_lock, flags);\n+\tsvm = to_svm(vcpu);\n+\n+\traw_spin_lock_irqsave(\u0026svm-\u003eir_list_lock, flags);\n \tlist_del(\u0026irqfd-\u003evcpu_list);\n-\traw_spin_unlock_irqrestore(\u0026to_svm(vcpu)-\u003eir_list_lock, flags);\n+\tif (list_empty(\u0026svm-\u003eir_list))\n+\t\tavic_remove_vcpu_from_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\n+\traw_spin_unlock_irqrestore(\u0026svm-\u003eir_list_lock, flags);\n }\n \n int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,\n@@ -932,6 +981,8 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,\n \t\tstruct vcpu_svm *svm = to_svm(vcpu);\n \t\tu64 entry;\n \t\tint ret;\n+\t\tint posted_intr;\n+\t\tbool is_vcpu_waiting = false;\n \n \t\t/*\n \t\t * Prevent the vCPU from being scheduled out or migrated until\n@@ -949,15 +1000,23 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,\n \t\t */\n \t\tentry = svm-\u003eavic_physical_id_entry;\n \t\tif (entry \u0026 AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) {\n-\t\t\tpi_data.cpu = entry \u0026 AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;\n+\t\t\tpi_data.apicid = entry \u0026 AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;\n+\t\t\tpi_data.flags = AMD_IOMMU_FLAG_VCPU_RUNNING;\n \t\t} else {\n-\t\t\tpi_data.cpu = -1;\n-\t\t\tpi_data.ga_log_intr = entry \u0026 AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;\n+\t\t\tposted_intr = !!(entry \u0026 AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR);\n+\t\t\tpi_data.flags = posted_intr \u003c\u003c AMD_IOMMU_FLAG_POSTED_INTR_SHIFT;\n+\t\t\tif (amd_iommu_gappi) {\n+\t\t\t\tpi_data.apicid = kvm_cpu_get_apicid(svm-\u003egappi_cpu);\n+\t\t\t\tif (list_empty(\u0026svm-\u003eir_list)) {\n+\t\t\t\t\tavic_add_vcpu_to_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\n+\t\t\t\t\tis_vcpu_waiting = true;\n+\t\t\t\t}\n+\t\t\t}\n \t\t}\n \n \t\tret = irq_set_vcpu_affinity(host_irq, \u0026pi_data);\n \t\tif (ret)\n-\t\t\treturn ret;\n+\t\t\tgoto gappi_err_out;\n \n \t\t/*\n \t\t * Revert to legacy mode if the IOMMU didn't provide metadata\n@@ -966,12 +1025,17 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,\n \t\t */\n \t\tif (WARN_ON_ONCE(!pi_data.ir_data)) {\n \t\t\tirq_set_vcpu_affinity(host_irq, NULL);\n-\t\t\treturn -EIO;\n+\t\t\tret = -EIO;\n+\t\t\tgoto gappi_err_out;\n \t\t}\n \n \t\tirqfd-\u003eirq_bypass_data = pi_data.ir_data;\n \t\tlist_add(\u0026irqfd-\u003evcpu_list, \u0026svm-\u003eir_list);\n \t\treturn 0;\n+gappi_err_out:\n+\t\tif (is_vcpu_waiting)\n+\t\t\tavic_remove_vcpu_from_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\n+\t\treturn ret;\n \t}\n \treturn irq_set_vcpu_affinity(host_irq, NULL);\n }\n@@ -1004,10 +1068,14 @@ enum avic_vcpu_action {\n \tAVIC_START_BLOCKING\t= BIT(1),\n };\n \n-static void avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu,\n-\t\t\t\t\t enum avic_vcpu_action action)\n+static void avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int apicid,\n+\t\t\t\t\t int cpu, enum avic_vcpu_action action)\n {\n-\tbool ga_log_intr = (action \u0026 AVIC_START_BLOCKING);\n+\tint posted_intr = !!(action \u0026 AVIC_START_BLOCKING) \u003c\u003c\n+\t\t\t AMD_IOMMU_FLAG_POSTED_INTR_SHIFT;\n+\tint is_vcpu_running = (apicid \u003e= 0) \u003c\u003c\n+\t\t\t AMD_IOMMU_FLAG_VCPU_RUNNING_SHIFT;\n+\tint flags = posted_intr | is_vcpu_running;\n \tstruct vcpu_svm *svm = to_svm(vcpu);\n \tstruct kvm_kernel_irqfd *irqfd;\n \n@@ -1017,16 +1085,30 @@ static void avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu,\n \t * Here, we go through the per-vcpu ir_list to update all existing\n \t * interrupt remapping table entry targeting this vcpu.\n \t */\n-\tif (list_empty(\u0026svm-\u003eir_list))\n+\tif (list_empty(\u0026svm-\u003eir_list)) {\n+\t\tif (amd_iommu_gappi \u0026\u0026 cpu \u003e= 0)\n+\t\t\tsvm-\u003egappi_cpu = cpu;\n \t\treturn;\n+\t}\n+\n+\tif (is_vcpu_running \u0026\u0026 amd_iommu_gappi) {\n+\t\t/* IF condition handles the initial state */\n+\t\tif (svm-\u003egappi_cpu != -1)\n+\t\t\tavic_remove_vcpu_from_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\n+\n+\t\tsvm-\u003egappi_cpu = cpu; /* Store cpu no as target for GAPPI */\n+\t} else if (amd_iommu_gappi) {\n+\t\tapicid = kvm_cpu_get_apicid(svm-\u003egappi_cpu);\n+\t\tavic_add_vcpu_to_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\n+\t}\n \n \tlist_for_each_entry(irqfd, \u0026svm-\u003eir_list, vcpu_list) {\n \t\tvoid *data = irqfd-\u003eirq_bypass_data;\n \n \t\tif (!(action \u0026 AVIC_TOGGLE_ON_OFF))\n-\t\t\tWARN_ON_ONCE(amd_iommu_update_ga(data, cpu, ga_log_intr));\n-\t\telse if (cpu \u003e= 0)\n-\t\t\tWARN_ON_ONCE(amd_iommu_activate_guest_mode(data, cpu, ga_log_intr));\n+\t\t\tWARN_ON_ONCE(amd_iommu_update_ga(data, apicid, flags));\n+\t\telse if (is_vcpu_running)\n+\t\t\tWARN_ON_ONCE(amd_iommu_activate_guest_mode(data, apicid, flags));\n \t\telse\n \t\t\tWARN_ON_ONCE(amd_iommu_deactivate_guest_mode(data));\n \t}\n@@ -1080,7 +1162,7 @@ static void __avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu,\n \n \tWRITE_ONCE(kvm_svm-\u003eavic_physical_id_table[vcpu-\u003evcpu_id], entry);\n \n-\tavic_update_iommu_vcpu_affinity(vcpu, h_physical_id, action);\n+\tavic_update_iommu_vcpu_affinity(vcpu, h_physical_id, cpu, action);\n \n \traw_spin_unlock_irqrestore(\u0026svm-\u003eir_list_lock, flags);\n }\n@@ -1123,7 +1205,7 @@ static void __avic_vcpu_put(struct kvm_vcpu *vcpu, enum avic_vcpu_action action)\n \t */\n \traw_spin_lock_irqsave(\u0026svm-\u003eir_list_lock, flags);\n \n-\tavic_update_iommu_vcpu_affinity(vcpu, -1, action);\n+\tavic_update_iommu_vcpu_affinity(vcpu, -1, -1, action);\n \n \tWARN_ON_ONCE(entry \u0026 AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR);\n \n@@ -1296,6 +1378,21 @@ static bool __init avic_want_avic_enabled(void)\n \treturn true;\n }\n \n+static void avic_gappi_wakeup_handler(void)\n+{\n+\tint cpu = smp_processor_id();\n+\tstruct list_head *vcpu_wakeup_list = \u0026per_cpu(gappi_vcpu_wakeup_list, cpu);\n+\traw_spinlock_t *spinlock = \u0026per_cpu(gappi_vcpu_wakeup_list_lock, cpu);\n+\tstruct vcpu_svm *svm;\n+\n+\traw_spin_lock(spinlock);\n+\tlist_for_each_entry(svm, vcpu_wakeup_list, gappi_vcpu_wakeup_list) {\n+\t\tif (kvm_lapic_find_highest_irr(\u0026svm-\u003evcpu) \u003e= 0)\n+\t\t\tkvm_vcpu_wake_up(\u0026svm-\u003evcpu);\n+\t}\n+\traw_spin_unlock(spinlock);\n+}\n+\n /*\n * Note:\n * - The module param avic enable both xAPIC and x2APIC mode.\n@@ -1304,12 +1401,18 @@ static bool __init avic_want_avic_enabled(void)\n */\n bool __init avic_hardware_setup(void)\n {\n+\tint cpu;\n \tavic = avic_want_avic_enabled();\n \tif (!avic)\n \t\treturn false;\n \n \tpr_info(\"AVIC enabled\\n\");\n \n+\tfor_each_possible_cpu(cpu) {\n+\t\tINIT_LIST_HEAD(\u0026per_cpu(gappi_vcpu_wakeup_list, cpu));\n+\t\traw_spin_lock_init(\u0026per_cpu(gappi_vcpu_wakeup_list_lock, cpu));\n+\t}\n+\n \t/* AVIC is a prerequisite for x2AVIC. */\n \tx2avic_enabled = boot_cpu_has(X86_FEATURE_X2AVIC);\n \tif (x2avic_enabled) {\n@@ -1333,6 +1436,7 @@ bool __init avic_hardware_setup(void)\n \t\tenable_ipiv = false;\n \n \tamd_iommu_register_ga_log_notifier(\u0026avic_ga_log_notifier);\n+\tkvm_set_posted_intr_wakeup_handler(\u0026avic_gappi_wakeup_handler);\n \n \treturn true;\n }\ndiff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c\nindex e02a38da5296e3..b687133f8528ba 100644\n--- a/arch/x86/kvm/svm/svm.c\n+++ b/arch/x86/kvm/svm/svm.c\n@@ -1356,6 +1356,8 @@ static void svm_vcpu_free(struct kvm_vcpu *vcpu)\n \n \tWARN_ON_ONCE(!list_empty(\u0026svm-\u003eir_list));\n \n+\tavic_destroy_vcpu(svm);\n+\n \tsvm_leave_nested(vcpu);\n \tsvm_free_nested(svm);\n \ndiff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h\nindex 5137416be593d7..47d5bb5d7103da 100644\n--- a/arch/x86/kvm/svm/svm.h\n+++ b/arch/x86/kvm/svm/svm.h\n@@ -362,6 +362,10 @@ struct vcpu_svm {\n \n \t/* Guest GIF value, used when vGIF is not enabled */\n \tbool guest_gif;\n+\n+\t/* GAPPI related fields */\n+\tstruct list_head gappi_vcpu_wakeup_list;\n+\tint gappi_cpu;\n };\n \n struct svm_cpu_data {\n@@ -909,6 +913,7 @@ void avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb);\n int avic_incomplete_ipi_interception(struct kvm_vcpu *vcpu);\n int avic_unaccelerated_access_interception(struct kvm_vcpu *vcpu);\n int avic_init_vcpu(struct vcpu_svm *svm);\n+void avic_destroy_vcpu(struct vcpu_svm *svm);\n void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu);\n void avic_vcpu_put(struct kvm_vcpu *vcpu);\n void avic_apicv_post_state_restore(struct kvm_vcpu *vcpu);\ndiff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h\nindex 834d8fabfba387..044179cab12e4b 100644\n--- a/drivers/iommu/amd/amd_iommu.h\n+++ b/drivers/iommu/amd/amd_iommu.h\n@@ -41,6 +41,7 @@ int amd_iommu_enable(void);\n void amd_iommu_disable(void);\n int amd_iommu_reenable(int mode);\n int amd_iommu_enable_faulting(unsigned int cpu);\n+extern bool amd_iommu_gappi;\n extern int amd_iommu_guest_ir;\n extern enum protection_domain_mode amd_iommu_pgtable;\n extern int amd_iommu_gpt_level;\ndiff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h\nindex f9f71808789303..de0b23306944b8 100644\n--- a/drivers/iommu/amd/amd_iommu_types.h\n+++ b/drivers/iommu/amd/amd_iommu_types.h\n@@ -94,6 +94,7 @@\n #define FEATURE_X2APIC\t\tBIT_ULL(2)\n #define FEATURE_NX\t\tBIT_ULL(3)\n #define FEATURE_GT\t\tBIT_ULL(4)\n+#define FEATURE_GAPPI\t\tBIT_ULL(5)\n #define FEATURE_IA\t\tBIT_ULL(6)\n #define FEATURE_GA\t\tBIT_ULL(7)\n #define FEATURE_HE\t\tBIT_ULL(8)\n@@ -113,6 +114,7 @@\n /* Extended Feature 2 Bits */\n #define FEATURE_SEVSNPIO_SUP\tBIT_ULL(1)\n #define FEATURE_GCR3TRPMODE\tBIT_ULL(3)\n+#define FEATURE_GAPPIDISSUP\tBIT_ULL(4)\n #define FEATURE_SNPAVICSUP\tGENMASK_ULL(7, 5)\n #define FEATURE_SNPAVICSUP_GAM(x) \\\n \t(FIELD_GET(FEATURE_SNPAVICSUP, x) == 0x1)\n@@ -190,6 +192,7 @@\n #define CONTROL_EPH_EN\t\t45\n #define CONTROL_XT_EN\t\t50\n #define CONTROL_INTCAPXT_EN\t51\n+#define CONTROL_GAPPI_EN\t55\n #define CONTROL_GCR3TRPMODE\t58\n #define CONTROL_IRTCACHEDIS\t59\n #define CONTROL_SNPAVIC_EN\t61\n@@ -1004,7 +1007,8 @@ union irte_ga_lo {\n \t\t no_fault\t: 1,\n \t\t /* ------ */\n \t\t ga_log_intr\t: 1,\n-\t\t rsvd1\t: 3,\n+\t\t rsvd1\t: 2,\n+\t\t gappi_dis\t: 1,\n \t\t is_run\t: 1,\n \t\t /* ------ */\n \t\t guest_mode\t: 1,\ndiff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c\nindex 3bdb380d23e9a9..b3e1d8ee7e9d63 100644\n--- a/drivers/iommu/amd/init.c\n+++ b/drivers/iommu/amd/init.c\n@@ -160,6 +160,9 @@ u8 amd_iommu_hpt_level;\n /* Guest page table level */\n int amd_iommu_gpt_level = PAGE_MODE_4_LEVEL;\n \n+bool amd_iommu_gappi;\n+EXPORT_SYMBOL(amd_iommu_gappi);\n+\n int amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC;\n static int amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE;\n \n@@ -3035,11 +3038,20 @@ static void enable_iommus_vapic(void)\n \t\treturn;\n \t}\n \n+\tif (amd_iommu_gappi \u0026\u0026\n+\t !(check_feature(FEATURE_GAPPI) \u0026\u0026\n+\t AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir))) {\n+\t\tpr_warn(\"GAPPI is not supported.\\n\");\n+\t\tamd_iommu_gappi = false;\n+\t}\n+\n \t/* Enabling GAM and SNPAVIC support */\n \tfor_each_iommu(iommu) {\n-\t\tif (iommu_init_ga_log(iommu) ||\n-\t\t iommu_ga_log_enable(iommu))\n-\t\t\treturn;\n+\t\tif (amd_iommu_gappi)\n+\t\t\tiommu_feature_enable(iommu, CONTROL_GAPPI_EN);\n+\t\telse if (iommu_init_ga_log(iommu) ||\n+\t\t\t iommu_ga_log_enable(iommu))\n+\t\t\t return;\n \n \t\tiommu_feature_enable(iommu, CONTROL_GAM_EN);\n \t\tif (amd_iommu_snp_en)\n@@ -3047,7 +3059,8 @@ static void enable_iommus_vapic(void)\n \t}\n \n \tamd_iommu_irq_ops.capability |= (1 \u003c\u003c IRQ_POSTING_CAP);\n-\tpr_info(\"Virtual APIC enabled\\n\");\n+\tpr_info(\"Virtual APIC enabled with %s\\n\",\n+\t\tamd_iommu_gappi ? \"GAPPI\" : \"GALOG\");\n #endif\n }\n \n@@ -3738,6 +3751,8 @@ static int __init parse_amd_iommu_options(char *str)\n \t\t} else if (strncmp(str, \"v2_pgsizes_only\", 15) == 0) {\n \t\t\tpr_info(\"Restricting V1 page-sizes to 4KiB/2MiB/1GiB\");\n \t\t\tamd_iommu_pgsize_bitmap = AMD_IOMMU_PGSIZES_V2;\n+\t\t} else if (strncmp(str, \"gappi\", 5) == 0) {\n+\t\t\tamd_iommu_gappi = true;\n \t\t} else {\n \t\t\tpr_notice(\"Unknown option - '%s'\\n\", str);\n \t\t}\ndiff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c\nindex 57dc8fabc7d9b9..4690cecc9aa7e4 100644\n--- a/drivers/iommu/amd/iommu.c\n+++ b/drivers/iommu/amd/iommu.c\n@@ -3959,19 +3959,28 @@ static const struct irq_domain_ops amd_ir_domain_ops = {\n \t.deactivate = irq_remapping_deactivate,\n };\n \n-static void __amd_iommu_update_ga(struct irte_ga *entry, int cpu,\n-\t\t\t\t bool ga_log_intr)\n+static void __amd_iommu_update_ga(struct irte_ga *entry, int apicid, int flags)\n {\n-\tif (cpu \u003e= 0) {\n+\tif (flags \u0026 AMD_IOMMU_FLAG_VCPU_RUNNING) {\n \t\tentry-\u003elo.fields_vapic.destination =\n-\t\t\t\t\tAPICID_TO_IRTE_DEST_LO(cpu);\n+\t\t\t\t\tAPICID_TO_IRTE_DEST_LO(apicid);\n \t\tentry-\u003ehi.fields.destination =\n-\t\t\t\t\tAPICID_TO_IRTE_DEST_HI(cpu);\n+\t\t\t\t\tAPICID_TO_IRTE_DEST_HI(apicid);\n \t\tentry-\u003elo.fields_vapic.is_run = true;\n \t\tentry-\u003elo.fields_vapic.ga_log_intr = false;\n \t} else {\n-\t\tentry-\u003elo.fields_vapic.is_run = false;\n-\t\tentry-\u003elo.fields_vapic.ga_log_intr = ga_log_intr;\n+\t\tbool posted_intr = !!(flags \u0026 AMD_IOMMU_FLAG_POSTED_INTR);\n+\t\tif (amd_iommu_gappi) {\n+\t\t\tentry-\u003elo.fields_vapic.gappi_dis = !posted_intr \u0026\u0026\n+\t\t\t\t\t\t\t check_feature2(FEATURE_GAPPIDISSUP);\n+\t\t\tentry-\u003elo.fields_vapic.is_run = false;\n+\t\t\tentry-\u003elo.fields_vapic.destination =\n+\t\t\t\t\t\tAPICID_TO_IRTE_DEST_LO(apicid);\n+\t\t\tentry-\u003ehi.fields.destination = APICID_TO_IRTE_DEST_HI(apicid);\n+\t\t} else {\n+\t\t\tentry-\u003elo.fields_vapic.is_run = false;\n+\t\t\tentry-\u003elo.fields_vapic.ga_log_intr = posted_intr;\n+\t\t}\n \t}\n }\n \n@@ -3992,7 +4001,7 @@ static void __amd_iommu_update_ga(struct irte_ga *entry, int cpu,\n * and thus don't require an invalidation to ensure the IOMMU consumes fresh\n * information.\n */\n-int amd_iommu_update_ga(void *data, int cpu, bool ga_log_intr)\n+int amd_iommu_update_ga(void *data, int apicid, int flags)\n {\n \tstruct amd_ir_data *ir_data = (struct amd_ir_data *)data;\n \tstruct irte_ga *entry = (struct irte_ga *) ir_data-\u003eentry;\n@@ -4006,14 +4015,14 @@ int amd_iommu_update_ga(void *data, int cpu, bool ga_log_intr)\n \tif (!ir_data-\u003eiommu)\n \t\treturn -ENODEV;\n \n-\t__amd_iommu_update_ga(entry, cpu, ga_log_intr);\n+\t__amd_iommu_update_ga(entry, apicid, flags);\n \n \treturn __modify_irte_ga(ir_data-\u003eiommu, ir_data-\u003eirq_2_irte.devid,\n \t\t\t\tir_data-\u003eirq_2_irte.index, entry);\n }\n EXPORT_SYMBOL(amd_iommu_update_ga);\n \n-int amd_iommu_activate_guest_mode(void *data, int cpu, bool ga_log_intr)\n+int amd_iommu_activate_guest_mode(void *data, int apicid, int flags)\n {\n \tstruct amd_ir_data *ir_data = (struct amd_ir_data *)data;\n \tstruct irte_ga *entry = (struct irte_ga *) ir_data-\u003eentry;\n@@ -4034,9 +4043,13 @@ int amd_iommu_activate_guest_mode(void *data, int cpu, bool ga_log_intr)\n \tentry-\u003elo.fields_vapic.guest_mode = 1;\n \tentry-\u003ehi.fields.ga_root_ptr = ir_data-\u003ega_root_ptr;\n \tentry-\u003ehi.fields.vector = ir_data-\u003ega_vector;\n-\tentry-\u003elo.fields_vapic.ga_tag = ir_data-\u003ega_tag;\n \n-\t__amd_iommu_update_ga(entry, cpu, ga_log_intr);\n+\tif (amd_iommu_gappi)\n+\t\tentry-\u003elo.fields_vapic.ga_tag = POSTED_INTR_WAKEUP_VECTOR;\n+\telse\n+\t\tentry-\u003elo.fields_vapic.ga_tag = ir_data-\u003ega_tag;\n+\n+\t__amd_iommu_update_ga(entry, apicid, flags);\n \n \treturn modify_irte_ga(ir_data-\u003eiommu, ir_data-\u003eirq_2_irte.devid,\n \t\t\t ir_data-\u003eirq_2_irte.index, entry);\n@@ -4107,8 +4120,8 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *info)\n \t\tir_data-\u003ega_vector = pi_data-\u003evector;\n \t\tir_data-\u003ega_tag = pi_data-\u003ega_tag;\n \t\tif (pi_data-\u003eis_guest_mode)\n-\t\t\tret = amd_iommu_activate_guest_mode(ir_data, pi_data-\u003ecpu,\n-\t\t\t\t\t\t\t pi_data-\u003ega_log_intr);\n+\t\t\tret = amd_iommu_activate_guest_mode(ir_data, pi_data-\u003eapicid,\n+\t\t\t\t\t\t\t pi_data-\u003eflags);\n \t\telse\n \t\t\tret = amd_iommu_deactivate_guest_mode(ir_data);\n \t} else {\ndiff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h\nindex edcee9f5335a6f..87e76f617ea185 100644\n--- a/include/linux/amd-iommu.h\n+++ b/include/linux/amd-iommu.h\n@@ -30,8 +30,8 @@ static inline void amd_iommu_detect(void) { }\n /* IOMMU AVIC Function */\n extern int amd_iommu_register_ga_log_notifier(int (*notifier)(u32));\n \n-extern int amd_iommu_update_ga(void *data, int cpu, bool ga_log_intr);\n-extern int amd_iommu_activate_guest_mode(void *data, int cpu, bool ga_log_intr);\n+extern int amd_iommu_update_ga(void *data, int apicid, int flags);\n+extern int amd_iommu_activate_guest_mode(void *data, int apicid, int flags);\n extern int amd_iommu_deactivate_guest_mode(void *data);\n \n #else /* defined(CONFIG_AMD_IOMMU) \u0026\u0026 defined(CONFIG_IRQ_REMAP) */\n@@ -42,12 +42,12 @@ amd_iommu_register_ga_log_notifier(int (*notifier)(u32))\n \treturn 0;\n }\n \n-static inline int amd_iommu_update_ga(void *data, int cpu, bool ga_log_intr)\n+static inline int amd_iommu_update_ga(void *data, int apicid, int flags)\n {\n \treturn 0;\n }\n \n-static inline int amd_iommu_activate_guest_mode(void *data, int cpu, bool ga_log_intr)\n+static inline int amd_iommu_activate_guest_mode(void *data, int apicid, int flags)\n {\n \treturn 0;\n }\n@@ -76,4 +76,11 @@ static inline int amd_iommu_snp_disable(void) { return 0; }\n static inline bool amd_iommu_sev_tio_supported(void) { return false; }\n #endif\n \n+#define AMD_IOMMU_FLAG_VCPU_RUNNING_SHIFT 0\n+#define AMD_IOMMU_FLAG_VCPU_RUNNING BIT(0)\n+\n+#define AMD_IOMMU_FLAG_POSTED_INTR_SHIFT 1\n+#define AMD_IOMMU_FLAG_POSTED_INTR BIT(1)\n+\n+extern bool amd_iommu_gappi;\n #endif /* _ASM_X86_AMD_IOMMU_H */\n"
} |
| 2/1 | 2026/06/26 22:59 | agent | patch-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"KVM_AMD",
"AMD_IOMMU"
],
"FocusSymbols": [
"avic_pi_update_irte",
"avic_update_iommu_vcpu_affinity",
"amd_iommu_update_ga",
"amd_iommu_activate_guest_mode",
"avic_add_vcpu_to_gappi_wakeup_list",
"avic_remove_vcpu_from_gappi_wakeup_list",
"avic_gappi_wakeup_handler",
"__amd_iommu_update_ga"
],
"Reasoning": "This patch introduces GAPPI (Guest APIC Posted Interrupts) support for AMD IOMMU and KVM SVM AVIC. It modifies core interrupt remapping and vCPU affinity logic, which is reachable in virtualized environments (e.g., nested KVM on AMD). Fuzzing is necessary to ensure the new wakeup lists and interrupt handling logic do not introduce concurrency bugs or memory corruption.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit c0768996eaac9664c1914a485a5e22859a96eb5b
Author: syz-cluster <triage@syzkaller.com>
Date: Fri Jun 26 22:59:34 2026 +0000
syz-cluster: applied patch under review
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index 37b94f484ef338..40a2206a33c08d 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -35,8 +35,8 @@ struct amd_iommu_pi_data {
u64 vapic_addr; /* Physical address of the vCPU's vAPIC. */
u32 ga_tag;
u32 vector; /* Guest vector of the interrupt */
- int cpu;
- bool ga_log_intr;
+ int apicid;
+ int flags;
bool is_guest_mode;
void *ir_data;
};
diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
index cdd5a6dc646f11..d238f65a8172bc 100644
--- a/arch/x86/kvm/svm/avic.c
+++ b/arch/x86/kvm/svm/avic.c
@@ -63,6 +63,9 @@
ga_tag; \
})
+static DEFINE_PER_CPU(struct list_head, gappi_vcpu_wakeup_list);
+static DEFINE_PER_CPU(raw_spinlock_t, gappi_vcpu_wakeup_list_lock);
+
static_assert(__AVIC_GATAG(AVIC_VM_ID_MASK, AVIC_VCPU_IDX_MASK) == -1u);
#define AVIC_AUTO_MODE -1
@@ -874,6 +877,9 @@ int avic_init_vcpu(struct vcpu_svm *svm)
INIT_LIST_HEAD(&svm->ir_list);
raw_spin_lock_init(&svm->ir_list_lock);
+ INIT_LIST_HEAD(&svm->gappi_vcpu_wakeup_list);
+ svm->gappi_cpu = -1;
+
if (!enable_apicv || !irqchip_in_kernel(vcpu->kvm))
return 0;
@@ -886,6 +892,44 @@ int avic_init_vcpu(struct vcpu_svm *svm)
return ret;
}
+static void avic_add_vcpu_to_gappi_wakeup_list(struct vcpu_svm *svm, int cpu)
+{
+ struct list_head *wakeup_list;
+ raw_spinlock_t *spinlock;
+
+ if (WARN_ON(cpu < 0))
+ return;
+
+ wakeup_list = &per_cpu(gappi_vcpu_wakeup_list, cpu);
+ spinlock = &per_cpu(gappi_vcpu_wakeup_list_lock, cpu);
+ raw_spin_lock(spinlock);
+ if (list_empty(&svm->gappi_vcpu_wakeup_list))
+ list_add_tail(&svm->gappi_vcpu_wakeup_list, wakeup_list);
+ raw_spin_unlock(spinlock);
+}
+
+static void avic_remove_vcpu_from_gappi_wakeup_list(struct vcpu_svm *svm, int cpu)
+{
+ raw_spinlock_t *spinlock;
+
+ if (WARN_ON(cpu < 0))
+ return;
+
+ spinlock = &per_cpu(gappi_vcpu_wakeup_list_lock, cpu);
+ raw_spin_lock(spinlock);
+ if (!list_empty(&svm->gappi_vcpu_wakeup_list))
+ list_del_init(&svm->gappi_vcpu_wakeup_list);
+ raw_spin_unlock(spinlock);
+}
+
+void avic_destroy_vcpu(struct vcpu_svm *svm)
+{
+ if (svm->gappi_cpu != -1 && amd_iommu_gappi) {
+ avic_remove_vcpu_from_gappi_wakeup_list(svm, svm->gappi_cpu);
+ svm->gappi_cpu = -1;
+ }
+}
+
void avic_apicv_post_state_restore(struct kvm_vcpu *vcpu)
{
avic_handle_dfr_update(vcpu);
@@ -896,13 +940,18 @@ static void svm_ir_list_del(struct kvm_kernel_irqfd *irqfd)
{
struct kvm_vcpu *vcpu = irqfd->irq_bypass_vcpu;
unsigned long flags;
+ struct vcpu_svm *svm;
if (!vcpu)
return;
- raw_spin_lock_irqsave(&to_svm(vcpu)->ir_list_lock, flags);
+ svm = to_svm(vcpu);
+
+ raw_spin_lock_irqsave(&svm->ir_list_lock, flags);
list_del(&irqfd->vcpu_list);
- raw_spin_unlock_irqrestore(&to_svm(vcpu)->ir_list_lock, flags);
+ if (list_empty(&svm->ir_list))
+ avic_remove_vcpu_from_gappi_wakeup_list(svm, svm->gappi_cpu);
+ raw_spin_unlock_irqrestore(&svm->ir_list_lock, flags);
}
int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
@@ -932,6 +981,8 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
struct vcpu_svm *svm = to_svm(vcpu);
u64 entry;
int ret;
+ int posted_intr;
+ bool is_vcpu_waiting = false;
/*
* Prevent the vCPU from being scheduled out or migrated until
@@ -949,15 +1000,23 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
*/
entry = svm->avic_physical_id_entry;
if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) {
- pi_data.cpu = entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
+ pi_data.apicid = entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
+ pi_data.flags = AMD_IOMMU_FLAG_VCPU_RUNNING;
} else {
- pi_data.cpu = -1;
- pi_data.ga_log_intr = entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;
+ posted_intr = !!(entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR);
+ pi_data.flags = posted_intr << AMD_IOMMU_FLAG_POSTED_INTR_SHIFT;
+ if (amd_iommu_gappi) {
+ pi_data.apicid = kvm_cpu_get_apicid(svm->gappi_cpu);
+ if (list_empty(&svm->ir_list)) {
+ avic_add_vcpu_to_gappi_wakeup_list(svm, svm->gappi_cpu);
+ is_vcpu_waiting = true;
+ }
+ }
}
ret = irq_set_vcpu_affinity(host_irq, &pi_data);
if (ret)
- return ret;
+ goto gappi_err_out;
/*
* Revert to legacy mode if the IOMMU didn't provide metadata
@@ -966,12 +1025,17 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
*/
if (WARN_ON_ONCE(!pi_data.ir_data)) {
irq_set_vcpu_affinity(host_irq, NULL);
- return -EIO;
+ ret = -EIO;
+ goto gappi_err_out;
}
irqfd->irq_bypass_data = pi_data.ir_data;
list_add(&irqfd->vcpu_list, &svm->ir_list);
return 0;
+gappi_err_out:
+ if (is_vcpu_waiting)
+ avic_remove_vcpu_from_gappi_wakeup_list(svm, svm->gappi_cpu);
+ return ret;
}
return irq_set_vcpu_affinity(host_irq, NULL);
}
@@ -1004,10 +1068,14 @@ enum avic_vcpu_action {
AVIC_START_BLOCKING = BIT(1),
};
-static void avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu,
- enum avic_vcpu_action action)
+static void avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int apicid,
+ int cpu, enum avic_vcpu_action action)
{
- bool ga_log_intr = (action & AVIC_START_BLOCKING);
+ int posted_intr = !!(action & AVIC_START_BLOCKING) <<
+ AMD_IOMMU_FLAG_POSTED_INTR_SHIFT;
+ int is_vcpu_running = (apicid >= 0) <<
+ AMD_IOMMU_FLAG_VCPU_RUNNING_SHIFT;
+ int flags = posted_intr | is_vcpu_running;
struct vcpu_svm *svm = to_svm(vcpu);
struct kvm_kernel_irqfd *irqfd;
@@ -1017,16 +1085,30 @@ static void avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu,
* Here, we go through the per-vcpu ir_list to update all existing
* interrupt remapping table entry targeting this vcpu.
*/
- if (list_empty(&svm->ir_list))
+ if (list_empty(&svm->ir_list)) {
+ if (amd_iommu_gappi && cpu >= 0)
+ svm->gappi_cpu = cpu;
return;
+ }
+
+ if (is_vcpu_running && amd_iommu_gappi) {
+ /* IF condition handles the initial state */
+ if (svm->gappi_cpu != -1)
+ avic_remove_vcpu_from_gappi_wakeup_list(svm, svm->gappi_cpu);
+
+ svm->gappi_cpu = cpu; /* Store cpu no as target for GAPPI */
+ } else if (amd_iommu_gappi) {
+ apicid = kvm_cpu_get_apicid(svm->gappi_cpu);
+ avic_add_vcpu_to_gappi_wakeup_list(svm, svm->gappi_cpu);
+ }
list_for_each_entry(irqfd, &svm->ir_list, vcpu_list) {
void *data = irqfd->irq_bypass_data;
if (!(action & AVIC_TOGGLE_ON_OFF))
- WARN_ON_ONCE(amd_iommu_update_ga(data, cpu, ga_log_intr));
- else if (cpu >= 0)
- WARN_ON_ONCE(amd_iommu_activate_guest_mode(data, cpu, ga_log_intr));
+ WARN_ON_ONCE(amd_iommu_update_ga(data, apicid, flags));
+ else if (is_vcpu_running)
+ WARN_ON_ONCE(amd_iommu_activate_guest_mode(data, apicid, flags));
else
WARN_ON_ONCE(amd_iommu_deactivate_guest_mode(data));
}
@@ -1080,7 +1162,7 @@ static void __avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu,
WRITE_ONCE(kvm_svm->avic_physical_id_table[vcpu->vcpu_id], entry);
- avic_update_iommu_vcpu_affinity(vcpu, h_physical_id, action);
+ avic_update_iommu_vcpu_affinity(vcpu, h_physical_id, cpu, action);
raw_spin_unlock_irqrestore(&svm->ir_list_lock, flags);
}
@@ -1123,7 +1205,7 @@ static void __avic_vcpu_put(struct kvm_vcpu *vcpu, enum avic_vcpu_action action)
*/
raw_spin_lock_irqsave(&svm->ir_list_lock, flags);
- avic_update_iommu_vcpu_affinity(vcpu, -1, action);
+ avic_update_iommu_vcpu_affinity(vcpu, -1, -1, action);
WARN_ON_ONCE(entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR);
@@ -1296,6 +1378,21 @@ static bool __init avic_want_avic_enabled(void)
return true;
}
+static void avic_gappi_wakeup_handler(void)
+{
+ int cpu = smp_processor_id();
+ struct list_head *vcpu_wakeup_list = &per_cpu(gappi_vcpu_wakeup_list, cpu);
+ raw_spinlock_t *spinlock = &per_cpu(gappi_vcpu_wakeup_list_lock, cpu);
+ struct vcpu_svm *svm;
+
+ raw_spin_lock(spinlock);
+ list_for_each_entry(svm, vcpu_wakeup_list, gappi_vcpu_wakeup_list) {
+ if (kvm_lapic_find_highest_irr(&svm->vcpu) >= 0)
+ kvm_vcpu_wake_up(&svm->vcpu);
+ }
+ raw_spin_unlock(spinlock);
+}
+
/*
* Note:
* - The module param avic enable both xAPIC and x2APIC mode.
@@ -1304,12 +1401,18 @@ static bool __init avic_want_avic_enabled(void)
*/
bool __init avic_hardware_setup(void)
{
+ int cpu;
avic = avic_want_avic_enabled();
if (!avic)
return false;
pr_info("AVIC enabled\n");
+ for_each_possible_cpu(cpu) {
+ INIT_LIST_HEAD(&per_cpu(gappi_vcpu_wakeup_list, cpu));
+ raw_spin_lock_init(&per_cpu(gappi_vcpu_wakeup_list_lock, cpu));
+ }
+
/* AVIC is a prerequisite for x2AVIC. */
x2avic_enabled = boot_cpu_has(X86_FEATURE_X2AVIC);
if (x2avic_enabled) {
@@ -1333,6 +1436,7 @@ bool __init avic_hardware_setup(void)
enable_ipiv = false;
amd_iommu_register_ga_log_notifier(&avic_ga_log_notifier);
+ kvm_set_posted_intr_wakeup_handler(&avic_gappi_wakeup_handler);
return true;
}
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index e02a38da5296e3..b687133f8528ba 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1356,6 +1356,8 @@ static void svm_vcpu_free(struct kvm_vcpu *vcpu)
WARN_ON_ONCE(!list_empty(&svm->ir_list));
+ avic_destroy_vcpu(svm);
+
svm_leave_nested(vcpu);
svm_free_nested(svm);
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 5137416be593d7..47d5bb5d7103da 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -362,6 +362,10 @@ struct vcpu_svm {
/* Guest GIF value, used when vGIF is not enabled */
bool guest_gif;
+
+ /* GAPPI related fields */
+ struct list_head gappi_vcpu_wakeup_list;
+ int gappi_cpu;
};
struct svm_cpu_data {
@@ -909,6 +913,7 @@ void avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb);
int avic_incomplete_ipi_interception(struct kvm_vcpu *vcpu);
int avic_unaccelerated_access_interception(struct kvm_vcpu *vcpu);
int avic_init_vcpu(struct vcpu_svm *svm);
+void avic_destroy_vcpu(struct vcpu_svm *svm);
void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
void avic_vcpu_put(struct kvm_vcpu *vcpu);
void avic_apicv_post_state_restore(struct kvm_vcpu *vcpu);
diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 834d8fabfba387..044179cab12e4b 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -41,6 +41,7 @@ int amd_iommu_enable(void);
void amd_iommu_disable(void);
int amd_iommu_reenable(int mode);
int amd_iommu_enable_faulting(unsigned int cpu);
+extern bool amd_iommu_gappi;
extern int amd_iommu_guest_ir;
extern enum protection_domain_mode amd_iommu_pgtable;
extern int amd_iommu_gpt_level;
diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
index f9f71808789303..de0b23306944b8 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -94,6 +94,7 @@
#define FEATURE_X2APIC BIT_ULL(2)
#define FEATURE_NX BIT_ULL(3)
#define FEATURE_GT BIT_ULL(4)
+#define FEATURE_GAPPI BIT_ULL(5)
#define FEATURE_IA BIT_ULL(6)
#define FEATURE_GA BIT_ULL(7)
#define FEATURE_HE BIT_ULL(8)
@@ -113,6 +114,7 @@
/* Extended Feature 2 Bits */
#define FEATURE_SEVSNPIO_SUP BIT_ULL(1)
#define FEATURE_GCR3TRPMODE BIT_ULL(3)
+#define FEATURE_GAPPIDISSUP BIT_ULL(4)
#define FEATURE_SNPAVICSUP GENMASK_ULL(7, 5)
#define FEATURE_SNPAVICSUP_GAM(x) \
(FIELD_GET(FEATURE_SNPAVICSUP, x) == 0x1)
@@ -190,6 +192,7 @@
#define CONTROL_EPH_EN 45
#define CONTROL_XT_EN 50
#define CONTROL_INTCAPXT_EN 51
+#define CONTROL_GAPPI_EN 55
#define CONTROL_GCR3TRPMODE 58
#define CONTROL_IRTCACHEDIS 59
#define CONTROL_SNPAVIC_EN 61
@@ -1004,7 +1007,8 @@ union irte_ga_lo {
no_fault : 1,
/* ------ */
ga_log_intr : 1,
- rsvd1 : 3,
+ rsvd1 : 2,
+ gappi_dis : 1,
is_run : 1,
/* ------ */
guest_mode : 1,
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 3bdb380d23e9a9..b3e1d8ee7e9d63 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -160,6 +160,9 @@ u8 amd_iommu_hpt_level;
/* Guest page table level */
int amd_iommu_gpt_level = PAGE_MODE_4_LEVEL;
+bool amd_iommu_gappi;
+EXPORT_SYMBOL(amd_iommu_gappi);
+
int amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC;
static int amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE;
@@ -3035,11 +3038,20 @@ static void enable_iommus_vapic(void)
return;
}
+ if (amd_iommu_gappi &&
+ !(check_feature(FEATURE_GAPPI) &&
+ AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir))) {
+ pr_warn("GAPPI is not supported.\n");
+ amd_iommu_gappi = false;
+ }
+
/* Enabling GAM and SNPAVIC support */
for_each_iommu(iommu) {
- if (iommu_init_ga_log(iommu) ||
- iommu_ga_log_enable(iommu))
- return;
+ if (amd_iommu_gappi)
+ iommu_feature_enable(iommu, CONTROL_GAPPI_EN);
+ else if (iommu_init_ga_log(iommu) ||
+ iommu_ga_log_enable(iommu))
+ return;
iommu_feature_enable(iommu, CONTROL_GAM_EN);
if (amd_iommu_snp_en)
@@ -3047,7 +3059,8 @@ static void enable_iommus_vapic(void)
}
amd_iommu_irq_ops.capability |= (1 << IRQ_POSTING_CAP);
- pr_info("Virtual APIC enabled\n");
+ pr_info("Virtual APIC enabled with %s\n",
+ amd_iommu_gappi ? "GAPPI" : "GALOG");
#endif
}
@@ -3738,6 +3751,8 @@ static int __init parse_amd_iommu_options(char *str)
} else if (strncmp(str, "v2_pgsizes_only", 15) == 0) {
pr_info("Restricting V1 page-sizes to 4KiB/2MiB/1GiB");
amd_iommu_pgsize_bitmap = AMD_IOMMU_PGSIZES_V2;
+ } else if (strncmp(str, "gappi", 5) == 0) {
+ amd_iommu_gappi = true;
} else {
pr_notice("Unknown option - '%s'\n", str);
}
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 57dc8fabc7d9b9..4690cecc9aa7e4 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -3959,19 +3959,28 @@ static const struct irq_domain_ops amd_ir_domain_ops = {
.deactivate = irq_remapping_deactivate,
};
-static void __amd_iommu_update_ga(struct irte_ga *entry, int cpu,
- bool ga_log_intr)
+static void __amd_iommu_update_ga(struct irte_ga *entry, int apicid, int flags)
{
- if (cpu >= 0) {
+ if (flags & AMD_IOMMU_FLAG_VCPU_RUNNING) {
entry->lo.fields_vapic.destination =
- APICID_TO_IRTE_DEST_LO(cpu);
+ APICID_TO_IRTE_DEST_LO(apicid);
entry->hi.fields.destination =
- APICID_TO_IRTE_DEST_HI(cpu);
+ APICID_TO_IRTE_DEST_HI(apicid);
entry->lo.fields_vapic.is_run = true;
entry->lo.fields_vapic.ga_log_intr = false;
} else {
- entry->lo.fields_vapic.is_run = false;
- entry->lo.fields_vapic.ga_log_intr = ga_log_intr;
+ bool posted_intr = !!(flags & AMD_IOMMU_FLAG_POSTED_INTR);
+ if (amd_iommu_gappi) {
+ entry->lo.fields_vapic.gappi_dis = !posted_intr &&
+ check_feature2(FEATURE_GAPPIDISSUP);
+ entry->lo.fields_vapic.is_run = false;
+ entry->lo.fields_vapic.destination =
+ APICID_TO_IRTE_DEST_LO(apicid);
+ entry->hi.fields.destination = APICID_TO_IRTE_DEST_HI(apicid);
+ } else {
+ entry->lo.fields_vapic.is_run = false;
+ entry->lo.fields_vapic.ga_log_intr = posted_intr;
+ }
}
}
@@ -3992,7 +4001,7 @@ static void __amd_iommu_update_ga(struct irte_ga *entry, int cpu,
* and thus don't require an invalidation to ensure the IOMMU consumes fresh
* information.
*/
-int amd_iommu_update_ga(void *data, int cpu, bool ga_log_intr)
+int amd_iommu_update_ga(void *data, int apicid, int flags)
{
struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
@@ -4006,14 +4015,14 @@ int amd_iommu_update_ga(void *data, int cpu, bool ga_log_intr)
if (!ir_data->iommu)
return -ENODEV;
- __amd_iommu_update_ga(entry, cpu, ga_log_intr);
+ __amd_iommu_update_ga(entry, apicid, flags);
return __modify_irte_ga(ir_data->iommu, ir_data->irq_2_irte.devid,
ir_data->irq_2_irte.index, entry);
}
EXPORT_SYMBOL(amd_iommu_update_ga);
-int amd_iommu_activate_guest_mode(void *data, int cpu, bool ga_log_intr)
+int amd_iommu_activate_guest_mode(void *data, int apicid, int flags)
{
struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
@@ -4034,9 +4043,13 @@ int amd_iommu_activate_guest_mode(void *data, int cpu, bool ga_log_intr)
entry->lo.fields_vapic.guest_mode = 1;
entry->hi.fields.ga_root_ptr = ir_data->ga_root_ptr;
entry->hi.fields.vector = ir_data->ga_vector;
- entry->lo.fields_vapic.ga_tag = ir_data->ga_tag;
- __amd_iommu_update_ga(entry, cpu, ga_log_intr);
+ if (amd_iommu_gappi)
+ entry->lo.fields_vapic.ga_tag = POSTED_INTR_WAKEUP_VECTOR;
+ else
+ entry->lo.fields_vapic.ga_tag = ir_data->ga_tag;
+
+ __amd_iommu_update_ga(entry, apicid, flags);
return modify_irte_ga(ir_data->iommu, ir_data->irq_2_irte.devid,
ir_data->irq_2_irte.index, entry);
@@ -4107,8 +4120,8 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *info)
ir_data->ga_vector = pi_data->vector;
ir_data->ga_tag = pi_data->ga_tag;
if (pi_data->is_guest_mode)
- ret = amd_iommu_activate_guest_mode(ir_data, pi_data->cpu,
- pi_data->ga_log_intr);
+ ret = amd_iommu_activate_guest_mode(ir_data, pi_data->apicid,
+ pi_data->flags);
else
ret = amd_iommu_deactivate_guest_mode(ir_data);
} else {
diff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h
index edcee9f5335a6f..87e76f617ea185 100644
--- a/include/linux/amd-iommu.h
+++ b/include/linux/amd-iommu.h
@@ -30,8 +30,8 @@ static inline void amd_iommu_detect(void) { }
/* IOMMU AVIC Function */
extern int amd_iommu_register_ga_log_notifier(int (*notifier)(u32));
-extern int amd_iommu_update_ga(void *data, int cpu, bool ga_log_intr);
-extern int amd_iommu_activate_guest_mode(void *data, int cpu, bool ga_log_intr);
+extern int amd_iommu_update_ga(void *data, int apicid, int flags);
+extern int amd_iommu_activate_guest_mode(void *data, int apicid, int flags);
extern int amd_iommu_deactivate_guest_mode(void *data);
#else /* defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP) */
@@ -42,12 +42,12 @@ amd_iommu_register_ga_log_notifier(int (*notifier)(u32))
return 0;
}
-static inline int amd_iommu_update_ga(void *data, int cpu, bool ga_log_intr)
+static inline int amd_iommu_update_ga(void *data, int apicid, int flags)
{
return 0;
}
-static inline int amd_iommu_activate_guest_mode(void *data, int cpu, bool ga_log_intr)
+static inline int amd_iommu_activate_guest_mode(void *data, int apicid, int flags)
{
return 0;
}
@@ -76,4 +76,11 @@ static inline int amd_iommu_snp_disable(void) { return 0; }
static inline bool amd_iommu_sev_tio_supported(void) { return false; }
#endif
+#define AMD_IOMMU_FLAG_VCPU_RUNNING_SHIFT 0
+#define AMD_IOMMU_FLAG_VCPU_RUNNING BIT(0)
+
+#define AMD_IOMMU_FLAG_POSTED_INTR_SHIFT 1
+#define AMD_IOMMU_FLAG_POSTED_INTR BIT(1)
+
+extern bool amd_iommu_gappi;
#endif /* _ASM_X86_AMD_IOMMU_H */
|
| 3/2 | 2026/06/26 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 10398 output: 19 thoughts: 371 Thoughts: **Fuzzing Target Evaluation** Okay, so I'm looking at this patch and immediately need to assess if it introduces functional changes to the kernel that warrant fuzzing. The files modified – `arch/x86/kvm/svm/avic.c`, `arch/x86/kvm/svm/svm.c`, `arch/x86/kvm/svm/svm.h`, along with some IOMMU files (`drivers/iommu/amd/*` and `include/linux/amd-iommu.h`) – immediately clue me in. It looks like we're dealing with Guest APIC Posted Interrupts (GAPPI) support within the AMD IOMMU and KVM SVM AVIC. This screams "virtualization" and "IOMMU," so it's a high-probability target. The next question: Is this reachable in a typical fuzzing environment? Can we trigger this in something like GCE or QEMU? Absolutely. KVM SVM – AMD's virtualization – can definitely be tested with nested virtualization, like running QEMU *with* KVM, or even within GCE instances that have nested virtualization enabled. Good news – syzkaller, which we're using, does run in QEMU/GCE, and it's definitely capable of fuzzing KVM. This patch clearly touches KVM SVM and the AMD IOMMU, so that's two separate areas that need checking. Hold on, `amd_iommu_gappi` – that's a *new* feature. I need to figure out what config options are needed. Let's see... I'm thinking `KVM_AMD` and `AMD_IOMMU` are the obvious candidates. Time to break out `grepper` and search for those config symbols. Let's find out what configurations are needed. |
| 4/2 | 2026/06/26 22:59 | tool | grepper |
0mArgs:{
"Expression": "config KVM_AMD"
}Results: {
"Output": "arch/x86/kvm/Kconfig=134=config KVM_INTEL_TDX\n--\narch/x86/kvm/Kconfig-145-\narch/x86/kvm/Kconfig:146:config KVM_AMD\narch/x86/kvm/Kconfig-147-\ttristate \"KVM for AMD processors support\"\n--\narch/x86/kvm/Kconfig-155-\narch/x86/kvm/Kconfig:156:config KVM_AMD_SEV\narch/x86/kvm/Kconfig-157-\tbool \"AMD Secure Encrypted Virtualization (SEV) support\"\n"
} |
| 5/2 | 2026/06/26 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 11371 output: 20 thoughts: 13 Thoughts: Okay, let's dive into this. Here's my thought process on checking the `AMD_IOMMU` configuration: **Analyzing AMD_IOMMU Configuration** Right, let's get to it. First, I need to check the `AMD_IOMMU` configuration. This is crucial for managing I/O devices, particularly in environments where virtualization or advanced hardware features are in play. I need to understand how it's set up to ensure proper device isolation and performance. I'll need to look at specific registers or configuration files, depending on the system and kernel version, but the objective remains the same: I need to quickly assess the current state and identify any potential bottlenecks or misconfigurations. Depending on what I find, I may need to dive deeper into the documentation for the specific AMD chipset I'm dealing with. Let's see what we've got! |
| 6/2 | 2026/06/26 22:59 | tool | grepper |
0mArgs:{
"Expression": "config AMD_IOMMU"
}Results: {
"Output": "drivers/iommu/amd/Kconfig-2-# AMD IOMMU support\ndrivers/iommu/amd/Kconfig:3:config AMD_IOMMU\ndrivers/iommu/amd/Kconfig-4-\tbool \"AMD IOMMU support\"\n--\ndrivers/iommu/amd/Kconfig-32-\ndrivers/iommu/amd/Kconfig:33:config AMD_IOMMU_IOMMUFD\ndrivers/iommu/amd/Kconfig-34-\tbool \"Enable IOMMUFD features for AMD IOMMU (EXPERIMENTAL)\"\n--\ndrivers/iommu/amd/Kconfig-42-\ndrivers/iommu/amd/Kconfig:43:config AMD_IOMMU_DEBUGFS\ndrivers/iommu/amd/Kconfig-44-\tbool \"Enable AMD IOMMU internals in DebugFS\"\n"
} |
| 7/2 | 2026/06/26 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 11807 output: 26 thoughts: 230 Thoughts: **Analyzing the AMD IOMMU GAPPI Patch** Okay, so this patch introduces `amd_iommu_gappi` activated by the `amd_iommu=gappi` boot parameter. My initial thought is, "can this be fuzzed?" The answer is *maybe*. Syzkaller won't pick this up on its own unless explicitly instructed, meaning it's dependent on the boot parameter being passed. However, the patch also touches `avic_update_iommu_vcpu_affinity` and `amd_iommu_activate_guest_mode` which are potential entry points regardless, so there is certainly a way in. But then, hold on a second. It also adds `avic_gappi_wakeup_handler` and a call to `kvm_set_posted_intr_wakeup_handler` with it. That's interesting! I need to quickly verify that `kvm_set_posted_intr_wakeup_handler` is even a thing... let's check the code. |
| 8/2 | 2026/06/26 23:00 | tool | grepper |
0mArgs:{
"Expression": "kvm_set_posted_intr_wakeup_handler"
}Results: {
"Output": "arch/x86/include/asm/irq.h=30=extern void fixup_irqs(void);\n--\narch/x86/include/asm/irq.h-32-#if IS_ENABLED(CONFIG_KVM)\narch/x86/include/asm/irq.h:33:extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void));\narch/x86/include/asm/irq.h-34-#endif\n--\narch/x86/kernel/irq.c=373=static void (*kvm_posted_intr_wakeup_handler)(void) = dummy_handler;\narch/x86/kernel/irq.c-374-\narch/x86/kernel/irq.c:375:void kvm_set_posted_intr_wakeup_handler(void (*handler)(void))\narch/x86/kernel/irq.c-376-{\n--\narch/x86/kernel/irq.c-383-}\narch/x86/kernel/irq.c:384:EXPORT_SYMBOL_FOR_KVM(kvm_set_posted_intr_wakeup_handler);\narch/x86/kernel/irq.c-385-\n--\narch/x86/kvm/svm/avic.c=1402=bool __init avic_hardware_setup(void)\n--\narch/x86/kvm/svm/avic.c-1438-\tamd_iommu_register_ga_log_notifier(\u0026avic_ga_log_notifier);\narch/x86/kvm/svm/avic.c:1439:\tkvm_set_posted_intr_wakeup_handler(\u0026avic_gappi_wakeup_handler);\narch/x86/kvm/svm/avic.c-1440-\n--\narch/x86/kvm/vmx/vmx.c=8476=void vmx_hardware_unsetup(void)\narch/x86/kvm/vmx/vmx.c-8477-{\narch/x86/kvm/vmx/vmx.c:8478:\tkvm_set_posted_intr_wakeup_handler(NULL);\narch/x86/kvm/vmx/vmx.c-8479-\n--\narch/x86/kvm/vmx/vmx.c=8598=__init int vmx_hardware_setup(void)\n--\narch/x86/kvm/vmx/vmx.c-8782-\narch/x86/kvm/vmx/vmx.c:8783:\tkvm_set_posted_intr_wakeup_handler(pi_wakeup_handler);\narch/x86/kvm/vmx/vmx.c-8784-\n"
} |
| 9/2 | 2026/06/26 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13004 output: 20 thoughts: 483 Thoughts: **Analyzing the GAPPI Support Patch** Okay, so this patch is introducing GAPPI support. My initial thought is to dive into the core changes and see how they are implemented. It looks like it's touching several key functions: `avic_update_iommu_vcpu_affinity`, `avic_pi_update_irte`, `amd_iommu_update_ga`, and `amd_iommu_activate_guest_mode`. These are all functional modifications, so it's a good starting point for detailed review. Now, a key question is reachability – can this new code actually be triggered in a real-world scenario? Considering this is KVM/SVM/AVIC related, it should be reachable when running nested KVM on AMD hardware, which increases my confidence. And, because syzkaller fuzzes KVM, this seems like a solid potential target for fuzzing, and so I should extract a list of focus symbols. I've identified these symbols for closer examination: `avic_update_iommu_vcpu_affinity`, `avic_pi_update_irte`, `amd_iommu_update_ga`, `amd_iommu_activate_guest_mode`, `avic_add_vcpu_to_gappi_wakeup_list`, `avic_remove_vcpu_from_gappi_wakeup_list`, and `avic_gappi_wakeup_handler`. Next, I need to check the scope of these functions, this is important. It looks like `avic_update_iommu_vcpu_affinity`, `avic_add_vcpu_to_gappi_wakeup_list`, `avic_remove_vcpu_from_gappi_wakeup_list` and `avic_gappi_wakeup_handler` are static. `avic_pi_update_irte` is not static. `amd_iommu_update_ga` and `amd_iommu_activate_guest_mode` are exported, which could have implications for how they are used and potentially exploited. Knowing which functions are static helps determine how easily they can be called from other parts of the kernel. Therefore, for further analysis, my focus list will be: `avic_pi_update_irte`, `amd_iommu_update_ga`, `amd_iommu_activate_guest_mode`, `avic_update_iommu_vcpu_affinity`, `avic_add_vcpu_to_gappi_wakeup_list`, `avic_remove_vcpu_from_gappi_wakeup_list` and `avic_gappi_wakeup_handler`. Finally, configuration is important. I'll need to confirm that `KVM_AMD`, `AMD_IOMMU`, and `IRQ_REMAP` are enabled or, if not, if they need to be. `IRQ_REMAP` is likely already enabled, but it's worth double-checking to ensure everything is set up correctly for this GAPPI support. |
| 10/2 | 2026/06/26 23:00 | tool | grepper |
0mArgs:{
"Expression": "config IRQ_REMAP"
}Results: {
"Output": "drivers/iommu/Kconfig=199=source \"drivers/iommu/riscv/Kconfig\"\ndrivers/iommu/Kconfig-200-\ndrivers/iommu/Kconfig:201:config IRQ_REMAP\ndrivers/iommu/Kconfig-202-\tbool \"Support for Interrupt Remapping\"\n"
} |
| 11/2 | 2026/06/26 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14249 output: 21 thoughts: 24 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience, presented in the first person: **Investigating the AMD_IOMMU and IRQ_REMAP Dependency** Alright, let's dive into this. I'm trying to quickly ascertain the dependency relationship between `AMD_IOMMU` and `IRQ_REMAP`. Is `AMD_IOMMU` a necessary prerequisite for `IRQ_REMAP` to function correctly with AMD hardware, or is it the other way around? Or, perhaps, do they simply co-exist in a way where enabling one necessitates enabling the other in certain configurations? This is a critical point that needs to be clarified, because misunderstanding this relationship can lead to significant headaches in system configuration, especially regarding DMA remapping and virtualization setups. I need to nail down if the kernel build configuration or runtime interaction hinges on this. Understanding the linkage between these features will dictate how I approach configuring the IOMMU for optimal performance and compatibility. I'll need to double check the kernel source, relevant documentation, and existing forum discussions or bug reports to get a solid understanding of this relationship. |
| 12/2 | 2026/06/26 23:00 | tool | grepper |
0mArgs:{
"Expression": "depends on.*IRQ_REMAP"
}Results: {
"Output": "arch/x86/Kconfig=460=config X86_X2APIC\narch/x86/Kconfig-461-\tbool \"x2APIC interrupt controller architecture support\"\narch/x86/Kconfig:462:\tdepends on X86_LOCAL_APIC \u0026\u0026 X86_64 \u0026\u0026 (IRQ_REMAP || HYPERVISOR_GUEST)\narch/x86/Kconfig-463-\tdefault y\n--\narch/x86/Kconfig=497=config X86_POSTED_MSI\narch/x86/Kconfig-498-\tbool \"Enable MSI and MSI-x delivery by posted interrupts\"\narch/x86/Kconfig:499:\tdepends on X86_64 \u0026\u0026 IRQ_REMAP\narch/x86/Kconfig-500-\thelp\n"
} |
| 13/2 | 2026/06/26 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14755 output: 20 thoughts: 16 Thoughts: Here's my thought process, summarized as you requested: **Kconfig Check** Okay, time to dive in. I need to get a handle on how this AMD IOMMU driver configuration is set up. The first place I'm going to look is the `drivers/iommu/amd/Kconfig` file. That's the standard location for driver configuration options within the kernel build system. I'm hoping to quickly identify the various compile-time parameters, dependencies, and default settings related to the AMD IOMMU implementation. This should give me a good baseline understanding before I start digging into the code itself. I'm expecting to see things like whether the driver is enabled by default, what features can be toggled, what hardware revisions are supported, and any associated dependencies on other kernel components. Time to see what's in there! |
| 14/2 | 2026/06/26 23:00 | tool | grepper |
0mArgs:{
"Expression": "config AMD_IOMMU"
}Results: {
"Output": "drivers/iommu/amd/Kconfig-2-# AMD IOMMU support\ndrivers/iommu/amd/Kconfig:3:config AMD_IOMMU\ndrivers/iommu/amd/Kconfig-4-\tbool \"AMD IOMMU support\"\n--\ndrivers/iommu/amd/Kconfig-32-\ndrivers/iommu/amd/Kconfig:33:config AMD_IOMMU_IOMMUFD\ndrivers/iommu/amd/Kconfig-34-\tbool \"Enable IOMMUFD features for AMD IOMMU (EXPERIMENTAL)\"\n--\ndrivers/iommu/amd/Kconfig-42-\ndrivers/iommu/amd/Kconfig:43:config AMD_IOMMU_DEBUGFS\ndrivers/iommu/amd/Kconfig-44-\tbool \"Enable AMD IOMMU internals in DebugFS\"\n"
} |
| 15/2 | 2026/06/26 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15187 output: 36 thoughts: 25 Thoughts: Here's my take on those thoughts: **Analyzing the AMD IOMMU Configuration Options** Okay, let's dive into the `drivers/iommu/amd/Kconfig` file. I need to get a clear picture of how the AMD IOMMU configuration is handled within the kernel build system. My immediate focus is that `config AMD_IOMMU` block. I need to understand what options are available, how they're structured, and what dependencies they have. This is standard operating procedure, obviously, but I'm looking for anything unusual or subtle, that is not immediately apparent. I need to get the overall context, the dependencies, and the implications of enabling or disabling the AMD IOMMU. Let's see what the configuration variables and associated help text reveal. I'm especially interested in how it interacts with other IOMMU configurations and the broader system architecture. Time to delve into the details. |
| 16/2 | 2026/06/26 23:00 | tool | read-file |
0mArgs:{
"File": "drivers/iommu/amd/Kconfig",
"FirstLine": 1,
"LineCount": 20
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\t# AMD IOMMU support\n 3:\tconfig AMD_IOMMU\n 4:\t\tbool \"AMD IOMMU support\"\n 5:\t\tselect SWIOTLB\n 6:\t\tselect PCI_MSI\n 7:\t\tselect PCI_ATS\n 8:\t\tselect PCI_PRI\n 9:\t\tselect PCI_PASID\n 10:\t\tselect IRQ_MSI_LIB\n 11:\t\tselect MMU_NOTIFIER\n 12:\t\tselect IOMMU_API\n 13:\t\tselect IOMMU_IOVA\n 14:\t\tselect IOMMU_SVA\n 15:\t\tselect IOMMU_IOPF\n 16:\t\tselect IOMMUFD_DRIVER if IOMMUFD\n 17:\t\tselect GENERIC_PT\n 18:\t\tselect IOMMU_PT\n 19:\t\tselect IOMMU_PT_AMDV1\n 20:\t\tselect IOMMU_PT_X86_64\n"
} |
| 17/2 | 2026/06/26 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15710 output: 39 thoughts: 41 Thoughts: **Investigating AMD IOMMU and KVM Configuration Dependencies** Okay, so I'm looking at these configurations: `AMD_IOMMU` and `KVM_AMD`. The names are pretty self-explanatory, but I need to understand their relationship. First things first, let's see if `KVM_AMD` has any dependencies. I want to know if `KVM_AMD` relies on anything specific to function, and if so, what those prerequisites are. Knowing the dependencies is key to ensuring proper system configuration and avoiding any potential conflicts down the line. It's all about making sure I'm setting things up correctly for optimal performance. |
| 18/2 | 2026/06/26 23:00 | tool | read-file |
0mArgs:{
"File": "arch/x86/kvm/Kconfig",
"FirstLine": 146,
"LineCount": 20
}Results: {
"Contents": " 146:\tconfig KVM_AMD\n 147:\t\ttristate \"KVM for AMD processors support\"\n 148:\t\tdepends on KVM \u0026\u0026 (CPU_SUP_AMD || CPU_SUP_HYGON)\n 149:\t\thelp\n 150:\t\t Provides support for KVM on AMD processors equipped with the AMD-V\n 151:\t\t (SVM) extensions.\n 152:\t\n 153:\t\t To compile this as a module, choose M here: the module\n 154:\t\t will be called kvm-amd.\n 155:\t\n 156:\tconfig KVM_AMD_SEV\n 157:\t\tbool \"AMD Secure Encrypted Virtualization (SEV) support\"\n 158:\t\tdefault y\n 159:\t\tdepends on KVM_AMD \u0026\u0026 X86_64\n 160:\t\tdepends on CRYPTO_DEV_SP_PSP \u0026\u0026 !(KVM_AMD=y \u0026\u0026 CRYPTO_DEV_CCP_DD=m)\n 161:\t\tselect ARCH_HAS_CC_PLATFORM\n 162:\t\tselect KVM_GENERIC_MEMORY_ATTRIBUTES\n 163:\t\tselect HAVE_KVM_ARCH_GMEM_PREPARE\n 164:\t\tselect HAVE_KVM_ARCH_GMEM_INVALIDATE\n 165:\t\tselect HAVE_KVM_ARCH_GMEM_POPULATE\n"
} |
| 19/2 | 2026/06/26 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 16290 output: 235 thoughts: 649 Thoughts: **GAPPI Support for AMD IOMMU and KVM SVM AVIC** Okay, so I'm looking at a patch that integrates GAPPI support into the AMD IOMMU and KVM SVM AVIC setup. The key configs here are `KVM_AMD` and `AMD_IOMMU` – that's the foundation we're working with. I've been reviewing the code and focusing on the relevant functions. My attention is drawn to: `avic_pi_update_irte`, `amd_iommu_update_ga`, `amd_iommu_activate_guest_mode`, `avic_update_iommu_vcpu_affinity`, `avic_add_vcpu_to_gappi_wakeup_list`, `avic_remove_vcpu_from_gappi_wakeup_list`, `avic_gappi_wakeup_handler`, and `__amd_iommu_update_ga`. We're talking core interrupt handling, vCPU affinity management, and the crucial logic for activating guest mode within the IOMMU. There are a few modified functions I should also take into account: `avic_destroy_vcpu`, `avic_init_vcpu`, `svm_ir_list_del`, `__avic_vcpu_load`, `__avic_vcpu_put`, `avic_hardware_setup`, `enable_iommus_vapic`, and `parse_amd_iommu_options`. This is a fundamental change, impacting how interrupts are managed within the virtualized environment and directly touches the IOMMU. The introduction of GAPPI means we're dealing with new wakeup lists and altered interrupt handling logic that requires rigorous testing. Concurrency bugs or memory corruption vulnerabilities are a concern here. I think we need to fuzz this! My assessment is that this warrants fuzzing, and the critical functions to target are the ones I listed earlier. The configs that are enabled are `KVM_AMD` and `AMD_IOMMU`. |
| 20/2 | 2026/06/26 23:00 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"KVM_AMD",
"AMD_IOMMU"
],
"FocusSymbols": [
"avic_pi_update_irte",
"avic_update_iommu_vcpu_affinity",
"amd_iommu_update_ga",
"amd_iommu_activate_guest_mode",
"avic_add_vcpu_to_gappi_wakeup_list",
"avic_remove_vcpu_from_gappi_wakeup_list",
"avic_gappi_wakeup_handler",
"__amd_iommu_update_ga"
],
"Reasoning": "This patch introduces GAPPI (Guest APIC Posted Interrupts) support for AMD IOMMU and KVM SVM AVIC. It modifies core interrupt remapping and vCPU affinity logic, which is reachable in virtualized environments (e.g., nested KVM on AMD). Fuzzing is necessary to ensure the new wakeup lists and interrupt handling logic do not introduce concurrency bugs or memory corruption.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"KVM_AMD",
"AMD_IOMMU"
],
"FocusSymbols": [
"avic_pi_update_irte",
"avic_update_iommu_vcpu_affinity",
"amd_iommu_update_ga",
"amd_iommu_activate_guest_mode",
"avic_add_vcpu_to_gappi_wakeup_list",
"avic_remove_vcpu_from_gappi_wakeup_list",
"avic_gappi_wakeup_handler",
"__amd_iommu_update_ga"
],
"Reasoning": "This patch introduces GAPPI (Guest APIC Posted Interrupts) support for AMD IOMMU and KVM SVM AVIC. It modifies core interrupt remapping and vCPU affinity logic, which is reachable in virtualized environments (e.g., nested KVM on AMD). Fuzzing is necessary to ensure the new wakeup lists and interrupt handling logic do not introduce concurrency bugs or memory corruption.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|