hv: riscv: add virtual interrupt injection support

Add virtual interrupt injection infrastructure for RISC-V hypervisor.
Implement vcpu_set_intr() and vcpu_clear_intr() to manage virtual
interrupt pending state by updating irqs_pending bitmap.
Add vcpu_inject_pending_intr() to inject pending interrupts into
VS-mode by updating HVIP CSR with atomic operations.

Tracked-On: #8844
Signed-off-by: Jian Jun Chen <jian.jun.chen@intel.com>
Acked-by: Wang Yu1 <yu1.wang@intel.com>
This commit is contained in:
Jian Jun Chen
2025-11-05 10:07:13 +08:00
committed by acrnsi-robot
parent b3fa6bbced
commit 75a932eeab
4 changed files with 76 additions and 1 deletions

View File

@@ -103,6 +103,8 @@ int32_t riscv_process_vcpu_requests(struct acrn_vcpu *vcpu)
memset(&vcpu->arch.trap, 0, sizeof(struct riscv_vcpu_trap_info));
vcpu->arch.trap.cause = EXCEPTION_INVALID;
}
vcpu_inject_pending_intr(vcpu);
}
return ret;
@@ -177,6 +179,8 @@ void arch_reset_vcpu(struct acrn_vcpu *vcpu)
memset(gctx, 0, sizeof(struct riscv_vcpu_guest_ctx));
memset(trap, 0, sizeof(struct riscv_vcpu_trap_info));
trap->cause = EXCEPTION_INVALID;
vcpu->arch.irqs_pending = 0UL;
vcpu->arch.irqs_pending_mask = 0UL;
}
void arch_context_switch_out(struct thread_object *prev)

View File

@@ -6,6 +6,7 @@
#include <types.h>
#include <vcpu.h>
#include <atomic.h>
#include <logmsg.h>
#include <asm/irq.h>
@@ -89,4 +90,66 @@ void vcpu_queue_exception(struct acrn_vcpu *vcpu,
arch->trap = *trap;
vcpu_make_request(vcpu, RISCV_VCPU_REQUEST_EXCEPTION);
}
}
}
int32_t vcpu_set_intr(struct acrn_vcpu *vcpu, uint32_t hwirq)
{
struct acrn_vcpu_arch *arch = &vcpu->arch;
int32_t ret = -1;
/* HVIP is a WARL CSR */
if (hwirq < BITS_PER_LONG) {
bitmap_set(hwirq, &arch->irqs_pending);
bitmap_set(hwirq, &arch->irqs_pending_mask);
vcpu_make_request(vcpu, RISCV_VCPU_REQUEST_EVENT);
signal_event(&vcpu->events[RISCV_VCPU_EVENT_VIRTUAL_INTERRUPT]);
ret = 0;
}
return ret;
}
int32_t vcpu_clear_intr(struct acrn_vcpu *vcpu, uint32_t hwirq)
{
struct acrn_vcpu_arch *arch = &vcpu->arch;
int32_t ret = -1;
/* HVIP is a WARL CSR */
if (hwirq < BITS_PER_LONG) {
bitmap_clear(hwirq, &arch->irqs_pending);
bitmap_set(hwirq, &arch->irqs_pending_mask);
vcpu_make_request(vcpu, RISCV_VCPU_REQUEST_EVENT);
ret = 0;
}
return ret;
}
bool vcpu_inject_pending_intr(struct acrn_vcpu *vcpu)
{
struct acrn_vcpu_arch *arch = &vcpu->arch;
uint64_t hvip, mask, val;
bool injected = false;
if (vcpu_take_request(vcpu, RISCV_VCPU_REQUEST_EVENT)) {
/*
* Only arch->irqs_pending_mask is cleared here;
* arch->irqs_pending remains unchanged.
* vcpu_set_intr/vcpu_clear_intr update individual bits of
* arch->irqs_pending as needed.
*
* Note: arch->irqs_pending does not reflect the actual
* VS-mode pending interrupt status, as it is not synchronized
* with hardware. This approach is simple but requires caution.
*/
mask = atomic_readandclear64(&arch->irqs_pending_mask);
val = arch->irqs_pending & mask;
hvip = cpu_csr_read(CSR_HVIP);
hvip &= ~mask;
hvip |= val;
cpu_csr_write(CSR_HVIP, hvip);
injected = true;
}
return injected;
}

View File

@@ -13,6 +13,9 @@
#ifndef ASSEMBLER
#define RISCV_VCPU_REQUEST_EXCEPTION 0U
#define RISCV_VCPU_REQUEST_EVENT 1U
#define RISCV_VCPU_EVENT_VIRTUAL_INTERRUPT 0U
struct riscv_vcpu_guest_ctx {
uint64_t vsstatus;
@@ -66,6 +69,8 @@ struct acrn_vcpu_arch {
struct riscv_vcpu_host_ctx hctx;
struct riscv_vcpu_trap_info trap;
uint64_t irqs_pending;
uint64_t irqs_pending_mask;
} __aligned(PAGE_SIZE);
struct acrn_vcpu;

View File

@@ -9,5 +9,8 @@
void vcpu_set_trap(struct acrn_vcpu *vcpu, struct riscv_vcpu_trap_info *trap);
void vcpu_queue_exception(struct acrn_vcpu *vcpu, struct riscv_vcpu_trap_info *trap);
int32_t vcpu_set_intr(struct acrn_vcpu *vcpu, uint32_t hwirq);
int32_t vcpu_clear_intr(struct acrn_vcpu *vcpu, uint32_t hwirq);
bool vcpu_inject_pending_intr(struct acrn_vcpu *vcpu);
#endif /* ARCH_RISCV_GUEST_VIRQ_H */