| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/13 13:36 | flow | patch-triage |
2mArgs:null Results: {
"EnableConfigs": [
"KVM_AMD",
"AMD_IOMMU",
"IRQ_REMAP"
],
"FocusSymbols": [
"avic_add_vcpu_to_gappi_wakeup_list",
"avic_remove_vcpu_from_gappi_wakeup_list",
"avic_gappi_wakeup_handler",
"avic_pi_update_irte",
"avic_update_iommu_vcpu_affinity",
"__amd_iommu_update_ga",
"amd_iommu_update_ga",
"amd_iommu_activate_guest_mode"
],
"Reasoning": "The patch introduces GAPPI (Guest APIC Posted Interrupts) support for AMD IOMMU and KVM SVM AVIC. It modifies the IRTE configuration for posted interrupts and introduces a new wakeup list for GAPPI in KVM. This is a functional change to core virtualization logic and should be fuzzed.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/13 13:36 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit c00c5acdd42b40db20f41c019f99168956380e1e\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Jul 13 13:36:22 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt\nindex 97007f4f69d4e8..d27f10cbb004cc 100644\n--- a/Documentation/admin-guide/kernel-parameters.txt\n+++ b/Documentation/admin-guide/kernel-parameters.txt\n@@ -455,7 +455,8 @@ Kernel parameters\n \t\t\t\t to 4 KiB.\n \t\t\tv2_pgsizes_only - Limit page-sizes used for v1 page-tables\n \t\t\t\t to 4KiB/2Mib/1GiB.\n-\n+\t\t\tgappi\t\t- Use GAPPI instead of GALOG for vCPU\n+\t\t\t\t\t wakeup notification.\n \n \tamd_iommu_dump=\t[HW,X86-64]\n \t\t\tEnable AMD IOMMU driver option to dump the ACPI table\ndiff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h\nindex 37b94f484ef338..af0cdfa32c447f 100644\n--- a/arch/x86/include/asm/irq_remapping.h\n+++ b/arch/x86/include/asm/irq_remapping.h\n@@ -35,8 +35,9 @@ 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+\tbool wakeup_intr;\n+\tbool is_running;\n \tbool is_guest_mode;\n \tvoid *ir_data;\n };\ndiff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h\nindex bcfeb5e7c0edf2..add8b7274cc2f8 100644\n--- a/arch/x86/include/asm/svm.h\n+++ b/arch/x86/include/asm/svm.h\n@@ -259,11 +259,12 @@ struct __attribute__ ((__packed__)) vmcb_control_area {\n #define AVIC_LOGICAL_ID_ENTRY_VALID_MASK\t\t(1 \u003c\u003c 31)\n \n /*\n- * GA_LOG_INTR is a synthetic flag that's never propagated to hardware-visible\n- * tables. GA_LOG_INTR is set if the vCPU needs device posted IRQs to generate\n- * GA log interrupts to wake the vCPU (because it's blocking or about to block).\n+ * WAKEUP_INTR is a synthetic flag that's never propagated to hardware-visible\n+ * tables. WAKEUP_INTR is set if the vCPU needs device posted IRQs to generate\n+ * GA log/GAPPI interrupts to wake the vCPU (because it's blocking or about to\n+ * block).\n */\n-#define AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR\t\tBIT_ULL(61)\n+#define AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR\t\tBIT_ULL(61)\n \n #define AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK\tGENMASK_ULL(11, 0)\n #define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK\tGENMASK_ULL(51, 12)\ndiff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c\nindex cdd5a6dc646f11..982a5988532ff4 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,42 @@ 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(unlikely(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+\tguard(raw_spinlock_irqsave)(spinlock);\n+\tif (list_empty(\u0026svm-\u003egappi_vcpu_wakeup_list))\n+\t\tlist_add_tail(\u0026svm-\u003egappi_vcpu_wakeup_list, wakeup_list);\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(unlikely(cpu \u003c 0)))\n+\t\treturn;\n+\n+\tspinlock = \u0026per_cpu(gappi_vcpu_wakeup_list_lock, cpu);\n+\tguard(raw_spinlock_irqsave)(spinlock);\n+\tif (!list_empty(\u0026svm-\u003egappi_vcpu_wakeup_list))\n+\t\tlist_del_init(\u0026svm-\u003egappi_vcpu_wakeup_list);\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 +938,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 (amd_iommu_gappi \u0026\u0026 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@@ -923,8 +970,6 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,\n \t\t * if AVIC is enabled/uninhibited in the future.\n \t\t */\n \t\tstruct amd_iommu_pi_data pi_data = {\n-\t\t\t.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)-\u003eavic_vm_id,\n-\t\t\t\t\t vcpu-\u003evcpu_idx),\n \t\t\t.is_guest_mode = kvm_vcpu_apicv_active(vcpu),\n \t\t\t.vapic_addr = avic_get_backing_page_address(to_svm(vcpu)),\n \t\t\t.vector = vector,\n@@ -932,6 +977,7 @@ 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\tbool is_vcpu_waiting = false;\n \n \t\t/*\n \t\t * Prevent the vCPU from being scheduled out or migrated until\n@@ -947,17 +993,33 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,\n \t\t * scheduled out, KVM will update the pCPU info when the vCPU\n \t\t * is awakened and/or scheduled in. See also avic_vcpu_load().\n \t\t */\n+\t\tif (amd_iommu_gappi)\n+\t\t\tpi_data.ga_tag = POSTED_INTR_WAKEUP_VECTOR;\n+\t\telse\n+\t\t\tpi_data.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)-\u003eavic_vm_id,\n+\t\t\t\t\t\t vcpu-\u003evcpu_idx);\n+\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.is_running = true;\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\tpi_data.apicid = -1;\n+\t\t\tpi_data.wakeup_intr = entry \u0026 AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR;\n+\t\t\tpi_data.is_running = false;\n+\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 +1028,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@@ -991,23 +1058,24 @@ enum avic_vcpu_action {\n \t * No unique action is required to deal with a vCPU that stops/starts\n \t * running. A vCPU that starts running by definition stops blocking as\n \t * well, and a vCPU that stops running can't have been blocking, i.e.\n-\t * doesn't need to toggle GALogIntr.\n+\t * doesn't need to toggle host wakeup notification.\n \t */\n \tAVIC_START_RUNNING\t= 0,\n \tAVIC_STOP_RUNNING\t= 0,\n \n \t/*\n-\t * When a vCPU starts blocking, KVM needs to set the GALogIntr flag\n-\t * int all associated IRTEs so that KVM can wake the vCPU if an IRQ is\n-\t * sent to the vCPU.\n+\t * When a vCPU starts blocking, KVM needs to request host wakeup\n+\t * notification in all associated IRTEs so that KVM can wake the vCPU\n+\t * if an IRQ is sent to the vCPU.\n \t */\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+\tbool wakeup_intr = (action \u0026 AVIC_START_BLOCKING);\n+\tbool is_running = apicid \u003e= 0;\n \tstruct vcpu_svm *svm = to_svm(vcpu);\n \tstruct kvm_kernel_irqfd *irqfd;\n \n@@ -1015,18 +1083,36 @@ static void avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu,\n \n \t/*\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 * interrupt remapping table entries 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_running \u0026\u0026 amd_iommu_gappi) {\n+\t\tif (svm-\u003egappi_cpu != -1)\n+\t\t\t/*\n+\t\t\t * Handle initial state when vCPU is loaded for the\n+\t\t\t * first time without any IRQ affinity.\n+\t\t\t */\n+\t\t\tavic_remove_vcpu_from_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\n+\n+\t\tsvm-\u003egappi_cpu = cpu; /* Store cpu number 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, wakeup_intr, is_running));\n+\t\telse if (is_running)\n+\t\t\tWARN_ON_ONCE(amd_iommu_activate_guest_mode(data, apicid, wakeup_intr,\n+\t\t\t\t\t\t\t\t is_running));\n \t\telse\n \t\t\tWARN_ON_ONCE(amd_iommu_deactivate_guest_mode(data));\n \t}\n@@ -1063,7 +1149,7 @@ static void __avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu,\n \tWARN_ON_ONCE(entry \u0026 AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK);\n \n \tentry \u0026= ~(AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK |\n-\t\t AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR);\n+\t\t AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR);\n \tentry |= (h_physical_id \u0026 AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK);\n \tentry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;\n \n@@ -1080,7 +1166,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,9 +1209,9 @@ 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+\tWARN_ON_ONCE(entry \u0026 AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR);\n \n \t/*\n \t * Keep the previous APIC ID in the entry so that a rogue doorbell from\n@@ -1137,11 +1223,11 @@ static void __avic_vcpu_put(struct kvm_vcpu *vcpu, enum avic_vcpu_action action)\n \t\tWRITE_ONCE(kvm_svm-\u003eavic_physical_id_table[vcpu-\u003evcpu_id], entry);\n \n \t/*\n-\t * Note! Don't set AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR in the table as\n+\t * Note! Don't set AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR in the table as\n \t * it's a synthetic flag that usurps an unused should-be-zero bit.\n \t */\n \tif (action \u0026 AVIC_START_BLOCKING)\n-\t\tentry |= AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;\n+\t\tentry |= AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR;\n \n \tsvm-\u003eavic_physical_id_entry = entry;\n \n@@ -1171,9 +1257,9 @@ void avic_vcpu_put(struct kvm_vcpu *vcpu)\n \n \t\t/*\n \t\t * The vCPU was preempted while blocking, ensure its IRTEs are\n-\t\t * configured to generate GA Log Interrupts.\n+\t\t * configured to request host wakeup notification.\n \t\t */\n-\t\tif (!(WARN_ON_ONCE(!(entry \u0026 AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR))))\n+\t\tif (!(WARN_ON_ONCE(!(entry \u0026 AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR))))\n \t\t\treturn;\n \t}\n \n@@ -1296,6 +1382,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 +1405,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,12 +1440,16 @@ 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 }\n \n void avic_hardware_unsetup(void)\n {\n-\tif (avic)\n-\t\tamd_iommu_register_ga_log_notifier(NULL);\n+\tif (!avic)\n+\t\treturn;\n+\n+\tamd_iommu_register_ga_log_notifier(NULL);\n+\tkvm_set_posted_intr_wakeup_handler(NULL);\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..7d2b1c24f6eccb 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@@ -462,6 +465,9 @@ static void iommu_disable(struct amd_iommu *iommu)\n \tiommu_feature_disable(iommu, CONTROL_GALOG_EN);\n \tiommu_feature_disable(iommu, CONTROL_GAINT_EN);\n \n+\t/* Disable IOMMU GAPPI */\n+\tiommu_feature_disable(iommu, CONTROL_GAPPI_EN);\n+\n \t/* Disable IOMMU PPR logging */\n \tiommu_feature_disable(iommu, CONTROL_PPRLOG_EN);\n \tiommu_feature_disable(iommu, CONTROL_PPRINT_EN);\n@@ -2996,6 +3002,13 @@ static void enable_iommus_vapic(void)\n \tstruct amd_iommu *iommu;\n \n \tfor_each_iommu(iommu) {\n+\t\t/*\n+\t\t * Disable GAPPI, do not check amd_iommu_gappi as it may be\n+\t\t * false in new kexec kernel even though previous kernel has\n+\t\t * enabled it.\n+\t\t */\n+\t\tiommu_feature_disable(iommu, CONTROL_GAPPI_EN);\n+\n \t\t/*\n \t\t * Disable GALog if already running. It could have been enabled\n \t\t * in the previous boot before kdump.\n@@ -3035,10 +3048,19 @@ 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\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\treturn;\n \n \t\tiommu_feature_enable(iommu, CONTROL_GAM_EN);\n@@ -3047,7 +3069,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 +3761,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..7eebf4745a6782 100644\n--- a/drivers/iommu/amd/iommu.c\n+++ b/drivers/iommu/amd/iommu.c\n@@ -3959,19 +3959,29 @@ 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,\n+\t\t\t\t bool wakeup_intr, bool is_running)\n {\n-\tif (cpu \u003e= 0) {\n+\tif (is_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\tif (amd_iommu_gappi) {\n+\t\t\tentry-\u003elo.fields_vapic.gappi_dis = !wakeup_intr \u0026\u0026\n+\t\t\t\t\t\tcheck_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 =\n+\t\t\t\t\t\tAPICID_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 = wakeup_intr;\n+\t\t}\n \t}\n }\n \n@@ -3979,20 +3989,20 @@ static void __amd_iommu_update_ga(struct irte_ga *entry, int cpu,\n * Update the pCPU information for an IRTE that is configured to post IRQs to\n * a vCPU, without issuing an IOMMU invalidation for the IRTE.\n *\n- * If the vCPU is associated with a pCPU (@cpu \u003e= 0), configure the Destination\n- * with the pCPU's APIC ID, set IsRun, and clear GALogIntr. If the vCPU isn't\n- * associated with a pCPU (@cpu \u003c 0), clear IsRun and set/clear GALogIntr based\n- * on input from the caller (e.g. KVM only requests GALogIntr when the vCPU is\n- * blocking and requires a notification wake event). I.e. treat vCPUs that are\n- * associated with a pCPU as running. This API is intended to be used when a\n- * vCPU is scheduled in/out (or stops running for any reason), to do a fast\n- * update of IsRun, GALogIntr, and (conditionally) Destination.\n+ * If the vCPU is scheduled to run on pCPU (@is_running = 1), configure the\n+ * Destination with the pCPU's APIC ID, set IsRun, and clear GALogIntr. If the\n+ * vCPU is scheduled out (@is_running = 0), clear IsRun and set/clear GALogIntr\n+ * and GAPPIDis based on input from the caller (e.g. KVM only requests\n+ * wakeup_intr when the vCPU is blocking and requires a notification wake\n+ * event). This API is intended to be used when a vCPU is scheduled in/out (or\n+ * stops running for any reason), to do a fast update of IsRun, GALogIntr,\n+ * GAPPIDis and (conditionally) Destination.\n *\n- * Per the IOMMU spec, the Destination, IsRun, and GATag fields are not cached\n- * and thus don't require an invalidation to ensure the IOMMU consumes fresh\n- * information.\n+ * Per the IOMMU spec, the Destination, IsRun, GATag and GAPPIDis fields are\n+ * not cached and thus don't require an invalidation to ensure the IOMMU\n+ * consumes fresh 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, bool wakeup_intr, bool is_running)\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 +4016,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, wakeup_intr, is_running);\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, bool wakeup_intr, bool is_running)\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@@ -4036,7 +4046,7 @@ int amd_iommu_activate_guest_mode(void *data, int cpu, bool ga_log_intr)\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+\t__amd_iommu_update_ga(entry, apicid, wakeup_intr, is_running);\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 +4117,9 @@ 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-\u003ewakeup_intr,\n+\t\t\t\t\t\t\t pi_data-\u003eis_running);\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..729d82c4e09e27 100644\n--- a/include/linux/amd-iommu.h\n+++ b/include/linux/amd-iommu.h\n@@ -30,8 +30,10 @@ 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, bool wakeup_intr,\n+\t\t\t bool is_running);\n+extern int amd_iommu_activate_guest_mode(void *data, int apicid, bool wakeup_intr,\n+\t\t\t\t\t bool is_running);\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 +44,14 @@ 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, bool wakeup_intr,\n+\t\t\t\t bool is_running)\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, bool wakeup_intr,\n+\t\t\t\t\t\tbool is_running)\n {\n \treturn 0;\n }\n@@ -76,4 +80,5 @@ 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+extern bool amd_iommu_gappi;\n #endif /* _ASM_X86_AMD_IOMMU_H */\n"
} |
| 2/1 | 2026/07/13 13:36 | agent | patch-evaluator |
2mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"KVM_AMD",
"AMD_IOMMU",
"IRQ_REMAP"
],
"FocusSymbols": [
"avic_add_vcpu_to_gappi_wakeup_list",
"avic_remove_vcpu_from_gappi_wakeup_list",
"avic_gappi_wakeup_handler",
"avic_pi_update_irte",
"avic_update_iommu_vcpu_affinity",
"__amd_iommu_update_ga",
"amd_iommu_update_ga",
"amd_iommu_activate_guest_mode"
],
"Reasoning": "The patch introduces GAPPI (Guest APIC Posted Interrupts) support for AMD IOMMU and KVM SVM AVIC. It modifies the IRTE configuration for posted interrupts and introduces a new wakeup list for GAPPI in KVM. This is a functional change to core virtualization logic and should be fuzzed.",
"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 c00c5acdd42b40db20f41c019f99168956380e1e
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Jul 13 13:36:22 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 97007f4f69d4e8..d27f10cbb004cc 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -455,7 +455,8 @@ Kernel parameters
to 4 KiB.
v2_pgsizes_only - Limit page-sizes used for v1 page-tables
to 4KiB/2Mib/1GiB.
-
+ gappi - Use GAPPI instead of GALOG for vCPU
+ wakeup notification.
amd_iommu_dump= [HW,X86-64]
Enable AMD IOMMU driver option to dump the ACPI table
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index 37b94f484ef338..af0cdfa32c447f 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -35,8 +35,9 @@ 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;
+ bool wakeup_intr;
+ bool is_running;
bool is_guest_mode;
void *ir_data;
};
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index bcfeb5e7c0edf2..add8b7274cc2f8 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -259,11 +259,12 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
#define AVIC_LOGICAL_ID_ENTRY_VALID_MASK (1 << 31)
/*
- * GA_LOG_INTR is a synthetic flag that's never propagated to hardware-visible
- * tables. GA_LOG_INTR is set if the vCPU needs device posted IRQs to generate
- * GA log interrupts to wake the vCPU (because it's blocking or about to block).
+ * WAKEUP_INTR is a synthetic flag that's never propagated to hardware-visible
+ * tables. WAKEUP_INTR is set if the vCPU needs device posted IRQs to generate
+ * GA log/GAPPI interrupts to wake the vCPU (because it's blocking or about to
+ * block).
*/
-#define AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR BIT_ULL(61)
+#define AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR BIT_ULL(61)
#define AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK GENMASK_ULL(11, 0)
#define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK GENMASK_ULL(51, 12)
diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
index cdd5a6dc646f11..982a5988532ff4 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,42 @@ 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(unlikely(cpu < 0)))
+ return;
+
+ wakeup_list = &per_cpu(gappi_vcpu_wakeup_list, cpu);
+ spinlock = &per_cpu(gappi_vcpu_wakeup_list_lock, cpu);
+ guard(raw_spinlock_irqsave)(spinlock);
+ if (list_empty(&svm->gappi_vcpu_wakeup_list))
+ list_add_tail(&svm->gappi_vcpu_wakeup_list, wakeup_list);
+}
+
+static void avic_remove_vcpu_from_gappi_wakeup_list(struct vcpu_svm *svm, int cpu)
+{
+ raw_spinlock_t *spinlock;
+
+ if (WARN_ON(unlikely(cpu < 0)))
+ return;
+
+ spinlock = &per_cpu(gappi_vcpu_wakeup_list_lock, cpu);
+ guard(raw_spinlock_irqsave)(spinlock);
+ if (!list_empty(&svm->gappi_vcpu_wakeup_list))
+ list_del_init(&svm->gappi_vcpu_wakeup_list);
+}
+
+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 +938,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 (amd_iommu_gappi && 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,
@@ -923,8 +970,6 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
* if AVIC is enabled/uninhibited in the future.
*/
struct amd_iommu_pi_data pi_data = {
- .ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
- vcpu->vcpu_idx),
.is_guest_mode = kvm_vcpu_apicv_active(vcpu),
.vapic_addr = avic_get_backing_page_address(to_svm(vcpu)),
.vector = vector,
@@ -932,6 +977,7 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
struct vcpu_svm *svm = to_svm(vcpu);
u64 entry;
int ret;
+ bool is_vcpu_waiting = false;
/*
* Prevent the vCPU from being scheduled out or migrated until
@@ -947,17 +993,33 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
* scheduled out, KVM will update the pCPU info when the vCPU
* is awakened and/or scheduled in. See also avic_vcpu_load().
*/
+ if (amd_iommu_gappi)
+ pi_data.ga_tag = POSTED_INTR_WAKEUP_VECTOR;
+ else
+ pi_data.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
+ vcpu->vcpu_idx);
+
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.is_running = true;
} else {
- pi_data.cpu = -1;
- pi_data.ga_log_intr = entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;
+ pi_data.apicid = -1;
+ pi_data.wakeup_intr = entry & AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR;
+ pi_data.is_running = false;
+
+ 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 +1028,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);
}
@@ -991,23 +1058,24 @@ enum avic_vcpu_action {
* No unique action is required to deal with a vCPU that stops/starts
* running. A vCPU that starts running by definition stops blocking as
* well, and a vCPU that stops running can't have been blocking, i.e.
- * doesn't need to toggle GALogIntr.
+ * doesn't need to toggle host wakeup notification.
*/
AVIC_START_RUNNING = 0,
AVIC_STOP_RUNNING = 0,
/*
- * When a vCPU starts blocking, KVM needs to set the GALogIntr flag
- * int all associated IRTEs so that KVM can wake the vCPU if an IRQ is
- * sent to the vCPU.
+ * When a vCPU starts blocking, KVM needs to request host wakeup
+ * notification in all associated IRTEs so that KVM can wake the vCPU
+ * if an IRQ is sent to the vCPU.
*/
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);
+ bool wakeup_intr = (action & AVIC_START_BLOCKING);
+ bool is_running = apicid >= 0;
struct vcpu_svm *svm = to_svm(vcpu);
struct kvm_kernel_irqfd *irqfd;
@@ -1015,18 +1083,36 @@ 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.
+ * interrupt remapping table entries 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_running && amd_iommu_gappi) {
+ if (svm->gappi_cpu != -1)
+ /*
+ * Handle initial state when vCPU is loaded for the
+ * first time without any IRQ affinity.
+ */
+ avic_remove_vcpu_from_gappi_wakeup_list(svm, svm->gappi_cpu);
+
+ svm->gappi_cpu = cpu; /* Store cpu number 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, wakeup_intr, is_running));
+ else if (is_running)
+ WARN_ON_ONCE(amd_iommu_activate_guest_mode(data, apicid, wakeup_intr,
+ is_running));
else
WARN_ON_ONCE(amd_iommu_deactivate_guest_mode(data));
}
@@ -1063,7 +1149,7 @@ static void __avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu,
WARN_ON_ONCE(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK);
entry &= ~(AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK |
- AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR);
+ AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR);
entry |= (h_physical_id & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK);
entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
@@ -1080,7 +1166,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,9 +1209,9 @@ 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);
+ WARN_ON_ONCE(entry & AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR);
/*
* Keep the previous APIC ID in the entry so that a rogue doorbell from
@@ -1137,11 +1223,11 @@ static void __avic_vcpu_put(struct kvm_vcpu *vcpu, enum avic_vcpu_action action)
WRITE_ONCE(kvm_svm->avic_physical_id_table[vcpu->vcpu_id], entry);
/*
- * Note! Don't set AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR in the table as
+ * Note! Don't set AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR in the table as
* it's a synthetic flag that usurps an unused should-be-zero bit.
*/
if (action & AVIC_START_BLOCKING)
- entry |= AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;
+ entry |= AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR;
svm->avic_physical_id_entry = entry;
@@ -1171,9 +1257,9 @@ void avic_vcpu_put(struct kvm_vcpu *vcpu)
/*
* The vCPU was preempted while blocking, ensure its IRTEs are
- * configured to generate GA Log Interrupts.
+ * configured to request host wakeup notification.
*/
- if (!(WARN_ON_ONCE(!(entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR))))
+ if (!(WARN_ON_ONCE(!(entry & AVIC_PHYSICAL_ID_ENTRY_WAKEUP_INTR))))
return;
}
@@ -1296,6 +1382,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 +1405,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,12 +1440,16 @@ 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;
}
void avic_hardware_unsetup(void)
{
- if (avic)
- amd_iommu_register_ga_log_notifier(NULL);
+ if (!avic)
+ return;
+
+ amd_iommu_register_ga_log_notifier(NULL);
+ kvm_set_posted_intr_wakeup_handler(NULL);
}
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..7d2b1c24f6eccb 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;
@@ -462,6 +465,9 @@ static void iommu_disable(struct amd_iommu *iommu)
iommu_feature_disable(iommu, CONTROL_GALOG_EN);
iommu_feature_disable(iommu, CONTROL_GAINT_EN);
+ /* Disable IOMMU GAPPI */
+ iommu_feature_disable(iommu, CONTROL_GAPPI_EN);
+
/* Disable IOMMU PPR logging */
iommu_feature_disable(iommu, CONTROL_PPRLOG_EN);
iommu_feature_disable(iommu, CONTROL_PPRINT_EN);
@@ -2996,6 +3002,13 @@ static void enable_iommus_vapic(void)
struct amd_iommu *iommu;
for_each_iommu(iommu) {
+ /*
+ * Disable GAPPI, do not check amd_iommu_gappi as it may be
+ * false in new kexec kernel even though previous kernel has
+ * enabled it.
+ */
+ iommu_feature_disable(iommu, CONTROL_GAPPI_EN);
+
/*
* Disable GALog if already running. It could have been enabled
* in the previous boot before kdump.
@@ -3035,10 +3048,19 @@ 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))
+ 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);
@@ -3047,7 +3069,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 +3761,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..7eebf4745a6782 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -3959,19 +3959,29 @@ 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,
+ bool wakeup_intr, bool is_running)
{
- if (cpu >= 0) {
+ if (is_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;
+ if (amd_iommu_gappi) {
+ entry->lo.fields_vapic.gappi_dis = !wakeup_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 = wakeup_intr;
+ }
}
}
@@ -3979,20 +3989,20 @@ static void __amd_iommu_update_ga(struct irte_ga *entry, int cpu,
* Update the pCPU information for an IRTE that is configured to post IRQs to
* a vCPU, without issuing an IOMMU invalidation for the IRTE.
*
- * If the vCPU is associated with a pCPU (@cpu >= 0), configure the Destination
- * with the pCPU's APIC ID, set IsRun, and clear GALogIntr. If the vCPU isn't
- * associated with a pCPU (@cpu < 0), clear IsRun and set/clear GALogIntr based
- * on input from the caller (e.g. KVM only requests GALogIntr when the vCPU is
- * blocking and requires a notification wake event). I.e. treat vCPUs that are
- * associated with a pCPU as running. This API is intended to be used when a
- * vCPU is scheduled in/out (or stops running for any reason), to do a fast
- * update of IsRun, GALogIntr, and (conditionally) Destination.
+ * If the vCPU is scheduled to run on pCPU (@is_running = 1), configure the
+ * Destination with the pCPU's APIC ID, set IsRun, and clear GALogIntr. If the
+ * vCPU is scheduled out (@is_running = 0), clear IsRun and set/clear GALogIntr
+ * and GAPPIDis based on input from the caller (e.g. KVM only requests
+ * wakeup_intr when the vCPU is blocking and requires a notification wake
+ * event). This API is intended to be used when a vCPU is scheduled in/out (or
+ * stops running for any reason), to do a fast update of IsRun, GALogIntr,
+ * GAPPIDis and (conditionally) Destination.
*
- * Per the IOMMU spec, the Destination, IsRun, and GATag fields are not cached
- * and thus don't require an invalidation to ensure the IOMMU consumes fresh
- * information.
+ * Per the IOMMU spec, the Destination, IsRun, GATag and GAPPIDis fields are
+ * not cached 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, bool wakeup_intr, bool is_running)
{
struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
@@ -4006,14 +4016,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, wakeup_intr, is_running);
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, bool wakeup_intr, bool is_running)
{
struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
@@ -4036,7 +4046,7 @@ int amd_iommu_activate_guest_mode(void *data, int cpu, bool ga_log_intr)
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);
+ __amd_iommu_update_ga(entry, apicid, wakeup_intr, is_running);
return modify_irte_ga(ir_data->iommu, ir_data->irq_2_irte.devid,
ir_data->irq_2_irte.index, entry);
@@ -4107,8 +4117,9 @@ 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->wakeup_intr,
+ pi_data->is_running);
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..729d82c4e09e27 100644
--- a/include/linux/amd-iommu.h
+++ b/include/linux/amd-iommu.h
@@ -30,8 +30,10 @@ 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, bool wakeup_intr,
+ bool is_running);
+extern int amd_iommu_activate_guest_mode(void *data, int apicid, bool wakeup_intr,
+ bool is_running);
extern int amd_iommu_deactivate_guest_mode(void *data);
#else /* defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP) */
@@ -42,12 +44,14 @@ 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, bool wakeup_intr,
+ bool is_running)
{
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, bool wakeup_intr,
+ bool is_running)
{
return 0;
}
@@ -76,4 +80,5 @@ static inline int amd_iommu_snp_disable(void) { return 0; }
static inline bool amd_iommu_sev_tio_supported(void) { return false; }
#endif
+extern bool amd_iommu_gappi;
#endif /* _ASM_X86_AMD_IOMMU_H */
|
| 3/2 | 2026/07/13 13:36 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13022 output: 36 thoughts: 791 Thoughts: **GAPPI Support for AMD IOMMU and KVM SVM AVIC: Fuzzing Potential** Okay, so I've got this patch introducing GAPPI support, Guest APIC Posted Interrupts, for AMD IOMMU and KVM SVM AVIC. Essentially, it's a functional change, a pretty deep one, affecting a bunch of core kernel areas. I see it touches documentation, some crucial x86 assembly includes, and then dives deep into KVM's SVM implementation and the AMD IOMMU drivers. The patch adds a new `amd_iommu=gappi` kernel parameter. It's modifying IRTEs for posted interrupts and introduces a new wakeup list for GAPPI within KVM. My initial thought is, is this reachable in a fuzzable environment? Since this code is directly linked to AMD IOMMU, KVM SVM and, specifically AVIC, I need to evaluate the potential. QEMU and Google Compute Engine allow nested virtualization on AMD hosts or even emulation. While AMD IOMMU emulation with AVIC in QEMU might be a bit sketchy, the *KVM code itself* is the real target here. Wait, Syzkaller runs in QEMU... and it supports fuzzing KVM. If we're on an AMD host with nested virtualization, or even emulating SVM, we should be able to reach KVM SVM code directly. Syzkaller supports KVM fuzzing, which means we *can* absolutely fuzz this! This is definitely worth pursuing. Now, let's zoom in on the specific functions that are most interesting for fuzzing: * `avic_init_vcpu`, `avic_add_vcpu_to_gappi_wakeup_list`, `avic_remove_vcpu_from_gappi_wakeup_list`, `avic_destroy_vcpu`, `svm_ir_list_del`, `avic_pi_update_irte`, `avic_update_iommu_vcpu_affinity`, `__avic_vcpu_load`, `__avic_vcpu_put`, `avic_vcpu_put`, `avic_gappi_wakeup_handler`, `avic_hardware_setup`, `avic_hardware_unsetup`, `__amd_iommu_update_ga`, `amd_iommu_update_ga`, `amd_iommu_activate_guest_mode`, and `amd_ir_set_vcpu_affinity`. Next step, I need to check the relevant Kconfig options to be sure the relevant features are enabled. Specifically, I'm looking at KVM_AMD, AMD_IOMMU, and IRQ_REMAP. Those need to be verified. |
| 4/2 | 2026/07/13 13:36 | tool | grepper |
0mArgs:{
"Expression": "config KVM_AMD",
"PathPrefix": "arch/x86/kvm/Kconfig"
}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/07/13 13:36 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14612 output: 34 thoughts: 16 Thoughts: Here's a summary of my thought process, as requested: **Assessing IOMMU and IRQ Remapping in This Context** Okay, first things first, I need to check the status of AMD_IOMMU and IRQ_REMAP. Those are the foundation stones, really. Given the likely constraints in this setup, they're probably key to achieving the desired outcome. I need to quickly establish if they are enabled and configured correctly, or if there's any hint of a problem there. Any issues with those and, frankly, we can probably stop there as other configurations will not be effective. So, those need to be solid. I want to know if they're up and running. |
| 6/2 | 2026/07/13 13:36 | tool | grepper |
0mError:no matches Args: {
"Expression": "config AMD_IOMMU",
"PathPrefix": "drivers/iommu/Kconfig"
}Results: {
"error": "no matches"
} |
| 7/2 | 2026/07/13 13:36 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14825 output: 32 thoughts: 21 Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue: **Navigating the AMD IOMMU Codebase** Right, *AMD_IOMMU*, that's the key. I need to find the configuration options for that. Based on experience, the most logical place to look first is the `drivers/iommu/amd/Kconfig` file. That's usually where these hardware-specific configuration options reside within the driver tree. It's almost a given. Time to confirm and get to work. |
| 8/2 | 2026/07/13 13:36 | tool | grepper |
0mArgs:{
"Expression": "config AMD_IOMMU",
"PathPrefix": "drivers/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"
} |
| 9/2 | 2026/07/13 13:36 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15213 output: 26 thoughts: 7 Thoughts: Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person: **Understanding IRQ_REMAP in Depth** Right, let's dive into this. IRQ_REMAP... I'm thinking about the implications. We're talking about remapping interrupt request lines, essentially decoupling the physical interrupt pins from the interrupt numbers presented to the CPU. The immediate benefit is, of course, a more flexible and robust interrupt routing system. We're getting away from the hardwired limitations of legacy interrupt controllers and embracing a more dynamic approach. The key question is, *how* is this remap implemented? Is it a translation table within the chipset? Is it managed by the host bridge? And what are the performance overheads associated with this indirection? I'd imagine that any latency introduced by the remapping process is the primary factor to consider - especially in performance critical environments. I'm also considering the implications for device drivers. Do they need to be aware of the remapping? Or is the system abstraction transparent enough to insulate the driver from these changes, allowing it to simply request an interrupt number and have the system handle the underlying remapping without its intervention? I'd hazard a guess that newer drivers are built with awareness, allowing some degree of control. Finally, what are the implications for virtualization? How does IRQ_REMAP play with interrupt virtualization techniques, like MSI-X and interrupt remapping in a virtualized environment? Is there a need to carefully manage the mapping of physical interrupts to virtual interrupt vectors? This is really crucial when dealing with nested virtualization or high-performance I/O virtualization. |
| 10/2 | 2026/07/13 13:36 | tool | grepper |
0mArgs:{
"Expression": "config IRQ_REMAP",
"PathPrefix": ""
}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/07/13 13:36 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15691 output: 36 thoughts: 175 Thoughts: **Investigating a Potential Fuzzing Target** Okay, so I'm looking at this `amd_iommu_gappi` feature and trying to figure out if it's a good target for fuzzing. First, I need to check if there are alternative configurations that might affect it. Okay, I see it's exported in `drivers/iommu/amd/init.c`. That's a good sign. Looks like it's enabled by the `amd_iommu=gappi` kernel parameter. Hmm, the obvious path to getting syzkaller to hit this would be to pass that parameter. But syzkaller doesn't automatically pass kernel parameters unless they're explicitly defined in its configuration, and I can't specify kernel parameters directly within Kconfig. That's a hurdle. So, fuzzing the parameter parsing itself isn't a viable option. Now, hold on a second... `amd_iommu_gappi` is a *global* variable. That changes things. Could it be exposed through sysfs or debugfs? If so, that opens a backdoor. I need to investigate if there's any mechanism to modify this global variable. Time to check for its exposure. |
| 12/2 | 2026/07/13 13:37 | tool | grepper |
0mArgs:{
"Expression": "amd_iommu_gappi",
"PathPrefix": "drivers/iommu/amd/"
}Results: {
"Output": "drivers/iommu/amd/amd_iommu.h=43=int amd_iommu_enable_faulting(unsigned int cpu);\ndrivers/iommu/amd/amd_iommu.h:44:extern bool amd_iommu_gappi;\ndrivers/iommu/amd/amd_iommu.h-45-extern int amd_iommu_guest_ir;\n--\ndrivers/iommu/amd/init.c=161=int amd_iommu_gpt_level = PAGE_MODE_4_LEVEL;\ndrivers/iommu/amd/init.c-162-\ndrivers/iommu/amd/init.c:163:bool amd_iommu_gappi;\ndrivers/iommu/amd/init.c:164:EXPORT_SYMBOL(amd_iommu_gappi);\ndrivers/iommu/amd/init.c-165-\n--\ndrivers/iommu/amd/init.c=2998=static void enable_iommus_vapic(void)\n--\ndrivers/iommu/amd/init.c-3005-\t\t/*\ndrivers/iommu/amd/init.c:3006:\t\t * Disable GAPPI, do not check amd_iommu_gappi as it may be\ndrivers/iommu/amd/init.c-3007-\t\t * false in new kexec kernel even though previous kernel has\n--\ndrivers/iommu/amd/init.c-3050-\ndrivers/iommu/amd/init.c:3051:\tif (amd_iommu_gappi \u0026\u0026\ndrivers/iommu/amd/init.c-3052-\t !(check_feature(FEATURE_GAPPI) \u0026\u0026\n--\ndrivers/iommu/amd/init.c-3054-\t\tpr_warn(\"GAPPI is not supported.\\n\");\ndrivers/iommu/amd/init.c:3055:\t\tamd_iommu_gappi = false;\ndrivers/iommu/amd/init.c-3056-\t}\n--\ndrivers/iommu/amd/init.c-3059-\tfor_each_iommu(iommu) {\ndrivers/iommu/amd/init.c:3060:\t\tif (amd_iommu_gappi)\ndrivers/iommu/amd/init.c-3061-\t\t\tiommu_feature_enable(iommu, CONTROL_GAPPI_EN);\n--\ndrivers/iommu/amd/init.c-3072-\tpr_info(\"Virtual APIC enabled with %s\\n\",\ndrivers/iommu/amd/init.c:3073:\t\tamd_iommu_gappi ? \"GAPPI\" : \"GALOG\");\ndrivers/iommu/amd/init.c-3074-#endif\n--\ndrivers/iommu/amd/init.c=3737=static int __init parse_amd_iommu_options(char *str)\n--\ndrivers/iommu/amd/init.c-3764-\t\t} else if (strncmp(str, \"gappi\", 5) == 0) {\ndrivers/iommu/amd/init.c:3765:\t\t\tamd_iommu_gappi = true;\ndrivers/iommu/amd/init.c-3766-\t\t} else {\n--\ndrivers/iommu/amd/iommu.c=3962=static void __amd_iommu_update_ga(struct irte_ga *entry, int apicid,\n--\ndrivers/iommu/amd/iommu.c-3972-\t} else {\ndrivers/iommu/amd/iommu.c:3973:\t\tif (amd_iommu_gappi) {\ndrivers/iommu/amd/iommu.c-3974-\t\t\tentry-\u003elo.fields_vapic.gappi_dis = !wakeup_intr \u0026\u0026\n"
} |
| 13/2 | 2026/07/13 13:37 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 17163 output: 25 thoughts: 2069 Thoughts: **Analysis of AMD IOMMU GAPPI Patch** Okay, so this patch seems to introduce GAPPI (Guest APIC-based Posted Interrupt) support for the AMD IOMMU, which I believe is related to interrupt handling. My initial thought is that `amd_iommu_gappi` is the key flag here, and it's set only when `amd_iommu=gappi` is passed as a kernel parameter. I've confirmed there's no other way to set it. The interesting point is how the code *behaves* when `amd_iommu_gappi` is *not* set. The patch does modify the non-GAPPI path, but it appears to be primarily a refactoring or cleanup. Variables are renamed (`ga_log_intr` to `wakeup_intr`) and some logic is tweaked, but the *functionality* remains essentially the same for the non-GAPPI path. The key change is that `amd_iommu_update_ga` now takes `apicid`, `wakeup_intr`, and `is_running` arguments, replacing the original `cpu` and `ga_log_intr`. Looking deeper, the original `cpu` argument in `avic_update_iommu_vcpu_affinity` was actually the APIC ID, not the CPU number, which this patch correctly captures. The renaming to `apicid` is thus more accurate and clearer. The new GAPPI-specific code, like `avic_add_vcpu_to_gappi_wakeup_list` and related changes, is entirely gated by the `amd_iommu_gappi` flag, which means it is inaccessible without passing `amd_iommu=gappi`. Given Syzkaller's behavior, I need to evaluate if the patch *should* be fuzzed. The patch seems to introduce *new* functional behavior, and that is GAPPI. Syzkaller can pass the needed kernel parameter. Therefore, this patch warrants fuzzing, since it introduces GAPPI. The required Kconfig options are `KVM_AMD` and `AMD_IOMMU` because they enable the fundamental AMD KVM and IOMMU functionality on which this GAPPI feature is built. |
| 14/2 | 2026/07/13 13:37 | tool | grepper |
0mArgs:{
"Expression": "config KVM_AMD",
"PathPrefix": ""
}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"
} |
| 15/2 | 2026/07/13 13:37 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 19922 output: 26 thoughts: 16 Thoughts: Okay, let's see. My first thought is: **Checking Dependencies for `AMD_IOMMU`** Right, so I need to quickly determine if the `AMD_IOMMU` module has any dependencies that I need to be aware of. I need to understand what other components or settings it relies on before I can properly assess its function or potential issues. This is a fundamental step for me; if it depends on something, I need to know *what* so I can assess whether that dependency is set up correctly, or what the knock-on effects of messing with `AMD_IOMMU` might be. Time to dig in and find out. |
| 16/2 | 2026/07/13 13:38 | tool | grepper |
0mArgs:{
"Expression": "config AMD_IOMMU",
"PathPrefix": ""
}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"
} |
| 17/2 | 2026/07/13 13:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 20321 output: 36 thoughts: 29 Thoughts: Here's my thought process, summarized as you requested: **Examining AMD IOMMU Dependencies** Okay, let's dive right in. To understand the complete picture of how `AMD_IOMMU` is configured and used, I need to get a handle on its dependencies. I'm going to navigate to the `drivers/iommu/amd/Kconfig` file. That's the logical place to start – it's where the configuration options for this specific AMD IOMMU driver are defined, and where I expect to find the relationships between `AMD_IOMMU` and other features or options within the kernel. I'm looking for the conditional logic, the `depends on` statements, any `select` statements, and anything that gives me insight into what else *must* be enabled or considered in order for `AMD_IOMMU` to be available and functional. I expect this file will reveal the key building blocks. Let's see what's there. |
| 18/2 | 2026/07/13 13:38 | 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"
} |
| 19/2 | 2026/07/13 13:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 20864 output: 36 thoughts: 23 Thoughts: Okay, let's get down to brass tacks. **I'm Deep in the Weeds on IOMMU Configuration** Right, so I'm focusing on getting this AMD IOMMU implementation configured properly. My initial thought is to make sure I've got `AMD_IOMMU` enabled in the config. That's the baseline. But I can't just stop there. The next key aspect of this, based on my understanding, would be to consider `IRQ_REMAP`. I need to figure out how that is going to interact with the IOMMU. Does it need to be enabled for optimal performance? Does the implementation depend on it? I need to think carefully about the implications of these settings. I know `IRQ_REMAP` is crucial to making sure that the interrupts are properly mapped through the IOMMU, therefore I need to make sure this is all set up correctly. This all ties together, but I need to make sure this is all functioning together properly. |
| 20/2 | 2026/07/13 13:38 | tool | read-file |
0mArgs:{
"File": "drivers/iommu/Kconfig",
"FirstLine": 190,
"LineCount": 20
}Results: {
"Contents": " 190:\t\t These IOMMUs allow virtualization of the address space used by most\n 191:\t\t cores within the multimedia subsystem.\n 192:\t\n 193:\t\t If unsure, say N here.\n 194:\t\n 195:\tsource \"drivers/iommu/amd/Kconfig\"\n 196:\tsource \"drivers/iommu/arm/Kconfig\"\n 197:\tsource \"drivers/iommu/intel/Kconfig\"\n 198:\tsource \"drivers/iommu/iommufd/Kconfig\"\n 199:\tsource \"drivers/iommu/riscv/Kconfig\"\n 200:\t\n 201:\tconfig IRQ_REMAP\n 202:\t\tbool \"Support for Interrupt Remapping\"\n 203:\t\tdepends on X86_64 \u0026\u0026 X86_IO_APIC \u0026\u0026 PCI_MSI \u0026\u0026 ACPI\n 204:\t\tselect IRQ_MSI_LIB\n 205:\t\thelp\n 206:\t\t Supports Interrupt remapping for IO-APIC and MSI devices.\n 207:\t\t To use x2apic mode in the CPU's which support x2APIC enhancements or\n 208:\t\t to support platforms with CPU's having \u003e 8 bit APIC ID, say Y.\n 209:\t\n"
} |
| 21/2 | 2026/07/13 13:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 21488 output: 116 thoughts: 743 Thoughts: **Analyzing AMD IOMMU and AVIC Functionality** Okay, so I'm digging into how the AMD IOMMU and Advanced Virtual Interrupt Controller (AVIC) play together, and it's becoming clear where the dependencies lie. Specifically, I see that `IRQ_REMAP` is crucial. It's essential for `amd_iommu_update_ga` and `amd_iommu_activate_guest_mode` to be defined and, therefore, usable. I confirmed this by checking the include file `linux/amd-iommu.h`, seeing that both `CONFIG_AMD_IOMMU` and `CONFIG_IRQ_REMAP` are required. Also, the KVM side requires `KVM_AMD`. Now, I want to identify the key symbols to focus on in this analysis. Let's see... I've identified: `avic_add_vcpu_to_gappi_wakeup_list`, `avic_remove_vcpu_from_gappi_wakeup_list`, `avic_gappi_wakeup_handler`, `__amd_iommu_update_ga`, `amd_iommu_update_ga`, and `amd_iommu_activate_guest_mode`. I'm also going to add a few more to the list that I've found while looking over the code: `avic_init_vcpu`, `avic_destroy_vcpu`, `avic_pi_update_irte` and `avic_update_iommu_vcpu_affinity`. I'll want to include all of these: `avic_add_vcpu_to_gappi_wakeup_list`, `avic_remove_vcpu_from_gappi_wakeup_list`, `avic_gappi_wakeup_handler`, `avic_pi_update_irte`, `avic_update_iommu_vcpu_affinity`, `__amd_iommu_update_ga`, `amd_iommu_update_ga`, and `amd_iommu_activate_guest_mode`. Next, I need to understand which of these functions are "hot path" – which ones are called frequently and are therefore likely performance bottlenecks. Looking at `avic_update_iommu_vcpu_affinity`, I see it's called from `__avic_vcpu_load` and `__avic_vcpu_put`, which are involved when a vCPU is scheduled in or out. This is somewhat hot, but not as hot as, say, VM-exit handlers. `avic_pi_update_irte` updates the IRTE, but it's not hot, not called constantly. `avic_gappi_wakeup_handler` is triggered by posted interrupt wakeups. `__amd_iommu_update_ga` is called from `amd_iommu_update_ga` and `amd_iommu_activate_guest_mode`, and these two are going to be important to look at. So my revised list of functions to focus on looks like this: * `avic_add_vcpu_to_gappi_wakeup_list` * `avic_remove_vcpu_from_gappi_wakeup_list` * `avic_gappi_wakeup_handler` * `avic_pi_update_irte` * `avic_update_iommu_vcpu_affinity` * `__amd_iommu_update_ga` * `amd_iommu_update_ga` * `amd_iommu_activate_guest_mode` Now, just to be thorough, I'll quickly verify that these functions do indeed exist and that I've got the names spelled correctly. |
| 22/2 | 2026/07/13 13:38 | tool | grepper |
0mArgs:{
"Expression": "(avic_add_vcpu_to_gappi_wakeup_list|avic_remove_vcpu_from_gappi_wakeup_list|avic_gappi_wakeup_handler|avic_pi_update_irte|avic_update_iommu_vcpu_affinity|__amd_iommu_update_ga|amd_iommu_update_ga|amd_iommu_activate_guest_mode)",
"PathPrefix": ""
}Results: {
"Output": "arch/x86/kvm/svm/avic.c=872=int avic_init_vcpu(struct vcpu_svm *svm)\n--\narch/x86/kvm/svm/avic.c-894-\narch/x86/kvm/svm/avic.c:895:static void avic_add_vcpu_to_gappi_wakeup_list(struct vcpu_svm *svm, int cpu)\narch/x86/kvm/svm/avic.c-896-{\n--\narch/x86/kvm/svm/avic.c-909-\narch/x86/kvm/svm/avic.c:910:static void avic_remove_vcpu_from_gappi_wakeup_list(struct vcpu_svm *svm, int cpu)\narch/x86/kvm/svm/avic.c-911-{\n--\narch/x86/kvm/svm/avic.c=923=void avic_destroy_vcpu(struct vcpu_svm *svm)\n--\narch/x86/kvm/svm/avic.c-925-\tif (svm-\u003egappi_cpu != -1 \u0026\u0026 amd_iommu_gappi) {\narch/x86/kvm/svm/avic.c:926:\t\tavic_remove_vcpu_from_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\narch/x86/kvm/svm/avic.c-927-\t\tsvm-\u003egappi_cpu = -1;\n--\narch/x86/kvm/svm/avic.c=937=static void svm_ir_list_del(struct kvm_kernel_irqfd *irqfd)\n--\narch/x86/kvm/svm/avic.c-950-\tif (amd_iommu_gappi \u0026\u0026 list_empty(\u0026svm-\u003eir_list))\narch/x86/kvm/svm/avic.c:951:\t\tavic_remove_vcpu_from_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\narch/x86/kvm/svm/avic.c-952-\traw_spin_unlock_irqrestore(\u0026svm-\u003eir_list_lock, flags);\n--\narch/x86/kvm/svm/avic.c-954-\narch/x86/kvm/svm/avic.c:955:int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,\narch/x86/kvm/svm/avic.c-956-\t\t\tunsigned int host_irq, uint32_t guest_irq,\n--\narch/x86/kvm/svm/avic.c-1013-\t\t\t\tif (list_empty(\u0026svm-\u003eir_list)) {\narch/x86/kvm/svm/avic.c:1014:\t\t\t\t\tavic_add_vcpu_to_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\narch/x86/kvm/svm/avic.c-1015-\t\t\t\t\tis_vcpu_waiting = true;\n--\narch/x86/kvm/svm/avic.c-1039-\t\tif (is_vcpu_waiting)\narch/x86/kvm/svm/avic.c:1040:\t\t\tavic_remove_vcpu_from_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\narch/x86/kvm/svm/avic.c-1041-\t\treturn ret;\n--\narch/x86/kvm/svm/avic.c=1046=enum avic_vcpu_action {\n--\narch/x86/kvm/svm/avic.c-1073-\narch/x86/kvm/svm/avic.c:1074:static void avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int apicid,\narch/x86/kvm/svm/avic.c-1075-\t\t\t\t\t int cpu, enum avic_vcpu_action action)\n--\narch/x86/kvm/svm/avic.c-1099-\t\t\t */\narch/x86/kvm/svm/avic.c:1100:\t\t\tavic_remove_vcpu_from_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\narch/x86/kvm/svm/avic.c-1101-\n--\narch/x86/kvm/svm/avic.c-1104-\t\tapicid = kvm_cpu_get_apicid(svm-\u003egappi_cpu);\narch/x86/kvm/svm/avic.c:1105:\t\tavic_add_vcpu_to_gappi_wakeup_list(svm, svm-\u003egappi_cpu);\narch/x86/kvm/svm/avic.c-1106-\t}\n--\narch/x86/kvm/svm/avic.c-1111-\t\tif (!(action \u0026 AVIC_TOGGLE_ON_OFF))\narch/x86/kvm/svm/avic.c:1112:\t\t\tWARN_ON_ONCE(amd_iommu_update_ga(data, apicid, wakeup_intr, is_running));\narch/x86/kvm/svm/avic.c-1113-\t\telse if (is_running)\narch/x86/kvm/svm/avic.c:1114:\t\t\tWARN_ON_ONCE(amd_iommu_activate_guest_mode(data, apicid, wakeup_intr,\narch/x86/kvm/svm/avic.c-1115-\t\t\t\t\t\t\t\t is_running));\n--\narch/x86/kvm/svm/avic.c=1121=static void __avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu,\n--\narch/x86/kvm/svm/avic.c-1168-\narch/x86/kvm/svm/avic.c:1169:\tavic_update_iommu_vcpu_affinity(vcpu, h_physical_id, cpu, action);\narch/x86/kvm/svm/avic.c-1170-\n--\narch/x86/kvm/svm/avic.c=1189=static void __avic_vcpu_put(struct kvm_vcpu *vcpu, enum avic_vcpu_action action)\n--\narch/x86/kvm/svm/avic.c-1211-\narch/x86/kvm/svm/avic.c:1212:\tavic_update_iommu_vcpu_affinity(vcpu, -1, -1, action);\narch/x86/kvm/svm/avic.c-1213-\n--\narch/x86/kvm/svm/avic.c=1344=static bool __init avic_want_avic_enabled(void)\n--\narch/x86/kvm/svm/avic.c-1384-\narch/x86/kvm/svm/avic.c:1385:static void avic_gappi_wakeup_handler(void)\narch/x86/kvm/svm/avic.c-1386-{\n--\narch/x86/kvm/svm/avic.c=1406=bool __init avic_hardware_setup(void)\n--\narch/x86/kvm/svm/avic.c-1442-\tamd_iommu_register_ga_log_notifier(\u0026avic_ga_log_notifier);\narch/x86/kvm/svm/avic.c:1443:\tkvm_set_posted_intr_wakeup_handler(\u0026avic_gappi_wakeup_handler);\narch/x86/kvm/svm/avic.c-1444-\n--\narch/x86/kvm/svm/svm.c=5272=struct kvm_x86_ops svm_x86_ops __initdata = {\n--\narch/x86/kvm/svm/svm.c-5377-\t.deliver_interrupt = svm_deliver_interrupt,\narch/x86/kvm/svm/svm.c:5378:\t.pi_update_irte = avic_pi_update_irte,\narch/x86/kvm/svm/svm.c-5379-\t.setup_mce = svm_setup_mce,\n--\narch/x86/kvm/svm/svm.h=920=void avic_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu);\narch/x86/kvm/svm/svm.h:921:int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,\narch/x86/kvm/svm/svm.h-922-\t\t\tunsigned int host_irq, uint32_t guest_irq,\n--\ndrivers/iommu/amd/iommu.c=3954=static const struct irq_domain_ops amd_ir_domain_ops = {\n--\ndrivers/iommu/amd/iommu.c-3961-\ndrivers/iommu/amd/iommu.c:3962:static void __amd_iommu_update_ga(struct irte_ga *entry, int apicid,\ndrivers/iommu/amd/iommu.c-3963-\t\t\t\t bool wakeup_intr, bool is_running)\n--\ndrivers/iommu/amd/iommu.c-4004- */\ndrivers/iommu/amd/iommu.c:4005:int amd_iommu_update_ga(void *data, int apicid, bool wakeup_intr, bool is_running)\ndrivers/iommu/amd/iommu.c-4006-{\n--\ndrivers/iommu/amd/iommu.c-4018-\ndrivers/iommu/amd/iommu.c:4019:\t__amd_iommu_update_ga(entry, apicid, wakeup_intr, is_running);\ndrivers/iommu/amd/iommu.c-4020-\n--\ndrivers/iommu/amd/iommu.c-4023-}\ndrivers/iommu/amd/iommu.c:4024:EXPORT_SYMBOL(amd_iommu_update_ga);\ndrivers/iommu/amd/iommu.c-4025-\ndrivers/iommu/amd/iommu.c:4026:int amd_iommu_activate_guest_mode(void *data, int apicid, bool wakeup_intr, bool is_running)\ndrivers/iommu/amd/iommu.c-4027-{\n--\ndrivers/iommu/amd/iommu.c-4048-\ndrivers/iommu/amd/iommu.c:4049:\t__amd_iommu_update_ga(entry, apicid, wakeup_intr, is_running);\ndrivers/iommu/amd/iommu.c-4050-\n--\ndrivers/iommu/amd/iommu.c-4053-}\ndrivers/iommu/amd/iommu.c:4054:EXPORT_SYMBOL(amd_iommu_activate_guest_mode);\ndrivers/iommu/amd/iommu.c-4055-\n--\ndrivers/iommu/amd/iommu.c=4088=static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *info)\n--\ndrivers/iommu/amd/iommu.c-4119-\t\tif (pi_data-\u003eis_guest_mode)\ndrivers/iommu/amd/iommu.c:4120:\t\t\tret = amd_iommu_activate_guest_mode(ir_data, pi_data-\u003eapicid,\ndrivers/iommu/amd/iommu.c-4121-\t\t\t\t\t\t\t pi_data-\u003ewakeup_intr,\n--\ninclude/linux/amd-iommu.h=31=extern int amd_iommu_register_ga_log_notifier(int (*notifier)(u32));\ninclude/linux/amd-iommu.h-32-\ninclude/linux/amd-iommu.h:33:extern int amd_iommu_update_ga(void *data, int apicid, bool wakeup_intr,\ninclude/linux/amd-iommu.h-34-\t\t\t bool is_running);\ninclude/linux/amd-iommu.h:35:extern int amd_iommu_activate_guest_mode(void *data, int apicid, bool wakeup_intr,\ninclude/linux/amd-iommu.h-36-\t\t\t\t\t bool is_running);\n--\ninclude/linux/amd-iommu.h=42=amd_iommu_register_ga_log_notifier(int (*notifier)(u32))\n--\ninclude/linux/amd-iommu.h-46-\ninclude/linux/amd-iommu.h:47:static inline int amd_iommu_update_ga(void *data, int apicid, bool wakeup_intr,\ninclude/linux/amd-iommu.h-48-\t\t\t\t bool is_running)\n--\ninclude/linux/amd-iommu.h-52-\ninclude/linux/amd-iommu.h:53:static inline int amd_iommu_activate_guest_mode(void *data, int apicid, bool wakeup_intr,\ninclude/linux/amd-iommu.h-54-\t\t\t\t\t\tbool is_running)\n"
} |
| 23/2 | 2026/07/13 13:39 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 26633 output: 226 thoughts: 237 Thoughts: **My Assessment of the GAPPI Patch** Okay, so I've reviewed this patch and I'm seeing it's focused on introducing GAPPI (Guest APIC Posted Interrupts) support for AMD IOMMU and KVM SVM AVIC, which is precisely the kind of low-level virtualization change that demands close scrutiny. I see the function names are all correctly formatted. Excellent. Specifically, I’ll need to make sure to include these functions in my testing suite: `avic_add_vcpu_to_gappi_wakeup_list`, `avic_remove_vcpu_from_gappi_wakeup_list`, `avic_gappi_wakeup_handler`, `avic_pi_update_irte`, `avic_update_iommu_vcpu_affinity`, `__amd_iommu_update_ga`, `amd_iommu_update_ga`, and `amd_iommu_activate_guest_mode`. These appear to be the core routines involved in managing the GAPPI wakeup list and updating the IRTEs, which will be critical to the integrity of this implementation. On the configuration front, I see the patch leverages `KVM_AMD`, `AMD_IOMMU`, and `IRQ_REMAP`, which I can now verify are included in my current testing environment. The reasoning provided correctly identifies this as a significant change affecting how posted interrupts are handled and how the KVM core virtualizes guest APICs. The IRTE modification aspect is particularly interesting and a potential source of subtle bugs. Given the fundamental nature of these changes, this is absolutely a candidate for fuzzing. In fact, this patch is going to require quite a bit of work, so let's call set-results. |
| 24/2 | 2026/07/13 13:39 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"KVM_AMD",
"AMD_IOMMU",
"IRQ_REMAP"
],
"FocusSymbols": [
"avic_add_vcpu_to_gappi_wakeup_list",
"avic_remove_vcpu_from_gappi_wakeup_list",
"avic_gappi_wakeup_handler",
"avic_pi_update_irte",
"avic_update_iommu_vcpu_affinity",
"__amd_iommu_update_ga",
"amd_iommu_update_ga",
"amd_iommu_activate_guest_mode"
],
"Reasoning": "The patch introduces GAPPI (Guest APIC Posted Interrupts) support for AMD IOMMU and KVM SVM AVIC. It modifies the IRTE configuration for posted interrupts and introduces a new wakeup list for GAPPI in KVM. This is a functional change to core virtualization logic and should be fuzzed.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"KVM_AMD",
"AMD_IOMMU",
"IRQ_REMAP"
],
"FocusSymbols": [
"avic_add_vcpu_to_gappi_wakeup_list",
"avic_remove_vcpu_from_gappi_wakeup_list",
"avic_gappi_wakeup_handler",
"avic_pi_update_irte",
"avic_update_iommu_vcpu_affinity",
"__amd_iommu_update_ga",
"amd_iommu_update_ga",
"amd_iommu_activate_guest_mode"
],
"Reasoning": "The patch introduces GAPPI (Guest APIC Posted Interrupts) support for AMD IOMMU and KVM SVM AVIC. It modifies the IRTE configuration for posted interrupts and introduces a new wakeup list for GAPPI in KVM. This is a functional change to core virtualization logic and should be fuzzed.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|