[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 08/11 v2] target/riscv: Update interrupt handling in CLIC mode
From: |
Ian Brockbank |
Subject: |
[PATCH 08/11 v2] target/riscv: Update interrupt handling in CLIC mode |
Date: |
Mon, 19 Aug 2024 17:02:19 +0100 |
From: Ian Brockbank <ian.brockbank@cirrus.com>
Decode CLIC interrupt information from exccode, includes interrupt
privilege mode, interrupt level, and irq number.
Then update CSRs xcause, xstatus, xepc, xintstatus and jump to
correct PC according to the CLIC specification.
Signed-off-by: LIU Zhiwei <zhiwei_liu@c-sky.com>
Signed-off-by: Ian Brockbank <ian.brockbank@cirrus.com>
---
target/riscv/cpu_helper.c | 129 +++++++++++++++++++++++++++++++++++---
1 file changed, 119 insertions(+), 10 deletions(-)
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 395a1d9140..944afb68d2 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -24,6 +24,7 @@
#include "internals.h"
#include "pmu.h"
#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
#include "exec/page-protection.h"
#include "instmap.h"
#include "tcg/tcg-op.h"
@@ -33,6 +34,7 @@
#include "cpu_bits.h"
#include "debug.h"
#include "tcg/oversized-guest.h"
+#include "hw/intc/riscv_clic.h"
int riscv_env_mmu_index(CPURISCVState *env, bool ifetch)
{
@@ -428,6 +430,20 @@ int riscv_cpu_vsirq_pending(CPURISCVState *env)
(irqs | irqs_f_vs), env->hviprio);
}
+static int riscv_cpu_local_irq_mode_enabled(CPURISCVState *env, int mode)
+{
+ switch (mode) {
+ case PRV_M:
+ return env->priv < PRV_M ||
+ (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE));
+ case PRV_S:
+ return env->priv < PRV_S ||
+ (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
+ default:
+ return false;
+ }
+}
+
static int riscv_cpu_local_irq_pending(CPURISCVState *env)
{
uint64_t irqs, pending, mie, hsie, vsie, irqs_f, irqs_f_vs;
@@ -506,6 +522,18 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int
interrupt_request)
return true;
}
}
+ if (interrupt_request & CPU_INTERRUPT_CLIC) {
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ int mode = get_field(env->exccode, RISCV_EXCP_CLIC_MODE);
+ int enabled = riscv_cpu_local_irq_mode_enabled(env, mode);
+ if (enabled) {
+ cs->exception_index = RISCV_EXCP_CLIC | env->exccode;
+ cs->interrupt_request = cs->interrupt_request &
~CPU_INTERRUPT_CLIC;
+ riscv_cpu_do_interrupt(cs);
+ return true;
+ }
+ }
return false;
}
@@ -1641,6 +1669,60 @@ static target_ulong riscv_transformed_insn(CPURISCVState
*env,
return xinsn;
}
+static target_ulong riscv_intr_pc(CPURISCVState *env, target_ulong tvec,
+ target_ulong tvt, bool async,
+ int cause, int mode)
+{
+ int mode1 = tvec & XTVEC_MODE;
+ int mode2 = tvec & XTVEC_FULL_MODE;
+
+ if (!async) {
+ return tvec & XTVEC_OBASE;
+ }
+ /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
+ switch (mode1) {
+ case XTVEC_CLINT_DIRECT:
+ return tvec & XTVEC_OBASE;
+ case XTVEC_CLINT_VECTORED:
+ return (tvec & XTVEC_OBASE) + cause * 4;
+ default:
+ if (env->clic && (mode2 == XTVEC_CLIC)) {
+ /* Non-vectored, clicintattr[i].shv = 0 || cliccfg.nvbits = 0 */
+ if (!riscv_clic_shv_interrupt(env->clic, cause)) {
+ /* NBASE = mtvec[XLEN-1:6]<<6 */
+ return tvec & XTVEC_NBASE;
+ } else {
+ /*
+ * pc := M[TBASE + XLEN/8 * exccode)] & ~1,
+ * TBASE = mtvt[XLEN-1:6]<<6
+ */
+ int size = TARGET_LONG_BITS / 8;
+ target_ulong tbase = (tvt & XTVEC_NBASE) + size * cause;
+ void *host = tlb_vaddr_to_host(env, tbase, MMU_DATA_LOAD,
mode);
+ if (host != NULL) {
+ target_ulong new_pc = tbase;
+ if (!riscv_clic_use_jump_table(env->clic)) {
+ /*
+ * Standard CLIC: the vector entry is a function
pointer
+ * so look up the destination.
+ */
+ new_pc = ldn_p(host, size);
+ host = tlb_vaddr_to_host(env, new_pc,
+ MMU_INST_FETCH, mode);
+ }
+ if (host) {
+ return new_pc;
+ }
+ }
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CLIC: load trap handler error!\n");
+ exit(1);
+ }
+ }
+ g_assert_not_reached();
+ }
+}
+
/*
* Handle Traps
*
@@ -1654,12 +1736,14 @@ void riscv_cpu_do_interrupt(CPUState *cs)
bool virt = env->virt_enabled;
bool write_gva = false;
uint64_t s;
+ int mode, level, irq;
/*
* cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide
* so we mask off the MSB and separate into trap type and cause.
*/
- bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
+ bool clic = !!(cs->exception_index & RISCV_EXCP_CLIC);
+ bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG) || clic;
target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
uint64_t deleg = async ? env->mideleg : env->medeleg;
bool s_injected = env->mvip & (1 << cause) & env->mvien &&
@@ -1746,6 +1830,28 @@ void riscv_cpu_do_interrupt(CPUState *cs)
}
}
+ if (clic) {
+ riscv_clic_decode_exccode(cause, &mode, &level, &irq);
+ cause = irq | get_field(env->mstatus, MSTATUS_MPP) << XCAUSE_XPP_SHIFT;
+ switch (mode) {
+ case PRV_M:
+ cause |= get_field(env->mintstatus, MINTSTATUS_MIL)
+ << XCAUSE_XPIL_SHIFT;
+ cause |= get_field(env->mstatus, MSTATUS_MIE) << XCAUSE_XPIE_SHIFT;
+ env->mintstatus = set_field(env->mintstatus, MINTSTATUS_MIL,
level);
+ break;
+ case PRV_S:
+ cause |= get_field(env->mintstatus, MINTSTATUS_SIL)
+ << XCAUSE_XPIL_SHIFT;
+ cause |= get_field(env->mstatus, MSTATUS_SPIE) <<
XCAUSE_XPIE_SHIFT;
+ env->mintstatus = set_field(env->mintstatus, MINTSTATUS_SIL,
level);
+ break;
+ }
+ } else {
+ mode = env->priv <= PRV_S && cause < 64 &&
+ ((deleg >> cause) & 1 || s_injected || vs_injected) ? PRV_S :
PRV_M;
+ }
+
trace_riscv_trap(env->mhartid, async, cause, env->pc, tval,
riscv_cpu_get_trap_name(cause, async));
@@ -1755,8 +1861,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 && cause < 64 &&
- (((deleg >> cause) & 1) || s_injected || vs_injected)) {
+ if (PRV_S == mode) {
/* handle the trap in S-mode */
if (riscv_has_ext(env, RVH)) {
uint64_t hdeleg = async ? env->hideleg : env->hedeleg;
@@ -1765,7 +1870,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
(((hdeleg >> cause) & 1) || vs_injected)) {
/* Trap to VS mode */
/*
- * See if we need to adjust cause. Yes if its VS mode interrupt
+ * See if we need to adjust cause. Yes if it's VS mode
interrupt
* no if hypervisor has delegated one of hs mode's interrupt
*/
if (async && (cause == IRQ_VS_TIMER || cause == IRQ_VS_SOFT ||
@@ -1796,13 +1901,15 @@ void riscv_cpu_do_interrupt(CPUState *cs)
s = set_field(s, MSTATUS_SPP, env->priv);
s = set_field(s, MSTATUS_SIE, 0);
env->mstatus = s;
- env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1));
+ if (async) {
+ env->scause = cause | SCAUSE_INT;
+ }
env->sepc = env->pc;
env->stval = tval;
env->htval = htval;
env->htinst = tinst;
- env->pc = (env->stvec >> 2 << 2) +
- ((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
+ env->pc = riscv_intr_pc(env, env->stvec, env->stvt, async,
+ cause & SCAUSE_EXCCODE, PRV_S);
riscv_cpu_set_mode(env, PRV_S, virt);
} else {
/* handle the trap in M-mode */
@@ -1827,13 +1934,15 @@ void riscv_cpu_do_interrupt(CPUState *cs)
s = set_field(s, MSTATUS_MPP, env->priv);
s = set_field(s, MSTATUS_MIE, 0);
env->mstatus = s;
- env->mcause = cause | ~(((target_ulong)-1) >> async);
+ if (async) {
+ env->mcause = cause | MCAUSE_INT;
+ }
env->mepc = env->pc;
env->mtval = tval;
env->mtval2 = mtval2;
env->mtinst = tinst;
- env->pc = (env->mtvec >> 2 << 2) +
- ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
+ env->pc = riscv_intr_pc(env, env->mtvec, env->mtvt, async,
+ cause & MCAUSE_EXCCODE, PRV_M);
riscv_cpu_set_mode(env, PRV_M, virt);
}
--
2.46.0.windows.1
This message and any attachments may contain privileged and confidential
information that is intended solely for the person(s) to whom it is addressed.
If you are not an intended recipient you must not: read; copy; distribute;
discuss; take any action in or make any reliance upon the contents of this
message; nor open or read any attachment. If you have received this message in
error, please notify us as soon as possible on the following telephone number
and destroy this message including any attachments. Thank you. Cirrus Logic
International (UK) Ltd and Cirrus Logic International Semiconductor Ltd are
companies registered in Scotland, with registered numbers SC089839 and SC495735
respectively. Our registered office is at 7B Nightingale Way, Quartermile,
Edinburgh, EH3 9EG, UK. Tel: +44 (0)131 272 7000. www.cirrus.com
- [PATCH 01/11 v2] target/riscv: Add CLIC CSR mintstatus, (continued)
- [PATCH 01/11 v2] target/riscv: Add CLIC CSR mintstatus, Ian Brockbank, 2024/08/19
- [PATCH 02/11 v2] target/riscv: Update CSR xintthresh in CLIC mode, Ian Brockbank, 2024/08/19
- [PATCH 10/11 v2] hw/riscv: add CLIC into virt machine, Ian Brockbank, 2024/08/19
- [PATCH 11/11 v2] tests: add riscv clic qtest case and a function in qtest, Ian Brockbank, 2024/08/19
- [PATCH 03/11 v2] hw/intc: Add CLIC device, Ian Brockbank, 2024/08/19
- [PATCH 05/11 v2] target/riscv: Update CSR xip in CLIC mode, Ian Brockbank, 2024/08/19
- [PATCH 07/11 v2] target/riscv: Update CSR xnxti in CLIC mode, Ian Brockbank, 2024/08/19
- [PATCH 06/11 v2] target/riscv: Update CSR xtvec in CLIC mode, Ian Brockbank, 2024/08/19
- [PATCH 04/11 v2] target/riscv: Update CSR xie in CLIC mode, Ian Brockbank, 2024/08/19
- [PATCH 09/11 v2] target/riscv: Update interrupt return in CLIC mode, Ian Brockbank, 2024/08/19
- [PATCH 08/11 v2] target/riscv: Update interrupt handling in CLIC mode,
Ian Brockbank <=