[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC v2 3/4] target/riscv: handle RNMI interrupt and exception
From: |
frank . chang |
Subject: |
[RFC v2 3/4] target/riscv: handle RNMI interrupt and exception |
Date: |
Thu, 1 Apr 2021 17:26:50 +0800 |
From: Frank Chang <frank.chang@sifive.com>
Signed-off-by: Frank Chang <frank.chang@sifive.com>
---
target/riscv/cpu_bits.h | 4 ++++
target/riscv/cpu_helper.c | 49 +++++++++++++++++++++++++++++++++++----
2 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index a376ede0cc5..937b1f28455 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -607,4 +607,8 @@
#define MIE_UTIE (1 << IRQ_U_TIMER)
#define MIE_SSIE (1 << IRQ_S_SOFT)
#define MIE_USIE (1 << IRQ_U_SOFT)
+
+/* RISC-V-specific interrupt pending bits. */
+#define CPU_INTERRUPT_RNMI CPU_INTERRUPT_TGT_EXT_0
+
#endif
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 21c54ef5613..67a633154a9 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -38,6 +38,19 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
#ifndef CONFIG_USER_ONLY
static int riscv_cpu_local_irq_pending(CPURISCVState *env)
{
+ if (riscv_feature(env, RISCV_FEATURE_RNMI)) {
+ /* Priority: RNMI > Other interrupt. */
+ if (env->nmip && env->nmie) {
+ return ctz64(env->nmip); /* since non-zero */
+ } else if (!env->nmie) {
+ /*
+ * We are already in RNMI handler,
+ * other interrupts cannot preempt.
+ */
+ return EXCP_NONE;
+ }
+ }
+
target_ulong irqs;
target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
@@ -80,7 +93,9 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
#if !defined(CONFIG_USER_ONLY)
- if (interrupt_request & CPU_INTERRUPT_HARD) {
+ uint32_t mask = CPU_INTERRUPT_HARD | CPU_INTERRUPT_RNMI;
+
+ if (interrupt_request & mask) {
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
int interruptno = riscv_cpu_local_irq_pending(env);
@@ -909,6 +924,23 @@ void riscv_cpu_do_interrupt(CPUState *cs)
target_ulong tval = 0;
target_ulong htval = 0;
target_ulong mtval2 = 0;
+ target_ulong nextpc;
+ bool nmi_execp = false;
+
+ if (riscv_feature(env, RISCV_FEATURE_RNMI)) {
+ nmi_execp = !env->nmie && !async;
+
+ if (env->nmip && async) {
+ env->nmie = false;
+ env->mnstatus = set_field(env->mnstatus, MSTATUS_MPP,
+ env->priv);
+ env->mncause = cause;
+ env->mnepc = env->pc;
+ env->pc = env->rnmi_irqvec;
+ riscv_cpu_set_mode(env, PRV_M);
+ goto handled;
+ }
+ }
if (cause == RISCV_EXCP_SEMIHOST) {
if (env->priv >= PRV_S) {
@@ -967,7 +999,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
__func__, env->mhartid, async, cause, env->pc, tval,
riscv_cpu_get_trap_name(cause, async));
- if (env->priv <= PRV_S &&
+ if (env->priv <= PRV_S && !nmi_execp &&
cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
/* handle the trap in S-mode */
if (riscv_has_ext(env, RVH)) {
@@ -1056,8 +1088,15 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->mepc = env->pc;
env->mbadaddr = tval;
env->mtval2 = mtval2;
- env->pc = (env->mtvec >> 2 << 2) +
- ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
+
+ if (nmi_execp) {
+ nextpc = env->rnmi_excpvec;
+ } else {
+ nextpc = (env->mtvec >> 2 << 2) +
+ ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
+ }
+ env->pc = nextpc;
+
riscv_cpu_set_mode(env, PRV_M);
}
@@ -1068,6 +1107,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
*/
env->two_stage_lookup = false;
+
+handled:
#endif
cs->exception_index = EXCP_NONE; /* mark handled to qemu */
}
--
2.17.1