Files
acrn-hypervisor/hypervisor/arch/riscv/trap.c
Yifan Liu 8c2e8a6b5d hv: riscv: Add initial vcpu and vcpu exit implementation
Unlike x86 which explicitly distinguishes guest traps and host traps (VM
exits vs. IDT trap gates), risc-v unifies them to a single trap gate
with bits in multiple CSRs representing the privilege mode before the
trap. This commit follows this design.

Due to this change the arch_vcpu_thread in risc-v was basically
abandoned, and used only as a first-time entry point to guest, with the
rest of the original x86 arch_vcpu_thread being re-implemented following
above single-entry design.

Save/restore routine is also being re-implemented to account for
both hs-mode traps and v-mode traps. sscratch is used to mark the place
where the context is being saved to/restored from. When sscratch is
zero at the time of the trap, the context is saved into host stack.
When sscratch is non-zero, the context is saved to vcpu->arch.regs
(similar for restore).

Tracked-On: #8841
Signed-off-by: Yifan Liu <yifan1.liu@intel.com>
Signed-off-by: Haicheng Li <haicheng.li@intel.com>
Acked-by: Wang Yu1 <yu1.wang@intel.com>
2025-11-14 10:44:41 +08:00

101 lines
2.1 KiB
C

/*
* Copyright (C) 2023-2025 Intel Corporation.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* Authors:
* Haicheng Li <haicheng.li@intel.com>
*/
#include <asm/csr.h>
#include <asm/trap.h>
#include <irq.h>
#include <vcpu.h>
#include <cpu.h>
#include <logmsg.h>
#include <notify.h>
#include <debug/dump.h>
#include <asm/guest/vcpu_exit.h>
static void unexpected_trap_handler(const struct intr_excp_ctx *ctx)
{
pr_err("Unexpected S mode trap 0x%lx\n", ctx->regs.cause);
/* Halt the CPU */
cpu_dead();
}
/* IRQ 1 - Supervisor software interrupt handler */
void s_sw_irq_handler(__unused uint32_t irq, __unused void *data)
{
cpu_csr_clear(CSR_SIP, IP_IE_SSI);
handle_smp_call();
}
static void dispatch_exception(const struct intr_excp_ctx *ctx)
{
uint16_t pcpu_id = get_pcpu_id();
/* Dump exception context */
dump_exception(ctx, pcpu_id);
/* Halt the CPU */
cpu_dead();
}
static void riscv_do_irq(const char *name, uint32_t src_id)
{
uint32_t acrn_irq = riscv_domain_get_acrn_irq(name, src_id);
if (riscv_is_valid_acrn_irq(acrn_irq)) {
do_irq(acrn_irq);
} else {
pr_err("%s: Invalid IRQ %d\n", __func__, acrn_irq);
}
}
void dispatch_interrupt(const struct intr_excp_ctx *ctx)
{
uint64_t trap_cause = ctx->regs.cause & (~TRAP_CAUSE_INTERRUPT_BITMASK);
switch (trap_cause) {
case TRAP_CAUSE_IRQ_S_EXT:
/**
* Handle TRAP_CAUSE_IRQ_S_EXT as a special case.
* Because recursion shall be avoided to comply with FuSa.
*
* FIXME:
* Abstract PLIC/AIA as a irqchip that implement a get_irq API
* to do the mapping between irq_num and PLIC source id or AIA's MSI.
*
* Pseudo-code:
* while ((src_id = get_pending_irq_from_chip()) != NONE) {
* riscv_do_irq(RISCV_IRQD_PLIC, src_id);
* }
*
*/
unexpected_trap_handler(ctx);
break;
case TRAP_CAUSE_IRQ_S_SOFT:
/* intentional fall-through */
case TRAP_CAUSE_IRQ_S_TIMER:
riscv_do_irq(RISCV_IRQD_CPU, trap_cause);
break;
default:
unexpected_trap_handler(ctx);
break;
}
}
void dispatch_trap(const struct intr_excp_ctx *ctx)
{
if ((ctx->regs.cause & TRAP_CAUSE_INTERRUPT_BITMASK) == 0UL) {
dispatch_exception(ctx);
} else {
dispatch_interrupt(ctx);
}
}