diff --git a/hypervisor/arch/riscv/Makefile b/hypervisor/arch/riscv/Makefile index 6a3d33c51..d3a033a9e 100644 --- a/hypervisor/arch/riscv/Makefile +++ b/hypervisor/arch/riscv/Makefile @@ -71,6 +71,7 @@ VP_C_SRCS += arch/riscv/guest/guest_memory.c VP_C_SRCS += arch/riscv/guest/vcpu.c VP_C_SRCS += arch/riscv/guest/vm.c VP_C_SRCS += arch/riscv/guest/vcpu_exit.c +VP_C_SRCS += arch/riscv/guest/virq.c VP_C_SRCS += arch/riscv/guest/vsbi.c VP_C_SRCS += arch/riscv/guest/vsbi/vsbi_base.c VP_C_SRCS += arch/riscv/guest/vsbi/vsbi_hsm.c diff --git a/hypervisor/arch/riscv/guest/vcpu.c b/hypervisor/arch/riscv/guest/vcpu.c index 2acd21895..2f600d2b0 100644 --- a/hypervisor/arch/riscv/guest/vcpu.c +++ b/hypervisor/arch/riscv/guest/vcpu.c @@ -18,6 +18,7 @@ #include #include #include +#include void vcpu_set_epc(struct acrn_vcpu *vcpu, uint64_t val) { @@ -97,12 +98,11 @@ int32_t riscv_process_vcpu_requests(struct acrn_vcpu *vcpu) int32_t ret = 0; if (vcpu_has_pending_request(vcpu)) { - /* - * To add new request processing, add the following: - * if (vcpu_take_request(vcpu, ARCH_SPECIFIC_REQUEST_MACRO)) { - * do_something(); - * } - */ + if (vcpu_take_request(vcpu, RISCV_VCPU_REQUEST_EXCEPTION)) { + vcpu_set_trap(vcpu, &vcpu->arch.trap); + memset(&vcpu->arch.trap, 0, sizeof(struct riscv_vcpu_trap_info)); + vcpu->arch.trap.cause = EXCEPTION_INVALID; + } } return ret; @@ -170,10 +170,13 @@ void arch_reset_vcpu(struct acrn_vcpu *vcpu) struct cpu_regs *regs = &(vcpu->arch.regs); struct riscv_vcpu_host_ctx *hctx = &(vcpu->arch.hctx); struct riscv_vcpu_guest_ctx *gctx = &(vcpu->arch.gctx); + struct riscv_vcpu_trap_info *trap = &(vcpu->arch.trap); memset(regs, 0, sizeof(struct cpu_regs)); memset(hctx, 0, sizeof(struct riscv_vcpu_host_ctx)); memset(gctx, 0, sizeof(struct riscv_vcpu_guest_ctx)); + memset(trap, 0, sizeof(struct riscv_vcpu_trap_info)); + trap->cause = EXCEPTION_INVALID; } void arch_context_switch_out(struct thread_object *prev) diff --git a/hypervisor/arch/riscv/guest/virq.c b/hypervisor/arch/riscv/guest/virq.c new file mode 100644 index 000000000..e69523f34 --- /dev/null +++ b/hypervisor/arch/riscv/guest/virq.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2025 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +/** + * @brief Inject a trap to VS-mode. + * + * This function handles the injection of a trap to VS-mode. The trap + * can be originated in the context of VS-mode or VU-mode. + * + * @param vcpu Pointer to vCPU. + * @param trap Pointer to the structure containing trap information + * (tval, epc, cause). + */ +void vcpu_set_trap(struct acrn_vcpu *vcpu, + struct riscv_vcpu_trap_info *trap) +{ + uint64_t vsstatus; + + /* Get VS-mode SSTATUS CSR */ + vsstatus = cpu_csr_read(CSR_VSSTATUS); + + /* Update SPP for VS-mode */ + vsstatus &= ~SSTATUS_SPP; + if (vcpu->arch.regs.status & SSTATUS_SPP) + vsstatus |= SSTATUS_SPP; + + /* Update SPIE for VS-mode */ + vsstatus &= ~SSTATUS_SPIE; + if (vsstatus & SSTATUS_SIE) + vsstatus |= SSTATUS_SPIE; + + /* Clear SIE for VS-mode */ + vsstatus &= ~SSTATUS_SIE; + + /* Update VS-mode SSTATUS CSR */ + cpu_csr_write(CSR_VSSTATUS, vsstatus); + + /* Update VS-mode exception info */ + cpu_csr_write(CSR_VSTVAL, trap->tval); + cpu_csr_write(CSR_VSEPC, trap->epc); + cpu_csr_write(CSR_VSCAUSE, trap->cause); + + /* Set SEPC to VS-mode exception vector base */ + vcpu->arch.regs.epc = cpu_csr_read(CSR_VSTVEC) & ~0x3UL; + + /* Set SPP to VS-mode */ + vcpu->arch.regs.status |= SSTATUS_SPP; +} + +/** + * @brief Queue an exception for a vCPU. + * + * Queues an exception for the specified vCPU. If an exception is already + * pending, it will be overwritten and a warning will be logged. Nested + * exceptions and exception prioritization are not supported. + * + * @param vcpu Pointer to the target acrn_vcpu structure. + * @param trap Pointer to the riscv_vcpu_trap_info structure with exception + * details. + * + * @note No action is taken if @p trap is NULL. + * @note This function is NOT thread-safe and is only expected to be called + * in the vcpu_thread/vcpu_trap_handler specified by vcpu. + */ +void vcpu_queue_exception(struct acrn_vcpu *vcpu, + struct riscv_vcpu_trap_info *trap) +{ + struct acrn_vcpu_arch *arch = &vcpu->arch; + + if (trap) { + /* + * Nested exceptions and exception priority are not supported. + * If an exception is pending injection, it will be overwritten + * by any new exception. + */ + if (arch->trap.cause != EXCEPTION_INVALID) { + pr_err("nested exception happened, prev excp = 0x%lx", + arch->trap.cause); + } + + arch->trap = *trap; + vcpu_make_request(vcpu, RISCV_VCPU_REQUEST_EXCEPTION); + } +} \ No newline at end of file diff --git a/hypervisor/include/arch/riscv/asm/guest/vcpu.h b/hypervisor/include/arch/riscv/asm/guest/vcpu.h index a95024432..6f3eb3d7d 100644 --- a/hypervisor/include/arch/riscv/asm/guest/vcpu.h +++ b/hypervisor/include/arch/riscv/asm/guest/vcpu.h @@ -12,6 +12,8 @@ #ifndef ASSEMBLER +#define RISCV_VCPU_REQUEST_EXCEPTION 0U + struct riscv_vcpu_guest_ctx { uint64_t vsstatus; uint64_t vsie; @@ -50,6 +52,12 @@ struct riscv_vcpu_host_ctx { uint64_t hip; }; +struct riscv_vcpu_trap_info { + uint64_t epc; + uint64_t cause; + uint64_t tval; +}; + struct acrn_vcpu_arch { /* This have to be the first member of acrn_vcpu_arch */ struct cpu_regs regs; @@ -57,6 +65,7 @@ struct acrn_vcpu_arch { struct riscv_vcpu_guest_ctx gctx; struct riscv_vcpu_host_ctx hctx; + struct riscv_vcpu_trap_info trap; } __aligned(PAGE_SIZE); struct acrn_vcpu; diff --git a/hypervisor/include/arch/riscv/asm/guest/virq.h b/hypervisor/include/arch/riscv/asm/guest/virq.h new file mode 100644 index 000000000..2a48e31b0 --- /dev/null +++ b/hypervisor/include/arch/riscv/asm/guest/virq.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2025 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ARCH_RISCV_GUEST_VIRQ_H +#define ARCH_RISCV_GUEST_VIRQ_H + +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); + +#endif /* ARCH_RISCV_GUEST_VIRQ_H */ diff --git a/hypervisor/include/arch/riscv/asm/irq.h b/hypervisor/include/arch/riscv/asm/irq.h index 99c439552..938d0de55 100644 --- a/hypervisor/include/arch/riscv/asm/irq.h +++ b/hypervisor/include/arch/riscv/asm/irq.h @@ -13,6 +13,7 @@ #include #define IPI_NOTIFY_CPU 0U +#define EXCEPTION_INVALID 0x7fffffffffffffffUL /* CPU-local interrupt count (room for standard causes) */ #define IRQ_NUM_CPU_DOMAIN 16U