qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [RFC v2 0/4] target/riscv: add RNMI support
@ 2021-04-01  9:26 frank.chang
  2021-04-01  9:26 ` [RFC v2 1/4] target/riscv: add RNMI cpu feature frank.chang
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: frank.chang @ 2021-04-01  9:26 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: Frank Chang

From: Frank Chang <frank.chang@sifive.com>

This patchset add suport of Resumable NMI (RNMI) in RISC-V.

There are four new CSRs and one new instruction added to allow NMI to be
resumable in RISC-V, which are:

=============================================================
  * mnscratch (0x350)
  * mnepc     (0x351)
  * mncause   (0x352)
  * mnstatus  (0x353)
=============================================================
  * mnret: To return from RNMI interrupt/exception handler.
=============================================================

RNMI also has higher priority than any other interrupts or exceptions
and cannot be disable by software.

RNMI may be used to route to other devices such as Bus Error Unit or
Watchdog Timer in the future.

The interrupt/exception trap handler addresses of RNMI are
implementation defined.

The technical proposal of RNMI can be found:
https://lists.riscv.org/g/tech-privileged/message/421

The port is available here:
https://github.com/sifive/qemu/tree/nmi-upstream-v2

To test RNMI, we have created another QEMU branch to have
RNMI feature enabled and also both SiFive Bus Error Unit and
Error Device included on sifive_e machine.

Bus Error Unit (BEU) is routed to RNMI with mncause value set to 3.
When any reads or writes to Error Device, it will drive BEU RNMI.
A freedom-e-sdk RNMI example is also provided for testing.
(We will also upstream BEU and Error Device in the near future.)

Two -cpu options are added for RNMI and BEU:
  * rnmi=true to enable RNMI feature
  * beu=true to enable BEU feature

Download and build freedom-e-sdk rnmi example:

1. git clone git@github.com:sifive/freedom-e-sdk.git
2. cd freedom-e-sdk
3. git checkout origin/dev/yihaoc/nmi -b nmi
4. git submodule init
5. git submodule update --recursive
6. Follow freedom-e-sdk guide to install freedom-e-sdk:
   https://sifive.github.io/freedom-e-sdk-docs/index.html
7. make PROGRAM=example-rnmi TARGET=qemu-sifive-e31 \
    CONFIGURATION=release software

Download, build and run freedom-e-sdk RNMI example on QEMU:

1. git clone git@github.com:sifive/qemu.git
2. cd qemu
3. git checkout origin/upstream-nmi-beu-error-device -b nmi-beu-error-device
4. git submodule init
5. git submodule update --recursive
6. ./configure --target-list=riscv32-softmmu
7. make -j
8. <path to qemu-system-riscv32> -nographic -M sifive_e \
    -cpu rv32,rnmi=true,beu=true \
    --bios none -kernel <path to example-rnmi.elf>

Output example:

RNMI Driver Example.
Cleared accrued bus error
Enter RNMI interrupt ISR.
mnscratch: 0x00000000
mnepc: 0x20401178
mncause: 0x00000003
mnstatus: 0x00001800
Try to trigger illegal instruction exception.
Enter RNMI exception ISR.
mscratch: 0x00000000
mepc: 0x20401208
mcause: 0x00000002
mstatus: 0x80007800
Return from RNMI exception ISR.
Handled TileLink bus error
Return from RNMI interrupt ISR.
Test passed!!

Changelog:

v2
  * split up the series into more commits for convenience of review.
  * add missing rnmi_irqvec and rnmi_excpvec properties to riscv_harts.

Frank Chang (4):
  target/riscv: add RNMI cpu feature
  target/riscv: add RNMI CSRs
  target/riscv: handle RNMI interrupt and exception
  target/riscv: add RNMI mnret instruction

 hw/riscv/riscv_hart.c                         |  8 +++
 include/hw/riscv/riscv_hart.h                 |  2 +
 target/riscv/cpu.c                            | 40 +++++++++++++
 target/riscv/cpu.h                            | 16 ++++-
 target/riscv/cpu_bits.h                       | 19 ++++++
 target/riscv/cpu_helper.c                     | 49 +++++++++++++--
 target/riscv/csr.c                            | 59 +++++++++++++++++++
 target/riscv/helper.h                         |  1 +
 target/riscv/insn32.decode                    |  3 +
 .../riscv/insn_trans/trans_privileged.c.inc   | 13 ++++
 target/riscv/op_helper.c                      | 31 ++++++++++
 11 files changed, 236 insertions(+), 5 deletions(-)

--
2.17.1



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC v2 1/4] target/riscv: add RNMI cpu feature
  2021-04-01  9:26 [RFC v2 0/4] target/riscv: add RNMI support frank.chang
@ 2021-04-01  9:26 ` frank.chang
  2021-04-01  9:26 ` [RFC v2 2/4] target/riscv: add RNMI CSRs frank.chang
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: frank.chang @ 2021-04-01  9:26 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: Frank Chang, Alistair Francis, Palmer Dabbelt, Sagar Karandikar,
	Bastian Koppelmann

From: Frank Chang <frank.chang@sifive.com>

Signed-off-by: Frank Chang <frank.chang@sifive.com>
---
 hw/riscv/riscv_hart.c         |  8 +++++++
 include/hw/riscv/riscv_hart.h |  2 ++
 target/riscv/cpu.c            | 40 +++++++++++++++++++++++++++++++++++
 target/riscv/cpu.h            | 12 ++++++++++-
 target/riscv/cpu_bits.h       |  6 ++++++
 5 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c
index 613ea2aaa0b..b8cb5088638 100644
--- a/hw/riscv/riscv_hart.c
+++ b/hw/riscv/riscv_hart.c
@@ -33,6 +33,10 @@ static Property riscv_harts_props[] = {
     DEFINE_PROP_STRING("cpu-type", RISCVHartArrayState, cpu_type),
     DEFINE_PROP_UINT64("resetvec", RISCVHartArrayState, resetvec,
                        DEFAULT_RSTVEC),
+    DEFINE_PROP_UINT64("rnmi_irqvec", RISCVHartArrayState, rnmi_irqvec,
+                       DEFAULT_RNMI_IRQVEC),
+    DEFINE_PROP_UINT64("rnmi_excpvec", RISCVHartArrayState, rnmi_excpvec,
+                       DEFAULT_RNMI_EXCPVEC),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -47,6 +51,10 @@ 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);
+    qdev_prop_set_uint64(DEVICE(&s->harts[idx]), "rnmi_irqvec",
+                                s->rnmi_irqvec);
+    qdev_prop_set_uint64(DEVICE(&s->harts[idx]), "rnmi_excpvec",
+                                s->rnmi_excpvec);
     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 bbc21cdc9a6..48e6730d832 100644
--- a/include/hw/riscv/riscv_hart.h
+++ b/include/hw/riscv/riscv_hart.h
@@ -38,6 +38,8 @@ struct RISCVHartArrayState {
     uint32_t hartid_base;
     char *cpu_type;
     uint64_t resetvec;
+    uint64_t rnmi_irqvec;
+    uint64_t rnmi_excpvec;
     RISCVCPU *harts;
 };
 
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 7d6ed80f6b6..9fb6ceb0ad8 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -137,6 +137,14 @@ static void set_feature(CPURISCVState *env, int feature)
     env->features |= (1ULL << feature);
 }
 
+static void set_rnmi_vectors(CPURISCVState *env, int irqvec, int excpvec)
+{
+#ifndef CONFIG_USER_ONLY
+    env->rnmi_irqvec = irqvec;
+    env->rnmi_excpvec = excpvec;
+#endif
+}
+
 static void set_resetvec(CPURISCVState *env, int resetvec)
 {
 #ifndef CONFIG_USER_ONLY
@@ -373,6 +381,23 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
     }
 }
 
+#ifndef CONFIG_USER_ONLY
+static void riscv_cpu_set_rnmi(void *opaque, int irq, int level)
+{
+    RISCVCPU *cpu = opaque;
+    CPURISCVState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
+
+    if (level) {
+        env->nmip |= 1 << irq;
+        cpu_interrupt(cs, CPU_INTERRUPT_RNMI);
+    } else {
+        env->nmip &= ~(1 << irq);
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_RNMI);
+    }
+}
+#endif
+
 static void riscv_cpu_realize(DeviceState *dev, Error **errp)
 {
     CPUState *cs = CPU(dev);
@@ -416,6 +441,16 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
 
     set_resetvec(env, cpu->cfg.resetvec);
 
+    if (cpu->cfg.rnmi) {
+        set_feature(env, RISCV_FEATURE_RNMI);
+        set_rnmi_vectors(env, cpu->cfg.rnmi_irqvec, cpu->cfg.rnmi_excpvec);
+#ifndef CONFIG_USER_ONLY
+        env->nmie = true;
+        qdev_init_gpio_in_named(DEVICE(cpu), riscv_cpu_set_rnmi,
+                                "rnmi", TARGET_LONG_BITS);
+#endif
+    }
+
     /* If only XLEN is set for misa, then set misa from properties */
     if (env->misa == RV32 || env->misa == RV64) {
         /* Do some ISA extension error checking */
@@ -555,6 +590,11 @@ static Property riscv_cpu_properties[] = {
     DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
     DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
     DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
+    DEFINE_PROP_BOOL("rnmi", RISCVCPU, cfg.rnmi, false),
+    DEFINE_PROP_UINT64("rnmi_irqvec", RISCVCPU, cfg.rnmi_irqvec,
+                       DEFAULT_RNMI_IRQVEC),
+    DEFINE_PROP_UINT64("rnmi_excpvec", RISCVCPU, cfg.rnmi_excpvec,
+                       DEFAULT_RNMI_EXCPVEC),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 0a33d387ba8..7d2bb7e7003 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -80,7 +80,8 @@
 enum {
     RISCV_FEATURE_MMU,
     RISCV_FEATURE_PMP,
-    RISCV_FEATURE_MISA
+    RISCV_FEATURE_MISA,
+    RISCV_FEATURE_RNMI,
 };
 
 #define PRIV_VERSION_1_10_0 0x00011000
@@ -178,6 +179,12 @@ struct CPURISCVState {
     target_ulong mcause;
     target_ulong mtval;  /* since: priv-1.10.0 */
 
+    /* NMI */
+    bool nmie;
+    target_ulong nmip;
+    target_ulong rnmi_irqvec;
+    target_ulong rnmi_excpvec;
+
     /* Hypervisor CSRs */
     target_ulong hstatus;
     target_ulong hedeleg;
@@ -304,6 +311,9 @@ struct RISCVCPU {
         bool mmu;
         bool pmp;
         uint64_t resetvec;
+        bool rnmi;
+        uint64_t rnmi_irqvec;
+        uint64_t rnmi_excpvec;
     } cfg;
 };
 
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index caf45992070..8e5f0be599a 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -526,6 +526,12 @@
 /* Default Reset Vector adress */
 #define DEFAULT_RSTVEC      0x1000
 
+/* Default RNMI Interrupt Vector address */
+#define DEFAULT_RNMI_IRQVEC     0x1000
+
+/* Default RNMI Exception Vector address */
+#define DEFAULT_RNMI_EXCPVEC    0x1000
+
 /* Exception causes */
 #define EXCP_NONE                                -1 /* sentinel value */
 #define RISCV_EXCP_INST_ADDR_MIS                 0x0
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC v2 2/4] target/riscv: add RNMI CSRs
  2021-04-01  9:26 [RFC v2 0/4] target/riscv: add RNMI support frank.chang
  2021-04-01  9:26 ` [RFC v2 1/4] target/riscv: add RNMI cpu feature frank.chang
@ 2021-04-01  9:26 ` frank.chang
  2021-04-01  9:26 ` [RFC v2 3/4] target/riscv: handle RNMI interrupt and exception frank.chang
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: frank.chang @ 2021-04-01  9:26 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: Frank Chang, Alistair Francis, Palmer Dabbelt, Sagar Karandikar,
	Bastian Koppelmann

From: Frank Chang <frank.chang@sifive.com>

Signed-off-by: Frank Chang <frank.chang@sifive.com>
---
 target/riscv/cpu.h      |  4 +++
 target/riscv/cpu_bits.h |  9 +++++++
 target/riscv/csr.c      | 59 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 7d2bb7e7003..674ee4dc999 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -180,6 +180,10 @@ struct CPURISCVState {
     target_ulong mtval;  /* since: priv-1.10.0 */
 
     /* NMI */
+    target_ulong mnscratch;
+    target_ulong mnepc;
+    target_ulong mncause; /* mncause without bit XLEN-1 set to 1 */
+    target_ulong mnstatus;
     bool nmie;
     target_ulong nmip;
     target_ulong rnmi_irqvec;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 8e5f0be599a..a376ede0cc5 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -166,6 +166,12 @@
 #define CSR_MTVAL           0x343
 #define CSR_MIP             0x344
 
+/* NMI */
+#define CSR_MNSCRATCH       0x350
+#define CSR_MNEPC           0x351
+#define CSR_MNCAUSE         0x352
+#define CSR_MNSTATUS        0x353
+
 /* Legacy Machine Trap Handling (priv v1.9.1) */
 #define CSR_MBADADDR        0x343
 
@@ -558,6 +564,9 @@
 #define RISCV_EXCP_INT_FLAG                0x80000000
 #define RISCV_EXCP_INT_MASK                0x7fffffff
 
+/* RNMI mnstatus CSR mask */
+#define MNSTATUS_MPP                       MSTATUS_MPP
+
 /* Interrupt causes */
 #define IRQ_U_SOFT                         0
 #define IRQ_S_SOFT                         1
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index d2585395bfb..489d6d90e68 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -188,6 +188,11 @@ static int pmp(CPURISCVState *env, int csrno)
 {
     return -!riscv_feature(env, RISCV_FEATURE_PMP);
 }
+
+static int nmi(CPURISCVState *env, int csrno)
+{
+    return -!riscv_feature(env, RISCV_FEATURE_RNMI);
+}
 #endif
 
 /* User Floating-Point CSRs */
@@ -713,6 +718,54 @@ static int write_mbadaddr(CPURISCVState *env, int csrno, target_ulong val)
     return 0;
 }
 
+static int read_mnscratch(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->mnscratch;
+    return 0;
+}
+
+static int write_mnscratch(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->mnscratch = val;
+    return 0;
+}
+
+static int read_mnepc(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->mnepc;
+    return 0;
+}
+
+static int write_mnepc(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->mnepc = val;
+    return 0;
+}
+
+static int read_mncause(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->mncause;
+    return 0;
+}
+
+static int write_mncause(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->mncause = val;
+    return 0;
+}
+
+static int read_mnstatus(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->mnstatus;
+    return 0;
+}
+
+static int write_mnstatus(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->mnstatus = val & MNSTATUS_MPP;
+    return 0;
+}
+
 static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
                    target_ulong new_value, target_ulong write_mask)
 {
@@ -1428,6 +1481,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     [CSR_MBADADDR] = { "mbadaddr", any,  read_mbadaddr, write_mbadaddr },
     [CSR_MIP]      = { "mip",      any,  NULL,    NULL, rmw_mip        },
 
+    /* NMI */
+    [CSR_MNSCRATCH] = { "mnscratch", nmi, read_mnscratch, write_mnscratch },
+    [CSR_MNEPC]     = { "mnepc",     nmi, read_mnepc,     write_mnepc     },
+    [CSR_MNCAUSE]   = { "mncause",   nmi, read_mncause,   write_mncause   },
+    [CSR_MNSTATUS]  = { "mnstatus",  nmi, read_mnstatus,  write_mnstatus  },
+
     /* Supervisor Trap Setup */
     [CSR_SSTATUS]    = { "sstatus",    smode, read_sstatus,    write_sstatus    },
     [CSR_SIE]        = { "sie",        smode, read_sie,        write_sie        },
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC v2 3/4] target/riscv: handle RNMI interrupt and exception
  2021-04-01  9:26 [RFC v2 0/4] target/riscv: add RNMI support frank.chang
  2021-04-01  9:26 ` [RFC v2 1/4] target/riscv: add RNMI cpu feature frank.chang
  2021-04-01  9:26 ` [RFC v2 2/4] target/riscv: add RNMI CSRs frank.chang
@ 2021-04-01  9:26 ` frank.chang
  2021-04-01  9:26 ` [RFC v2 4/4] target/riscv: add RNMI mnret instruction frank.chang
  2021-04-01  9:36 ` [RFC v2 0/4] target/riscv: add RNMI support Frank Chang
  4 siblings, 0 replies; 6+ messages in thread
From: frank.chang @ 2021-04-01  9:26 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: Frank Chang, Alistair Francis, Palmer Dabbelt, Sagar Karandikar,
	Bastian Koppelmann

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



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC v2 4/4] target/riscv: add RNMI mnret instruction
  2021-04-01  9:26 [RFC v2 0/4] target/riscv: add RNMI support frank.chang
                   ` (2 preceding siblings ...)
  2021-04-01  9:26 ` [RFC v2 3/4] target/riscv: handle RNMI interrupt and exception frank.chang
@ 2021-04-01  9:26 ` frank.chang
  2021-04-01  9:36 ` [RFC v2 0/4] target/riscv: add RNMI support Frank Chang
  4 siblings, 0 replies; 6+ messages in thread
From: frank.chang @ 2021-04-01  9:26 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: Keith Packard, Sagar Karandikar, Frank Chang, Bastian Koppelmann,
	Bin Meng, Richard Henderson, Alistair Francis, Palmer Dabbelt,
	Alex Bennée

From: Frank Chang <frank.chang@sifive.com>

Signed-off-by: Frank Chang <frank.chang@sifive.com>
---
 target/riscv/helper.h                         |  1 +
 target/riscv/insn32.decode                    |  3 ++
 .../riscv/insn_trans/trans_privileged.c.inc   | 13 ++++++++
 target/riscv/op_helper.c                      | 31 +++++++++++++++++++
 4 files changed, 48 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index e3f3f41e891..0914d777d6d 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -65,6 +65,7 @@ DEF_HELPER_4(csrrc, tl, env, tl, tl, tl)
 #ifndef CONFIG_USER_ONLY
 DEF_HELPER_2(sret, tl, env, tl)
 DEF_HELPER_2(mret, tl, env, tl)
+DEF_HELPER_2(mnret, tl, env, tl)
 DEF_HELPER_1(wfi, void, env)
 DEF_HELPER_1(tlb_flush, void, env)
 #endif
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 84080dd18ca..557f3394276 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -97,6 +97,9 @@ wfi         0001000    00101 00000 000 00000 1110011
 sfence_vma  0001001    ..... ..... 000 00000 1110011 @sfence_vma
 sfence_vm   0001000    00100 ..... 000 00000 1110011 @sfence_vm
 
+# *** NMI ***
+mnret       0111000    00010 00000 000 00000 1110011
+
 # *** RV32I Base Instruction Set ***
 lui      ....................       ..... 0110111 @u
 auipc    ....................       ..... 0010111 @u
diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc
index 32312be2024..63c49dfe6fb 100644
--- a/target/riscv/insn_trans/trans_privileged.c.inc
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
@@ -106,6 +106,19 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a)
 #endif
 }
 
+static bool trans_mnret(DisasContext *ctx, arg_mnret *a)
+{
+#ifndef CONFIG_USER_ONLY
+    tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+    gen_helper_mnret(cpu_pc, cpu_env, cpu_pc);
+    exit_tb(ctx); /* no chaining */
+    ctx->base.is_jmp = DISAS_NORETURN;
+    return true;
+#else
+    return false;
+#endif
+}
+
 static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
 {
 #ifndef CONFIG_USER_ONLY
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 1eddcb94de7..b9601776153 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -175,6 +175,37 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
     return retpc;
 }
 
+target_ulong helper_mnret(CPURISCVState *env, target_ulong cpu_pc_deb)
+{
+    if (!riscv_feature(env, RISCV_FEATURE_RNMI)) {
+        /* RNMI feature is not presented. */
+        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+    }
+
+    if (!(env->priv >= PRV_M)) {
+        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+    }
+
+    /* Get return PC from mnepc CSR. */
+    target_ulong retpc = env->mnepc;
+    if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
+        riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
+    }
+
+    /* Get previous privilege level from mnstatus CSR. */
+    target_ulong prev_priv = get_field(env->mnstatus, MNSTATUS_MPP);
+
+    if (!pmp_get_num_rules(env) && (prev_priv != PRV_M)) {
+        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+    }
+
+    riscv_cpu_set_mode(env, prev_priv);
+
+    env->nmie = true;
+
+    return retpc;
+}
+
 void helper_wfi(CPURISCVState *env)
 {
     CPUState *cs = env_cpu(env);
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [RFC v2 0/4] target/riscv: add RNMI support
  2021-04-01  9:26 [RFC v2 0/4] target/riscv: add RNMI support frank.chang
                   ` (3 preceding siblings ...)
  2021-04-01  9:26 ` [RFC v2 4/4] target/riscv: add RNMI mnret instruction frank.chang
@ 2021-04-01  9:36 ` Frank Chang
  4 siblings, 0 replies; 6+ messages in thread
From: Frank Chang @ 2021-04-01  9:36 UTC (permalink / raw)
  To: frank.chang; +Cc: qemu-riscv, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 4480 bytes --]

<frank.chang@sifive.com> 於 2021年4月1日 週四 下午5:27寫道:

> From: Frank Chang <frank.chang@sifive.com>
>
> This patchset add suport of Resumable NMI (RNMI) in RISC-V.
>
> There are four new CSRs and one new instruction added to allow NMI to be
> resumable in RISC-V, which are:
>
> =============================================================
>   * mnscratch (0x350)
>   * mnepc     (0x351)
>   * mncause   (0x352)
>   * mnstatus  (0x353)
> =============================================================
>   * mnret: To return from RNMI interrupt/exception handler.
> =============================================================
>
> RNMI also has higher priority than any other interrupts or exceptions
> and cannot be disable by software.
>
> RNMI may be used to route to other devices such as Bus Error Unit or
> Watchdog Timer in the future.
>
> The interrupt/exception trap handler addresses of RNMI are
> implementation defined.
>
> The technical proposal of RNMI can be found:
> https://lists.riscv.org/g/tech-privileged/message/421
>
> The port is available here:
> https://github.com/sifive/qemu/tree/nmi-upstream-v2
>
> To test RNMI, we have created another QEMU branch to have
> RNMI feature enabled and also both SiFive Bus Error Unit and
> Error Device included on sifive_e machine.
>
> Bus Error Unit (BEU) is routed to RNMI with mncause value set to 3.
> When any reads or writes to Error Device, it will drive BEU RNMI.
> A freedom-e-sdk RNMI example is also provided for testing.
> (We will also upstream BEU and Error Device in the near future.)
>
> Two -cpu options are added for RNMI and BEU:
>   * rnmi=true to enable RNMI feature
>   * beu=true to enable BEU feature
>
> Download and build freedom-e-sdk rnmi example:
>
> 1. git clone git@github.com:sifive/freedom-e-sdk.git
> 2. cd freedom-e-sdk
> 3. git checkout origin/dev/yihaoc/nmi -b nmi
> 4. git submodule init
> 5. git submodule update --recursive
> 6. Follow freedom-e-sdk guide to install freedom-e-sdk:
>    https://sifive.github.io/freedom-e-sdk-docs/index.html
> 7. make PROGRAM=example-rnmi TARGET=qemu-sifive-e31 \
>     CONFIGURATION=release software
>

freedom-e-sdk RNMI example code is available at:
https://github.com/sifive/freedom-e-sdk/tree/dev/yihaoc/nmi/software/example-rnmi


>
> Download, build and run freedom-e-sdk RNMI example on QEMU:
>
> 1. git clone git@github.com:sifive/qemu.git
> 2. cd qemu
> 3. git checkout origin/upstream-nmi-beu-error-device -b
> nmi-beu-error-device
> 4. git submodule init
> 5. git submodule update --recursive
> 6. ./configure --target-list=riscv32-softmmu
> 7. make -j
> 8. <path to qemu-system-riscv32> -nographic -M sifive_e \
>     -cpu rv32,rnmi=true,beu=true \
>     --bios none -kernel <path to example-rnmi.elf>
>
> Output example:
>
> RNMI Driver Example.
> Cleared accrued bus error
> Enter RNMI interrupt ISR.
> mnscratch: 0x00000000
> mnepc: 0x20401178
> mncause: 0x00000003
> mnstatus: 0x00001800
> Try to trigger illegal instruction exception.
> Enter RNMI exception ISR.
> mscratch: 0x00000000
> mepc: 0x20401208
> mcause: 0x00000002
> mstatus: 0x80007800
> Return from RNMI exception ISR.
> Handled TileLink bus error
> Return from RNMI interrupt ISR.
> Test passed!!
>
> Changelog:
>
> v2
>   * split up the series into more commits for convenience of review.
>   * add missing rnmi_irqvec and rnmi_excpvec properties to riscv_harts.
>
> Frank Chang (4):
>   target/riscv: add RNMI cpu feature
>   target/riscv: add RNMI CSRs
>   target/riscv: handle RNMI interrupt and exception
>   target/riscv: add RNMI mnret instruction
>
>  hw/riscv/riscv_hart.c                         |  8 +++
>  include/hw/riscv/riscv_hart.h                 |  2 +
>  target/riscv/cpu.c                            | 40 +++++++++++++
>  target/riscv/cpu.h                            | 16 ++++-
>  target/riscv/cpu_bits.h                       | 19 ++++++
>  target/riscv/cpu_helper.c                     | 49 +++++++++++++--
>  target/riscv/csr.c                            | 59 +++++++++++++++++++
>  target/riscv/helper.h                         |  1 +
>  target/riscv/insn32.decode                    |  3 +
>  .../riscv/insn_trans/trans_privileged.c.inc   | 13 ++++
>  target/riscv/op_helper.c                      | 31 ++++++++++
>  11 files changed, 236 insertions(+), 5 deletions(-)
>
> --
> 2.17.1
>
>
>

[-- Attachment #2: Type: text/html, Size: 5810 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-04-01  9:39 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-01  9:26 [RFC v2 0/4] target/riscv: add RNMI support frank.chang
2021-04-01  9:26 ` [RFC v2 1/4] target/riscv: add RNMI cpu feature frank.chang
2021-04-01  9:26 ` [RFC v2 2/4] target/riscv: add RNMI CSRs frank.chang
2021-04-01  9:26 ` [RFC v2 3/4] target/riscv: handle RNMI interrupt and exception frank.chang
2021-04-01  9:26 ` [RFC v2 4/4] target/riscv: add RNMI mnret instruction frank.chang
2021-04-01  9:36 ` [RFC v2 0/4] target/riscv: add RNMI support Frank Chang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).