diff --git a/hypervisor/arch/riscv/Makefile b/hypervisor/arch/riscv/Makefile index af4d7c2ac..9818967c4 100644 --- a/hypervisor/arch/riscv/Makefile +++ b/hypervisor/arch/riscv/Makefile @@ -38,6 +38,7 @@ ARCH_ASFLAGS += -march=rv64$(subst $() $(),_,$(RV_ISA)) # HV host assembly sources HOST_S_SRCS += arch/riscv/boot/cpu_entry.S +HOST_S_SRCS += arch/riscv/intr.S # HV host C sources HOST_C_SRCS += arch/riscv/init.c @@ -47,6 +48,7 @@ HOST_C_SRCS += arch/riscv/timer.c HOST_C_SRCS += arch/riscv/trap.c HOST_C_SRCS += arch/riscv/cpu.c HOST_C_SRCS += arch/riscv/logmsg.c +HOST_C_SRCS += arch/riscv/irq.c # Virtual platform assembly sources VP_S_SRCS += diff --git a/hypervisor/arch/riscv/intr.S b/hypervisor/arch/riscv/intr.S new file mode 100644 index 000000000..31daa57ce --- /dev/null +++ b/hypervisor/arch/riscv/intr.S @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023-2025 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Authors: + * Haicheng Li + */ + +#include +#include + + .text + + .balign 4 + .globl strap_handler +strap_handler: + /** Save CPU registers (`struct cpu_regs` within `struct intr_excp_ctx`) to stack. */ + cpu_ctx_save + + /** Pass sp in a0, as the argument to dispatch_trap(). */ + mv a0, sp + call dispatch_trap + + /** Restore CPU registers (`struct cpu_regs` within `struct intr_excp_ctx`) from stack. */ + cpu_ctx_restore + sret diff --git a/hypervisor/arch/riscv/irq.c b/hypervisor/arch/riscv/irq.c new file mode 100644 index 000000000..057009440 --- /dev/null +++ b/hypervisor/arch/riscv/irq.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023-2025 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Authors: + * Haicheng Li + */ + +#include +#include +#include + +static void init_interrupt_arch(__unused uint16_t pcpu_id) +{ + uint64_t addr = (uint64_t)&strap_handler; + + /* + * According to RISC-V Privileged Architecture + * 12.1.2. Supervisor Trap Vector Base Address (stvec) Register: + * The BASE field in stvec is a field that can hold any valid virtual + * or physical address, subject to the following alignment constraints: + * the address must be ``4-byte aligned``, and MODE settings other than + * Direct might impose additional alignment constraints on the + * value in the BASE field. + */ + cpu_csr_write(stvec, (addr | TRAP_VECTOR_MODE_DIRECT)); + + cpu_csr_write(sie, (IP_IE_SSI | IP_IE_STI | IP_IE_SEI)); +} + +/* + * TODO: + * This is the first step toward aligning with the common IRQ framework. + * For simplicity in this patchset, which focuses only on initialization, + * init_interrupt() is defined directly in arch/riscv/irq.c. + * + * Because interrupt handler registration via request_irq() is not yet + * implemented for RISC-V, fully aligning with the framework would require + * adding a few empty arch-specific functions as placeholders. + * + * Once request_irq() support is introduced, we can complete the integration + * with the common IRQ framework. + */ +void init_interrupt(uint16_t pcpu_id) +{ + init_interrupt_arch(pcpu_id); + + CPU_IRQ_ENABLE_ON_CONFIG(); +} diff --git a/hypervisor/arch/riscv/trap.c b/hypervisor/arch/riscv/trap.c index 5fb8f0259..9da25fa64 100644 --- a/hypervisor/arch/riscv/trap.c +++ b/hypervisor/arch/riscv/trap.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2024 Intel Corporation. All rights reserved. + * Copyright (C) 2023-2025 Intel Corporation. * * SPDX-License-Identifier: BSD-3-Clause * @@ -7,11 +7,33 @@ * Haicheng Li */ -#include +#include #include -#include "trap.h" +#include +#include +#include +#include +#include -#define MAX_IRQ_HANDLER 6 +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 */ +static void s_sw_irq_handler(void) +{ + cpu_csr_clear(sip, IP_IE_SSI); + handle_smp_call(); +} + +static void dispatch_exception(const struct intr_excp_ctx *ctx) +{ + unexpected_trap_handler(ctx); +} /* * FIXME: @@ -21,35 +43,35 @@ * code table. 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. */ -void sexpt_handler(void) +/** + * TODO: add support for handler registration via request_irq() and + * further adoption of the common IRQ framework. + */ +static void dispatch_interrupt(const struct intr_excp_ctx *ctx) { - /* TODO: add early_printk here to announce Panic */ - while(1) {}; -} + uint64_t trap_cause = ctx->regs.cause & (~TRAP_CAUSE_INTERRUPT_BITMASK); -static void stimer_handler(void) -{ - timer_irq_handler(); -} - -/* The irq handler array is not complete. So far, only timer handler is added. */ -static irq_handler_t sirq_handler[] = { - sexpt_handler, - sexpt_handler, - sexpt_handler, - sexpt_handler, - sexpt_handler, - stimer_handler, - sexpt_handler, -}; - -void sint_handler(int irq) -{ - if (irq < MAX_IRQ_HANDLER) { - sirq_handler[irq](); - } else { - sirq_handler[MAX_IRQ_HANDLER](); + switch (trap_cause) { + case TRAP_CAUSE_IRQ_S_SOFT: + s_sw_irq_handler(); + break; + case TRAP_CAUSE_IRQ_S_TIMER: + timer_irq_handler(); + break; + /* TODO: add support for external interrupt */ + default: + unexpected_trap_handler(ctx); + break; } do_softirq(); } + +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); + } +} diff --git a/hypervisor/arch/riscv/trap.h b/hypervisor/arch/riscv/trap.h deleted file mode 100644 index 02a0c888d..000000000 --- a/hypervisor/arch/riscv/trap.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2023-2024 Intel Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Authors: - * Haicheng Li - */ - -#ifndef __RISCV_TRAP_H__ -#define __RISCV_TRAP_H__ - -typedef void (* irq_handler_t)(void); - -#endif diff --git a/hypervisor/include/arch/riscv/asm/cpu.h b/hypervisor/include/arch/riscv/asm/cpu.h index a443e46f7..66ad34d53 100644 --- a/hypervisor/include/arch/riscv/asm/cpu.h +++ b/hypervisor/include/arch/riscv/asm/cpu.h @@ -140,6 +140,9 @@ static inline void arch_asm_pause(void) #define CPU_INT_ALL_DISABLE(x) local_irq_save(x) #define CPU_INT_ALL_RESTORE(x) local_irq_restore(x) +#define CPU_IRQ_ENABLE_ON_CONFIG local_irq_enable +#define CPU_IRQ_DISABLE_ON_CONFIG local_irq_disable + void wait_sync_change(volatile const uint64_t *sync, uint64_t wake_sync); void init_percpu_hart_id(uint32_t bsp_hart_id); uint16_t get_pcpu_id_from_hart_id(uint32_t hart_id); diff --git a/hypervisor/include/arch/riscv/asm/irq.h b/hypervisor/include/arch/riscv/asm/irq.h index 880db7d0d..97c5f7f42 100644 --- a/hypervisor/include/arch/riscv/asm/irq.h +++ b/hypervisor/include/arch/riscv/asm/irq.h @@ -10,6 +10,14 @@ #ifndef RISCV_IRQ_H #define RISCV_IRQ_H +#include + #define IPI_NOTIFY_CPU 0 +struct intr_excp_ctx { + struct cpu_regs regs; +}; + +void init_interrupt(uint16_t pcpu_id); + #endif /* RISCV_IRQ_H */ diff --git a/hypervisor/include/arch/riscv/asm/trap.h b/hypervisor/include/arch/riscv/asm/trap.h new file mode 100644 index 000000000..51c48e1c2 --- /dev/null +++ b/hypervisor/include/arch/riscv/asm/trap.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Authors: + * Haicheng Li + */ + +#ifndef RISCV_TRAP_H +#define RISCV_TRAP_H + +#define TRAP_VECTOR_MODE_DIRECT 0U +#define TRAP_VECTOR_MODE_VECTORED 1U + +/** + * The Interrupt bit (most significant bit) in the scause register + * is set if the trap was caused by an interrupt. + */ +#define TRAP_CAUSE_INTERRUPT_BITMASK (1UL << 63U) + +/* Trap Cause Codes - Interrupt */ +/* Software Interrupt */ +#define TRAP_CAUSE_IRQ_S_SOFT 1UL /* Supervisor software interrupt */ +#define TRAP_CAUSE_IRQ_VS_SOFT 2UL /* Virtual supervisor software interrupt */ +#define TRAP_CAUSE_IRQ_M_SOFT 3UL /* Machine software interrupt */ +/* Timer Interrupt */ +#define TRAP_CAUSE_IRQ_S_TIMER 5UL /* Supervisor timer interrupt */ +#define TRAP_CAUSE_IRQ_VS_TIMER 6UL /* Virtual supervisor timer interrupt */ +#define TRAP_CAUSE_IRQ_M_TIMER 7UL /* Machine timer interrupt */ +/* External Interrupt */ +#define TRAP_CAUSE_IRQ_S_EXT 9UL /* Supervisor external interrupt */ +#define TRAP_CAUSE_IRQ_VS_EXT 10UL /* Virtual supervisor external interrupt */ +#define TRAP_CAUSE_IRQ_M_EXT 11UL /* Machine external interrupt */ +#define TRAP_CAUSE_IRQ_S_GUEST_EXT 12UL /* Supervisor guest external interrupt */ +#define TRAP_CAUSE_IRQ_COUNTER_OVF 13UL /* Reserved for counter-overflow interrupt */ + +/* Interrupt Pending/Enable registers flags */ +/* Software Interrupt */ +#define IP_IE_SSI (1UL << TRAP_CAUSE_IRQ_S_SOFT) +#define IP_IE_VSSI (1UL << TRAP_CAUSE_IRQ_VS_SOFT) +#define IP_IE_MSI (1UL << TRAP_CAUSE_IRQ_M_SOFT) +/* Timer Interrupt */ +#define IP_IE_STI (1UL << TRAP_CAUSE_IRQ_S_TIMER) +#define IP_IE_VSTI (1UL << TRAP_CAUSE_IRQ_VS_TIMER) +#define IP_IE_MTI (1UL << TRAP_CAUSE_IRQ_M_TIMER) +/* External Interrupt */ +#define IP_IE_SEI (1UL << TRAP_CAUSE_IRQ_S_EXT) +#define IP_IE_VSEI (1UL << TRAP_CAUSE_IRQ_VS_EXT) +#define IP_IE_MEI (1UL << TRAP_CAUSE_IRQ_M_EXT) +#define IP_IE_SGEI (1UL << TRAP_CAUSE_IRQ_S_GUEST_EXT) +#define IP_IE_LCOFI (1UL << TRAP_CAUSE_IRQ_COUNTER_OVF) + +#ifndef ASSEMBLER +#include + +extern uint64_t strap_handler; + +void dispatch_trap(const struct intr_excp_ctx *ctx); + +#endif /* ASSEMBLER */ + +#endif /* RISCV_TRAP_H */ diff --git a/hypervisor/include/common/cpu.h b/hypervisor/include/common/cpu.h index 1aa633a9c..0e10ab9a1 100644 --- a/hypervisor/include/common/cpu.h +++ b/hypervisor/include/common/cpu.h @@ -24,6 +24,8 @@ /* hypervisor stack bottom magic('intl') */ #define SP_BOTTOM_MAGIC 0x696e746cUL +#ifndef ASSEMBLER + /* CPU states defined */ enum pcpu_boot_state { PCPU_STATE_RESET = 0U, @@ -66,4 +68,6 @@ static inline void asm_pause(void) arch_asm_pause(); } +#endif /* ASSEMBLER */ + #endif /* COMMON_CPU_H */