mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 08:13:54 -06:00
target/riscv: Handle Smrnmi interrupt and exception
Because the RNMI interrupt trap handler address is implementation defined. We add the 'rnmi-interrupt-vector' and 'rnmi-exception-vector' as the property of the harts. It’s very easy for users to set the address based on their expectation. This patch also adds the functionality to handle the RNMI signals. Signed-off-by: Frank Chang <frank.chang@sifive.com> Signed-off-by: Tommy Wu <tommy.wu@sifive.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250106054336.1878291-4-frank.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
5db557f82b
commit
c1149f69ab
6 changed files with 152 additions and 7 deletions
|
@ -554,6 +554,18 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
|
|||
uint64_t vsbits, irq_delegated;
|
||||
int virq;
|
||||
|
||||
/* Priority: RNMI > Other interrupt. */
|
||||
if (riscv_cpu_cfg(env)->ext_smrnmi) {
|
||||
/* If mnstatus.NMIE == 0, all interrupts are disabled. */
|
||||
if (!get_field(env->mnstatus, MNSTATUS_NMIE)) {
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
if (env->rnmip) {
|
||||
return ctz64(env->rnmip); /* since non-zero */
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine interrupt enable state of all privilege modes */
|
||||
if (env->virt_enabled) {
|
||||
mie = 1;
|
||||
|
@ -616,7 +628,9 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
|
|||
|
||||
bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
{
|
||||
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);
|
||||
|
@ -748,6 +762,30 @@ void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen)
|
|||
env->geilen = geilen;
|
||||
}
|
||||
|
||||
void riscv_cpu_set_rnmi(RISCVCPU *cpu, uint32_t irq, bool level)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
CPUState *cs = CPU(cpu);
|
||||
bool release_lock = false;
|
||||
|
||||
if (!bql_locked()) {
|
||||
release_lock = true;
|
||||
bql_lock();
|
||||
}
|
||||
|
||||
if (level) {
|
||||
env->rnmip |= 1 << irq;
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_RNMI);
|
||||
} else {
|
||||
env->rnmip &= ~(1 << irq);
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_RNMI);
|
||||
}
|
||||
|
||||
if (release_lock) {
|
||||
bql_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
|
@ -1897,6 +1935,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
bool write_gva = false;
|
||||
bool always_storeamo = (env->excp_uw2 & RISCV_UW2_ALWAYS_STORE_AMO);
|
||||
uint64_t s;
|
||||
int mode;
|
||||
|
||||
/*
|
||||
* cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide
|
||||
|
@ -1914,7 +1953,24 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
target_ulong htval = 0;
|
||||
target_ulong mtval2 = 0;
|
||||
int sxlen = 0;
|
||||
int mxlen = 0;
|
||||
int mxlen = 16 << riscv_cpu_mxl(env);
|
||||
bool nnmi_excep = false;
|
||||
|
||||
if (cpu->cfg.ext_smrnmi && env->rnmip && async) {
|
||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_NMIE, false);
|
||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPV,
|
||||
env->virt_enabled);
|
||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPP,
|
||||
env->priv);
|
||||
env->mncause = cause | ((target_ulong)1U << (mxlen - 1));
|
||||
env->mnepc = env->pc;
|
||||
env->pc = env->rnmi_irqvec;
|
||||
|
||||
/* Trapping to M mode, virt is disabled */
|
||||
riscv_cpu_set_mode(env, PRV_M, false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!async) {
|
||||
/* set tval to badaddr for traps with address information */
|
||||
|
@ -2008,8 +2064,10 @@ 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)) {
|
||||
mode = env->priv <= PRV_S && cause < 64 &&
|
||||
(((deleg >> cause) & 1) || s_injected || vs_injected) ? PRV_S : PRV_M;
|
||||
|
||||
if (mode == PRV_S) {
|
||||
/* handle the trap in S-mode */
|
||||
/* save elp status */
|
||||
if (cpu_get_fcfien(env)) {
|
||||
|
@ -2064,6 +2122,14 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
|
||||
riscv_cpu_set_mode(env, PRV_S, virt);
|
||||
} else {
|
||||
/*
|
||||
* If the hart encounters an exception while executing in M-mode
|
||||
* with the mnstatus.NMIE bit clear, the exception is an RNMI exception.
|
||||
*/
|
||||
nnmi_excep = cpu->cfg.ext_smrnmi &&
|
||||
!get_field(env->mnstatus, MNSTATUS_NMIE) &&
|
||||
!async;
|
||||
|
||||
/* handle the trap in M-mode */
|
||||
/* save elp status */
|
||||
if (cpu_get_fcfien(env)) {
|
||||
|
@ -2091,14 +2157,22 @@ 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;
|
||||
mxlen = 16 << riscv_cpu_mxl(env);
|
||||
env->mcause = cause | ((target_ulong)async << (mxlen - 1));
|
||||
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);
|
||||
|
||||
/*
|
||||
* For RNMI exception, program counter is set to the RNMI exception
|
||||
* trap handler address.
|
||||
*/
|
||||
if (nnmi_excep) {
|
||||
env->pc = env->rnmi_excpvec;
|
||||
} else {
|
||||
env->pc = (env->mtvec >> 2 << 2) +
|
||||
((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
|
||||
}
|
||||
riscv_cpu_set_mode(env, PRV_M, virt);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue