When entering guest in virtual-VS/VU mode (aka nested guest), check and inject nested virtual interrupt right before guest entry.
Signed-off-by: Anup Patel <[email protected]> --- arch/riscv/include/asm/kvm_vcpu_nested.h | 1 + arch/riscv/kvm/vcpu.c | 3 ++ arch/riscv/kvm/vcpu_nested.c | 49 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/arch/riscv/include/asm/kvm_vcpu_nested.h b/arch/riscv/include/asm/kvm_vcpu_nested.h index 6bfb67702610..6d9d252a378c 100644 --- a/arch/riscv/include/asm/kvm_vcpu_nested.h +++ b/arch/riscv/include/asm/kvm_vcpu_nested.h @@ -86,6 +86,7 @@ void kvm_riscv_vcpu_nested_set_virt(struct kvm_vcpu *vcpu, void kvm_riscv_vcpu_nested_trap_redirect(struct kvm_vcpu *vcpu, struct kvm_cpu_trap *trap, bool prev_priv); +void kvm_riscv_vcpu_nested_vsirq_process(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_nested_reset(struct kvm_vcpu *vcpu); int kvm_riscv_vcpu_nested_init(struct kvm_vcpu *vcpu); diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 077637aff9a2..f8c4344c2b1f 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -934,6 +934,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) */ kvm_riscv_local_tlb_sanitize(vcpu); + /* Check and inject nested virtual interrupts */ + kvm_riscv_vcpu_nested_vsirq_process(vcpu); + trace_kvm_entry(vcpu); guest_timing_enter_irqoff(); diff --git a/arch/riscv/kvm/vcpu_nested.c b/arch/riscv/kvm/vcpu_nested.c index 214206fc28bb..9b2b3369a232 100644 --- a/arch/riscv/kvm/vcpu_nested.c +++ b/arch/riscv/kvm/vcpu_nested.c @@ -172,6 +172,55 @@ void kvm_riscv_vcpu_nested_trap_redirect(struct kvm_vcpu *vcpu, false, prev_priv, gva); } +void kvm_riscv_vcpu_nested_vsirq_process(struct kvm_vcpu *vcpu) +{ + struct kvm_vcpu_nested *ns = &vcpu->arch.nested; + struct kvm_vcpu_nested_csr *nsc = &ns->csr; + struct kvm_cpu_trap trap; + unsigned long irqs; + bool next_spp; + int vsirq; + + /* Do nothing if nested virtualization is OFF */ + if (!ns->virt) + return; + + /* Determine the virtual-VS mode interrupt number */ + vsirq = 0; + irqs = nsc->hvip; + irqs &= nsc->vsie << VSIP_TO_HVIP_SHIFT; + irqs &= nsc->hideleg; + if (irqs & BIT(IRQ_VS_EXT)) + vsirq = IRQ_S_EXT; + else if (irqs & BIT(IRQ_VS_TIMER)) + vsirq = IRQ_S_TIMER; + else if (irqs & BIT(IRQ_VS_SOFT)) + vsirq = IRQ_S_SOFT; + if (vsirq <= 0) + return; + + /* + * Determine whether we are resuming in virtual-VS mode + * or virtual-VU mode. + */ + next_spp = !!(vcpu->arch.guest_context.sstatus & SR_SPP); + + /* + * If we are going to virtual-VS mode and interrupts are + * disabled then do nothing. + */ + if (next_spp && !(ncsr_read(CSR_VSSTATUS) & SR_SIE)) + return; + + /* Take virtual-VS mode interrupt */ + trap.scause = CAUSE_IRQ_FLAG | vsirq; + trap.sepc = vcpu->arch.guest_context.sepc; + trap.stval = 0; + trap.htval = 0; + trap.htinst = 0; + kvm_riscv_vcpu_trap_smode_redirect(vcpu, &trap, next_spp); +} + void kvm_riscv_vcpu_nested_reset(struct kvm_vcpu *vcpu) { struct kvm_vcpu_nested *ns = &vcpu->arch.nested; -- 2.43.0

