* [PATCH v10 0/7] Add Smrnmi support
@ 2024-12-17 6:24 frank.chang
2024-12-17 6:24 ` [PATCH v10 1/7] target/riscv: Add 'ext_smrnmi' in the RISCVCPUConfig frank.chang
` (6 more replies)
0 siblings, 7 replies; 14+ messages in thread
From: frank.chang @ 2024-12-17 6:24 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Frank Chang
From: Frank Chang <frank.chang@sifive.com>
This patchset added support for Smrnmi Extension 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 (0x740)
* mnepc (0x741)
* mncause (0x742)
* mnstatus (0x744)
=============================================================
* mnret: To return from RNMI interrupt/exception handler.
=============================================================
RNMI also has higher priority than any other interrupts or exceptions
and cannot be disabled 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.
If anyone wants to test the patches, we can use the customized OpenSBI[1],
and the customized QEMU[2].
We implemented a PoC RNMI trap handler in the customized OpenSBI.
In the customized QEMU, we use the Smrnmi patches and the patch from
Damien Hedde[3]. The patch from Damien Hedde can be used to inject
the RNMI signal with the qmp command.
[1] https://github.com/TommyWu-fdgkhdkgh/opensbi/tree/dev/twu/master
[2] https://github.com/sifive/qemu/tree/upstream-smrnmi-v10
[3] https://lists.gnu.org/archive/html/qemu-devel/2019-06/msg06232.html
Test commands :
$ ./build/qemu-system-riscv64 -M virt -cpu rv64,smrnmi=true,
rnmi-interrupt-vector={Offset of the RNMI handler in the customized
OpenSBI.} -m 4G -smp 2 -serial mon:stdio -serial null -nographic
-bios fw_jump.elf -kernel Image -initrd rootfs.cpio
-qmp unix:/tmp/qmp-sock,server,wait=off
Use qmp command to inject the RNMI.
Assert RNMI:
$ ./scripts/qmp/qmp-shell /tmp/qmp-sock
(QEMU) gpio-set path=/machine/soc0/harts[0] gpio=riscv.cpu.rnmi number=0 value=true
De-assert RNMI:
(QEMU) gpio-set path=/machine/soc0/harts[0] gpio=riscv.cpu.rnmi number=0 value=false
Changelog:
v10
* Disable Smrnmi for the 'max' type CPU.
v9
* Add Zicfilp support for Smrnmi.
* Change the existence checks for 'rnmi-interrupt-vector' and
'rnmi-exception-vector' to use 'num_rnmi_irqvec' and 'num_rnmi_excpvec'.
* Add warn_once messages for cases where the user sets
'rnmi-interrupt-vector' or 'rnmi-exception-vector' property without
enabling Smrnmi.
v8
* Set virt to false when trapping to M-mode by RNMI.
(Thanks to Clément for the suggestions.)
v7
* Rename 'nmi_execp' to 'nnmi_excep' and refactor RNMI exception
checking codes.
(Thanks to Clément for the suggestions.)
* Add the missing REQUIRE_SMRNMI() check and remove the redundant
check in 'helper_mnret'.
* Rebase to riscv-to-apply.next.
(Thanks to Alistair for the suggestions.)
v6
* Delete the redundant code in 'riscv_cpu_do_interrupt'.
(Thank Alvin for the suggestion.)
* Split the shared code in 'helper_mret' and 'helper_mnret' into a
helper function 'check_ret_from_m_mode'.
(Thank Alistair for the suggestion.)
v5
* Move the patch that adds the Smrnmi extension to the last patch.
(Thank Alistair for the suggestion.)
* Implement an M-mode software PoC for this with implemented handlers.
(Thank Andrew Jones for the suggestion.)
* Add a commit message to all patches of the series.
(Thank Andrew Jones for the suggestion.)
v4
* Fix some coding style issues.
(Thank Daniel for the suggestions.)
v3
* Update to the newest version of Smrnmi extension specification.
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 (2):
target/riscv: Add Zicfilp support for Smrnmi
target/riscv: Disable Smrnmi for the 'max' type CPU
Tommy Wu (5):
target/riscv: Add 'ext_smrnmi' in the RISCVCPUConfig
target/riscv: Add Smrnmi CSRs
target/riscv: Handle Smrnmi interrupt and exception
target/riscv: Add Smrnmi mnret instruction
target/riscv: Add Smrnmi cpu extension
hw/riscv/riscv_hart.c | 40 ++++++++
include/hw/riscv/riscv_hart.h | 4 +
target/riscv/cpu.c | 18 ++++
target/riscv/cpu.h | 10 ++
target/riscv/cpu_bits.h | 24 +++++
target/riscv/cpu_cfg.h | 1 +
target/riscv/cpu_helper.c | 96 +++++++++++++++++--
target/riscv/csr.c | 82 ++++++++++++++++
target/riscv/helper.h | 1 +
target/riscv/insn32.decode | 3 +
.../riscv/insn_trans/trans_privileged.c.inc | 20 ++++
target/riscv/op_helper.c | 54 ++++++++++-
target/riscv/tcg/tcg-cpu.c | 6 ++
13 files changed, 348 insertions(+), 11 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v10 1/7] target/riscv: Add 'ext_smrnmi' in the RISCVCPUConfig
2024-12-17 6:24 [PATCH v10 0/7] Add Smrnmi support frank.chang
@ 2024-12-17 6:24 ` frank.chang
2024-12-17 6:24 ` [PATCH v10 2/7] target/riscv: Add Smrnmi CSRs frank.chang
` (5 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: frank.chang @ 2024-12-17 6:24 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Tommy Wu, Frank Chang
From: Tommy Wu <tommy.wu@sifive.com>
The boolean variable 'ext_smrnmi' is used to determine whether the
Smrnmi extension exists.
Signed-off-by: Frank Chang <frank.chang@sifive.com>
Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
---
target/riscv/cpu_cfg.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index fe0c4173d2..28b43932db 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -129,6 +129,7 @@ struct RISCVCPUConfig {
bool ext_ssaia;
bool ext_sscofpmf;
bool ext_smepmp;
+ bool ext_smrnmi;
bool rvv_ta_all_1s;
bool rvv_ma_all_1s;
bool rvv_vl_half_avl;
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 2/7] target/riscv: Add Smrnmi CSRs
2024-12-17 6:24 [PATCH v10 0/7] Add Smrnmi support frank.chang
2024-12-17 6:24 ` [PATCH v10 1/7] target/riscv: Add 'ext_smrnmi' in the RISCVCPUConfig frank.chang
@ 2024-12-17 6:24 ` frank.chang
2024-12-17 6:24 ` [PATCH v10 3/7] target/riscv: Handle Smrnmi interrupt and exception frank.chang
` (4 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: frank.chang @ 2024-12-17 6:24 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Tommy Wu, Frank Chang
From: Tommy Wu <tommy.wu@sifive.com>
The Smrnmi extension adds the 'mnscratch', 'mnepc', 'mncause',
'mnstatus' CSRs.
Signed-off-by: Frank Chang <frank.chang@sifive.com>
Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
---
target/riscv/cpu.c | 5 +++
target/riscv/cpu.h | 7 ++++
target/riscv/cpu_bits.h | 11 ++++++
target/riscv/csr.c | 82 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 105 insertions(+)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 6748185206..ade9e6e190 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1134,6 +1134,11 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
riscv_trigger_reset_hold(env);
}
+ if (cpu->cfg.ext_smrnmi) {
+ env->rnmip = 0;
+ env->mnstatus = set_field(env->mnstatus, MNSTATUS_NMIE, false);
+ }
+
if (kvm_enabled()) {
kvm_riscv_reset_vcpu(cpu);
}
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 284b112821..a2cb471b3c 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -486,6 +486,13 @@ struct CPUArchState {
uint64_t kvm_timer_state;
uint64_t kvm_timer_frequency;
#endif /* CONFIG_KVM */
+
+ /* RNMI */
+ target_ulong mnscratch;
+ target_ulong mnepc;
+ target_ulong mncause; /* mncause without bit XLEN-1 set to 1 */
+ target_ulong mnstatus;
+ target_ulong rnmip;
};
/*
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index fe4e34c64a..9e9637263d 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -353,6 +353,12 @@
#define CSR_PMPADDR14 0x3be
#define CSR_PMPADDR15 0x3bf
+/* RNMI */
+#define CSR_MNSCRATCH 0x740
+#define CSR_MNEPC 0x741
+#define CSR_MNCAUSE 0x742
+#define CSR_MNSTATUS 0x744
+
/* Debug/Trace Registers (shared with Debug Mode) */
#define CSR_TSELECT 0x7a0
#define CSR_TDATA1 0x7a1
@@ -634,6 +640,11 @@ typedef enum {
#define SATP64_ASID 0x0FFFF00000000000ULL
#define SATP64_PPN 0x00000FFFFFFFFFFFULL
+/* RNMI mnstatus CSR mask */
+#define MNSTATUS_NMIE 0x00000008
+#define MNSTATUS_MNPV 0x00000080
+#define MNSTATUS_MNPP 0x00001800
+
/* VM modes (satp.mode) privileged ISA 1.10 */
#define VM_1_10_MBARE 0
#define VM_1_10_SV32 1
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index b6fa8ae53f..65daf6d138 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -597,6 +597,17 @@ static RISCVException debug(CPURISCVState *env, int csrno)
return RISCV_EXCP_ILLEGAL_INST;
}
+
+static RISCVException rnmi(CPURISCVState *env, int csrno)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (cpu->cfg.ext_smrnmi) {
+ return RISCV_EXCP_NONE;
+ }
+
+ return RISCV_EXCP_ILLEGAL_INST;
+}
#endif
static RISCVException seed(CPURISCVState *env, int csrno)
@@ -4654,6 +4665,67 @@ static RISCVException write_upmbase(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+static RISCVException read_mnscratch(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mnscratch;
+ return RISCV_EXCP_NONE;
+}
+
+static int write_mnscratch(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->mnscratch = val;
+ return RISCV_EXCP_NONE;
+}
+
+static int read_mnepc(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mnepc;
+ return RISCV_EXCP_NONE;
+}
+
+static int write_mnepc(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->mnepc = val;
+ return RISCV_EXCP_NONE;
+}
+
+static int read_mncause(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mncause;
+ return RISCV_EXCP_NONE;
+}
+
+static int write_mncause(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->mncause = val;
+ return RISCV_EXCP_NONE;
+}
+
+static int read_mnstatus(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mnstatus;
+ return RISCV_EXCP_NONE;
+}
+
+static int write_mnstatus(CPURISCVState *env, int csrno, target_ulong val)
+{
+ target_ulong mask = (MNSTATUS_NMIE | MNSTATUS_MNPP);
+
+ if (riscv_has_ext(env, RVH)) {
+ /* Flush tlb on mnstatus fields that affect VM. */
+ if ((val ^ env->mnstatus) & MNSTATUS_MNPV) {
+ tlb_flush(env_cpu(env));
+ }
+
+ mask |= MNSTATUS_MNPV;
+ }
+
+ /* mnstatus.mnie can only be cleared by hardware. */
+ env->mnstatus = (env->mnstatus & MNSTATUS_NMIE) | (val & mask);
+ return RISCV_EXCP_NONE;
+}
+
#endif
/* Crypto Extension */
@@ -5161,6 +5233,16 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
write_sstateen_1_3,
.min_priv_ver = PRIV_VERSION_1_12_0 },
+ /* RNMI */
+ [CSR_MNSCRATCH] = { "mnscratch", rnmi, read_mnscratch, write_mnscratch,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MNEPC] = { "mnepc", rnmi, read_mnepc, write_mnepc,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MNCAUSE] = { "mncause", rnmi, read_mncause, write_mncause,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MNSTATUS] = { "mnstatus", rnmi, read_mnstatus, write_mnstatus,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+
/* Supervisor Trap Setup */
[CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus,
NULL, read_sstatus_i128 },
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 3/7] target/riscv: Handle Smrnmi interrupt and exception
2024-12-17 6:24 [PATCH v10 0/7] Add Smrnmi support frank.chang
2024-12-17 6:24 ` [PATCH v10 1/7] target/riscv: Add 'ext_smrnmi' in the RISCVCPUConfig frank.chang
2024-12-17 6:24 ` [PATCH v10 2/7] target/riscv: Add Smrnmi CSRs frank.chang
@ 2024-12-17 6:24 ` frank.chang
2024-12-26 12:42 ` Daniel Henrique Barboza
2024-12-17 6:24 ` [PATCH v10 4/7] target/riscv: Add Smrnmi mnret instruction frank.chang
` (3 subsequent siblings)
6 siblings, 1 reply; 14+ messages in thread
From: frank.chang @ 2024-12-17 6:24 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Tommy Wu, Frank Chang
From: Tommy Wu <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>
Signed-off-by: Tommy Wu <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(),
};
@@ -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);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 4/7] target/riscv: Add Smrnmi mnret instruction
2024-12-17 6:24 [PATCH v10 0/7] Add Smrnmi support frank.chang
` (2 preceding siblings ...)
2024-12-17 6:24 ` [PATCH v10 3/7] target/riscv: Handle Smrnmi interrupt and exception frank.chang
@ 2024-12-17 6:24 ` frank.chang
2024-12-26 12:47 ` Daniel Henrique Barboza
2024-12-17 6:24 ` [PATCH v10 5/7] target/riscv: Add Smrnmi cpu extension frank.chang
` (2 subsequent siblings)
6 siblings, 1 reply; 14+ messages in thread
From: frank.chang @ 2024-12-17 6:24 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Tommy Wu, Frank Chang
From: Tommy Wu <tommy.wu@sifive.com>
This patch adds a new instruction 'mnret'. 'mnret' is an M-mode-only
instruction that uses the values in `mnepc` and `mnstatus` to return to the
program counter, privilege mode, and virtualization mode of the
interrupted context.
Signed-off-by: Frank Chang <frank.chang@sifive.com>
Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
---
target/riscv/helper.h | 1 +
target/riscv/insn32.decode | 3 ++
.../riscv/insn_trans/trans_privileged.c.inc | 20 +++++++++
target/riscv/op_helper.c | 45 ++++++++++++++++---
4 files changed, 64 insertions(+), 5 deletions(-)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 451261ce5a..16ea240d26 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -131,6 +131,7 @@ DEF_HELPER_6(csrrw_i128, tl, env, int, tl, tl, tl, tl)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(sret, tl, env)
DEF_HELPER_1(mret, tl, env)
+DEF_HELPER_1(mnret, tl, env)
DEF_HELPER_1(wfi, void, env)
DEF_HELPER_1(wrs_nto, void, env)
DEF_HELPER_1(tlb_flush, void, env)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index e9139ec1b9..942c434c6e 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -121,6 +121,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
{
diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc
index ecd3b8b2c9..73f940d406 100644
--- a/target/riscv/insn_trans/trans_privileged.c.inc
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
@@ -18,6 +18,12 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define REQUIRE_SMRNMI(ctx) do { \
+ if (!ctx->cfg_ptr->ext_smrnmi) { \
+ return false; \
+ } \
+} while (0)
+
static bool trans_ecall(DisasContext *ctx, arg_ecall *a)
{
/* always generates U-level ECALL, fixed in do_interrupt handler */
@@ -106,6 +112,20 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a)
#endif
}
+static bool trans_mnret(DisasContext *ctx, arg_mnret *a)
+{
+#ifndef CONFIG_USER_ONLY
+ REQUIRE_SMRNMI(ctx);
+ decode_save_opc(ctx, 0);
+ gen_helper_mnret(cpu_pc, tcg_env);
+ tcg_gen_exit_tb(NULL, 0); /* 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 eddedacf4b..63ec53e992 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -321,24 +321,30 @@ target_ulong helper_sret(CPURISCVState *env)
return retpc;
}
-target_ulong helper_mret(CPURISCVState *env)
+static void check_ret_from_m_mode(CPURISCVState *env, target_ulong retpc,
+ target_ulong prev_priv)
{
if (!(env->priv >= PRV_M)) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
- target_ulong retpc = env->mepc;
if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
}
- uint64_t mstatus = env->mstatus;
- target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
-
if (riscv_cpu_cfg(env)->pmp &&
!pmp_get_num_rules(env) && (prev_priv != PRV_M)) {
riscv_raise_exception(env, RISCV_EXCP_INST_ACCESS_FAULT, GETPC());
}
+}
+
+target_ulong helper_mret(CPURISCVState *env)
+{
+ target_ulong retpc = env->mepc;
+ uint64_t mstatus = env->mstatus;
+ target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
+
+ check_ret_from_m_mode(env, retpc, prev_priv);
target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV) &&
(prev_priv != PRV_M);
@@ -370,6 +376,35 @@ target_ulong helper_mret(CPURISCVState *env)
return retpc;
}
+target_ulong helper_mnret(CPURISCVState *env)
+{
+ target_ulong retpc = env->mnepc;
+ target_ulong prev_priv = get_field(env->mnstatus, MNSTATUS_MNPP);
+ target_ulong prev_virt;
+
+ check_ret_from_m_mode(env, retpc, prev_priv);
+
+ prev_virt = get_field(env->mnstatus, MNSTATUS_MNPV) &&
+ (prev_priv != PRV_M);
+ env->mnstatus = set_field(env->mnstatus, MNSTATUS_NMIE, true);
+
+ /*
+ * If MNRET changes the privilege mode to a mode
+ * less privileged than M, it also sets mstatus.MPRV to 0.
+ */
+ if (prev_priv < PRV_M) {
+ env->mstatus = set_field(env->mstatus, MSTATUS_MPRV, false);
+ }
+
+ if (riscv_has_ext(env, RVH) && prev_virt) {
+ riscv_cpu_swap_hypervisor_regs(env);
+ }
+
+ riscv_cpu_set_mode(env, prev_priv, prev_virt);
+
+ return retpc;
+}
+
void helper_wfi(CPURISCVState *env)
{
CPUState *cs = env_cpu(env);
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 5/7] target/riscv: Add Smrnmi cpu extension
2024-12-17 6:24 [PATCH v10 0/7] Add Smrnmi support frank.chang
` (3 preceding siblings ...)
2024-12-17 6:24 ` [PATCH v10 4/7] target/riscv: Add Smrnmi mnret instruction frank.chang
@ 2024-12-17 6:24 ` frank.chang
2024-12-26 12:51 ` Daniel Henrique Barboza
2024-12-17 6:24 ` [PATCH v10 6/7] target/riscv: Add Zicfilp support for Smrnmi frank.chang
2024-12-17 6:24 ` [PATCH v10 7/7] target/riscv: Disable Smrnmi for the 'max' type CPU frank.chang
6 siblings, 1 reply; 14+ messages in thread
From: frank.chang @ 2024-12-17 6:24 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Tommy Wu, Frank Chang
From: Tommy Wu <tommy.wu@sifive.com>
This adds the properties for ISA extension Smrnmi.
Signed-off-by: Frank Chang <frank.chang@sifive.com>
Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
---
target/riscv/cpu.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e6988f44c6..7a4aa235ce 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -193,6 +193,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(smaia, PRIV_VERSION_1_12_0, ext_smaia),
ISA_EXT_DATA_ENTRY(smcntrpmf, PRIV_VERSION_1_12_0, ext_smcntrpmf),
ISA_EXT_DATA_ENTRY(smepmp, PRIV_VERSION_1_12_0, ext_smepmp),
+ ISA_EXT_DATA_ENTRY(smrnmi, PRIV_VERSION_1_12_0, ext_smrnmi),
ISA_EXT_DATA_ENTRY(smstateen, PRIV_VERSION_1_12_0, ext_smstateen),
ISA_EXT_DATA_ENTRY(ssaia, PRIV_VERSION_1_12_0, ext_ssaia),
ISA_EXT_DATA_ENTRY(ssccptr, PRIV_VERSION_1_11_0, has_priv_1_11),
@@ -1621,6 +1622,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
MULTI_EXT_CFG_BOOL("smaia", ext_smaia, false),
MULTI_EXT_CFG_BOOL("smepmp", ext_smepmp, false),
+ MULTI_EXT_CFG_BOOL("smrnmi", ext_smrnmi, false),
MULTI_EXT_CFG_BOOL("smstateen", ext_smstateen, false),
MULTI_EXT_CFG_BOOL("ssaia", ext_ssaia, false),
MULTI_EXT_CFG_BOOL("svade", ext_svade, false),
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 6/7] target/riscv: Add Zicfilp support for Smrnmi
2024-12-17 6:24 [PATCH v10 0/7] Add Smrnmi support frank.chang
` (4 preceding siblings ...)
2024-12-17 6:24 ` [PATCH v10 5/7] target/riscv: Add Smrnmi cpu extension frank.chang
@ 2024-12-17 6:24 ` frank.chang
2024-12-26 12:53 ` Daniel Henrique Barboza
2024-12-17 6:24 ` [PATCH v10 7/7] target/riscv: Disable Smrnmi for the 'max' type CPU frank.chang
6 siblings, 1 reply; 14+ messages in thread
From: frank.chang @ 2024-12-17 6:24 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Frank Chang
From: Frank Chang <frank.chang@sifive.com>
Zicfilp extension introduces the MNPELP (bit 9) in mnstatus.
The MNPELP field holds the previous ELP.
When a RNMI trap is delivered, the MNPELP is set to ELP and ELP set
to NO_LP_EXPECTED. Upon a mnret, if the mnstatus.MNPP holds the
value y, then ELP is set to the value of MNPELP if yLPE is 1;
otherwise, it is set to NO_LP_EXPECTED.
Signed-off-by: Frank Chang <frank.chang@sifive.com>
---
target/riscv/cpu_bits.h | 1 +
target/riscv/cpu_helper.c | 11 ++++++++++-
target/riscv/op_helper.c | 9 +++++++++
3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 17787fd693..be9d0f5c05 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -643,6 +643,7 @@ typedef enum {
/* RNMI mnstatus CSR mask */
#define MNSTATUS_NMIE 0x00000008
#define MNSTATUS_MNPV 0x00000080
+#define MNSTATUS_MNPELP 0x00000200
#define MNSTATUS_MNPP 0x00001800
/* VM modes (satp.mode) privileged ISA 1.10 */
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index e5ffbbbd83..1fb1e31031 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1918,6 +1918,10 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->mnepc = env->pc;
env->pc = env->rnmi_irqvec;
+ if (cpu_get_fcfien(env)) {
+ env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, env->elp);
+ }
+
/* Trapping to M mode, virt is disabled */
riscv_cpu_set_mode(env, PRV_M, false);
@@ -2085,7 +2089,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
/* handle the trap in M-mode */
/* save elp status */
if (cpu_get_fcfien(env)) {
- env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, env->elp);
+ if (nnmi_excep) {
+ env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP,
+ env->elp);
+ } else {
+ env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, env->elp);
+ }
}
if (riscv_has_ext(env, RVH)) {
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 63ec53e992..a4b625fcd9 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -402,6 +402,15 @@ target_ulong helper_mnret(CPURISCVState *env)
riscv_cpu_set_mode(env, prev_priv, prev_virt);
+ /*
+ * If forward cfi enabled for new priv, restore elp status
+ * and clear mnpelp in mnstatus
+ */
+ if (cpu_get_fcfien(env)) {
+ env->elp = get_field(env->mnstatus, MNSTATUS_MNPELP);
+ }
+ env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, 0);
+
return retpc;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 7/7] target/riscv: Disable Smrnmi for the 'max' type CPU
2024-12-17 6:24 [PATCH v10 0/7] Add Smrnmi support frank.chang
` (5 preceding siblings ...)
2024-12-17 6:24 ` [PATCH v10 6/7] target/riscv: Add Zicfilp support for Smrnmi frank.chang
@ 2024-12-17 6:24 ` frank.chang
6 siblings, 0 replies; 14+ messages in thread
From: frank.chang @ 2024-12-17 6:24 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Frank Chang
From: Frank Chang <frank.chang@sifive.com>
When Smrnmi is present, the firmware (e.g., OpenSBI) must set
mnstatus.NMIE to 1 before enabling any interrupts. Otherwise, all
interrupts will be disabled. Since our current OpenSBI does not
support Smrnmi yet, let's disable Smrnmi for the 'max' type CPU for
now. We can re-enable it once OpenSBI includes proper support for it.
Signed-off-by: Frank Chang <frank.chang@sifive.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
target/riscv/tcg/tcg-cpu.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 3480767b35..f3fb1c432b 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -1429,6 +1429,12 @@ static void riscv_init_max_cpu_extensions(Object *obj)
if (env->misa_mxl != MXL_RV32) {
isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcf), false);
}
+
+ /*
+ * ext_smrnmi requires OpenSBI changes that our current
+ * image does not have. Disable it for now.
+ */
+ isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_smrnmi), false);
}
static bool riscv_cpu_has_max_extensions(Object *cpu_obj)
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v10 3/7] target/riscv: Handle Smrnmi interrupt and exception
2024-12-17 6:24 ` [PATCH v10 3/7] target/riscv: Handle Smrnmi interrupt and exception frank.chang
@ 2024-12-26 12:42 ` Daniel Henrique Barboza
2024-12-31 3:11 ` Frank Chang
0 siblings, 1 reply; 14+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-26 12:42 UTC (permalink / raw)
To: frank.chang, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li, Liu Zhiwei,
Tommy Wu
On 12/17/24 3:24 AM, frank.chang@sifive.com wrote:
> From: Tommy Wu <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>
> Signed-off-by: Tommy Wu <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.
With that said:
Reviewed-by: Daniel Henrique Barboza <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);
> }
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 4/7] target/riscv: Add Smrnmi mnret instruction
2024-12-17 6:24 ` [PATCH v10 4/7] target/riscv: Add Smrnmi mnret instruction frank.chang
@ 2024-12-26 12:47 ` Daniel Henrique Barboza
0 siblings, 0 replies; 14+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-26 12:47 UTC (permalink / raw)
To: frank.chang, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li, Liu Zhiwei,
Tommy Wu
On 12/17/24 3:24 AM, frank.chang@sifive.com wrote:
> From: Tommy Wu <tommy.wu@sifive.com>
>
> This patch adds a new instruction 'mnret'. 'mnret' is an M-mode-only
> instruction that uses the values in `mnepc` and `mnstatus` to return to the
> program counter, privilege mode, and virtualization mode of the
> interrupted context.
>
> 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>
> target/riscv/helper.h | 1 +
> target/riscv/insn32.decode | 3 ++
> .../riscv/insn_trans/trans_privileged.c.inc | 20 +++++++++
> target/riscv/op_helper.c | 45 ++++++++++++++++---
> 4 files changed, 64 insertions(+), 5 deletions(-)
>
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index 451261ce5a..16ea240d26 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -131,6 +131,7 @@ DEF_HELPER_6(csrrw_i128, tl, env, int, tl, tl, tl, tl)
> #ifndef CONFIG_USER_ONLY
> DEF_HELPER_1(sret, tl, env)
> DEF_HELPER_1(mret, tl, env)
> +DEF_HELPER_1(mnret, tl, env)
> DEF_HELPER_1(wfi, void, env)
> DEF_HELPER_1(wrs_nto, void, env)
> DEF_HELPER_1(tlb_flush, void, env)
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
> index e9139ec1b9..942c434c6e 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -121,6 +121,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
> {
> diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc
> index ecd3b8b2c9..73f940d406 100644
> --- a/target/riscv/insn_trans/trans_privileged.c.inc
> +++ b/target/riscv/insn_trans/trans_privileged.c.inc
> @@ -18,6 +18,12 @@
> * this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> +#define REQUIRE_SMRNMI(ctx) do { \
> + if (!ctx->cfg_ptr->ext_smrnmi) { \
> + return false; \
> + } \
> +} while (0)
> +
> static bool trans_ecall(DisasContext *ctx, arg_ecall *a)
> {
> /* always generates U-level ECALL, fixed in do_interrupt handler */
> @@ -106,6 +112,20 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a)
> #endif
> }
>
> +static bool trans_mnret(DisasContext *ctx, arg_mnret *a)
> +{
> +#ifndef CONFIG_USER_ONLY
> + REQUIRE_SMRNMI(ctx);
> + decode_save_opc(ctx, 0);
> + gen_helper_mnret(cpu_pc, tcg_env);
> + tcg_gen_exit_tb(NULL, 0); /* 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 eddedacf4b..63ec53e992 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -321,24 +321,30 @@ target_ulong helper_sret(CPURISCVState *env)
> return retpc;
> }
>
> -target_ulong helper_mret(CPURISCVState *env)
> +static void check_ret_from_m_mode(CPURISCVState *env, target_ulong retpc,
> + target_ulong prev_priv)
> {
> if (!(env->priv >= PRV_M)) {
> riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
> }
>
> - target_ulong retpc = env->mepc;
> if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
> riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
> }
>
> - uint64_t mstatus = env->mstatus;
> - target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
> -
> if (riscv_cpu_cfg(env)->pmp &&
> !pmp_get_num_rules(env) && (prev_priv != PRV_M)) {
> riscv_raise_exception(env, RISCV_EXCP_INST_ACCESS_FAULT, GETPC());
> }
> +}
> +
> +target_ulong helper_mret(CPURISCVState *env)
> +{
> + target_ulong retpc = env->mepc;
> + uint64_t mstatus = env->mstatus;
> + target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
> +
> + check_ret_from_m_mode(env, retpc, prev_priv);
>
> target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV) &&
> (prev_priv != PRV_M);
> @@ -370,6 +376,35 @@ target_ulong helper_mret(CPURISCVState *env)
> return retpc;
> }
>
> +target_ulong helper_mnret(CPURISCVState *env)
> +{
> + target_ulong retpc = env->mnepc;
> + target_ulong prev_priv = get_field(env->mnstatus, MNSTATUS_MNPP);
> + target_ulong prev_virt;
> +
> + check_ret_from_m_mode(env, retpc, prev_priv);
> +
> + prev_virt = get_field(env->mnstatus, MNSTATUS_MNPV) &&
> + (prev_priv != PRV_M);
> + env->mnstatus = set_field(env->mnstatus, MNSTATUS_NMIE, true);
> +
> + /*
> + * If MNRET changes the privilege mode to a mode
> + * less privileged than M, it also sets mstatus.MPRV to 0.
> + */
> + if (prev_priv < PRV_M) {
> + env->mstatus = set_field(env->mstatus, MSTATUS_MPRV, false);
> + }
> +
> + if (riscv_has_ext(env, RVH) && prev_virt) {
> + riscv_cpu_swap_hypervisor_regs(env);
> + }
> +
> + riscv_cpu_set_mode(env, prev_priv, prev_virt);
> +
> + return retpc;
> +}
> +
> void helper_wfi(CPURISCVState *env)
> {
> CPUState *cs = env_cpu(env);
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 5/7] target/riscv: Add Smrnmi cpu extension
2024-12-17 6:24 ` [PATCH v10 5/7] target/riscv: Add Smrnmi cpu extension frank.chang
@ 2024-12-26 12:51 ` Daniel Henrique Barboza
0 siblings, 0 replies; 14+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-26 12:51 UTC (permalink / raw)
To: frank.chang, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li, Liu Zhiwei,
Tommy Wu
Frank,
I believe patch 7 should be squashed in with this one. This patch will break
'check-functional' because the 'max' CPU isn't able to support Smrnmi and we're
only fixing it 2 patches later. In theory this is fine but it can be problematic
when doing bisecting looking for bugs.
If you merge patch 7 with this patch please also add:
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Thanks,
Daniel
On 12/17/24 3:24 AM, frank.chang@sifive.com wrote:
> From: Tommy Wu <tommy.wu@sifive.com>
>
> This adds the properties for ISA extension Smrnmi.
>
> Signed-off-by: Frank Chang <frank.chang@sifive.com>
> Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
> ---
> target/riscv/cpu.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index e6988f44c6..7a4aa235ce 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -193,6 +193,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
> ISA_EXT_DATA_ENTRY(smaia, PRIV_VERSION_1_12_0, ext_smaia),
> ISA_EXT_DATA_ENTRY(smcntrpmf, PRIV_VERSION_1_12_0, ext_smcntrpmf),
> ISA_EXT_DATA_ENTRY(smepmp, PRIV_VERSION_1_12_0, ext_smepmp),
> + ISA_EXT_DATA_ENTRY(smrnmi, PRIV_VERSION_1_12_0, ext_smrnmi),
> ISA_EXT_DATA_ENTRY(smstateen, PRIV_VERSION_1_12_0, ext_smstateen),
> ISA_EXT_DATA_ENTRY(ssaia, PRIV_VERSION_1_12_0, ext_ssaia),
> ISA_EXT_DATA_ENTRY(ssccptr, PRIV_VERSION_1_11_0, has_priv_1_11),
> @@ -1621,6 +1622,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
>
> MULTI_EXT_CFG_BOOL("smaia", ext_smaia, false),
> MULTI_EXT_CFG_BOOL("smepmp", ext_smepmp, false),
> + MULTI_EXT_CFG_BOOL("smrnmi", ext_smrnmi, false),
> MULTI_EXT_CFG_BOOL("smstateen", ext_smstateen, false),
> MULTI_EXT_CFG_BOOL("ssaia", ext_ssaia, false),
> MULTI_EXT_CFG_BOOL("svade", ext_svade, false),
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 6/7] target/riscv: Add Zicfilp support for Smrnmi
2024-12-17 6:24 ` [PATCH v10 6/7] target/riscv: Add Zicfilp support for Smrnmi frank.chang
@ 2024-12-26 12:53 ` Daniel Henrique Barboza
0 siblings, 0 replies; 14+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-26 12:53 UTC (permalink / raw)
To: frank.chang, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Bin Meng, Weiwei Li, Liu Zhiwei
On 12/17/24 3:24 AM, frank.chang@sifive.com wrote:
> From: Frank Chang <frank.chang@sifive.com>
>
> Zicfilp extension introduces the MNPELP (bit 9) in mnstatus.
> The MNPELP field holds the previous ELP.
>
> When a RNMI trap is delivered, the MNPELP is set to ELP and ELP set
> to NO_LP_EXPECTED. Upon a mnret, if the mnstatus.MNPP holds the
> value y, then ELP is set to the value of MNPELP if yLPE is 1;
> otherwise, it is set to NO_LP_EXPECTED.
>
> Signed-off-by: Frank Chang <frank.chang@sifive.com>
> ---
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> target/riscv/cpu_bits.h | 1 +
> target/riscv/cpu_helper.c | 11 ++++++++++-
> target/riscv/op_helper.c | 9 +++++++++
> 3 files changed, 20 insertions(+), 1 deletion(-)
>
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 17787fd693..be9d0f5c05 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -643,6 +643,7 @@ typedef enum {
> /* RNMI mnstatus CSR mask */
> #define MNSTATUS_NMIE 0x00000008
> #define MNSTATUS_MNPV 0x00000080
> +#define MNSTATUS_MNPELP 0x00000200
> #define MNSTATUS_MNPP 0x00001800
>
> /* VM modes (satp.mode) privileged ISA 1.10 */
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index e5ffbbbd83..1fb1e31031 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -1918,6 +1918,10 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> env->mnepc = env->pc;
> env->pc = env->rnmi_irqvec;
>
> + if (cpu_get_fcfien(env)) {
> + env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, env->elp);
> + }
> +
> /* Trapping to M mode, virt is disabled */
> riscv_cpu_set_mode(env, PRV_M, false);
>
> @@ -2085,7 +2089,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> /* handle the trap in M-mode */
> /* save elp status */
> if (cpu_get_fcfien(env)) {
> - env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, env->elp);
> + if (nnmi_excep) {
> + env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP,
> + env->elp);
> + } else {
> + env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, env->elp);
> + }
> }
>
> if (riscv_has_ext(env, RVH)) {
> diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> index 63ec53e992..a4b625fcd9 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -402,6 +402,15 @@ target_ulong helper_mnret(CPURISCVState *env)
>
> riscv_cpu_set_mode(env, prev_priv, prev_virt);
>
> + /*
> + * If forward cfi enabled for new priv, restore elp status
> + * and clear mnpelp in mnstatus
> + */
> + if (cpu_get_fcfien(env)) {
> + env->elp = get_field(env->mnstatus, MNSTATUS_MNPELP);
> + }
> + env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, 0);
> +
> return retpc;
> }
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 3/7] target/riscv: Handle Smrnmi interrupt and exception
2024-12-26 12:42 ` Daniel Henrique Barboza
@ 2024-12-31 3:11 ` Frank Chang
2024-12-31 9:19 ` Daniel Henrique Barboza
0 siblings, 1 reply; 14+ messages in thread
From: Frank Chang @ 2024-12-31 3:11 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, Palmer Dabbelt, Alistair Francis,
Bin Meng, Weiwei Li, Liu Zhiwei, Tommy Wu
[-- Attachment #1: Type: text/plain, Size: 15114 bytes --]
On Thu, Dec 26, 2024 at 8:42 PM Daniel Henrique Barboza <
dbarboza@ventanamicro.com> wrote:
>
>
> On 12/17/24 3:24 AM, frank.chang@sifive.com wrote:
> > From: Tommy Wu <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>
> > Signed-off-by: Tommy Wu <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.
Regards,
Frank Chang
>
> With that said:
>
> Reviewed-by: Daniel Henrique Barboza <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);
> > }
> >
>
>
[-- Attachment #2: Type: text/html, Size: 19478 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 3/7] target/riscv: Handle Smrnmi interrupt and exception
2024-12-31 3:11 ` Frank Chang
@ 2024-12-31 9:19 ` Daniel Henrique Barboza
0 siblings, 0 replies; 14+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-31 9:19 UTC (permalink / raw)
To: Frank Chang
Cc: qemu-devel, qemu-riscv, Palmer Dabbelt, Alistair Francis,
Bin Meng, Weiwei Li, Liu Zhiwei, Tommy Wu
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);
> > }
> >
>
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2024-12-31 9:20 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-17 6:24 [PATCH v10 0/7] Add Smrnmi support frank.chang
2024-12-17 6:24 ` [PATCH v10 1/7] target/riscv: Add 'ext_smrnmi' in the RISCVCPUConfig frank.chang
2024-12-17 6:24 ` [PATCH v10 2/7] target/riscv: Add Smrnmi CSRs frank.chang
2024-12-17 6:24 ` [PATCH v10 3/7] target/riscv: Handle Smrnmi interrupt and exception frank.chang
2024-12-26 12:42 ` Daniel Henrique Barboza
2024-12-31 3:11 ` Frank Chang
2024-12-31 9:19 ` Daniel Henrique Barboza
2024-12-17 6:24 ` [PATCH v10 4/7] target/riscv: Add Smrnmi mnret instruction frank.chang
2024-12-26 12:47 ` Daniel Henrique Barboza
2024-12-17 6:24 ` [PATCH v10 5/7] target/riscv: Add Smrnmi cpu extension frank.chang
2024-12-26 12:51 ` Daniel Henrique Barboza
2024-12-17 6:24 ` [PATCH v10 6/7] target/riscv: Add Zicfilp support for Smrnmi frank.chang
2024-12-26 12:53 ` Daniel Henrique Barboza
2024-12-17 6:24 ` [PATCH v10 7/7] target/riscv: Disable Smrnmi for the 'max' type CPU frank.chang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.