| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/13 07:14 | flow | patch-triage |
12mArgs:null Results: {
"EnableConfigs": [
"KVM"
],
"FocusSymbols": [
"kvm_riscv_vcpu_aia_set_csr",
"kvm_riscv_vcpu_general_set_csr",
"kvm_riscv_vcpu_set_interrupt",
"kvm_riscv_vcpu_unset_interrupt"
],
"Reasoning": "The patch replaces lockless atomic bitops with a raw spinlock for tracking pending VCPU interrupts in RISC-V KVM. This is a functional change that affects interrupt injection and synchronization. Fuzzing should focus on functions that set/unset interrupts and CSRs, which are accessible via KVM ioctls and not on the absolute hottest VM exit path.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/13 07:14 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 6f01e369469bc70ff62cb490ea6592dd0f295e72\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Jul 13 07:14:54 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h\nindex 60017ceec9d2af..e2d5808169e44d 100644\n--- a/arch/riscv/include/asm/kvm_host.h\n+++ b/arch/riscv/include/asm/kvm_host.h\n@@ -209,13 +209,13 @@ struct kvm_vcpu_arch {\n \t/*\n \t * VCPU interrupts\n \t *\n-\t * We have a lockless approach for tracking pending VCPU interrupts\n-\t * implemented using atomic bitops. The irqs_pending bitmap represent\n-\t * pending interrupts whereas irqs_pending_mask represent bits changed\n-\t * in irqs_pending. Our approach is modeled around multiple producer\n-\t * and single consumer problem where the consumer is the VCPU itself.\n+\t * The irqs_pending bitmap represents pending interrupts whereas\n+\t * irqs_pending_mask represents bits changed in irqs_pending. Updates\n+\t * to these bitmaps are serialized so vcpu interrupt sync/flush cannot\n+\t * drop a newly injected interrupt while syncing guest-visible HVIP.\n \t */\n #define KVM_RISCV_VCPU_NR_IRQS\t64\n+\traw_spinlock_t irqs_pending_lock;\n \tDECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS);\n \tDECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);\n \ndiff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c\nindex bafb009c5ce559..225e4aed81a377 100644\n--- a/arch/riscv/kvm/aia.c\n+++ b/arch/riscv/kvm/aia.c\n@@ -53,12 +53,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu)\n \tstruct kvm_vcpu_aia_csr *csr = \u0026vcpu-\u003earch.aia_context.guest_csr;\n \tunsigned long mask, val;\n \n+\tlockdep_assert_held(\u0026vcpu-\u003earch.irqs_pending_lock);\n+\n \tif (!kvm_riscv_aia_available())\n \t\treturn;\n \n-\tif (READ_ONCE(vcpu-\u003earch.irqs_pending_mask[1])) {\n-\t\tmask = xchg_acquire(\u0026vcpu-\u003earch.irqs_pending_mask[1], 0);\n-\t\tval = READ_ONCE(vcpu-\u003earch.irqs_pending[1]) \u0026 mask;\n+\tmask = vcpu-\u003earch.irqs_pending_mask[1];\n+\tif (mask) {\n+\t\tvcpu-\u003earch.irqs_pending_mask[1] = 0;\n+\t\tval = vcpu-\u003earch.irqs_pending[1] \u0026 mask;\n \n \t\tcsr-\u003ehviph \u0026= ~mask;\n \t\tcsr-\u003ehviph |= val;\n@@ -69,6 +72,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)\n {\n \tstruct kvm_vcpu_aia_csr *csr = \u0026vcpu-\u003earch.aia_context.guest_csr;\n \n+\tlockdep_assert_held(\u0026vcpu-\u003earch.irqs_pending_lock);\n+\n \tif (kvm_riscv_aia_available())\n \t\tcsr-\u003evsieh = ncsr_read(CSR_VSIEH);\n }\n@@ -78,11 +83,13 @@ bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)\n {\n \tunsigned long seip;\n \n+\tlockdep_assert_held(\u0026vcpu-\u003earch.irqs_pending_lock);\n+\n \tif (!kvm_riscv_aia_available())\n \t\treturn false;\n \n #ifdef CONFIG_32BIT\n-\tif (READ_ONCE(vcpu-\u003earch.irqs_pending[1]) \u0026\n+\tif (vcpu-\u003earch.irqs_pending[1] \u0026\n \t (vcpu-\u003earch.aia_context.guest_csr.vsieh \u0026 upper_32_bits(mask)))\n \t\treturn true;\n #endif\n@@ -207,6 +214,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,\n {\n \tstruct kvm_vcpu_aia_csr *csr = \u0026vcpu-\u003earch.aia_context.guest_csr;\n \tunsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);\n+#ifdef CONFIG_32BIT\n+\tunsigned long flags;\n+#endif\n \n \tif (!riscv_isa_extension_available(vcpu-\u003earch.isa, SSAIA))\n \t\treturn -ENOENT;\n@@ -216,11 +226,18 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,\n \treg_num = array_index_nospec(reg_num, regs_max);\n \n \tif (kvm_riscv_aia_available()) {\n-\t\t((unsigned long *)csr)[reg_num] = val;\n-\n #ifdef CONFIG_32BIT\n-\t\tif (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph))\n-\t\t\tWRITE_ONCE(vcpu-\u003earch.irqs_pending_mask[1], 0);\n+\t\tif (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) {\n+\t\t\traw_spin_lock_irqsave(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n+\t\t\t((unsigned long *)csr)[reg_num] = val;\n+\t\t\tvcpu-\u003earch.irqs_pending_mask[1] = 0;\n+\t\t\traw_spin_unlock_irqrestore(\u0026vcpu-\u003earch.irqs_pending_lock,\n+\t\t\t\t\t\t flags);\n+\t\t} else {\n+\t\t\t((unsigned long *)csr)[reg_num] = val;\n+\t\t}\n+#else\n+\t\t((unsigned long *)csr)[reg_num] = val;\n #endif\n \t}\n \ndiff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c\nindex cf6e231e76e254..7d8d20839d46ee 100644\n--- a/arch/riscv/kvm/vcpu.c\n+++ b/arch/riscv/kvm/vcpu.c\n@@ -80,6 +80,7 @@ static void kvm_riscv_vcpu_context_reset(struct kvm_vcpu *vcpu,\n \n static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset)\n {\n+\tunsigned long flags;\n \tbool loaded;\n \n \t/**\n@@ -104,8 +105,10 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset)\n \n \tkvm_riscv_vcpu_aia_reset(vcpu);\n \n+\traw_spin_lock_irqsave(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n \tbitmap_zero(vcpu-\u003earch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS);\n \tbitmap_zero(vcpu-\u003earch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);\n+\traw_spin_unlock_irqrestore(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n \n \tkvm_riscv_vcpu_pmu_reset(vcpu);\n \n@@ -151,6 +154,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)\n \n \t/* Setup VCPU hfence queue */\n \tspin_lock_init(\u0026vcpu-\u003earch.hfence_lock);\n+\traw_spin_lock_init(\u0026vcpu-\u003earch.irqs_pending_lock);\n \n \tspin_lock_init(\u0026vcpu-\u003earch.reset_state.lock);\n \n@@ -352,10 +356,13 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)\n {\n \tstruct kvm_vcpu_csr *csr = \u0026vcpu-\u003earch.guest_csr;\n \tunsigned long mask, val;\n+\tunsigned long flags;\n \n-\tif (READ_ONCE(vcpu-\u003earch.irqs_pending_mask[0])) {\n-\t\tmask = xchg_acquire(\u0026vcpu-\u003earch.irqs_pending_mask[0], 0);\n-\t\tval = READ_ONCE(vcpu-\u003earch.irqs_pending[0]) \u0026 mask;\n+\traw_spin_lock_irqsave(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n+\tmask = vcpu-\u003earch.irqs_pending_mask[0];\n+\tif (mask) {\n+\t\tvcpu-\u003earch.irqs_pending_mask[0] = 0;\n+\t\tval = vcpu-\u003earch.irqs_pending[0] \u0026 mask;\n \n \t\tcsr-\u003ehvip \u0026= ~mask;\n \t\tcsr-\u003ehvip |= val;\n@@ -363,11 +370,13 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)\n \n \t/* Flush AIA high interrupts */\n \tkvm_riscv_vcpu_aia_flush_interrupts(vcpu);\n+\traw_spin_unlock_irqrestore(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n }\n \n void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)\n {\n \tunsigned long hvip;\n+\tunsigned long flags;\n \tstruct kvm_vcpu_arch *v = \u0026vcpu-\u003earch;\n \tstruct kvm_vcpu_csr *csr = \u0026vcpu-\u003earch.guest_csr;\n \n@@ -376,27 +385,29 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)\n \n \t/* Sync-up HVIP.VSSIP bit changes does by Guest */\n \thvip = ncsr_read(CSR_HVIP);\n+\traw_spin_lock_irqsave(\u0026v-\u003eirqs_pending_lock, flags);\n \tif ((csr-\u003ehvip ^ hvip) \u0026 (1UL \u003c\u003c IRQ_VS_SOFT)) {\n \t\tif (hvip \u0026 (1UL \u003c\u003c IRQ_VS_SOFT)) {\n-\t\t\tif (!test_and_set_bit(IRQ_VS_SOFT,\n-\t\t\t\t\t v-\u003eirqs_pending_mask))\n-\t\t\t\tset_bit(IRQ_VS_SOFT, v-\u003eirqs_pending);\n+\t\t\tif (!__test_and_set_bit(IRQ_VS_SOFT,\n+\t\t\t\t\t\tv-\u003eirqs_pending_mask))\n+\t\t\t\t__set_bit(IRQ_VS_SOFT, v-\u003eirqs_pending);\n \t\t} else {\n-\t\t\tif (!test_and_set_bit(IRQ_VS_SOFT,\n-\t\t\t\t\t v-\u003eirqs_pending_mask))\n-\t\t\t\tclear_bit(IRQ_VS_SOFT, v-\u003eirqs_pending);\n+\t\t\tif (!__test_and_set_bit(IRQ_VS_SOFT,\n+\t\t\t\t\t\tv-\u003eirqs_pending_mask))\n+\t\t\t\t__clear_bit(IRQ_VS_SOFT, v-\u003eirqs_pending);\n \t\t}\n \t}\n \n \t/* Sync up the HVIP.LCOFIP bit changes (only clear) by the guest */\n \tif ((csr-\u003ehvip ^ hvip) \u0026 (1UL \u003c\u003c IRQ_PMU_OVF)) {\n \t\tif (!(hvip \u0026 (1UL \u003c\u003c IRQ_PMU_OVF)) \u0026\u0026\n-\t\t !test_and_set_bit(IRQ_PMU_OVF, v-\u003eirqs_pending_mask))\n-\t\t\tclear_bit(IRQ_PMU_OVF, v-\u003eirqs_pending);\n+\t\t !__test_and_set_bit(IRQ_PMU_OVF, v-\u003eirqs_pending_mask))\n+\t\t\t__clear_bit(IRQ_PMU_OVF, v-\u003eirqs_pending);\n \t}\n \n \t/* Sync-up AIA high interrupts */\n \tkvm_riscv_vcpu_aia_sync_interrupts(vcpu);\n+\traw_spin_unlock_irqrestore(\u0026v-\u003eirqs_pending_lock, flags);\n \n \t/* Sync-up timer CSRs */\n \tkvm_riscv_vcpu_timer_sync(vcpu);\n@@ -404,6 +415,8 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)\n \n int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)\n {\n+\tunsigned long flags;\n+\n \t/*\n \t * We only allow VS-mode software, timer, and external\n \t * interrupts when irq is one of the local interrupts\n@@ -416,9 +429,10 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)\n \t irq != IRQ_PMU_OVF)\n \t\treturn -EINVAL;\n \n-\tset_bit(irq, vcpu-\u003earch.irqs_pending);\n-\tsmp_mb__before_atomic();\n-\tset_bit(irq, vcpu-\u003earch.irqs_pending_mask);\n+\traw_spin_lock_irqsave(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n+\t__set_bit(irq, vcpu-\u003earch.irqs_pending);\n+\t__set_bit(irq, vcpu-\u003earch.irqs_pending_mask);\n+\traw_spin_unlock_irqrestore(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n \n \tkvm_vcpu_kick(vcpu);\n \n@@ -427,6 +441,8 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)\n \n int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)\n {\n+\tunsigned long flags;\n+\n \t/*\n \t * We only allow VS-mode software, timer, counter overflow and external\n \t * interrupts when irq is one of the local interrupts\n@@ -439,26 +455,33 @@ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)\n \t irq != IRQ_PMU_OVF)\n \t\treturn -EINVAL;\n \n-\tclear_bit(irq, vcpu-\u003earch.irqs_pending);\n-\tsmp_mb__before_atomic();\n-\tset_bit(irq, vcpu-\u003earch.irqs_pending_mask);\n+\traw_spin_lock_irqsave(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n+\t__clear_bit(irq, vcpu-\u003earch.irqs_pending);\n+\t__set_bit(irq, vcpu-\u003earch.irqs_pending_mask);\n+\traw_spin_unlock_irqrestore(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n \n \treturn 0;\n }\n \n bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)\n {\n+\tunsigned long flags;\n \tunsigned long ie;\n+\tbool ret;\n \n+\traw_spin_lock_irqsave(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n \tie = ((vcpu-\u003earch.guest_csr.vsie \u0026 VSIP_VALID_MASK)\n \t\t\u003c\u003c VSIP_TO_HVIP_SHIFT) \u0026 (unsigned long)mask;\n \tie |= vcpu-\u003earch.guest_csr.vsie \u0026 ~IRQ_LOCAL_MASK \u0026\n \t\t(unsigned long)mask;\n-\tif (READ_ONCE(vcpu-\u003earch.irqs_pending[0]) \u0026 ie)\n-\t\treturn true;\n+\tret = vcpu-\u003earch.irqs_pending[0] \u0026 ie;\n \n \t/* Check AIA high interrupts */\n-\treturn kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);\n+\tif (!ret)\n+\t\tret = kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);\n+\traw_spin_unlock_irqrestore(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n+\n+\treturn ret;\n }\n \n void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)\ndiff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c\nindex bb920e8923c930..cba3682944b694 100644\n--- a/arch/riscv/kvm/vcpu_onereg.c\n+++ b/arch/riscv/kvm/vcpu_onereg.c\n@@ -298,6 +298,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,\n {\n \tstruct kvm_vcpu_csr *csr = \u0026vcpu-\u003earch.guest_csr;\n \tunsigned long regs_max = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);\n+\tunsigned long flags;\n \n \tif (reg_num \u003e= regs_max)\n \t\treturn -ENOENT;\n@@ -309,10 +310,14 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,\n \t\treg_val \u003c\u003c= VSIP_TO_HVIP_SHIFT;\n \t}\n \n-\t((unsigned long *)csr)[reg_num] = reg_val;\n-\n-\tif (reg_num == KVM_REG_RISCV_CSR_REG(sip))\n-\t\tWRITE_ONCE(vcpu-\u003earch.irqs_pending_mask[0], 0);\n+\tif (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {\n+\t\traw_spin_lock_irqsave(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n+\t\t((unsigned long *)csr)[reg_num] = reg_val;\n+\t\tvcpu-\u003earch.irqs_pending_mask[0] = 0;\n+\t\traw_spin_unlock_irqrestore(\u0026vcpu-\u003earch.irqs_pending_lock, flags);\n+\t} else {\n+\t\t((unsigned long *)csr)[reg_num] = reg_val;\n+\t}\n \n \treturn 0;\n }\n"
} |
| 2/1 | 2026/07/13 07:14 | agent | patch-evaluator |
12mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"KVM"
],
"FocusSymbols": [
"kvm_riscv_vcpu_aia_set_csr",
"kvm_riscv_vcpu_general_set_csr",
"kvm_riscv_vcpu_set_interrupt",
"kvm_riscv_vcpu_unset_interrupt"
],
"Reasoning": "The patch replaces lockless atomic bitops with a raw spinlock for tracking pending VCPU interrupts in RISC-V KVM. This is a functional change that affects interrupt injection and synchronization. Fuzzing should focus on functions that set/unset interrupts and CSRs, which are accessible via KVM ioctls and not on the absolute hottest VM exit path.",
"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 6f01e369469bc70ff62cb490ea6592dd0f295e72
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Jul 13 07:14:54 2026 +0000
syz-cluster: applied patch under review
diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index 60017ceec9d2af..e2d5808169e44d 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -209,13 +209,13 @@ struct kvm_vcpu_arch {
/*
* VCPU interrupts
*
- * We have a lockless approach for tracking pending VCPU interrupts
- * implemented using atomic bitops. The irqs_pending bitmap represent
- * pending interrupts whereas irqs_pending_mask represent bits changed
- * in irqs_pending. Our approach is modeled around multiple producer
- * and single consumer problem where the consumer is the VCPU itself.
+ * The irqs_pending bitmap represents pending interrupts whereas
+ * irqs_pending_mask represents bits changed in irqs_pending. Updates
+ * to these bitmaps are serialized so vcpu interrupt sync/flush cannot
+ * drop a newly injected interrupt while syncing guest-visible HVIP.
*/
#define KVM_RISCV_VCPU_NR_IRQS 64
+ raw_spinlock_t irqs_pending_lock;
DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c
index bafb009c5ce559..225e4aed81a377 100644
--- a/arch/riscv/kvm/aia.c
+++ b/arch/riscv/kvm/aia.c
@@ -53,12 +53,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu)
struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
unsigned long mask, val;
+ lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
+
if (!kvm_riscv_aia_available())
return;
- if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) {
- mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0);
- val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask;
+ mask = vcpu->arch.irqs_pending_mask[1];
+ if (mask) {
+ vcpu->arch.irqs_pending_mask[1] = 0;
+ val = vcpu->arch.irqs_pending[1] & mask;
csr->hviph &= ~mask;
csr->hviph |= val;
@@ -69,6 +72,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
+ lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
+
if (kvm_riscv_aia_available())
csr->vsieh = ncsr_read(CSR_VSIEH);
}
@@ -78,11 +83,13 @@ bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
{
unsigned long seip;
+ lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
+
if (!kvm_riscv_aia_available())
return false;
#ifdef CONFIG_32BIT
- if (READ_ONCE(vcpu->arch.irqs_pending[1]) &
+ if (vcpu->arch.irqs_pending[1] &
(vcpu->arch.aia_context.guest_csr.vsieh & upper_32_bits(mask)))
return true;
#endif
@@ -207,6 +214,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
{
struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
unsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
+#ifdef CONFIG_32BIT
+ unsigned long flags;
+#endif
if (!riscv_isa_extension_available(vcpu->arch.isa, SSAIA))
return -ENOENT;
@@ -216,11 +226,18 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
reg_num = array_index_nospec(reg_num, regs_max);
if (kvm_riscv_aia_available()) {
- ((unsigned long *)csr)[reg_num] = val;
-
#ifdef CONFIG_32BIT
- if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph))
- WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0);
+ if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) {
+ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+ ((unsigned long *)csr)[reg_num] = val;
+ vcpu->arch.irqs_pending_mask[1] = 0;
+ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock,
+ flags);
+ } else {
+ ((unsigned long *)csr)[reg_num] = val;
+ }
+#else
+ ((unsigned long *)csr)[reg_num] = val;
#endif
}
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index cf6e231e76e254..7d8d20839d46ee 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -80,6 +80,7 @@ static void kvm_riscv_vcpu_context_reset(struct kvm_vcpu *vcpu,
static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset)
{
+ unsigned long flags;
bool loaded;
/**
@@ -104,8 +105,10 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset)
kvm_riscv_vcpu_aia_reset(vcpu);
+ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
+ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
kvm_riscv_vcpu_pmu_reset(vcpu);
@@ -151,6 +154,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
/* Setup VCPU hfence queue */
spin_lock_init(&vcpu->arch.hfence_lock);
+ raw_spin_lock_init(&vcpu->arch.irqs_pending_lock);
spin_lock_init(&vcpu->arch.reset_state.lock);
@@ -352,10 +356,13 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
unsigned long mask, val;
+ unsigned long flags;
- if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) {
- mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0);
- val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask;
+ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+ mask = vcpu->arch.irqs_pending_mask[0];
+ if (mask) {
+ vcpu->arch.irqs_pending_mask[0] = 0;
+ val = vcpu->arch.irqs_pending[0] & mask;
csr->hvip &= ~mask;
csr->hvip |= val;
@@ -363,11 +370,13 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
/* Flush AIA high interrupts */
kvm_riscv_vcpu_aia_flush_interrupts(vcpu);
+ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
}
void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
{
unsigned long hvip;
+ unsigned long flags;
struct kvm_vcpu_arch *v = &vcpu->arch;
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
@@ -376,27 +385,29 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
/* Sync-up HVIP.VSSIP bit changes does by Guest */
hvip = ncsr_read(CSR_HVIP);
+ raw_spin_lock_irqsave(&v->irqs_pending_lock, flags);
if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) {
if (hvip & (1UL << IRQ_VS_SOFT)) {
- if (!test_and_set_bit(IRQ_VS_SOFT,
- v->irqs_pending_mask))
- set_bit(IRQ_VS_SOFT, v->irqs_pending);
+ if (!__test_and_set_bit(IRQ_VS_SOFT,
+ v->irqs_pending_mask))
+ __set_bit(IRQ_VS_SOFT, v->irqs_pending);
} else {
- if (!test_and_set_bit(IRQ_VS_SOFT,
- v->irqs_pending_mask))
- clear_bit(IRQ_VS_SOFT, v->irqs_pending);
+ if (!__test_and_set_bit(IRQ_VS_SOFT,
+ v->irqs_pending_mask))
+ __clear_bit(IRQ_VS_SOFT, v->irqs_pending);
}
}
/* Sync up the HVIP.LCOFIP bit changes (only clear) by the guest */
if ((csr->hvip ^ hvip) & (1UL << IRQ_PMU_OVF)) {
if (!(hvip & (1UL << IRQ_PMU_OVF)) &&
- !test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask))
- clear_bit(IRQ_PMU_OVF, v->irqs_pending);
+ !__test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask))
+ __clear_bit(IRQ_PMU_OVF, v->irqs_pending);
}
/* Sync-up AIA high interrupts */
kvm_riscv_vcpu_aia_sync_interrupts(vcpu);
+ raw_spin_unlock_irqrestore(&v->irqs_pending_lock, flags);
/* Sync-up timer CSRs */
kvm_riscv_vcpu_timer_sync(vcpu);
@@ -404,6 +415,8 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
{
+ unsigned long flags;
+
/*
* We only allow VS-mode software, timer, and external
* interrupts when irq is one of the local interrupts
@@ -416,9 +429,10 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
irq != IRQ_PMU_OVF)
return -EINVAL;
- set_bit(irq, vcpu->arch.irqs_pending);
- smp_mb__before_atomic();
- set_bit(irq, vcpu->arch.irqs_pending_mask);
+ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+ __set_bit(irq, vcpu->arch.irqs_pending);
+ __set_bit(irq, vcpu->arch.irqs_pending_mask);
+ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
kvm_vcpu_kick(vcpu);
@@ -427,6 +441,8 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
{
+ unsigned long flags;
+
/*
* We only allow VS-mode software, timer, counter overflow and external
* interrupts when irq is one of the local interrupts
@@ -439,26 +455,33 @@ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
irq != IRQ_PMU_OVF)
return -EINVAL;
- clear_bit(irq, vcpu->arch.irqs_pending);
- smp_mb__before_atomic();
- set_bit(irq, vcpu->arch.irqs_pending_mask);
+ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+ __clear_bit(irq, vcpu->arch.irqs_pending);
+ __set_bit(irq, vcpu->arch.irqs_pending_mask);
+ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
return 0;
}
bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
{
+ unsigned long flags;
unsigned long ie;
+ bool ret;
+ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
<< VSIP_TO_HVIP_SHIFT) & (unsigned long)mask;
ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK &
(unsigned long)mask;
- if (READ_ONCE(vcpu->arch.irqs_pending[0]) & ie)
- return true;
+ ret = vcpu->arch.irqs_pending[0] & ie;
/* Check AIA high interrupts */
- return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
+ if (!ret)
+ ret = kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
+ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+
+ return ret;
}
void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)
diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
index bb920e8923c930..cba3682944b694 100644
--- a/arch/riscv/kvm/vcpu_onereg.c
+++ b/arch/riscv/kvm/vcpu_onereg.c
@@ -298,6 +298,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
{
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
unsigned long regs_max = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);
+ unsigned long flags;
if (reg_num >= regs_max)
return -ENOENT;
@@ -309,10 +310,14 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
reg_val <<= VSIP_TO_HVIP_SHIFT;
}
- ((unsigned long *)csr)[reg_num] = reg_val;
-
- if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
- WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0);
+ if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
+ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+ ((unsigned long *)csr)[reg_num] = reg_val;
+ vcpu->arch.irqs_pending_mask[0] = 0;
+ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+ } else {
+ ((unsigned long *)csr)[reg_num] = reg_val;
+ }
return 0;
}
|
| 3/2 | 2026/07/13 07:14 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 6474 output: 28 thoughts: 501 Thoughts: **Analyzing the RISC-V KVM Patch** Okay, so I'm looking at this patch for the RISC-V KVM implementation. It's a significant functional change, as it seems to be moving from a lockless approach using atomic bit operations for handling `irqs_pending` and `irqs_pending_mask` bitmaps to using a `raw_spinlock_t irqs_pending_lock` within `struct kvm_vcpu_arch`. This replaces the previous method of synchronization which used atomic bitops. That's interesting, and definitely warrants some serious fuzzing. My immediate concern is understanding the scope of this change and identifying the key functions affected. Let's see, it's modifying several files: `arch/riscv/include/asm/kvm_host.h`, `arch/riscv/kvm/aia.c`, `arch/riscv/kvm/vcpu.c`, and `arch/riscv/kvm/vcpu_onereg.c`. That gives me a good starting point. Now, let's identify those functions so they can be added to the `FocusSymbols` list. From `aia.c`, we've got `kvm_riscv_vcpu_aia_flush_interrupts`, `kvm_riscv_vcpu_aia_sync_interrupts`, `kvm_riscv_vcpu_aia_has_interrupts`, and `kvm_riscv_vcpu_aia_set_csr`. Next, from `vcpu.c`: `kvm_riscv_reset_vcpu`, `kvm_arch_vcpu_create`, `kvm_riscv_vcpu_flush_interrupts`, `kvm_riscv_vcpu_sync_interrupts`, `kvm_riscv_vcpu_set_interrupt`, `kvm_riscv_vcpu_unset_interrupt`, and `kvm_riscv_vcpu_has_interrupts`. Finally, from `vcpu_onereg.c`: `kvm_riscv_vcpu_general_set_csr`. Got it. Before I dig deeper into the code itself, I should check the Kconfig options required for this patch to be enabled. It's located in `arch/riscv/kvm/`, so I need to check the Kconfig files in `arch/riscv/` and `arch/riscv/kvm/` to determine the configuration dependencies. That'll be important for reproduction and fuzzing environment setup. |
| 4/2 | 2026/07/13 07:15 | tool | grepper |
0mArgs:{
"Expression": "config KVM",
"PathPrefix": "arch/riscv/"
}Results: {
"Output": "arch/riscv/kvm/Kconfig=18=if VIRTUALIZATION\narch/riscv/kvm/Kconfig-19-\narch/riscv/kvm/Kconfig:20:config KVM\narch/riscv/kvm/Kconfig-21-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n"
} |
| 5/2 | 2026/07/13 07:15 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7650 output: 31 thoughts: 120 Thoughts: **Analyzing the KVM Configuration for RISC-V Architecture** Okay, so the initial focus is on the `KVM` configuration. I need to quickly determine if this is the *only* configuration involved. Let me check for others that might be relevant. The patch mentions `#ifdef CONFIG_32BIT` within `arch/riscv/kvm/aia.c`. My initial reaction is that it might be tied to a 32-bit architecture. However, a closer look suggests that's not the case; it's just an `ifdef`. The 64-bit code has changes as well, so it's not exclusively for 32-bit. Thus, `CONFIG_32BIT` isn't a *requirement* for this patch. My next step is to examine the source files to understand the conditional compilation logic, in this case `arch/riscv/kvm/aia.c` and `arch/riscv/kvm/vcpu.c`. The aim here is to see what portions are actually affected by any potential conditional compilation and ensure full coverage is gained from the investigation. |
| 6/2 | 2026/07/13 07:15 | tool | grepper |
0mArgs:{
"Expression": "aia\\.o",
"PathPrefix": "arch/riscv/kvm/"
}Results: {
"Output": "arch/riscv/kvm/Makefile=10=obj-$(CONFIG_KVM) += kvm.o\n--\narch/riscv/kvm/Makefile-12-# Ordered alphabetically\narch/riscv/kvm/Makefile:13:kvm-y += aia.o\narch/riscv/kvm/Makefile-14-kvm-y += aia_aplic.o\n"
} |
| 7/2 | 2026/07/13 07:15 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 8144 output: 41 thoughts: 283 Thoughts: **Focusing on KVM Configuration and Interrupt Handling** Okay, so it looks like `KVM` is the only configuration I need to consider for this. Time to get laser-focused on the relevant functions. Let me filter those out to make this manageable. Alright, here's a working list: `kvm_riscv_vcpu_aia_flush_interrupts`, `kvm_riscv_vcpu_aia_sync_interrupts`, `kvm_riscv_vcpu_aia_has_interrupts`, `kvm_riscv_vcpu_aia_set_csr`, `kvm_riscv_reset_vcpu`, `kvm_arch_vcpu_create`, `kvm_riscv_vcpu_flush_interrupts`, `kvm_riscv_vcpu_sync_interrupts`, `kvm_riscv_vcpu_set_interrupt`, `kvm_riscv_vcpu_unset_interrupt`, `kvm_riscv_vcpu_has_interrupts`, and `kvm_riscv_vcpu_general_set_csr`. Now, I'm thinking some of these are probably hot paths, specifically, `kvm_riscv_vcpu_flush_interrupts`, `kvm_riscv_vcpu_sync_interrupts`, and `kvm_riscv_vcpu_has_interrupts` jump out immediately. These are the usual suspects for performance bottlenecks in a virtualized interrupt system. The next logical step is to check if these are invoked directly within the VM exit loop. That'll be a key indicator of their potential impact. |
| 8/2 | 2026/07/13 07:15 | tool | grepper |
0mArgs:{
"Expression": "kvm_riscv_vcpu_flush_interrupts",
"PathPrefix": "arch/riscv/kvm/"
}Results: {
"Output": "arch/riscv/kvm/vcpu.c=350=int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)\n--\narch/riscv/kvm/vcpu.c-354-\narch/riscv/kvm/vcpu.c:355:void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)\narch/riscv/kvm/vcpu.c-356-{\n--\narch/riscv/kvm/vcpu.c=853=int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)\n--\narch/riscv/kvm/vcpu.c-938-\t\t */\narch/riscv/kvm/vcpu.c:939:\t\tkvm_riscv_vcpu_flush_interrupts(vcpu);\narch/riscv/kvm/vcpu.c-940-\n--\narch/riscv/kvm/vcpu_onereg.c=273=static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu,\n--\narch/riscv/kvm/vcpu_onereg.c-285-\tif (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {\narch/riscv/kvm/vcpu_onereg.c:286:\t\tkvm_riscv_vcpu_flush_interrupts(vcpu);\narch/riscv/kvm/vcpu_onereg.c-287-\t\t*out_val = (csr-\u003ehvip \u003e\u003e VSIP_TO_HVIP_SHIFT) \u0026 VSIP_VALID_MASK;\n"
} |
| 9/2 | 2026/07/13 07:15 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 9272 output: 41 thoughts: 55 Thoughts: Okay, here's my take on those thoughts, framed as my own mental processing as an expert: **Investigating Interrupt Handling within the KVM/RISC-V Virtual Machine** Alright, let's see... So, from what I'm piecing together, based on how the code flows, it seems pretty clear that `kvm_riscv_vcpu_flush_interrupts` *definitely* gets called within `kvm_arch_vcpu_ioctl_run`. That's not entirely surprising, given the role of `ioctl_run` as the main loop. That makes sense for handling pending interrupts, preventing stale interrupts, and ensuring the VCPU operates cleanly. And, thinking about how interrupts are handled in this environment, I'm virtually certain `kvm_riscv_vcpu_sync_interrupts` is also likely called within that same `kvm_arch_vcpu_ioctl_run` function. It's the logical place to ensure that the VCPU's interrupt state is synchronized with the host, isn't it? Gotta make sure everything's in sync to avoid any weirdness with the guest. Gotta keep that interrupt pipeline clean! So, those two are probably a key part of the run loop interrupt processing strategy. |
| 10/2 | 2026/07/13 07:15 | tool | grepper |
0mArgs:{
"Expression": "kvm_riscv_vcpu_sync_interrupts",
"PathPrefix": "arch/riscv/kvm/"
}Results: {
"Output": "arch/riscv/kvm/vcpu.c=355=void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)\n--\narch/riscv/kvm/vcpu.c-375-\narch/riscv/kvm/vcpu.c:376:void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)\narch/riscv/kvm/vcpu.c-377-{\n--\narch/riscv/kvm/vcpu.c=853=int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)\n--\narch/riscv/kvm/vcpu.c-971-\t\t/* Syncup interrupts state with HW */\narch/riscv/kvm/vcpu.c:972:\t\tkvm_riscv_vcpu_sync_interrupts(vcpu);\narch/riscv/kvm/vcpu.c-973-\n"
} |
| 11/2 | 2026/07/13 07:15 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 9900 output: 41 thoughts: 55 Thoughts: Okay, here's my take on those hot paths related to RISC-V KVM interrupts. **Diving Deep into KVM RISC-V Interrupt Handling** Right, let's see, `kvm_riscv_vcpu_flush_interrupts` and `kvm_riscv_vcpu_sync_interrupts` are known performance bottlenecks – no surprises there, they're always going to be. They're central to interrupt delivery, so we're constantly optimizing those. But, I'm thinking, what about `kvm_riscv_vcpu_has_interrupts`? It is probably less of an issue, but maybe we have an opportunity to optimize that. We might be able to make some gains, even if they're small. It's the kind of thing that could contribute to a cumulative improvement overall. Always important to re-evaluate the low hanging fruit, even though it's less impactful than the big ones. Gotta make sure we're not spending too much time here, however. |
| 12/2 | 2026/07/13 07:15 | tool | grepper |
0mArgs:{
"Expression": "kvm_riscv_vcpu_has_interrupts",
"PathPrefix": "arch/riscv/kvm/"
}Results: {
"Output": "arch/riscv/kvm/vcpu.c=221=int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)\narch/riscv/kvm/vcpu.c-222-{\narch/riscv/kvm/vcpu.c:223:\treturn (kvm_riscv_vcpu_has_interrupts(vcpu, -1ULL) \u0026\u0026\narch/riscv/kvm/vcpu.c-224-\t\t!kvm_riscv_vcpu_stopped(vcpu) \u0026\u0026 !vcpu-\u003earch.pause);\n--\narch/riscv/kvm/vcpu.c=442=int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)\n--\narch/riscv/kvm/vcpu.c-465-\narch/riscv/kvm/vcpu.c:466:bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)\narch/riscv/kvm/vcpu.c-467-{\n--\narch/riscv/kvm/vcpu_timer.c=130=bool kvm_riscv_vcpu_timer_pending(struct kvm_vcpu *vcpu)\n--\narch/riscv/kvm/vcpu_timer.c-135-\tif (!kvm_riscv_delta_cycles2ns(t-\u003enext_cycles, gt, t) ||\narch/riscv/kvm/vcpu_timer.c:136:\t kvm_riscv_vcpu_has_interrupts(vcpu, 1UL \u003c\u003c IRQ_VS_TIMER))\narch/riscv/kvm/vcpu_timer.c-137-\t\treturn true;\n"
} |
| 13/2 | 2026/07/13 07:15 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 10677 output: 40 thoughts: 51 Thoughts: Okay, here's my take on those thoughts, framed as my own: **Analyzing Potential Bottlenecks in KVM/RISC-V Performance** Alright, I'm thinking about performance optimization within the RISC-V KVM implementation. I've been focusing on the critical paths, and `kvm_arch_vcpu_runnable` is definitely screaming out as a potential bottleneck. We're spending a lot of time there, so it demands careful scrutiny. But, I also need to broaden the focus. We shouldn't neglect other potentially high-frequency routines. Specifically, I should be looking at `kvm_riscv_vcpu_set_interrupt` and `kvm_riscv_vcpu_unset_interrupt`. Interrupt handling is fundamental, and if those functions are called frequently, they could easily become performance limiters. I need to profile and benchmark these areas as well, to get a holistic view of the performance landscape. There might be some low-hanging fruit in there. Gotta look everywhere. |
| 14/2 | 2026/07/13 07:16 | tool | grepper |
0mArgs:{
"Expression": "kvm_riscv_vcpu_set_interrupt",
"PathPrefix": "arch/riscv/kvm/"
}Results: {
"Output": "arch/riscv/kvm/aia_imsic.c=614=static void imsic_swfile_extirq_update(struct kvm_vcpu *vcpu)\n--\narch/riscv/kvm/aia_imsic.c-629-\t imsic_mrif_topei(mrif, imsic-\u003enr_eix, imsic-\u003enr_msis))\narch/riscv/kvm/aia_imsic.c:630:\t\tkvm_riscv_vcpu_set_interrupt(vcpu, IRQ_VS_EXT);\narch/riscv/kvm/aia_imsic.c-631-\telse\n--\narch/riscv/kvm/vcpu.c=249=long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,\n--\narch/riscv/kvm/vcpu.c-261-\t\tif (irq.irq == KVM_INTERRUPT_SET)\narch/riscv/kvm/vcpu.c:262:\t\t\treturn kvm_riscv_vcpu_set_interrupt(vcpu, IRQ_VS_EXT);\narch/riscv/kvm/vcpu.c-263-\t\telse\n--\narch/riscv/kvm/vcpu.c=376=void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)\n--\narch/riscv/kvm/vcpu.c-415-\narch/riscv/kvm/vcpu.c:416:int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)\narch/riscv/kvm/vcpu.c-417-{\n--\narch/riscv/kvm/vcpu_pmu.c=293=static void kvm_riscv_pmu_overflow(struct perf_event *perf_event,\n--\narch/riscv/kvm/vcpu_pmu.c-328-\tset_bit(pmc-\u003eidx, kvpmu-\u003epmc_overflown);\narch/riscv/kvm/vcpu_pmu.c:329:\tkvm_riscv_vcpu_set_interrupt(vcpu, IRQ_PMU_OVF);\narch/riscv/kvm/vcpu_pmu.c-330-\n--\narch/riscv/kvm/vcpu_sbi_replace.c=45=static int kvm_sbi_ext_ipi_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,\n--\narch/riscv/kvm/vcpu_sbi_replace.c-71-\t\t}\narch/riscv/kvm/vcpu_sbi_replace.c:72:\t\tret = kvm_riscv_vcpu_set_interrupt(tmp, IRQ_VS_SOFT);\narch/riscv/kvm/vcpu_sbi_replace.c-73-\t\tif (ret \u003c 0)\n--\narch/riscv/kvm/vcpu_sbi_v01.c=16=static int kvm_sbi_ext_v01_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,\n--\narch/riscv/kvm/vcpu_sbi_v01.c-59-\t\t\t\tcontinue;\narch/riscv/kvm/vcpu_sbi_v01.c:60:\t\t\tret = kvm_riscv_vcpu_set_interrupt(rvcpu, IRQ_VS_SOFT);\narch/riscv/kvm/vcpu_sbi_v01.c-61-\t\t\tif (ret \u003c 0)\n--\narch/riscv/kvm/vcpu_timer.c=43=static enum hrtimer_restart kvm_riscv_vcpu_hrtimer_expired(struct hrtimer *h)\n--\narch/riscv/kvm/vcpu_timer.c-56-\tt-\u003enext_set = false;\narch/riscv/kvm/vcpu_timer.c:57:\tkvm_riscv_vcpu_set_interrupt(vcpu, IRQ_VS_TIMER);\narch/riscv/kvm/vcpu_timer.c-58-\n"
} |
| 15/2 | 2026/07/13 07:16 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 12064 output: 40 thoughts: 49 Thoughts: Okay, here's my interpretation of those thoughts, framed as my own: **Considering Interrupt Handling in the RISC-V KVM Implementation** Right, `kvm_riscv_vcpu_set_interrupt` is the function that gets called, as I recall, from a variety of sources within the KVM/RISC-V implementation – ioctl calls, timer events, inter-processor interrupts (IPIs), even PMU overflow events, among others. That makes sense, it’s the primary mechanism to inject an interrupt into a vCPU. But wait a second... If we have a clear function to *set* an interrupt, what's the corresponding function to *unset* an interrupt? Where and when does `kvm_riscv_vcpu_unset_interrupt` come into play, or is there an alternative mechanism for clearing an interrupt that I should keep in mind? I need to think this through. I need to understand the full interrupt lifecycle management. Is it handled implicitly through other mechanisms, like when the vCPU acknowledges the interrupt, or do we have an explicit function specifically for de-asserting an interrupt? I should probably review the interrupt handling code path and control flow more carefully to be sure I understand this. |
| 16/2 | 2026/07/13 07:16 | tool | grepper |
0mArgs:{
"Expression": "kvm_riscv_vcpu_unset_interrupt",
"PathPrefix": "arch/riscv/kvm/"
}Results: {
"Output": "arch/riscv/kvm/aia_imsic.c=614=static void imsic_swfile_extirq_update(struct kvm_vcpu *vcpu)\n--\narch/riscv/kvm/aia_imsic.c-631-\telse\narch/riscv/kvm/aia_imsic.c:632:\t\tkvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_EXT);\narch/riscv/kvm/aia_imsic.c-633-\n--\narch/riscv/kvm/aia_imsic.c=637=static void imsic_swfile_read(struct kvm_vcpu *vcpu, bool clear,\n--\narch/riscv/kvm/aia_imsic.c-651-\t\tmemset(imsic-\u003eswfile, 0, sizeof(*imsic-\u003eswfile));\narch/riscv/kvm/aia_imsic.c:652:\t\tkvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_EXT);\narch/riscv/kvm/aia_imsic.c-653-\t}\n--\narch/riscv/kvm/vcpu.c=249=long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,\n--\narch/riscv/kvm/vcpu.c-263-\t\telse\narch/riscv/kvm/vcpu.c:264:\t\t\treturn kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_EXT);\narch/riscv/kvm/vcpu.c-265-\t}\n--\narch/riscv/kvm/vcpu.c=416=int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)\n--\narch/riscv/kvm/vcpu.c-441-\narch/riscv/kvm/vcpu.c:442:int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)\narch/riscv/kvm/vcpu.c-443-{\n--\narch/riscv/kvm/vcpu_sbi_v01.c=16=static int kvm_sbi_ext_v01_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,\n--\narch/riscv/kvm/vcpu_sbi_v01.c-45-\tcase SBI_EXT_0_1_CLEAR_IPI:\narch/riscv/kvm/vcpu_sbi_v01.c:46:\t\tret = kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_SOFT);\narch/riscv/kvm/vcpu_sbi_v01.c-47-\t\tbreak;\n--\narch/riscv/kvm/vcpu_timer.c=85=static int kvm_riscv_vcpu_update_hrtimer(struct kvm_vcpu *vcpu, u64 ncycles)\n--\narch/riscv/kvm/vcpu_timer.c-93-\narch/riscv/kvm/vcpu_timer.c:94:\tkvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_TIMER);\narch/riscv/kvm/vcpu_timer.c-95-\n"
} |
| 17/2 | 2026/07/13 07:16 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13290 output: 42 thoughts: 94 Thoughts: Okay, here's my assessment of the situation: **Targeting Interrupt Handling & CSR Updates in the RISC-V KVM Implementation** Right, so I'm thinking about the most relevant functions for this particular issue. From my experience with the KVM RISC-V code, `kvm_riscv_vcpu_set_interrupt` and `kvm_riscv_vcpu_unset_interrupt` are definitely strong contenders for investigation. They're central to how interrupts are managed within the virtual CPU context. I need to understand what's happening there. Beyond interrupt setting and unsetting, I should look at how CSR updates are implemented. That brings me to `kvm_riscv_vcpu_aia_set_csr` and `kvm_riscv_vcpu_general_set_csr`. These seem like they could be very important, too. I need to check how the AIA-related CSRs are being handled. These could be involved, specifically the AIA CSRs. Let's start with `kvm_riscv_vcpu_aia_set_csr`. I need to dig into that function and trace the data flow; that is where I'll begin. |
| 18/2 | 2026/07/13 07:16 | tool | grepper |
0mArgs:{
"Expression": "kvm_riscv_vcpu_aia_set_csr",
"PathPrefix": "arch/riscv/kvm/"
}Results: {
"Output": "arch/riscv/kvm/aia.c=190=int kvm_riscv_vcpu_aia_get_csr(struct kvm_vcpu *vcpu,\n--\narch/riscv/kvm/aia.c-210-\narch/riscv/kvm/aia.c:211:int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,\narch/riscv/kvm/aia.c-212-\t\t\t unsigned long reg_num,\n--\narch/riscv/kvm/vcpu_onereg.c=402=static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,\n--\narch/riscv/kvm/vcpu_onereg.c-425-\tcase KVM_REG_RISCV_CSR_AIA:\narch/riscv/kvm/vcpu_onereg.c:426:\t\trc = kvm_riscv_vcpu_aia_set_csr(vcpu, reg_num, reg_val);\narch/riscv/kvm/vcpu_onereg.c-427-\t\tbreak;\n"
} |
| 19/2 | 2026/07/13 07:16 | llm | patch-evaluator |
10mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13987 output: 42 thoughts: 644 Thoughts: **My Fuzzing Target Selection for RISC-V KVM Interrupt Handling** Okay, so I'm thinking about fuzzing this RISC-V KVM interrupt handling change, which involves the introduction of a spinlock to replace lockless atomic bit operations. The goal is to focus on functions that directly interact with the newly added lock and modified bitmaps. Based on the code, `kvm_riscv_vcpu_general_set_csr` is called from `kvm_riscv_vcpu_set_reg_csr`, which, conveniently, is triggered by the `KVM_SET_ONE_REG` ioctl. This ioctl path is ideal for fuzzing. Let's break down my target selection process. First, I want to identify the key functions that are accessible and affected by the changes. I've pinpointed a few: * `kvm_riscv_vcpu_aia_set_csr` * `kvm_riscv_vcpu_general_set_csr` * `kvm_riscv_vcpu_set_interrupt` * `kvm_riscv_vcpu_unset_interrupt` These aren't the absolute hottest paths, like the VM exit loop, which is a key consideration. I want to avoid functions that are part of the core VM exit loop to get a broader test distribution. Now, I considered `kvm_riscv_vcpu_flush_interrupts` and `kvm_riscv_vcpu_sync_interrupts`, but those are right in the VM exit loop, and I want to avoid those. Similarly, `kvm_riscv_vcpu_aia_flush_interrupts` and `kvm_riscv_vcpu_aia_sync_interrupts` would be invoked on hot paths, so these are off the list too. So, in summary, I'm confident that the following are the best targets for fuzzing, given that they set/unset interrupts and CSRs: * `kvm_riscv_vcpu_aia_set_csr` * `kvm_riscv_vcpu_general_set_csr` * `kvm_riscv_vcpu_set_interrupt` * `kvm_riscv_vcpu_unset_interrupt` Next, I need to confirm the build configuration. Looking into the Kconfig, `CONFIG_KVM` is indeed the primary, and only, configuration needed for this RISC-V KVM code. Given that the code is in `arch/riscv/kvm/` I'm confident about this. Finally, let me just verify `kvm_riscv_vcpu_general_set_csr` is the correct name. |
| 20/2 | 2026/07/13 07:27 | tool | grepper |
0mArgs:{
"Expression": "kvm_riscv_vcpu_general_set_csr",
"PathPrefix": "arch/riscv/kvm/"
}Results: {
"Output": "arch/riscv/kvm/vcpu_onereg.c=273=static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu,\n--\narch/riscv/kvm/vcpu_onereg.c-294-\narch/riscv/kvm/vcpu_onereg.c:295:static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,\narch/riscv/kvm/vcpu_onereg.c-296-\t\t\t\t\t unsigned long reg_num,\n--\narch/riscv/kvm/vcpu_onereg.c=402=static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,\n--\narch/riscv/kvm/vcpu_onereg.c-422-\tcase KVM_REG_RISCV_CSR_GENERAL:\narch/riscv/kvm/vcpu_onereg.c:423:\t\trc = kvm_riscv_vcpu_general_set_csr(vcpu, reg_num, reg_val);\narch/riscv/kvm/vcpu_onereg.c-424-\t\tbreak;\n"
} |
| 21/2 | 2026/07/13 07:27 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15594 output: 172 thoughts: 15 Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience: **Internal Monologue: Affirmation and Procedural Refinement** Yes, that's exactly what I'm seeing too, the analysis is solid. The conclusion reached is correct, and I agree with the implied direction. Now, let's move forward efficiently. Forget generic naming conventions; the next step calls for a clear identifier for this step. The action here involves recording the key outcomes of the process, a natural designation would be to call it `set-results`. It will be clear to me, and should be clear for anyone else looking into this code, that this identifier represents the step where the significant derived outputs are captured. |
| 22/2 | 2026/07/13 07:27 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"KVM"
],
"FocusSymbols": [
"kvm_riscv_vcpu_aia_set_csr",
"kvm_riscv_vcpu_general_set_csr",
"kvm_riscv_vcpu_set_interrupt",
"kvm_riscv_vcpu_unset_interrupt"
],
"Reasoning": "The patch replaces lockless atomic bitops with a raw spinlock for tracking pending VCPU interrupts in RISC-V KVM. This is a functional change that affects interrupt injection and synchronization. Fuzzing should focus on functions that set/unset interrupts and CSRs, which are accessible via KVM ioctls and not on the absolute hottest VM exit path.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"KVM"
],
"FocusSymbols": [
"kvm_riscv_vcpu_aia_set_csr",
"kvm_riscv_vcpu_general_set_csr",
"kvm_riscv_vcpu_set_interrupt",
"kvm_riscv_vcpu_unset_interrupt"
],
"Reasoning": "The patch replaces lockless atomic bitops with a raw spinlock for tracking pending VCPU interrupts in RISC-V KVM. This is a functional change that affects interrupt injection and synchronization. Fuzzing should focus on functions that set/unset interrupts and CSRs, which are accessible via KVM ioctls and not on the absolute hottest VM exit path.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|