mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2026-05-05 12:22:53 +00:00
hv: riscv: irq: add interrupt initialization and handlers
This patch implements interrupt initialization and the basic exception/interrupt handling flow on RISC-V. init_interrupt() needs to be invoked during CPU initialization to set up the trap vector and enable the interrupt. RISC-V exception and interrupt handling includes: - Saving and restoring CPU registers around traps - Implementing handlers for: - Supervisor software interrupt - Supervisor timer interrupt - Halting the CPU for all other interrupts and exceptions ------ TODOs: 1. add support for registering interrupt handlers via request_irq() and further adoption of the common IRQ framework. 2. add support for external interrupt. Tracked-On: #8813 Signed-off-by: Haicheng Li <haicheng.li@intel.com> Co-developed-by: Shiqing Gao <shiqing.gao@intel.com> Signed-off-by: Shiqing Gao <shiqing.gao@intel.com> Reviewed-by: Yifan Liu <yifan1.liu@intel.com> Acked-by: Wang, Yu1 <yu1.wang@intel.com>
This commit is contained in:
committed by
acrnsi-robot
parent
0fc843de84
commit
fc495b946a
@@ -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 +=
|
||||
|
||||
27
hypervisor/arch/riscv/intr.S
Normal file
27
hypervisor/arch/riscv/intr.S
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Authors:
|
||||
* Haicheng Li <haicheng.li@intel.com>
|
||||
*/
|
||||
|
||||
#include <asm/trap.h>
|
||||
#include <cpu.h>
|
||||
|
||||
.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
|
||||
50
hypervisor/arch/riscv/irq.c
Normal file
50
hypervisor/arch/riscv/irq.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Authors:
|
||||
* Haicheng Li <haicheng.li@intel.com>
|
||||
*/
|
||||
|
||||
#include <asm/trap.h>
|
||||
#include <cpu.h>
|
||||
#include <types.h>
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -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 <haicheng.li@intel.com>
|
||||
*/
|
||||
|
||||
#include <softirq.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/timer.h>
|
||||
#include "trap.h"
|
||||
#include <asm/trap.h>
|
||||
#include <cpu.h>
|
||||
#include <logmsg.h>
|
||||
#include <notify.h>
|
||||
#include <softirq.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Authors:
|
||||
* Haicheng Li <haicheng.li@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __RISCV_TRAP_H__
|
||||
#define __RISCV_TRAP_H__
|
||||
|
||||
typedef void (* irq_handler_t)(void);
|
||||
|
||||
#endif
|
||||
@@ -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);
|
||||
|
||||
@@ -10,6 +10,14 @@
|
||||
#ifndef RISCV_IRQ_H
|
||||
#define RISCV_IRQ_H
|
||||
|
||||
#include <cpu.h>
|
||||
|
||||
#define IPI_NOTIFY_CPU 0
|
||||
|
||||
struct intr_excp_ctx {
|
||||
struct cpu_regs regs;
|
||||
};
|
||||
|
||||
void init_interrupt(uint16_t pcpu_id);
|
||||
|
||||
#endif /* RISCV_IRQ_H */
|
||||
|
||||
63
hypervisor/include/arch/riscv/asm/trap.h
Normal file
63
hypervisor/include/arch/riscv/asm/trap.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2025 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Authors:
|
||||
* Haicheng Li <haicheng.li@intel.com>
|
||||
*/
|
||||
|
||||
#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 <asm/irq.h>
|
||||
|
||||
extern uint64_t strap_handler;
|
||||
|
||||
void dispatch_trap(const struct intr_excp_ctx *ctx);
|
||||
|
||||
#endif /* ASSEMBLER */
|
||||
|
||||
#endif /* RISCV_TRAP_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 */
|
||||
|
||||
Reference in New Issue
Block a user