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


Reply via email to