:p
atchew
Login
In TCG mode, helper_csrwr_estat() updates CSR.ESTAT.IS[1:0] (SWI0/SWI1) when the guest writes CSR_ESTAT, but it did not update the CPU interrupt request state. As a result, software interrupts could be observed as pending in CSR.ESTAT while no interrupt exception was taken. Update CPU_INTERRUPT_HARD after modifying CSR_ESTAT, matching the behavior of loongarch_cpu_set_irq(). The helper runs without the Big QEMU Lock (BQL), so take the BQL while calling cpu_interrupt(). Fixes: 5b1dedfe848b ("target/loongarch: Add LoongArch CSR instruction") Reported-by: Andrew S. Rightenburg <andrew@rail5.org> Signed-off-by: Andrew S. Rightenburg <andrew@rail5.org> --- target/loongarch/tcg/csr_helper.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/loongarch/tcg/csr_helper.c +++ b/target/loongarch/tcg/csr_helper.c @@ -XXX,XX +XXX,XX @@ target_ulong helper_csrrd_msgir(CPULoongArchState *env) target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val) { int64_t old_v = env->CSR_ESTAT; + CPUState *cs = env_cpu(env); /* Only IS[1:0] can be written */ env->CSR_ESTAT = deposit64(env->CSR_ESTAT, 0, 2, val); + /* + * Software interrupts (SWI0/SWI1) are latched in CSR.ESTAT.IS[1:0]. + * Make sure the CPU interrupt request state tracks the pending bits, + * matching the behavior of loongarch_cpu_set_irq(). + */ + if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) { + bql_lock(); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + bql_unlock(); + } + return old_v; } -- 2.47.3
In TCG mode, helper_csrwr_estat() updates CSR.ESTAT.IS[1:0] (SWI0/SWI1) when the guest writes CSR_ESTAT, but it did not update the CPU interrupt request state. As a result, software interrupts could be observed as pending in CSR.ESTAT while no interrupt exception was taken. Update CPU_INTERRUPT_HARD after modifying CSR_ESTAT, matching the behavior of loongarch_cpu_set_irq(). The helper runs without the Big QEMU Lock (BQL), so take the BQL while calling cpu_interrupt(). Fixes: 5b1dedfe848b ("target/loongarch: Add LoongArch CSR instruction") Reported-by: Andrew S. Rightenburg <andrew@rail5.org> Signed-off-by: Andrew S. Rightenburg <andrew@rail5.org> Signed-off-by: Bibo Mao <maobibo@loongson.cn> --- target/loongarch/cpu.c | 20 ++++++++++++++------ target/loongarch/internals.h | 1 + target/loongarch/tcg/csr_helper.c | 10 ++++++++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -XXX,XX +XXX,XX @@ static vaddr loongarch_cpu_get_pc(CPUState *cs) #ifndef CONFIG_USER_ONLY #include "hw/loongarch/virt.h" +void loongarch_cpu_update_irq(LoongArchCPU *cpu) +{ + CPULoongArchState *env = &cpu->env; + CPUState *cs = CPU(cpu); + CPUSysState *sys = env_sys(env); + + if (FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS)) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + void loongarch_cpu_set_irq(void *opaque, int irq, int level) { LoongArchCPU *cpu = opaque; CPULoongArchState *env = &cpu->env; - CPUState *cs = CPU(cpu); CPUSysState *sys = env_sys(env); if (irq < 0 || irq >= N_IRQS) { @@ -XXX,XX +XXX,XX @@ void loongarch_cpu_set_irq(void *opaque, int irq, int level) kvm_loongarch_set_interrupt(cpu, irq, level); } else if (tcg_enabled()) { sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, irq, 1, level != 0); - if (FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS)) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } + loongarch_cpu_update_irq(cpu); } } diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -XXX,XX +XXX,XX @@ void restore_fp_status(CPULoongArchState *env); #ifndef CONFIG_USER_ONLY extern const VMStateDescription vmstate_loongarch_cpu; +void loongarch_cpu_update_irq(LoongArchCPU *cpu); void loongarch_cpu_set_irq(void *opaque, int irq, int level); void loongarch_constant_timer_cb(void *opaque); diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/loongarch/tcg/csr_helper.c +++ b/target/loongarch/tcg/csr_helper.c @@ -XXX,XX +XXX,XX @@ target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val) /* Only IS[1:0] can be written */ sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, 0, 2, val); + /* + * Software interrupts (SWI0/SWI1) are latched in CSR.ESTAT.IS[1:0]. + * Make sure the CPU interrupt request state tracks the pending bits, + * matching the behavior of loongarch_cpu_set_irq(). + */ + if ((old_v ^ val) & 0x3) { + bql_lock(); + loongarch_cpu_update_irq(env_archcpu(env)); + bql_unlock(); + } return old_v; } base-commit: b428fe036233cbd15d37e3c027ab6ca4d3661a80 -- 2.54.0