qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v10 3/7] target/riscv: Handle Smrnmi interrupt and exception


From: Daniel Henrique Barboza
Subject: Re: [PATCH v10 3/7] target/riscv: Handle Smrnmi interrupt and exception
Date: Tue, 31 Dec 2024 06:19:35 -0300
User-agent: Mozilla Thunderbird



On 12/31/24 12:11 AM, Frank Chang wrote:
On Thu, Dec 26, 2024 at 8:42 PM Daniel Henrique Barboza <dbarboza@ventanamicro.com 
<mailto:dbarboza@ventanamicro.com>> wrote:



    On 12/17/24 3:24 AM, frank.chang@sifive.com <mailto:frank.chang@sifive.com> 
wrote:
     > From: Tommy Wu <tommy.wu@sifive.com <mailto:tommy.wu@sifive.com>>
     >
     > 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 
<mailto:frank.chang@sifive.com>>
     > Signed-off-by: Tommy Wu <tommy.wu@sifive.com 
<mailto:tommy.wu@sifive.com>>
     > ---
     >   hw/riscv/riscv_hart.c         | 40 +++++++++++++++++
     >   include/hw/riscv/riscv_hart.h |  4 ++
     >   target/riscv/cpu.c            | 11 +++++
     >   target/riscv/cpu.h            |  3 ++
     >   target/riscv/cpu_bits.h       | 12 +++++
     >   target/riscv/cpu_helper.c     | 85 ++++++++++++++++++++++++++++++++---
     >   6 files changed, 150 insertions(+), 5 deletions(-)
     >
     > diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c
     > index 0df454772f..f5e40e608d 100644
     > --- a/hw/riscv/riscv_hart.c
     > +++ b/hw/riscv/riscv_hart.c
     > @@ -26,6 +26,7 @@
     >   #include "target/riscv/cpu.h"
     >   #include "hw/qdev-properties.h"
     >   #include "hw/riscv/riscv_hart.h"
     > +#include "qemu/error-report.h"
     >
     >   static const Property riscv_harts_props[] = {
     >       DEFINE_PROP_UINT32("num-harts", RISCVHartArrayState, num_harts, 1),
     > @@ -33,6 +34,22 @@ static const Property riscv_harts_props[] = {
     >       DEFINE_PROP_STRING("cpu-type", RISCVHartArrayState, cpu_type),
     >       DEFINE_PROP_UINT64("resetvec", RISCVHartArrayState, resetvec,
     >                          DEFAULT_RSTVEC),
     > +    /*
     > +     * Smrnmi implementation-defined interrupt and exception trap 
handlers.
     > +     *
     > +     * When an RNMI interrupt is detected, the hart then enters M-mode 
and
     > +     * jumps to the address defined by "rnmi-interrupt-vector".
     > +     *
     > +     * When the hart encounters an exception while executing in M-mode 
with
     > +     * the mnstatus.NMIE bit clear, the hart then jumps to the address
     > +     * defined by "rnmi-exception-vector".
     > +     */
     > +    DEFINE_PROP_ARRAY("rnmi-interrupt-vector", RISCVHartArrayState,
     > +                      num_rnmi_irqvec, rnmi_irqvec, qdev_prop_uint64,
     > +                      uint64_t),
     > +    DEFINE_PROP_ARRAY("rnmi-exception-vector", RISCVHartArrayState,
     > +                      num_rnmi_excpvec, rnmi_excpvec, qdev_prop_uint64,
     > +                      uint64_t),
     >       DEFINE_PROP_END_OF_LIST(),

    This except will result in a conflict because "DEFINE_PROP_END_OF_LIST()," 
was removed
    in master.


Thanks, Daniel

The commit to drop "DEFINE_PROP_END_OF_LIST()" is not applied to 
riscv-to-apply.next yet.
But I will remove it from the v11 patchset.


Thanks! The reason it isn't in riscv-to-apply.next yet is because we had a 
riscv queue merged
10 days ago or so and master is now ahead of it. But riscv.next will derive 
from master later
on so might as well base stuff on top of master for now.


Thanks,

Daniel




Regards,
Frank Chang


    With that said:

    Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com 
<mailto:dbarboza@ventanamicro.com>>


     >   };
     >
     > @@ -47,6 +64,29 @@ static bool riscv_hart_realize(RISCVHartArrayState 
*s, int idx,
     >   {
     >       object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], 
cpu_type);
     >       qdev_prop_set_uint64(DEVICE(&s->harts[idx]), "resetvec", 
s->resetvec);
     > +
     > +    if (s->harts[idx].cfg.ext_smrnmi) {
     > +        if (idx < s->num_rnmi_irqvec) {
     > +            qdev_prop_set_uint64(DEVICE(&s->harts[idx]),
     > +                                 "rnmi-interrupt-vector", 
s->rnmi_irqvec[idx]);
     > +        }
     > +
     > +        if (idx < s->num_rnmi_excpvec) {
     > +            qdev_prop_set_uint64(DEVICE(&s->harts[idx]),
     > +                                 "rnmi-exception-vector", 
s->rnmi_excpvec[idx]);
     > +        }
     > +    } else {
     > +        if (s->num_rnmi_irqvec > 0) {
     > +            warn_report_once("rnmi-interrupt-vector property is ignored 
"
     > +                             "because Smrnmi extension is not 
enabled.");
     > +        }
     > +
     > +        if (s->num_rnmi_excpvec > 0) {
     > +            warn_report_once("rnmi-exception-vector property is ignored 
"
     > +                             "because Smrnmi extension is not 
enabled.");
     > +        }
     > +    }
     > +
     >       s->harts[idx].env.mhartid = s->hartid_base + idx;
     >       qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]);
     >       return qdev_realize(DEVICE(&s->harts[idx]), NULL, errp);
     > diff --git a/include/hw/riscv/riscv_hart.h 
b/include/hw/riscv/riscv_hart.h
     > index 912b4a2682..a6ed73a195 100644
     > --- a/include/hw/riscv/riscv_hart.h
     > +++ b/include/hw/riscv/riscv_hart.h
     > @@ -38,6 +38,10 @@ struct RISCVHartArrayState {
     >       uint32_t hartid_base;
     >       char *cpu_type;
     >       uint64_t resetvec;
     > +    uint32_t num_rnmi_irqvec;
     > +    uint64_t *rnmi_irqvec;
     > +    uint32_t num_rnmi_excpvec;
     > +    uint64_t *rnmi_excpvec;
     >       RISCVCPU *harts;
     >   };
     >
     > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
     > index ade9e6e190..e6988f44c6 100644
     > --- a/target/riscv/cpu.c
     > +++ b/target/riscv/cpu.c
     > @@ -1419,6 +1419,11 @@ static void riscv_cpu_set_irq(void *opaque, int 
irq, int level)
     >           g_assert_not_reached();
     >       }
     >   }
     > +
     > +static void riscv_cpu_set_nmi(void *opaque, int irq, int level)
     > +{
     > +    riscv_cpu_set_rnmi(RISCV_CPU(opaque), irq, level);
     > +}
     >   #endif /* CONFIG_USER_ONLY */
     >
     >   static bool riscv_cpu_is_dynamic(Object *cpu_obj)
     > @@ -1442,6 +1447,8 @@ static void riscv_cpu_init(Object *obj)
     >   #ifndef CONFIG_USER_ONLY
     >       qdev_init_gpio_in(DEVICE(obj), riscv_cpu_set_irq,
     >                         IRQ_LOCAL_MAX + IRQ_LOCAL_GUEST_MAX);
     > +    qdev_init_gpio_in_named(DEVICE(cpu), riscv_cpu_set_nmi,
     > +                            "riscv.cpu.rnmi", RNMI_MAX);
     >   #endif /* CONFIG_USER_ONLY */
     >
     >       general_user_opts = g_hash_table_new(g_str_hash, g_str_equal);
     > @@ -2797,6 +2804,10 @@ static const Property riscv_cpu_properties[] = {
     >
     >   #ifndef CONFIG_USER_ONLY
     >       DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, 
DEFAULT_RSTVEC),
     > +    DEFINE_PROP_UINT64("rnmi-interrupt-vector", RISCVCPU, 
env.rnmi_irqvec,
     > +                       DEFAULT_RNMI_IRQVEC),
     > +    DEFINE_PROP_UINT64("rnmi-exception-vector", RISCVCPU, 
env.rnmi_excpvec,
     > +                       DEFAULT_RNMI_EXCPVEC),
     >   #endif
     >
     >       DEFINE_PROP_BOOL("short-isa-string", RISCVCPU, 
cfg.short_isa_string, false),
     > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
     > index a2cb471b3c..8dc5b4d002 100644
     > --- a/target/riscv/cpu.h
     > +++ b/target/riscv/cpu.h
     > @@ -493,6 +493,8 @@ struct CPUArchState {
     >       target_ulong mncause; /* mncause without bit XLEN-1 set to 1 */
     >       target_ulong mnstatus;
     >       target_ulong rnmip;
     > +    uint64_t rnmi_irqvec;
     > +    uint64_t rnmi_excpvec;
     >   };
     >
     >   /*
     > @@ -591,6 +593,7 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState 
*env);
     >   int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
     >   uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask,
     >                                 uint64_t value);
     > +void riscv_cpu_set_rnmi(RISCVCPU *cpu, uint32_t irq, bool level);
     >   void riscv_cpu_interrupt(CPURISCVState *env);
     >   #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip 
value */
     >   void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void 
*),
     > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
     > index 9e9637263d..17787fd693 100644
     > --- a/target/riscv/cpu_bits.h
     > +++ b/target/riscv/cpu_bits.h
     > @@ -680,6 +680,12 @@ typedef enum {
     >   /* Default Reset Vector address */
     >   #define DEFAULT_RSTVEC      0x1000
     >
     > +/* Default RNMI Interrupt Vector address */
     > +#define DEFAULT_RNMI_IRQVEC     0x0
     > +
     > +/* Default RNMI Exception Vector address */
     > +#define DEFAULT_RNMI_EXCPVEC    0x0
     > +
     >   /* Exception causes */
     >   typedef enum RISCVException {
     >       RISCV_EXCP_NONE = -1, /* sentinel value */
     > @@ -734,6 +740,9 @@ typedef enum RISCVException {
     >   /* -1 is due to bit zero of hgeip and hgeie being ROZ. */
     >   #define IRQ_LOCAL_GUEST_MAX                (TARGET_LONG_BITS - 1)
     >
     > +/* RNMI causes */
     > +#define RNMI_MAX                           16
     > +
     >   /* mip masks */
     >   #define MIP_USIP                           (1 << IRQ_U_SOFT)
     >   #define MIP_SSIP                           (1 << IRQ_S_SOFT)
     > @@ -972,6 +981,9 @@ typedef enum RISCVException {
     >   #define MHPMEVENT_IDX_MASK                 0xFFFFF
     >   #define MHPMEVENT_SSCOF_RESVD              16
     >
     > +/* RISC-V-specific interrupt pending bits. */
     > +#define CPU_INTERRUPT_RNMI                 CPU_INTERRUPT_TGT_EXT_0
     > +
     >   /* JVT CSR bits */
     >   #define JVT_MODE                           0x3F
     >   #define JVT_BASE                           (~0x3F)
     > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
     > index 750c0537ca..e5ffbbbd83 100644
     > --- a/target/riscv/cpu_helper.c
     > +++ b/target/riscv/cpu_helper.c
     > @@ -505,6 +505,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;
     > @@ -567,7 +579,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);
     > @@ -699,6 +713,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;
     > @@ -1849,6 +1887,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
     > @@ -1867,6 +1906,23 @@ void riscv_cpu_do_interrupt(CPUState *cs)
     >       target_ulong mtval2 = 0;
     >       int sxlen = 0;
     >       int mxlen = 0;
     > +    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 << (TARGET_LONG_BITS - 
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 */
     > @@ -1960,8 +2016,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)) {
     > @@ -2016,6 +2074,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)) {
     > @@ -2049,8 +2115,17 @@ void riscv_cpu_do_interrupt(CPUState *cs)
     >           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);
     >       }
     >





reply via email to

[Prev in Thread] Current Thread [Next in Thread]